Project

General

Profile

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

    
28
/* include all configuration functions */
29
require_once("globals.inc");
30
require_once("util.inc");
31
require_once("gwlb.inc");
32
require_once("ipsec.inc");
33
require_once("vpn.inc");
34

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

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

    
50
	if (empty($value)) {
51
		return false;
52
	}
53

    
54
	$list = explode(',', $value);
55

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

    
62
	return true;
63
}
64

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

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

    
76
	return $interface_arr_cache;
77
}
78

    
79
/*
80
 * does_interface_exist($interface): return true or false if a interface is
81
 * detected.
82
 */
83
function does_interface_exist($interface, $flush = false) {
84
	global $config;
85

    
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
	global $config;
104

    
105
	if (!$vip) {
106
		return false;
107
	}
108

    
109

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

    
125
	$ifacedata = pfSense_getall_interface_addresses($realif);
126

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

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

    
143
	return false;
144
}
145

    
146
function interfaces_loopback_configure() {
147
	global $g;
148

    
149
	if (platform_booting()) {
150
		echo gettext("Configuring loopback interface...");
151
		mute_kernel_msgs();
152
	}
153
	pfSense_interface_setaddress("lo0", "127.0.0.1");
154
	interfaces_bring_up("lo0");
155
	if (platform_booting()) {
156
		unmute_kernel_msgs();
157
		echo gettext("done.") . "\n";
158
	}
159
	return 0;
160
}
161

    
162
function vlan_valid_tag($tag = NULL) {
163

    
164
	if ($tag == NULL || empty($tag) ||
165
	    !is_numericint($tag) || intval($tag) < 1 || intval($tag) > 4094) {
166
		return (false);
167
	}
168
	return (true);
169
}
170

    
171
function qinq_inuse($qinq = NULL, $inqtag = NULL) {
172
        global $config;
173

    
174
	if ($qinq == NULL || $inqtag == NULL ||
175
	    !is_array($qinq) || !vlan_valid_tag($inqtag)) {
176
		return (false);
177
	}
178

    
179
        $iflist = get_configured_interface_list(true);
180
        foreach ($iflist as $if) {
181
                if ($config['interfaces'][$if]['if'] == qinq_interface($qinq, $inqtag)) {
182
                        return (true);
183
                }
184
        }
185

    
186
        return (false);
187
}
188

    
189
function qinq_interface($qinq = NULL, $inqtag = NULL) {
190

    
191
	if ($qinq == NULL || $inqtag == NULL || !is_array($qinq) ||
192
	    !isset($qinq['if']) || !isset($qinq['tag']) ||
193
	    !vlan_valid_tag($qinq['tag']) || !vlan_valid_tag($inqtag)) {
194
		return (NULL);
195
	}
196
	return ("{$qinq['if']}.{$qinq['tag']}.{$inqtag}");
197
}
198

    
199
function interface_is_qinq($if = NULL) {
200
	global $config;
201

    
202
	if ($if == NULL || empty($if) || !is_array($config['qinqs']['qinqentry'])) {
203
		return (NULL);
204
	}
205

    
206
	/* Check basic format. */
207
	list($qinqif, $vlantag, $inqtag) = explode(".", $if);
208
	if (empty($qinqif) || empty($vlantag) || empty($inqtag) ||
209
	    !vlan_valid_tag($vlantag) || !vlan_valid_tag($inqtag)) {
210
		return (NULL);
211
	}
212

    
213
	foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
214
		if ("{$qinqif}.{$vlantag}" != $qinq['vlanif']) {
215
			continue;
216
		}
217
		if (empty($qinq['members'])) {
218
			continue;
219
		}
220
		foreach (explode(" ", $qinq['members']) as $tag) {
221
			if ($if == qinq_interface($qinq, $tag)) {
222
				return ($qinq);
223
			}
224
		}
225
	}
226

    
227
	return (NULL);
228
}
229

    
230
function vlan_inuse($vlan) {
231
	global $config;
232

    
233
	if ($vlan == NULL || !is_array($vlan)) {
234
		return (false);
235
	}
236

    
237
	$iflist = get_configured_interface_list(true);
238
	foreach ($iflist as $if) {
239
		if ($config['interfaces'][$if]['if'] == $vlan['vlanif']) {
240
			return (true);
241
		}
242
	}
243

    
244
	return (false);
245
}
246

    
247
function interface_is_vlan($if = NULL) {
248
	global $config;
249

    
250
	if ($if == NULL || empty($if) || is_array($if)) {
251
		return (NULL);
252
	}
253

    
254
	/* Check basic format. */
255
	list($vlanif, $vlantag) = explode(".", $if);
256
	if (empty($vlanif) || empty($vlantag) || !vlan_valid_tag($vlantag)) {
257
		return (NULL);
258
	}
259

    
260
	/* Find the VLAN interface. */
261
	if (isset($config['vlans']['vlan']) && is_array($config['vlans']['vlan'])) {
262
		foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
263
			if ($if == $vlan['vlanif']) {
264
				return ($vlan);
265
			}
266
		}
267
	}
268

    
269
	/* Check for the first level tag in QinQ interfaces. */
270
	if (isset($config['qinqs']['qinqentry']) && is_array($config['qinqs']['qinqentry'])) {
271
		foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
272
			if ($if == $qinq['vlanif']) {
273
				return ($qinq);
274
			}
275
		}
276
	}
277

    
278
	return (NULL);
279
}
280

    
281
function vlan_interface($vlan = NULL) {
282
	if ($vlan == NULL || !is_array($vlan) || !isset($vlan['if']) ||
283
	    !isset($vlan['tag']) || !vlan_valid_tag($vlan['tag'])) {
284
		return (NULL);
285
	}
286
	return ("{$vlan['if']}.{$vlan['tag']}");
287
}
288

    
289
function interface_set_macaddr($interface, $mac_addr) {
290
	if (empty($mac_addr) || !is_macaddr($mac_addr)) {
291
		return;
292
	}
293

    
294
	$current_mac = get_interface_mac($interface);
295

    
296
	/*
297
	 * Don't try to reapply the MAC if it's already applied.
298
	 * When ifconfig link is used, it cycles the interface down/up, which
299
	 * triggers the interface config again, which attempts to apply the
300
	 * MAC again, which cycles the link again...
301
	 */
302
	if ($mac_addr != $current_mac) {
303
		mwexec("/sbin/ifconfig " . escapeshellarg($interface) .
304
		    " link " . escapeshellarg($mac_addr));
305
	}
306
}
307

    
308
function interface_is_parent($if, $parent_check) {
309

    
310
	$parent_array = get_parent_interface($if);
311
	if (count($parent_array) > 1) {
312
		$parent = $parent_array;
313
	} else {
314
		$parent = $parent_array[0];
315
	}
316
	if (is_array($parent)) {
317
		foreach ($parent as $parentif) {
318
			if (strcasecmp($parent_check, $parentif) == 0) {
319
				return (TRUE);
320
			}
321
		}
322
	} else {
323
		$realif = get_real_interface($parent);
324
		if (strcasecmp($parent_check, $realif) == 0) {
325
			return (TRUE);
326
		}
327
	}
328
	return (FALSE);
329
}
330

    
331
function interface_has_clones($if) {
332
	global $config;
333

    
334
	/* Check LAGGs. */
335
	if (isset($config['laggs']) && isset($config['laggs']['lagg']) &&
336
	    is_array($config['laggs']['lagg'])) {
337
		foreach ($config['laggs']['lagg'] as $lagg) {
338
			if (interface_is_parent($lagg['laggif'], $if)) {
339
				return (TRUE);
340
			}
341
		}
342
	}
343
	/* Check VLANs. */
344
	if (isset($config['vlans']) && isset($config['vlans']['vlan']) &&
345
	    is_array($config['vlans']['vlan'])) {
346
		foreach ($config['vlans']['vlan'] as $vlan) {
347
			if (interface_is_parent($vlan['if'], $if)) {
348
				return (TRUE);
349
			}
350
		}
351
	}
352
	/* Check bridges. */
353
	if (isset($config['bridges']) && isset($config['bridges']['bridged']) &&
354
	    is_array($config['bridges']['bridged'])) {
355
		foreach ($config['bridges']['bridged'] as $bridge) {
356
			$members = explode(',', $bridge['members']);
357
			foreach ($members as $member) {
358
				if (interface_is_parent($member, $if)) {
359
					return (TRUE);
360
				}
361
			}
362
		}
363
	}
364

    
365
	return (FALSE);
366
}
367

    
368
function interfaces_vlan_configure($parentif = "") {
369
	global $config, $g;
370
	$dhcp6c_list = array();
371

    
372
	if (is_array($config['vlans']['vlan']) &&
373
	    count($config['vlans']['vlan'])) {
374
		if (platform_booting()) {
375
			echo gettext("Configuring VLAN interfaces...");
376
		}
377
		foreach ($config['vlans']['vlan'] as $vlan) {
378
			if (empty($vlan['vlanif'])) {
379
				$vlan['vlanif'] = vlan_interface($vlan);
380
			}
381
			if (!empty($parentif) && ($parentif != $vlan['if'])) {
382
				continue;
383
			}
384
			/* configure dhcp6 enabled VLAN interfaces later
385
			 * see https://redmine.pfsense.org/issues/3965 */
386
			$if = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
387
			if (!empty($config['interfaces'][$if]['ipaddrv6']) &&
388
			    $config['interfaces'][$if]['ipaddrv6'] == "dhcp6") {
389
				$dhcp6c_list[$if] = $vlan;
390
				continue;
391
			}
392

    
393
			/* XXX: Maybe we should report any errors?! */
394
			interface_vlan_configure($vlan, false);
395
		}
396
		foreach ($dhcp6c_list as $if => $vlan) {
397
			interface_vlan_configure($vlan, false);
398
		}
399
		/* Invalidate cache */
400
		get_interface_arr(true);
401
		if (platform_booting()) {
402
			echo gettext("done.") . "\n";
403
		}
404
	}
405
}
406

    
407
function interface_vlan_configure(&$vlan, $flush = true) {
408
	global $config, $g;
409

    
410
	if (!is_array($vlan)) {
411
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
412
		return(NULL);
413
	}
414
	$if = $vlan['if'];
415
	if (empty($if)) {
416
		log_error(gettext("interface_vlan_configure called with if undefined."));
417
		return(NULL);
418
	}
419

    
420
	$vlanif = empty($vlan['vlanif']) ? vlan_interface($vlan) : $vlan['vlanif'];
421
	if ($vlanif == NULL) {
422
		log_error(gettext("vlan_interface called with if undefined var."));
423
		return(NULL);
424
	}
425
	$tag = $vlan['tag'];
426
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
427

    
428
	/* make sure the parent interface is up */
429
	interfaces_bring_up($if);
430
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
431
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
432

    
433
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
434
		pfSense_interface_destroy($vlanif);
435
	}
436

    
437
	$tmpvlanif = pfSense_interface_create2("vlan");
438
	pfSense_interface_rename($tmpvlanif, $vlanif);
439
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
440

    
441
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
442

    
443
	interfaces_bring_up($vlanif);
444

    
445
	/* invalidate interface cache */
446
	if ($flush) {
447
		get_interface_arr(true);
448
	}
449

    
450
	/* configure interface if assigned */
451
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
452
	if ($assignedif) {
453
		if (isset($config['interfaces'][$assignedif]['enable'])) {
454
			interface_configure($assignedif, true);
455
		}
456
	}
457

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

    
461
	if (interface_vlan_mtu_configured($vlanif)) {
462
		set_interface_mtu($vlanif, interface_vlan_mtu_configured($vlanif));
463
	}
464

    
465
	return $vlanif;
466
}
467

    
468
/*
469
 * reconfigure VLAN childs interfaces after MTU changes, see
470
 * https://redmine.pfsense.org/issues/11035
471
 */
472
function interfaces_vlan_configure_mtu($parentif = "") {
473
	global $config;
474

    
475
	init_config_arr(array('ppps', 'ppp'));
476
	if (!is_array($config['vlans']['vlan']) ||
477
	    !count($config['vlans']['vlan'])) {
478
		return;
479
	}
480

    
481
	foreach ($config['vlans']['vlan'] as $vlan) {
482
		if ($parentif != $vlan['if']) {
483
			continue;
484
		}
485
		if (interface_vlan_mtu_configured($vlan['vlanif'])) {
486
		       set_interface_mtu($vlan['vlanif'],
487
			   interface_vlan_mtu_configured($vlan['vlanif']));
488
		}
489
		if (empty($config['ppps']['ppp'])) {
490
			continue;
491
		}
492
		// PPP interfaces must be restarted to adjust MTU changes
493
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
494
			$ports = explode(',', $ppp['ports']);
495
			foreach ($ports as $pid => $port) {
496
				if ($port != $vlan['vlanif']) {
497
					continue;
498
				}
499
				$confif = convert_real_interface_to_friendly_interface_name($ppp['if']);
500
				interface_configure($confif);
501
			}
502
		}
503
	}
504
}
505

    
506
function interface_qinq_configure(&$qinq, $fd = NULL, $flush = true) {
507
	global $config, $g;
508

    
509
	if (!is_array($qinq)) {
510
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
511
		return;
512
	}
513

    
514
	$qinqif = $qinq['if'];
515
	$tag = $qinq['tag'];
516
	if (empty($qinqif)) {
517
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
518
		return;
519
	}
520

    
521
	if (!does_interface_exist($qinqif)) {
522
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
523
		return;
524
	}
525

    
526
	$vlanif = interface_vlan_configure($qinq);
527
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
528
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
529
		return;
530
	}
531

    
532
	if ($fd == NULL) {
533
		$exec = true;
534
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
535
	} else {
536
		$exec = false;
537
	}
538
	/* make sure the parent is converted to ng_vlan(4) and is up */
539
	interfaces_bring_up($qinqif);
540

    
541
	$ngif = str_replace(".", "_", $vlanif);
542
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
543
		exec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1");
544
		exec("/usr/sbin/ngctl msg {$ngif}qinq: gettable > /dev/null 2>&1", $result);
545
		if (empty($result)) {
546
			fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
547
			fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
548
			fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
549
		}
550
	} else {
551
		fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
552
		fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
553
		fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
554
	}
555

    
556
	/* invalidate interface cache */
557
	if ($flush) {
558
		get_interface_arr(true);
559
	}
560

    
561
	if (interface_is_vlan($qinqif) == NULL) {
562
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
563
	}
564

    
565
	$macaddr = get_interface_mac($qinqif);
566
	if (!empty($qinq['members'])) {
567
		$qinqcmdbuf = "";
568
		$members = explode(" ", $qinq['members']);
569
		foreach ($members as $qtag) {
570
			$qinq2 = array();
571
			$qinq2['tag'] = $qtag;
572
			$qinq2['if'] = $vlanif;
573
			interface_qinq2_configure($qinq2, $qinqcmdbuf, $macaddr,
574
			    false);
575
			unset($qinq2);
576
		}
577
		if (strlen($qinqcmdbuf) > 0) {
578
			fwrite($fd, $qinqcmdbuf);
579
		}
580
	}
581
	if ($exec == true) {
582
		fclose($fd);
583
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd > /dev/null 2>&1");
584
	}
585

    
586
	interfaces_bring_up($qinqif);
587
	if (!empty($qinq['members'])) {
588
		$members = explode(" ", $qinq['members']);
589
		foreach ($members as $qtag) {
590
			interfaces_bring_up(qinq_interface($qinq, $qtag));
591
		}
592
	}
593

    
594
	return $vlanif;
595
}
596

    
597
function interfaces_qinq_configure($ovpn=false) {
598
	global $config, $g;
599

    
600
	if (is_array($config['qinqs']['qinqentry']) &&
601
	    count($config['qinqs']['qinqentry'])) {
602
		if (platform_booting() && $ovpn) {
603
			echo gettext("Configuring OpenVPN QinQ interfaces...");
604
		} elseif (platform_booting()) {
605
			echo gettext("Configuring QinQ interfaces...");
606
		}
607
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
608
			if (($ovpn && strstr($qinq['if'], "ovpn")) ||
609
			    (!$ovpn && !strstr($qinq['if'], "ovpn"))) {
610
				interface_qinq_configure($qinq, NULL, false);
611
			}
612
		}
613
		/* Invalidate cache */
614
		get_interface_arr(true);
615
		if (platform_booting()) {
616
			echo gettext("done.") . "\n";
617
		}
618
	}
619
}
620

    
621
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr, $flush = true) {
622
	global $config, $g;
623

    
624
	if (!is_array($qinq)) {
625
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
626
		return;
627
	}
628

    
629
	$if = $qinq['if'];
630
	if (empty($if)) {
631
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
632
		return;
633
	}
634
	$tag = $qinq['tag'];
635
	$vlanif = "{$if}.{$tag}";
636
	$ngif = str_replace(".", "_", $if);
637
	if (strlen($vlanif) > IF_NAMESIZE) {
638
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
639
		    $vlanif, IF_NAMESIZE, "\n"));
640
		return;
641
	}
642

    
643
	exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1");
644
	$cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n";
645
	$cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n";
646
	$cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n";
647
	$cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n";
648
	$cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n";
649

    
650
	/* invalidate interface cache */
651
	if ($flush) {
652
		get_interface_arr(true);
653
	}
654

    
655
	return $vlanif;
656
}
657

    
658
function interfaces_create_wireless_clones() {
659
	global $config, $g;
660

    
661
	$iflist = get_configured_interface_list();
662

    
663
	foreach ($iflist as $if) {
664
		$realif = $config['interfaces'][$if]['if'];
665
		if (!is_interface_wireless($realif)) {
666
			continue;
667
		}
668
		interface_wireless_clone(interface_get_wireless_clone($realif),
669
		    $config['interfaces'][$if]);
670
	}
671

    
672
	if (isset($config['wireless']['clone']) &&
673
	    is_array($config['wireless']['clone']) &&
674
	    count($config['wireless']['clone'])) {
675
		if (platform_booting()) {
676
			echo gettext("Creating wireless clone interfaces...");
677
		}
678
		/* Invalidate cache */
679
		get_interface_arr(true);
680
		foreach ($config['wireless']['clone'] as $clone) {
681
			if (empty($clone['cloneif'])) {
682
				continue;
683
			}
684
			if (does_interface_exist($clone['cloneif'])) {
685
				continue;
686
			}
687
			/* XXX: Maybe we should report any errors?! */
688
			interface_wireless_clone($clone['cloneif'], $clone);
689
		}
690
		if (platform_booting()) {
691
			echo gettext("done.") . "\n";
692
		}
693
	}
694
}
695

    
696
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
697
	global $config;
698

    
699
	if (!isset($config['bridges']['bridged']) ||
700
	    !is_array($config['bridges']['bridged']) ||
701
	    !count($config['bridges']['bridged'])) {
702
		return;
703
	}
704

    
705
	$i = 0;
706
	foreach ($config['bridges']['bridged'] as $bridge) {
707
		if (empty($bridge['bridgeif'])) {
708
			$bridge['bridgeif'] = "bridge{$i}";
709
		}
710
		if (!empty($realif) && ($realif != $bridge['bridgeif'])) {
711
			continue;
712
		}
713
		$ifname = false;
714
		foreach ($config['interfaces'] as $intname => $intpar) {
715
			if ($intpar['if'] == $bridge['bridgeif']) {
716
				$ifname = $intname;
717
				break;
718
			}
719
		}
720

    
721
		if ($ifname && ($config['interfaces'][$ifname]['ipaddrv6'] == "track6")) {
722
			if ($checkmember == 1) {
723
				continue;
724
			} else {
725
				$checkmember = 0;
726
			}
727
		} elseif (($checkmember == 2) && !$ifname) {
728
			continue;
729
		}
730

    
731
		/* XXX: Maybe we should report any errors?! */
732
		interface_bridge_configure($bridge, $checkmember, false);
733
		$i++;
734
	}
735

    
736
	/* Invalidate cache */
737
	get_interface_arr(true);
738
}
739

    
740
function interface_bridge_configure(&$bridge, $checkmember = 0, $flush = true) {
741
	global $config, $g;
742

    
743
	if (!is_array($bridge)) {
744
		return;
745
	}
746

    
747
	if (empty($bridge['members'])) {
748
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
749
		return;
750
	}
751

    
752
	$members = explode(',', $bridge['members']);
753
	if (!count($members)) {
754
		return;
755
	}
756

    
757
	/* Calculate smaller mtu and enforce it */
758
	$smallermtu = 0;
759
	$foundgif = false;
760
	foreach ($members as $member) {
761
		$realif = get_real_interface($member);
762
		$mtu = get_interface_mtu($realif);
763
		if (substr($realif, 0, 3) == "gif") {
764
			$foundgif = true;
765
			if ($checkmember == 1) {
766
				return;
767
			}
768
			if ($mtu <= 1500) {
769
				continue;
770
			}
771
		}
772
		if ($smallermtu == 0 && !empty($mtu)) {
773
			$smallermtu = $mtu;
774
		} elseif (!empty($mtu) && $mtu < $smallermtu) {
775
			$smallermtu = $mtu;
776
		}
777
	}
778
	if ($foundgif == false && $checkmember == 2) {
779
		return;
780
	}
781

    
782
	/* Just in case anything is not working well */
783
	if ($smallermtu == 0) {
784
		$smallermtu = 1500;
785
	}
786

    
787
	if (!empty($bridge['bridgeif'])) {
788
		pfSense_interface_destroy($bridge['bridgeif']);
789
		pfSense_interface_create2($bridge['bridgeif']);
790
		$bridgeif = escapeshellarg($bridge['bridgeif']);
791
	} else {
792
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
793
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
794
		$bridgeif = pfSense_interface_create2("bridge");
795
		$bridge['bridgeif'] = $bridgeif;
796
	}
797

    
798
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
799
	if ($bridgemtu > $smallermtu) {
800
		$smallermtu = $bridgemtu;
801
	}
802

    
803
	$checklist = get_configured_interface_list();
804

    
805
	/* Add interfaces to bridge */
806
	foreach ($members as $member) {
807
		if (empty($checklist[$member])) {
808
			continue;
809
		}
810
		$realif = get_real_interface($member);
811
		if (!$realif) {
812
			log_error(gettext("realif not defined in interfaces bridge - up"));
813
			continue;
814
		}
815
		/* make sure the parent interface is up */
816
		pfSense_interface_mtu($realif, $smallermtu);
817
		interfaces_bring_up($realif);
818
		enable_hardware_offloading($member);
819
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
820
	}
821

    
822
	if (isset($bridge['enablestp'])) {
823
		interface_bridge_configure_stp($bridge);
824
	}
825

    
826
	interface_bridge_configure_advanced($bridge);
827

    
828
	interface_bridge_configure_ip6linklocal($bridge);
829

    
830
	if ($flush) {
831
		get_interface_arr(true);
832
	}
833

    
834
	if ($bridge['bridgeif']) {
835
		interfaces_bring_up($bridge['bridgeif']);
836
	} else {
837
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
838
	}
839
}
840

    
841
function interface_bridge_configure_stp($bridge) {
842
	if (isset($bridge['enablestp'])) {
843
		$bridgeif = trim($bridge['bridgeif']);
844
		/* configure spanning tree proto */
845
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
846

    
847
		if (!empty($bridge['stp'])) {
848
			$stpifs = explode(',', $bridge['stp']);
849
			foreach ($stpifs as $stpif) {
850
				$realif = get_real_interface($stpif);
851
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
852
			}
853
		}
854
		if (!empty($bridge['maxage'])) {
855
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
856
		}
857
		if (!empty($bridge['fwdelay'])) {
858
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
859
		}
860
		if (!empty($bridge['hellotime'])) {
861
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
862
		}
863
		if (!empty($bridge['priority'])) {
864
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
865
		}
866
		if (!empty($bridge['holdcnt'])) {
867
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
868
		}
869
		if (!empty($bridge['ifpriority'])) {
870
			$pconfig = explode(",", $bridge['ifpriority']);
871
			$ifpriority = array();
872
			foreach ($pconfig as $cfg) {
873
				$embcfg = explode_assoc(":", $cfg);
874
				foreach ($embcfg as $key => $value) {
875
					$ifpriority[$key] = $value;
876
				}
877
			}
878
			foreach ($ifpriority as $key => $value) {
879
				$realif = get_real_interface($key);
880
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
881
			}
882
		}
883
		if (!empty($bridge['ifpathcost'])) {
884
			$pconfig = explode(",", $bridge['ifpathcost']);
885
			$ifpathcost = array();
886
			foreach ($pconfig as $cfg) {
887
				$embcfg = explode_assoc(":", $cfg);
888
				foreach ($embcfg as $key => $value) {
889
					$ifpathcost[$key] = $value;
890
				}
891
			}
892
			foreach ($ifpathcost as $key => $value) {
893
				$realif = get_real_interface($key);
894
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
895
			}
896
		}
897
	}
898
}
899

    
900
function interface_bridge_configure_advanced($bridge) {
901
	$bridgeif = trim($bridge['bridgeif']);
902

    
903
	if ($bridge['maxaddr'] <> "") {
904
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
905
	}
906
	if ($bridge['timeout'] <> "") {
907
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
908
	}
909
	if (!empty($bridge['span'])) {
910
		$spanifs = explode(",", $bridge['span']);
911
		foreach ($spanifs as $spanif) {
912
			$realif = get_real_interface($spanif);
913
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
914
		}
915
	}
916
	if (!empty($bridge['edge'])) {
917
		$edgeifs = explode(',', $bridge['edge']);
918
		foreach ($edgeifs as $edgeif) {
919
			$realif = get_real_interface($edgeif);
920
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
921
		}
922
	}
923
	if (!empty($bridge['autoedge'])) {
924
		$edgeifs = explode(',', $bridge['autoedge']);
925
		foreach ($edgeifs as $edgeif) {
926
			$realif = get_real_interface($edgeif);
927
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
928
		}
929
	}
930
	if (!empty($bridge['ptp'])) {
931
		$ptpifs = explode(',', $bridge['ptp']);
932
		foreach ($ptpifs as $ptpif) {
933
			$realif = get_real_interface($ptpif);
934
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
935
		}
936
	}
937
	if (!empty($bridge['autoptp'])) {
938
		$ptpifs = explode(',', $bridge['autoptp']);
939
		foreach ($ptpifs as $ptpif) {
940
			$realif = get_real_interface($ptpif);
941
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
942
		}
943
	}
944
	if (!empty($bridge['static'])) {
945
		$stickyifs = explode(',', $bridge['static']);
946
		foreach ($stickyifs as $stickyif) {
947
			$realif = get_real_interface($stickyif);
948
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
949
		}
950
	}
951
	if (!empty($bridge['private'])) {
952
		$privateifs = explode(',', $bridge['private']);
953
		foreach ($privateifs as $privateif) {
954
			$realif = get_real_interface($privateif);
955
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
956
		}
957
	}
958
}
959

    
960
function interface_bridge_configure_ip6linklocal($bridge) {
961
	$bridgeif = trim($bridge['bridgeif']);
962

    
963
	$members = explode(',', $bridge['members']);
964
	if (!count($members)) {
965
		return;
966
	}
967

    
968
	$auto_linklocal = isset($bridge['ip6linklocal']);
969
	$bridgeop = $auto_linklocal ? '' : '-';
970
	$memberop = $auto_linklocal ? '-' : '';
971

    
972
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
973
	foreach ($members as $member) {
974
		$realif = get_real_interface($member);
975
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
976
	}
977
}
978

    
979
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
980
	global $config;
981

    
982
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
983
		return;
984
	}
985

    
986
	if ($flagsapplied == false) {
987
		$mtu = get_interface_mtu($bridgeif);
988
		$mtum = get_interface_mtu($interface);
989
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
990
			pfSense_interface_mtu($interface, $mtu);
991
		}
992

    
993
		hardware_offloading_applyflags($interface);
994
		interfaces_bring_up($interface);
995
	}
996

    
997
	pfSense_bridge_add_member($bridgeif, $interface);
998
	if (is_array($config['bridges']['bridged'])) {
999
		foreach ($config['bridges']['bridged'] as $bridge) {
1000
			if ($bridgeif == $bridge['bridgeif']) {
1001
				interface_bridge_configure_stp($bridge);
1002
				interface_bridge_configure_advanced($bridge);
1003
			}
1004
		}
1005
	}
1006
}
1007

    
1008
function interfaces_lagg_configure($realif = "") {
1009
	global $config, $g;
1010
	$i = 0;
1011
	if (is_array($config['laggs']['lagg']) &&
1012
	    count($config['laggs']['lagg'])) {
1013
		if (platform_booting()) {
1014
			echo gettext("Configuring LAGG interfaces...");
1015
		}
1016
		foreach ($config['laggs']['lagg'] as $lagg) {
1017
			if (empty($lagg['laggif'])) {
1018
				$lagg['laggif'] = "lagg{$i}";
1019
			}
1020
			if (!empty($realif) && $realif != $lagg['laggif']) {
1021
				continue;
1022
			}
1023
			/* XXX: Maybe we should report any errors?! */
1024
			interface_lagg_configure($lagg, false);
1025
			$i++;
1026
		}
1027
		/* Invalidate cache */
1028
		get_interface_arr(true);
1029
		if (platform_booting()) {
1030
			echo gettext("done.") . "\n";
1031
		}
1032
	}
1033
}
1034

    
1035
function interface_lagg_configure($lagg, $flush = true) {
1036
	global $config, $g;
1037

    
1038
	if (!is_array($lagg)) {
1039
		return -1;
1040
	}
1041

    
1042
	$members = explode(',', $lagg['members']);
1043
	if (!count($members)) {
1044
		return -1;
1045
	}
1046

    
1047
	if (platform_booting() || !(empty($lagg['laggif']))) {
1048
		pfSense_interface_destroy($lagg['laggif']);
1049
		pfSense_interface_create2($lagg['laggif']);
1050
		$laggif = $lagg['laggif'];
1051
	} else {
1052
		$laggif = pfSense_interface_create2("lagg");
1053
	}
1054

    
1055
	/* Check if MTU was defined for this lagg interface */
1056
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
1057
	if ($lagg_mtu == 0 &&
1058
	    is_array($config['interfaces'])) {
1059
		foreach ($config['interfaces'] as $tmpinterface) {
1060
			if ($tmpinterface['if'] == $lagg['laggif'] &&
1061
			    !empty($tmpinterface['mtu'])) {
1062
				$lagg_mtu = $tmpinterface['mtu'];
1063
				break;
1064
			}
1065
		}
1066
	}
1067

    
1068
	/* Just in case anything is not working well */
1069
	if ($lagg_mtu == 0) {
1070
		$lagg_mtu = 1500;
1071
	}
1072

    
1073
	// put failover master interface on top of list
1074
	if (($lagg['proto'] == 'failover') && isset($lagg['failovermaster']) &&
1075
	    ($lagg['failovermaster'] != 'auto')) {
1076
		unset($members[array_search($lagg['failovermaster'], $members)]);
1077
		$members = array_merge(array($lagg['failovermaster']), $members);
1078
	}
1079

    
1080
	if (($lagg['proto'] == 'lacp') && isset($lagg['lacptimeout']) &&
1081
	    ($lagg['lacptimeout'] != 'slow')) {
1082
		$lacptimeout = 'lacp_fast_timeout';
1083
	} else {
1084
		$lacptimeout = '';
1085
	}
1086

    
1087
	if ((($lagg['proto'] == 'lacp') || ($lagg['proto'] == 'loadbalance')) &&
1088
	    isset($lagg['lagghash']) && !empty($lagg['lagghash'])) {
1089
		$lagghash = 'lagghash ' . escapeshellarg($lagg['lagghash']);
1090
	} else {
1091
		$lagghash = '';
1092
	}
1093

    
1094
	foreach ($members as $member) {
1095
		if (!does_interface_exist($member)) {
1096
			continue;
1097
		}
1098

    
1099
		/* make sure the parent interface is up */
1100
		pfSense_interface_mtu($member, $lagg_mtu);
1101
		interfaces_bring_up($member);
1102
		hardware_offloading_applyflags($member);
1103

    
1104
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
1105
		$laggif = str_replace("\0", "", $laggif);
1106
		$member = str_replace("\0", "", $member);
1107
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
1108
	}
1109

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

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

    
1116
	interfaces_bring_up($laggif);
1117

    
1118
	return $laggif;
1119
}
1120

    
1121
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
1122
function interface_gre_configure(&$gre, $grekey = "", $flush = true) {
1123
	global $config, $g;
1124

    
1125
	if (!is_array($gre)) {
1126
		return -1;
1127
	}
1128

    
1129
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1130
	if (!interface_is_vlan($realif)) {
1131
		$realif = get_real_interface($gre['if']);
1132
	}
1133
	$realifip = get_interface_ip($gre['if']);
1134
	$realifip6 = get_interface_ipv6($gre['if']);
1135

    
1136
	/* do not run ifconfig without correct $realifip */
1137
	if ((!$realifip && is_ipaddrv4($gre['remote-addr'])) || 
1138
	    (!$realifip6 && is_ipaddrv6($gre['remote-addr']))) {
1139
		return -1;
1140
	}
1141

    
1142
	/* make sure the parent interface is up */
1143
	interfaces_bring_up($realif);
1144

    
1145
	if (platform_booting() || !(empty($gre['greif']))) {
1146
		pfSense_interface_destroy($gre['greif']);
1147
		pfSense_interface_create2($gre['greif']);
1148
		$greif = $gre['greif'];
1149
	} else {
1150
		$greif = pfSense_interface_create2("gre");
1151
	}
1152

    
1153
	$tunnel_type = '';
1154
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1155
		$tunnel_type = 'v4';
1156
	}
1157
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1158
		$tunnel_type .= 'v6';
1159
	}
1160

    
1161
	/* Do not change the order here for more see gre(4) NOTES section. */
1162
	if (is_ipaddrv6($gre['remote-addr'])) {
1163
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1164
	} else {
1165
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1166
	}
1167
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1168
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1169
	}
1170
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1171
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1172
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr6']) . " " . escapeshellarg($gre['tunnel-remote-addr6']) . " prefixlen 128");
1173
	}
1174

    
1175
	$parentif = get_real_interface($gre['if']);
1176
	if ($parentif) {
1177
		interfaces_bring_up($parentif);
1178
	} else {
1179
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1180
	}
1181

    
1182
	if (isset($gre['link1'])) {
1183
		if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1184
			mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1185
		}
1186
		if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1187
			mwexec("/sbin/route -6 add " . escapeshellarg($gre['tunnel-remote-addr6']) . "/" . escapeshellarg($gre['tunnel-remote-net6']) . " " . escapeshellarg($gre['tunnel-local-addr6']));
1188
		}
1189
	}
1190
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1191
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1192
		unlink_if_exists("{$g['tmp_path']}/{$greif}_router.last");
1193
	}
1194
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1195
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr6']);
1196
		unlink_if_exists("{$g['tmp_path']}/{$greif}_routerv6.last");
1197
	}
1198

    
1199
	if ($flush) {
1200
		get_interface_arr(true);
1201
	}
1202

    
1203
	interfaces_bring_up($greif);
1204

    
1205
	return $greif;
1206
}
1207

    
1208
function interface_is_type($if = NULL, $type) {
1209
	global $config;
1210
	switch ($type) {
1211
		case "gre":
1212
			$list = 'gres';
1213
			$entry = 'gre';
1214
			$entif = 'greif';
1215
			break;
1216
		case "gif":
1217
			$list = 'gifs';
1218
			$entry = 'gif';
1219
			$entif = 'gifif';
1220
			break;
1221
		case "lagg":
1222
			$list = 'laggs';
1223
			$entry = 'lagg';
1224
			$entif = 'laggif';
1225
			break;
1226
		default:
1227
			break;
1228
	}
1229

    
1230
	if (!isset($config[$list][$entry]) || !is_array($config[$list][$entry])) {
1231
		return (NULL);
1232
	}
1233

    
1234
	foreach ($config[$list][$entry] as $ent) {
1235
		if ($ent[$entif] == $if) {
1236
			return ($ent);
1237
		}
1238
	}
1239
	return (NULL);
1240
}
1241

    
1242
function is_greipsec($if) {
1243
	global $config;
1244

    
1245
	if (ipsec_enabled() && is_array($config['gres']) &&
1246
	    is_array($config['gres']['gre']) &&
1247
	    is_array($config['ipsec']['phase2'])) {
1248
		foreach ($config['gres']['gre'] as $gre) {
1249
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
1250
				foreach ($config['ipsec']['phase2'] as $ph2ent) {
1251
					if (($ph1ent['ikeid'] == $ph2ent['ikeid']) && ($ph2ent['mode'] == 'transport') &&
1252
					    !isset($ph1ent['disabled']) && !isset($ph2ent['disabled']) &&
1253
					    ($ph1ent['interface'] == $gre['if']) && ($gre['greif'] == $if) &&
1254
					    ($ph1ent['remote-gateway'] == $gre['remote-addr'])) {
1255
						    return true;
1256
					}
1257
				}
1258
			}
1259
		}
1260
	}
1261
	return false;
1262
}
1263

    
1264
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1265
function interface_gif_configure(&$gif, $gifkey = "", $flush = true) {
1266
	global $config, $g;
1267

    
1268
	if (!is_array($gif)) {
1269
		return -1;
1270
	}
1271

    
1272
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1273
	if (!interface_is_vlan($realif)) {
1274
		$realif = get_real_interface($gif['if']);
1275
	}
1276
	$ipaddr = get_interface_ip($gif['if']);
1277

    
1278
	if (is_ipaddrv4($gif['remote-addr'])) {
1279
		if (is_ipaddrv4($ipaddr)) {
1280
			$realifip = $ipaddr;
1281
		} else {
1282
			$realifip = get_interface_ip($gif['if']);
1283
		}
1284
		$realifgw = get_interface_gateway($gif['if']);
1285
	} elseif (is_ipaddrv6($gif['remote-addr'])) {
1286
		if (is_ipaddrv6($ipaddr)) {
1287
			$realifip = $ipaddr;
1288
		} else {
1289
			$realifip = get_interface_ipv6($gif['if']);
1290
		}
1291
		$realifgw = get_interface_gateway_v6($gif['if']);
1292
	}
1293

    
1294
	/* do not run ifconfig without correct $realifip */
1295
	if ((!is_ipaddrv4($realifip) && is_ipaddrv4($gif['remote-addr'])) || 
1296
	    (!is_ipaddrv6($realifip) && is_ipaddrv6($gif['remote-addr']))) {
1297
		return -1;
1298
	}
1299

    
1300
	/* make sure the parent interface is up */
1301
	$parentif = get_real_interface($gif['if']);
1302
	if ($parentif) {
1303
		interfaces_bring_up($parentif);
1304
	} else {
1305
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gif_configure()"));
1306
	}
1307

    
1308
	if (platform_booting() || !(empty($gif['gifif']))) {
1309
		pfSense_interface_destroy($gif['gifif']);
1310
		pfSense_interface_create2($gif['gifif']);
1311
		$gifif = $gif['gifif'];
1312
	} else {
1313
		$gifif = pfSense_interface_create2("gif");
1314
	}
1315

    
1316
	/* Do not change the order here for more see gif(4) NOTES section. */
1317
	if (is_ipaddrv6($gif['remote-addr'])) {
1318
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1319
	} else {
1320
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1321
	}
1322
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1323
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1324
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1325
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1326
	} else {
1327
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1328
	}
1329
	if (isset($gif['link1'])) {
1330
		pfSense_interface_flags($gifif, IFF_LINK1);
1331
	}
1332
	if (isset($gif['link2'])) {
1333
		pfSense_interface_flags($gifif, IFF_LINK2);
1334
	}
1335
	if ($gifif) {
1336
		interfaces_bring_up($gifif);
1337
		$gifmtu = "";
1338
		$currentgifmtu = get_interface_mtu($gifif);
1339
		foreach ($config['interfaces'] as $tmpinterface) {
1340
			if ($tmpinterface['if'] == $gifif) {
1341
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1342
					$gifmtu = $tmpinterface['mtu'];
1343
				}
1344
			}
1345
		}
1346
		if (is_numericint($gifmtu)) {
1347
			if ($gifmtu != $currentgifmtu) {
1348
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1349
			}
1350
		}
1351
	} else {
1352
		log_error(gettext("could not bring gifif up -- variable not defined"));
1353
	}
1354

    
1355
	if (!platform_booting()) {
1356
		$iflist = get_configured_interface_list();
1357
		foreach ($iflist as $ifname) {
1358
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1359
				if (get_interface_gateway($ifname)) {
1360
					system_routing_configure($ifname);
1361
					break;
1362
				}
1363
				if (get_interface_gateway_v6($ifname)) {
1364
					system_routing_configure($ifname);
1365
					break;
1366
				}
1367
			}
1368
		}
1369
	}
1370

    
1371

    
1372
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1373
		file_put_contents("{$g['tmp_path']}/{$gifif}_router",
1374
		    $gif['tunnel-remote-addr']);
1375
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_router.last");
1376
	} elseif (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1377
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6",
1378
		    $gif['tunnel-remote-addr']);
1379
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_routerv6.last");
1380
	}
1381

    
1382
	route_add_or_change($gif['remote-addr'], $realifgw);
1383

    
1384
	if ($flush) {
1385
		get_interface_arr(true);
1386
	}
1387

    
1388
	interfaces_bring_up($gifif);
1389

    
1390
	return $gifif;
1391
}
1392

    
1393
function interfaces_tunnel_configure($checkparent = 0, $realif = "", $type = "") {
1394
	global $config;
1395

    
1396
	if (!in_array($type, array('gre', 'gif'))) {
1397
		return;
1398
	}
1399

    
1400
	if (!is_array($config["{$type}s"][$type]) ||
1401
	    !count($config["{$type}s"][$type])) {
1402
		return;
1403
	}
1404

    
1405
	foreach ($config["{$type}s"][$type] as $i => $tunnel) {
1406
		if (empty($tunnel["{$type}if"])) {
1407
			$tunnel["{$type}if"] = $type . $i;
1408
		}
1409
		if (!empty($realif) && $realif != $tunnel["{$type}if"]) {
1410
			continue;
1411
		}
1412

    
1413
		if ($checkparent == 1) {
1414
			if (substr($tunnel['if'], 0, 4) == '_vip') {
1415
				continue;
1416
			}
1417
			if (substr($tunnel['if'], 0, 5) == '_lloc') {
1418
				continue;
1419
			}
1420
			if (!empty($config['interfaces'][$tunnel['if']]) &&
1421
			    $config['interfaces'][$tunnel['if']]['ipaddrv6'] ==
1422
			    "track6") {
1423
				continue;
1424
			}
1425
		} elseif ($checkparent == 2) {
1426
			if ((substr($tunnel['if'], 0, 4) != '_vip' &&
1427
			    substr($tunnel['if'], 0, 5) != '_lloc') &&
1428
			    (empty($config['interfaces'][$tunnel['if']]) ||
1429
			    $config['interfaces'][$tunnel['if']]['ipaddrv6'] !=
1430
			    "track6")) {
1431
				continue;
1432
			}
1433
		}
1434
		if ($type == 'gif') {
1435
			interface_gif_configure($tunnel, "", false);
1436
		} elseif ($type == 'gre') {
1437
			interface_gre_configure($tunnel, "", false);
1438
		}
1439
	}
1440

    
1441
	/* Invalidate cache */
1442
	get_interface_arr(true);
1443
}
1444

    
1445
/* Build a list of IPsec interfaces */
1446
function interface_ipsec_vti_list_p1($ph1ent) {
1447
	global $config;
1448
	$iface_list = array();
1449

    
1450
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1451
		return $iface_list;
1452
	}
1453

    
1454
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1455
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1456
		return $iface_list;
1457
	}
1458

    
1459
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1460
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1461
		foreach ($vtisubnet_spec as $vtisub) {
1462
			$iface_list[ipsec_get_ifname($ph1ent, $vtisub['reqid'])] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1463
		}
1464
	} else {
1465
		/* For IKEv2, only create one interface with additional addresses as aliases */
1466
		$iface_list[ipsec_get_ifname($ph1ent)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1467
	}
1468
	return $iface_list;
1469
}
1470
function interface_ipsec_vti_list_all() {
1471
	global $config;
1472
	$iface_list = array();
1473
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1474
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1475
			if ($ph1ent['disabled']) {
1476
				continue;
1477
			}
1478
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1479
		}
1480
	}
1481
	return $iface_list;
1482
}
1483

    
1484
function is_interface_ipsec_vti_assigned($phase2) {
1485
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1486
	$vti_interface = null;
1487
	$vtisubnet_spec = ipsec_vti($phase1, true);
1488
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1489
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1490
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1491
			foreach ($vtisubnet_spec as $idx => $vtisub) {
1492
				/* Is this for this P2? */
1493
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1494
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1495
					$vti_interface = ipsec_get_ifname($phase1, $vtisub['reqid']);
1496
				}
1497
			}
1498
		} else {
1499
			$vti_interface = ipsec_get_ifname($phase1);
1500
		}
1501
	}
1502
	/* Check if this interface is assigned */
1503
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1504
}
1505
function interface_ipsec_vti_configure($ph1ent, $gateways_status = false) {
1506
	global $config, $ipsec_reqid_base;
1507

    
1508
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1509
		return false;
1510
	}
1511

    
1512
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1513
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1514
		return false;
1515
	}
1516

    
1517
	$left_spec = ipsec_get_phase1_src($ph1ent, $gateways_status);
1518

    
1519
	/* Attempt to resolve the remote gateway if needed */
1520
	$right_spec = ipsec_get_phase1_dst($ph1ent);
1521
	if (empty($right_spec)) {
1522
		/* Far end cannot be resolved */
1523
		return false;
1524
	}
1525

    
1526
	$iface_addrs = array();
1527
	$reqids = array();
1528

    
1529
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1530
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1531
		/* Form a single interface for each P2 entry */
1532
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1533
			$ipsecif = ipsec_get_ifname($ph1ent, $vtisub['reqid']);
1534
			if (!is_array($iface_addrs[$ipsecif])) {
1535
				$iface_addrs[$ipsecif] = array();
1536
			}
1537
			$vtisub['alias'] = "";
1538
			$iface_addrs[$ipsecif][] = $vtisub;
1539
			$reqids[$ipsecif] = $vtisub['reqid'];
1540
		}
1541
	} else {
1542
		/* For IKEv2, only create one interface with additional addresses as aliases */
1543
		$ipsecif = ipsec_get_ifname($ph1ent);
1544
		if (!is_array($iface_addrs[$ipsecif])) {
1545
			$iface_addrs[$ipsecif] = array();
1546
		}
1547
		$have_v4 = false;
1548
		$have_v6 = false;
1549
		foreach ($vtisubnet_spec as $vtisub) {
1550
			// Alias stuff
1551
			$vtisub['alias'] = "";
1552
			if (is_ipaddrv6($vtisub['left'])) {
1553
				if ($have_v6) {
1554
					$vtisub['alias'] = " alias";
1555
				}
1556
				$have_v6 = true;
1557
			} else {
1558
				if ($have_v4) {
1559
					$vtisub['alias'] = " alias";
1560
				}
1561
				$have_v4 = true;
1562
			}
1563
			$iface_addrs[$ipsecif][] = $vtisub;
1564
		}
1565
		/* IKEv2 w/o Split uses the reqid of the first P2 */
1566
		$reqids[$ipsecif] = $vtisubnet_spec[0]['reqid'];
1567
	}
1568

    
1569
	foreach ($iface_addrs as $ipsecif => $addrs) {
1570
		if (!is_array($addrs)) {
1571
			continue;
1572
		}
1573
		// Create IPsec interface
1574
		if (does_interface_exist($ipsecif)) {
1575
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy");
1576
		}
1577
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsec_reqid_base + $reqids[$ipsecif]));
1578

    
1579
		/* Apply the outer tunnel addresses to the interface */
1580
		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
1581
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up");
1582

    
1583
		/* Loop through all of the addresses for this interface and apply them as needed */
1584
		foreach ($addrs as $addr) {
1585
			// apply interface addresses
1586
			if (is_v6($addr['left'])) {
1587
				$inet = "inet6";
1588
				$gwtype = "v6";
1589
				$right = '';
1590
			} else {
1591
				$inet = "inet";
1592
				$gwtype = "";
1593
				$right = escapeshellarg($addr['right']);
1594
			}
1595

    
1596
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias']);
1597
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1598
			if (empty($addr['alias'])) {
1599
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1600
				unlink_if_exists("/tmp/{$ipsecif}_router{$gwtype}.last");
1601
			}
1602
		}
1603
		/* Check/set the MTU if the user configured a custom value.
1604
		 * https://redmine.pfsense.org/issues/9111 */
1605
		$currentvtimtu = get_interface_mtu($ipsecif);
1606
		foreach ($config['interfaces'] as $tmpinterface) {
1607
			if ($tmpinterface['if'] == $ipsecif) {
1608
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1609
					$vtimtu = $tmpinterface['mtu'];
1610
				}
1611
			}
1612
		}
1613
		if (is_numericint($vtimtu)) {
1614
			if ($vtimtu != $currentvtimtu) {
1615
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1616
			}
1617
		}
1618
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1619
	}
1620
	return true;
1621
}
1622

    
1623
function interfaces_ipsec_vti_configure($gateways_status = false) {
1624
	global $config;
1625

    
1626
	/* Fetch gateway status if not passed */
1627
	if (!is_array($gateways_status)) {
1628
		$gateways_status = return_gateways_status(true);
1629
	}
1630
	if (is_array($config['ipsec']) &&
1631
	    is_array($config['ipsec']['phase1']) &&
1632
	    is_array($config['ipsec']['phase2'])) {
1633
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1634
			if ($ph1ent['disabled']) {
1635
				continue;
1636
			}
1637
			if (interface_ipsec_vti_configure($ph1ent, $gateways_status) &&
1638
			    !$bootmsg && platform_booting()) {
1639
				echo gettext("Configuring IPsec VTI interfaces...");
1640
				$bootmsg = true;
1641
			}
1642
		}
1643
	}
1644
	if (platform_booting() && $bootmsg) {
1645
		echo gettext("done.") . "\n";
1646
	}
1647
}
1648

    
1649
function interfaces_configure() {
1650
	global $config, $g;
1651

    
1652
	/* Set up our loopback interface */
1653
	interfaces_loopback_configure();
1654

    
1655
	/* create the unconfigured wireless clones */
1656
	interfaces_create_wireless_clones();
1657

    
1658
	/* set up LAGG virtual interfaces */
1659
	interfaces_lagg_configure();
1660

    
1661
	/* set up VLAN virtual interfaces */
1662
	interfaces_vlan_configure();
1663

    
1664
	interfaces_qinq_configure(false);
1665

    
1666
	$iflist = get_configured_interface_with_descr();
1667
	$delayed_list = array();
1668
	$bridge_list = array();
1669
	$track6_list = array();
1670
	$dhcp6c_list = array();
1671

    
1672
	/* This is needed to speedup interfaces on bootup. */
1673
	$reload = false;
1674
	if (!platform_booting()) {
1675
		$reload = true;
1676
	}
1677

    
1678
	foreach ($iflist as $if => $ifname) {
1679
		$realif = $config['interfaces'][$if]['if'];
1680
		if (strstr($realif, "bridge")) {
1681
			$bridge_list[$if] = $ifname;
1682
		} elseif (strstr($realif, "gre")) {
1683
			$delayed_list[$if] = $ifname;
1684
		} elseif (strstr($realif, "gif")) {
1685
			$delayed_list[$if] = $ifname;
1686
		} elseif (strstr($realif, "ovpn")) {
1687
			continue;
1688
		} elseif (strstr($realif, "ipsec")) {
1689
			continue;
1690
		} elseif (!empty($config['interfaces'][$if]['ipaddrv6']) &&
1691
		    $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1692
			$track6_list[$if] = $ifname;
1693
		} else {
1694
			/* do not run dhcp6c if track interface does not exists
1695
			 * see https://redmine.pfsense.org/issues/3965
1696
			 * and https://redmine.pfsense.org/issues/11633 */ 
1697
			if (!empty($config['interfaces'][$if]['ipaddrv6']) &&
1698
			    $config['interfaces'][$if]['ipaddrv6'] == "dhcp6") {
1699
				$tr6list = link_interface_to_track6($if);
1700
				if (is_array($tr6list) && !empty($tr6list)) {
1701
					$dhcp6c_list[$if] = $ifname;
1702
					continue;
1703
				}
1704
			}
1705
			if (platform_booting()) {
1706
				printf(gettext("Configuring %s interface..."),
1707
				    $ifname);
1708
			}
1709

    
1710
			if ($g['debug']) {
1711
				log_error(sprintf(gettext("Configuring %s"),
1712
				    $ifname));
1713
			}
1714
			interface_configure($if, $reload);
1715
			if (platform_booting()) {
1716
				echo gettext("done.") . "\n";
1717
			}
1718
		}
1719
	}
1720

    
1721
	/*
1722
	 * NOTE: The following function parameter consists of
1723
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1724
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1725
	 */
1726

    
1727
	/* set up GRE virtual interfaces */
1728
	interfaces_tunnel_configure(1,'','gre');
1729

    
1730
	/* set up GIF virtual interfaces */
1731
	interfaces_tunnel_configure(1,'','gif');
1732

    
1733
	/* set up BRIDGE virtual interfaces */
1734
	interfaces_bridge_configure(1);
1735

    
1736
	foreach ($track6_list as $if => $ifname) {
1737
		if (platform_booting()) {
1738
			printf(gettext("Configuring %s interface..."), $ifname);
1739
		}
1740
		if ($g['debug']) {
1741
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1742
		}
1743

    
1744
		interface_configure($if, $reload);
1745

    
1746
		if (platform_booting()) {
1747
			echo gettext("done.") . "\n";
1748
		}
1749
	}
1750

    
1751
	/* bring up vip interfaces */
1752
	interfaces_vips_configure();
1753

    
1754
	/* set up GRE virtual interfaces */
1755
	interfaces_tunnel_configure(2,'','gre');
1756

    
1757
	/* set up GIF virtual interfaces */
1758
	interfaces_tunnel_configure(2,'','gif');
1759

    
1760
	foreach ($delayed_list as $if => $ifname) {
1761
		if (platform_booting()) {
1762
			printf(gettext("Configuring %s interface..."), $ifname);
1763
		}
1764
		if ($g['debug']) {
1765
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1766
		}
1767

    
1768
		interface_configure($if, $reload);
1769

    
1770
		if (platform_booting()) {
1771
			echo gettext("done.") . "\n";
1772
		}
1773
	}
1774

    
1775
	/* set up BRIDGE virtual interfaces */
1776
	interfaces_bridge_configure(2);
1777

    
1778
	foreach ($bridge_list as $if => $ifname) {
1779
		if (platform_booting()) {
1780
			printf(gettext("Configuring %s interface..."), $ifname);
1781
		}
1782
		if ($g['debug']) {
1783
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1784
		}
1785

    
1786
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1787
		// redmine #3997
1788
		interface_reconfigure($if, $reload);
1789
		interfaces_vips_configure($if);
1790

    
1791
		if (platform_booting()) {
1792
			echo gettext("done.") . "\n";
1793
		}
1794
	}
1795

    
1796
	foreach ($dhcp6c_list as $if => $ifname) {
1797
		if (platform_booting()) {
1798
			printf(gettext("Configuring %s interface..."), $ifname);
1799
		}
1800
		if ($g['debug']) {
1801
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1802
		}
1803

    
1804
		interface_configure($if, $reload);
1805

    
1806
		if (platform_booting()) {
1807
			echo gettext("done.") . "\n";
1808
		}
1809
	}
1810

    
1811
	/* set up IPsec VTI interfaces */
1812
	interfaces_ipsec_vti_configure();
1813

    
1814
	/* configure interface groups */
1815
	interfaces_group_setup();
1816

    
1817
	if (!platform_booting()) {
1818
		/* reconfigure static routes (kernel may have deleted them) */
1819
		system_routing_configure();
1820

    
1821
		/* reload IPsec tunnels */
1822
		ipsec_configure();
1823

    
1824
		/* restart dns servers (defering dhcpd reload) */
1825
		if (isset($config['dnsmasq']['enable'])) {
1826
			services_dnsmasq_configure(false);
1827
		}
1828
		if (isset($config['unbound']['enable'])) {
1829
			services_unbound_configure(false);
1830
		}
1831

    
1832
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1833
		services_dhcpd_configure();
1834
	}
1835

    
1836
	return 0;
1837
}
1838

    
1839
function interface_reconfigure($interface = "wan", $reloadall = false) {
1840
	interface_bring_down($interface);
1841
	interface_configure($interface, $reloadall);
1842
}
1843

    
1844
function interface_vip_bring_down($vip) {
1845
	global $g;
1846

    
1847
	$vipif = get_real_interface($vip['interface']);
1848
	switch ($vip['mode']) {
1849
		case "proxyarp":
1850
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1851
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1852
			}
1853
			break;
1854
		case "ipalias":
1855
			if (does_interface_exist($vipif)) {
1856
				if (is_ipaddrv6($vip['subnet'])) {
1857
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1858
				} else {
1859
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1860
				}
1861
			}
1862
			break;
1863
		case "carp":
1864
			/* XXX: Is enough to delete ip address? */
1865
			if (does_interface_exist($vipif)) {
1866
				if (is_ipaddrv6($vip['subnet'])) {
1867
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1868
				} else {
1869
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1870
				}
1871
			}
1872
			break;
1873
	}
1874
}
1875

    
1876
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1877
	global $config, $g;
1878

    
1879
	if (!isset($config['interfaces'][$interface])) {
1880
		return;
1881
	}
1882

    
1883
	if ($g['debug']) {
1884
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1885
	}
1886

    
1887
	/*
1888
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1889
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1890
	 * Keep this in mind while doing changes here!
1891
	 */
1892
	if ($ifacecfg === false) {
1893
		$ifcfg = $config['interfaces'][$interface];
1894
		$ppps = $config['ppps']['ppp'];
1895
		$realif = get_real_interface($interface);
1896
		$realifv6 = get_real_interface($interface, "inet6", true);
1897
	} elseif (!is_array($ifacecfg)) {
1898
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1899
		$ifcfg = $config['interfaces'][$interface];
1900
		$ppps = $config['ppps']['ppp'];
1901
		$realif = get_real_interface($interface);
1902
		$realifv6 = get_real_interface($interface, "inet6", true);
1903
	} else {
1904
		$ifcfg = $ifacecfg['ifcfg'];
1905
		$ppps = $ifacecfg['ppps'];
1906
		if (isset($ifacecfg['ifcfg']['realif'])) {
1907
			$realif = $ifacecfg['ifcfg']['realif'];
1908
			/* XXX: Any better way? */
1909
			$realifv6 = $realif;
1910
		} else {
1911
			$realif = get_real_interface($interface);
1912
			$realifv6 = get_real_interface($interface, "inet6", true);
1913
		}
1914
	}
1915

    
1916
	/* check all gateways, including dynamic,
1917
	 * see https://redmine.pfsense.org/issues/12920 */
1918
	foreach (return_gateways_array(true) as $gw) {
1919
		if ($gw['friendlyiface'] == $interface) {
1920
			$restart_gateways_monitor = true;
1921
			break;
1922
		}
1923
	}
1924

    
1925
	switch ($ifcfg['ipaddr']) {
1926
		case "ppp":
1927
		case "pppoe":
1928
		case "pptp":
1929
		case "l2tp":
1930
			if (is_array($ppps) && count($ppps)) {
1931
				foreach ($ppps as $pppid => $ppp) {
1932
					if ($realif == $ppp['if']) {
1933
						if (isset($ppp['ondemand']) && !$destroy) {
1934
							send_event("interface reconfigure {$interface}");
1935
							break;
1936
						}
1937
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1938
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1939
							sleep(2);
1940
						}
1941
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1942
						break;
1943
					}
1944
				}
1945
			}
1946
			break;
1947
		case "dhcp":
1948
			kill_dhclient_process($realif);
1949
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1950
			if (does_interface_exist("$realif")) {
1951
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1952
				interface_vip_cleanup($interface, "inet4");
1953
				if ($destroy == true) {
1954
					pfSense_interface_flags($realif, -IFF_UP);
1955
				}
1956
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1957
			}
1958
			break;
1959
		default:
1960
			if (does_interface_exist("$realif")) {
1961
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1962
				interface_vip_cleanup($interface, "inet4");
1963
				if ($destroy == true) {
1964
					pfSense_interface_flags($realif, -IFF_UP);
1965
				}
1966
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1967
			}
1968
			break;
1969
	}
1970

    
1971
	$track6 = array();
1972
	switch ($ifcfg['ipaddrv6']) {
1973
		case "slaac":
1974
		case "dhcp6":
1975
			interface_dhcpv6_configure($interface, $ifcfg, true);
1976
			if (does_interface_exist($realifv6)) {
1977
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 -accept_rtadv");
1978
				$ip6 = find_interface_ipv6($realifv6);
1979
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1980
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1981
				}
1982
				interface_vip_cleanup($interface, "inet6");
1983
				if ($destroy == true) {
1984
					pfSense_interface_flags($realif, -IFF_UP);
1985
				}
1986
			}
1987
			$track6 = link_interface_to_track6($interface);
1988
			break;
1989
		case "6rd":
1990
		case "6to4":
1991
			$realif = "{$interface}_stf";
1992
			if (does_interface_exist("$realif")) {
1993
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1994
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1995
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1996
					$destroy = true;
1997
				} else {
1998
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1999
					$ip6 = get_interface_ipv6($interface);
2000
					if (is_ipaddrv6($ip6)) {
2001
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2002
					}
2003
				}
2004
				interface_vip_cleanup($interface, "inet6");
2005
				if ($destroy == true) {
2006
					pfSense_interface_flags($realif, -IFF_UP);
2007
				}
2008
			}
2009
			$track6 = link_interface_to_track6($interface);
2010
			break;
2011
		default:
2012
			if (does_interface_exist("$realif")) {
2013
				$ip6 = get_interface_ipv6($interface);
2014
				if (is_ipaddrv6($ip6)) {
2015
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2016
				}
2017
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
2018
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
2019
				}
2020
				interface_vip_cleanup($interface, "inet6");
2021
				if ($destroy == true) {
2022
					pfSense_interface_flags($realif, -IFF_UP);
2023
				}
2024
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2025
			}
2026
			$track6 = link_interface_to_track6($interface);
2027
			break;
2028
	}
2029

    
2030
	if (!empty($track6) && is_array($track6)) {
2031
		if (!function_exists('services_dhcpd_configure')) {
2032
			require_once('services.inc');
2033
		}
2034
		/* Bring down radvd and dhcp6 on these interfaces */
2035
		services_dhcpd_configure('inet6', $track6);
2036
	}
2037

    
2038
	$old_router = '';
2039
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
2040
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
2041
	}
2042

    
2043
	/* remove interface up file if it exists */
2044
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
2045
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
2046
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
2047
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
2048
		rename("{$g['tmp_path']}/{$realif}_router", "{$g['tmp_path']}/{$realif}_router.last");
2049
	}
2050
	if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
2051
		rename("{$g['tmp_path']}/{$realif}_routerv6", "{$g['tmp_path']}/{$realif}_routerv6.last");
2052
	}
2053
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
2054
	unlink_if_exists("{$g['varetc_path']}/nameserver_v6{$interface}");
2055
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
2056
	unlink_if_exists("{$g['varetc_path']}/searchdomain_v6{$interface}");
2057
	unlink_if_exists("{$g['tmp_path']}/{$interface}_upstart4");
2058
	unlink_if_exists("{$g['tmp_path']}/{$interface}_upstart6");
2059

    
2060
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
2061
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
2062
	if (is_array($ifcfg['wireless'])) {
2063
		kill_hostapd($realif);
2064
		mwexec(kill_wpasupplicant($realif));
2065
		unlink_if_exists("{$g['varetc_path']}/wpa_supplicant_{$realif}.*");
2066
		unlink_if_exists("{$g['varetc_path']}/hostapd_{$realif}.conf");
2067
	}
2068

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

    
2073
			/* Invalidate cache */
2074
			get_interface_arr(true);
2075
		}
2076
	}
2077

    
2078
	/* If interface has a gateway, we need to bounce dpinger to keep dpinger happy */
2079
	if ($restart_gateways_monitor) {
2080
		setup_gateways_monitor();
2081
	}
2082

    
2083
	return;
2084
}
2085

    
2086
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
2087
	global $config;
2088
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
2089
		unset($config["virtualip_carp_maintenancemode"]);
2090
		write_config("Leave CARP maintenance mode");
2091
	} elseif (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
2092
		$config["virtualip_carp_maintenancemode"] = true;
2093
		write_config(gettext("Enter CARP maintenance mode"));
2094
	}
2095
	init_config_arr(array('virtualip', 'vip'));
2096
	$viparr = &$config['virtualip']['vip'];
2097

    
2098
	if (is_array($viparr)) {
2099
		foreach ($viparr as $vip) {
2100
			if ($vip['mode'] == "carp") {
2101
				interface_carp_configure($vip, true);
2102
			}
2103
		}
2104
	}
2105
}
2106

    
2107
function interface_wait_tentative($interface, $timeout = 10) {
2108
	if (!does_interface_exist($interface)) {
2109
		return false;
2110
	}
2111

    
2112
	$time = 0;
2113
	while ($time <= $timeout) {
2114
		$if = pfSense_get_interface_addresses($interface);
2115
		if (!isset($if['tentative'])) {
2116
			return true;
2117
		}
2118
		sleep(1);
2119
		$time++;
2120
	}
2121

    
2122
	return false;
2123
}
2124

    
2125
function interface_isppp_type($interface) {
2126
	global $config;
2127

    
2128
	if (!is_array($config['interfaces'][$interface])) {
2129
		return false;
2130
	}
2131

    
2132
	switch ($config['interfaces'][$interface]['ipaddr']) {
2133
		case 'pptp':
2134
		case 'l2tp':
2135
		case 'pppoe':
2136
		case 'ppp':
2137
			return true;
2138
			break;
2139
		default:
2140
			return false;
2141
			break;
2142
	}
2143
}
2144

    
2145
function interfaces_ptpid_used($ptpid) {
2146
	global $config;
2147

    
2148
	if (is_array($config['ppps']['ppp'])) {
2149
		foreach ($config['ppps']['ppp'] as & $settings) {
2150
			if ($ptpid == $settings['ptpid']) {
2151
				return true;
2152
			}
2153
		}
2154
	}
2155

    
2156
	return false;
2157
}
2158

    
2159
function interfaces_ptpid_next() {
2160

    
2161
	$ptpid = 0;
2162
	while (interfaces_ptpid_used($ptpid)) {
2163
		$ptpid++;
2164
	}
2165

    
2166
	return $ptpid;
2167
}
2168

    
2169
function getMPDCRONSettings($pppif) {
2170
	global $config;
2171

    
2172
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2173
	if (is_array($config['cron']['item'])) {
2174
		foreach ($config['cron']['item'] as $i => $item) {
2175
			if (stripos($item['command'], $cron_cmd_file) !== false) {
2176
				return array("ID" => $i, "ITEM" => $item);
2177
			}
2178
		}
2179
	}
2180

    
2181
	return NULL;
2182
}
2183

    
2184
function handle_pppoe_reset($post_array) {
2185
	global $config, $g;
2186

    
2187
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2188
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2189

    
2190
	if (!is_array($config['cron']['item'])) {
2191
		$config['cron']['item'] = array();
2192
	}
2193

    
2194
	$itemhash = getMPDCRONSettings($pppif);
2195

    
2196
	// reset cron items if necessary and return
2197
	if (empty($post_array['pppoe-reset-type'])) {
2198
		if (isset($itemhash)) {
2199
			unset($config['cron']['item'][$itemhash['ID']]);
2200
		}
2201
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2202
		return;
2203
	}
2204

    
2205
	if (empty($itemhash)) {
2206
		$itemhash = array();
2207
	}
2208
	$item = array();
2209
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2210
		$item['minute'] = $post_array['pppoe_resetminute'] ? $post_array['pppoe_resetminute'] : "*";
2211
		$item['hour'] = $post_array['pppoe_resethour'] ? $post_array['pppoe_resethour'] : "*";
2212
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2213
			$date = explode("/", $post_array['pppoe_resetdate']);
2214
			$item['mday'] = $date[1];
2215
			$item['month'] = $date[0];
2216
		} else {
2217
			$item['mday'] = "*";
2218
			$item['month'] = "*";
2219
		}
2220
		$item['wday'] = "*";
2221
		$item['who'] = "root";
2222
		$item['command'] = $cron_cmd_file;
2223
	} elseif (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2224
		switch ($post_array['pppoe_pr_preset_val']) {
2225
			case "monthly":
2226
				$item['minute'] = "0";
2227
				$item['hour'] = "0";
2228
				$item['mday'] = "1";
2229
				$item['month'] = "*";
2230
				$item['wday'] = "*";
2231
				break;
2232
			case "weekly":
2233
				$item['minute'] = "0";
2234
				$item['hour'] = "0";
2235
				$item['mday'] = "*";
2236
				$item['month'] = "*";
2237
				$item['wday'] = "0";
2238
				break;
2239
			case "daily":
2240
				$item['minute'] = "0";
2241
				$item['hour'] = "0";
2242
				$item['mday'] = "*";
2243
				$item['month'] = "*";
2244
				$item['wday'] = "*";
2245
				break;
2246
			case "hourly":
2247
				$item['minute'] = "0";
2248
				$item['hour'] = "*";
2249
				$item['mday'] = "*";
2250
				$item['month'] = "*";
2251
				$item['wday'] = "*";
2252
				break;
2253
		} // end switch
2254
		$item['who'] = "root";
2255
		$item['command'] = $cron_cmd_file;
2256
	}
2257
	if (empty($item)) {
2258
		return;
2259
	}
2260
	if (isset($itemhash['ID'])) {
2261
		$config['cron']['item'][$itemhash['ID']] = $item;
2262
	} else {
2263
		$config['cron']['item'][] = $item;
2264
	}
2265
}
2266

    
2267
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2268
	global $config;
2269
	$ppp_list = array();
2270
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2271
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2272
			$ports = explode(",", $ppp['ports']);
2273
			foreach($ports as $port) {
2274
				foreach($triggerinterfaces as $vip) {
2275
					if ($port == "_vip{$vip['uniqid']}") {
2276
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2277
						$ppp_list[$if] = 1;
2278
					}
2279
				}
2280
			}
2281
		}
2282
	}
2283
	foreach($ppp_list as $pppif => $dummy) {
2284
		interface_ppps_configure($pppif);
2285
	}
2286
}
2287

    
2288
/*
2289
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2290
 * It writes the mpd config file to /var/etc every time the link is opened.
2291
 */
2292
function interface_ppps_configure($interface) {
2293
	global $config, $g;
2294

    
2295
	/* Return for unassigned interfaces. This is a minimum requirement. */
2296
	if (empty($config['interfaces'][$interface])) {
2297
		return 0;
2298
	}
2299
	$ifcfg = $config['interfaces'][$interface];
2300
	if (!isset($ifcfg['enable'])) {
2301
		return 0;
2302
	}
2303

    
2304
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2305
	if (!is_dir("/var/spool/lock")) {
2306
		mkdir("/var/spool/lock", 0777, true);
2307
	}
2308
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2309
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2310
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2311
	}
2312

    
2313
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2314
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2315
			if ($ifcfg['if'] == $ppp['if']) {
2316
				break;
2317
			}
2318
		}
2319
	}
2320
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2321
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2322
		return 0;
2323
	}
2324
	$pppif = $ifcfg['if'];
2325
	if ($ppp['type'] == "ppp") {
2326
		$type = "modem";
2327
	} else {
2328
		$type = $ppp['type'];
2329
	}
2330
	$upper_type = strtoupper($ppp['type']);
2331

    
2332
	$confports = explode(',', $ppp['ports']);
2333
	if ($type == "modem") {
2334
		$ports = $confports;
2335
	} else {
2336
		$ports = array();
2337
		foreach ($confports as $pid => $port) {
2338
			if (strstr($port, "_vip")) {
2339
				if (get_carp_interface_status($port) != "MASTER") {
2340
					continue;
2341
				}
2342
			}
2343
			$ports[$pid] = get_real_interface($port);
2344
			if (empty($ports[$pid])) {
2345
				return 0;
2346
			}
2347
		}
2348
	}
2349
	$localips = explode(',', $ppp['localip']);
2350
	$gateways = explode(',', $ppp['gateway']);
2351
	$subnets = explode(',', $ppp['subnet']);
2352

    
2353
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2354
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2355
	 */
2356
	foreach ($ports as $pid => $port) {
2357
		switch ($ppp['type']) {
2358
			case "pppoe":
2359
				/* Bring the parent interface up */
2360
				interfaces_bring_up($port);
2361
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2362
				$ngif = str_replace(".", "_", $port);
2363
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2364
				break;
2365
			case "pptp":
2366
			case "l2tp":
2367
				/* configure interface */
2368
				if (is_ipaddr($localips[$pid])) {
2369
					// Manually configure interface IP/subnet
2370
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2371
					interfaces_bring_up($port);
2372
				} elseif (empty($localips[$pid])) {
2373
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2374
				}
2375

    
2376
				if (!is_ipaddr($localips[$pid])) {
2377
					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));
2378
					$localips[$pid] = "0.0.0.0";
2379
				}
2380
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2381
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2382
				}
2383
				if (!is_ipaddr($gateways[$pid])) {
2384
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $dhcp_gateway, $gway));
2385
					return 0;
2386
				}
2387
				break;
2388
			case "ppp":
2389
				if (!file_exists("{$port}")) {
2390
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2391
					return 0;
2392
				}
2393
				break;
2394
			default:
2395
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2396
				break;
2397
		}
2398
	}
2399

    
2400
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2401
	    (is_array($ports) && count($ports) > 1)) {
2402
		$multilink = "enable";
2403
	} else {
2404
		$multilink = "disable";
2405
	}
2406

    
2407
	if ($type == "modem") {
2408
		if (is_ipaddr($ppp['localip'])) {
2409
			$localip = $ppp['localip'];
2410
		} else {
2411
			$localip = '0.0.0.0';
2412
		}
2413

    
2414
		if (is_ipaddr($ppp['gateway'])) {
2415
			$gateway = $ppp['gateway'];
2416
		} else {
2417
			$gateway = "10.64.64.{$pppid}";
2418
		}
2419
		$ranges = "{$localip}/0 {$gateway}/0";
2420

    
2421
		if (empty($ppp['apnum'])) {
2422
			$ppp['apnum'] = 1;
2423
		}
2424
	} else {
2425
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2426
	}
2427

    
2428
	if (isset($ppp['ondemand'])) {
2429
		$ondemand = "enable";
2430
	} else {
2431
		$ondemand = "disable";
2432
	}
2433
	if (!isset($ppp['idletimeout'])) {
2434
		$ppp['idletimeout'] = 0;
2435
	}
2436

    
2437
	if (empty($ppp['username']) && $type == "modem") {
2438
		$ppp['username'] = "user";
2439
		$ppp['password'] = "none";
2440
	}
2441
	if (empty($ppp['password']) && $type == "modem") {
2442
		$passwd = "none";
2443
	} else {
2444
		$passwd = base64_decode($ppp['password']);
2445
	}
2446

    
2447
	$bandwidths = explode(',', $ppp['bandwidth']);
2448
	$defaultmtu = "1492";
2449
	if (!empty($ifcfg['mtu'])) {
2450
		$defaultmtu = intval($ifcfg['mtu']);
2451
	}
2452
	if (isset($ppp['mtu'])) {
2453
		$mtus = explode(',', $ppp['mtu']);
2454
	}
2455
	if (isset($ppp['mru'])) {
2456
		$mrus = explode(',', $ppp['mru']);
2457
	}
2458
	if (isset($ppp['mrru'])) {
2459
		$mrrus = explode(',', $ppp['mrru']);
2460
	}
2461
	if (!empty($ifcfg['ipaddrv6'])) {
2462
		$ipv6cp = "set bundle enable ipv6cp";
2463
	}
2464

    
2465
	// Construct the mpd.conf file
2466
	$mpdconf = <<<EOD
2467
startup:
2468
	# configure the console
2469
	set console close
2470
	# configure the web server
2471
	set web close
2472

    
2473
default:
2474
{$ppp['type']}client:
2475
	create bundle static {$interface}
2476
	set bundle period 6
2477
	set bundle lowat 0
2478
	set bundle hiwat 0
2479
	set bundle min-con 3
2480
	set bundle min-dis 6
2481
	set bundle enable bw-manage
2482
	{$ipv6cp}
2483
	set iface name {$pppif}
2484

    
2485
EOD;
2486

    
2487
	if (isset($ifcfg['descr'])) {
2488
		$mpdconf .= <<<EOD
2489
	set iface description "{$ifcfg['descr']}"
2490

    
2491
EOD;
2492
	}
2493
	$setdefaultgw = false;
2494
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2495
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2496
	if ($defgw4['interface'] == $interface) {
2497
		$setdefaultgw = true;
2498
	}
2499

    
2500
/* Omit this, we maintain the default route by other means, and it causes problems with
2501
 * default gateway switching. See redmine #1837 for original issue
2502
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2503
 * edge case. redmine #6495 open to address.
2504
 */
2505
	if ($setdefaultgw == true) {
2506
		$mpdconf .= <<<EOD
2507
	set iface route default
2508

    
2509
EOD;
2510
	}
2511

    
2512
	$mpdconf .= <<<EOD
2513
	set iface {$ondemand} on-demand
2514
	set iface idle {$ppp['idletimeout']}
2515

    
2516
EOD;
2517

    
2518
	if (isset($ppp['ondemand'])) {
2519
		$mpdconf .= <<<EOD
2520
	set iface addrs 10.10.1.1 10.10.1.2
2521

    
2522
EOD;
2523
	}
2524

    
2525
	if (isset($ppp['mtu-override']) &&
2526
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2527
		/* Find the smaller MTU set on ports */
2528
		$mtu = $defaultmtu;
2529
		foreach ($ports as $pid => $port) {
2530
			if (empty($mtus[$pid])) {
2531
				$mtus[$pid] = $defaultmtu;
2532
			}
2533
			if ($type == "pppoe") {
2534
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2535
					$mtus[$pid] = get_interface_mtu($port) - 8;
2536
				}
2537
			}
2538
			if ($mtu > $mtus[$pid]) {
2539
				$mtu = $mtus[$pid];
2540
			}
2541
		}
2542
		$mpdconf .= <<<EOD
2543
	set iface mtu {$mtu} override
2544

    
2545
EOD;
2546
	}
2547

    
2548
	if (isset($ppp['tcpmssfix'])) {
2549
		$tcpmss = "disable";
2550
	} else {
2551
		$tcpmss = "enable";
2552
	}
2553
	$mpdconf .= <<<EOD
2554
	set iface {$tcpmss} tcpmssfix
2555

    
2556
EOD;
2557

    
2558
	$mpdconf .= <<<EOD
2559
	set iface up-script /usr/local/sbin/ppp-linkup
2560
	set iface down-script /usr/local/sbin/ppp-linkdown
2561
	set ipcp ranges {$ranges}
2562

    
2563
EOD;
2564
	if (isset($ppp['vjcomp'])) {
2565
		$mpdconf .= <<<EOD
2566
	set ipcp no vjcomp
2567

    
2568
EOD;
2569
	}
2570

    
2571
	if (isset($config['system']['dnsallowoverride'])) {
2572
		$mpdconf .= <<<EOD
2573
	set ipcp enable req-pri-dns
2574
	set ipcp enable req-sec-dns
2575

    
2576
EOD;
2577
	}
2578

    
2579
	if (!isset($ppp['verbose_log'])) {
2580
		$mpdconf .= <<<EOD
2581
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2582

    
2583
EOD;
2584
	}
2585

    
2586
	foreach ($ports as $pid => $port) {
2587
		$port = get_real_interface($port);
2588
		$mpdconf .= <<<EOD
2589

    
2590
	create link static {$interface}_link{$pid} {$type}
2591
	set link action bundle {$interface}
2592
	set link {$multilink} multilink
2593
	set link keep-alive 10 60
2594
	set link max-redial 0
2595

    
2596
EOD;
2597
		if (isset($ppp['shortseq'])) {
2598
			$mpdconf .= <<<EOD
2599
	set link no shortseq
2600

    
2601
EOD;
2602
		}
2603

    
2604
		if (isset($ppp['acfcomp'])) {
2605
			$mpdconf .= <<<EOD
2606
	set link no acfcomp
2607

    
2608
EOD;
2609
		}
2610

    
2611
		if (isset($ppp['protocomp'])) {
2612
			$mpdconf .= <<<EOD
2613
	set link no protocomp
2614

    
2615
EOD;
2616
		}
2617

    
2618
		$mpdconf .= <<<EOD
2619
	set link disable chap pap
2620
	set link accept chap pap eap
2621
	set link disable incoming
2622

    
2623
EOD;
2624

    
2625

    
2626
		if (!empty($bandwidths[$pid])) {
2627
			$mpdconf .= <<<EOD
2628
	set link bandwidth {$bandwidths[$pid]}
2629

    
2630
EOD;
2631
		}
2632

    
2633
		if (empty($mtus[$pid])) {
2634
			$mtus[$pid] = $defaultmtu;
2635
		}
2636
		if ($type == "pppoe") {
2637
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2638
				$mtus[$pid] = get_interface_mtu($port) - 8;
2639
			}
2640
		}
2641
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2642
		    !isset($ppp['mtu-override']) &&
2643
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2644
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2645
			$mpdconf .= <<<EOD
2646
	set link mtu {$mtus[$pid]}
2647

    
2648
EOD;
2649
		}
2650

    
2651
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2652
		    !isset($ppp['mtu-override']) &&
2653
		    !empty($mrus[$pid])) {
2654
			$mpdconf .= <<<EOD
2655
	set link mru {$mrus[$pid]}
2656

    
2657
EOD;
2658
		}
2659

    
2660
		if (!empty($mrrus[$pid])) {
2661
			$mpdconf .= <<<EOD
2662
	set link mrru {$mrrus[$pid]}
2663

    
2664
EOD;
2665
		}
2666

    
2667
		$mpdconf .= <<<EOD
2668
	set auth authname "{$ppp['username']}"
2669
	set auth password {$passwd}
2670

    
2671
EOD;
2672
		if ($type == "modem") {
2673
			$mpdconf .= <<<EOD
2674
	set modem device {$ppp['ports']}
2675
	set modem script DialPeer
2676
	set modem idle-script Ringback
2677
	set modem watch -cd
2678
	set modem var \$DialPrefix "DT"
2679
	set modem var \$Telephone "{$ppp['phone']}"
2680

    
2681
EOD;
2682
		}
2683
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2684
			$mpdconf .= <<<EOD
2685
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2686

    
2687
EOD;
2688
		}
2689
		if (isset($ppp['initstr']) && $type == "modem") {
2690
			$initstr = base64_decode($ppp['initstr']);
2691
			$mpdconf .= <<<EOD
2692
	set modem var \$InitString "{$initstr}"
2693

    
2694
EOD;
2695
		}
2696
		if (isset($ppp['simpin']) && $type == "modem") {
2697
			if ($ppp['pin-wait'] == "") {
2698
				$ppp['pin-wait'] = 0;
2699
			}
2700
			$mpdconf .= <<<EOD
2701
	set modem var \$SimPin "{$ppp['simpin']}"
2702
	set modem var \$PinWait "{$ppp['pin-wait']}"
2703

    
2704
EOD;
2705
		}
2706
		if (isset($ppp['apn']) && $type == "modem") {
2707
			$mpdconf .= <<<EOD
2708
	set modem var \$APN "{$ppp['apn']}"
2709
	set modem var \$APNum "{$ppp['apnum']}"
2710

    
2711
EOD;
2712
		}
2713
		if ($type == "pppoe") {
2714
			$hostuniq = '';
2715
			if (!empty($ppp['hostuniq'])) {
2716
				if (preg_match('/^0x[a-fA-F0-9]+$/', $ppp['hostuniq'])) {
2717
					$hostuniq = strtolower($ppp['hostuniq']) .'|';
2718
				} elseif (preg_match('/^[a-zA-Z0-9]+$/i', $ppp['hostuniq'])) {
2719
					$hostuniq = '0x' . bin2hex($ppp['hostuniq']) . '|';
2720
				}
2721
			}
2722
			// Send a null service name if none is set.
2723
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2724
			$mpdconf .= <<<EOD
2725
	set pppoe service "{$hostuniq}{$provider}"
2726

    
2727
EOD;
2728
		}
2729
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2730
			$mpdconf .= <<<EOD
2731
	set pppoe max-payload {$mtus[$pid]}
2732

    
2733
EOD;
2734
		}
2735
		if ($type == "pppoe") {
2736
			$mpdconf .= <<<EOD
2737
	set pppoe iface {$port}
2738

    
2739
EOD;
2740
		}
2741

    
2742
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2743
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2744
			$mpdconf .= <<<EOD
2745
	set l2tp secret "{$secret}"
2746

    
2747
EOD;
2748
		}
2749

    
2750
		if (($type == "pptp") || ($type == "l2tp")) {
2751
			$mpdconf .= <<<EOD
2752
	set {$type} self {$localips[$pid]}
2753
	set {$type} peer {$gateways[$pid]}
2754

    
2755
EOD;
2756
		}
2757

    
2758
		$mpdconf .= "\topen\n";
2759
	} //end foreach ($port)
2760

    
2761

    
2762
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2763
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2764
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2765
	} else {
2766
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2767
		if (!$fd) {
2768
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2769
			return 0;
2770
		}
2771
		// Write out mpd_ppp.conf
2772
		fwrite($fd, $mpdconf);
2773
		fclose($fd);
2774
		unset($mpdconf);
2775
	}
2776

    
2777
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2778
	if (isset($ppp['uptime'])) {
2779
		if (!file_exists("/conf/{$pppif}.log")) {
2780
			file_put_contents("/conf/{$pppif}.log", '');
2781
		}
2782
	} else {
2783
		if (file_exists("/conf/{$pppif}.log")) {
2784
			@unlink("/conf/{$pppif}.log");
2785
		}
2786
	}
2787

    
2788
	/* clean up old lock files */
2789
	foreach ($ports as $port) {
2790
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2791
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2792
		}
2793
	}
2794

    
2795
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2796
	/* random IPv6 interface identifier during boot. More details at */
2797
	/* https://forum.netgate.com/post/592474 */
2798
	if (platform_booting() && is_array($config['interfaces'])) {
2799
		$count = 0;
2800
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2801
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2802
				$tempaddr[$count]['if'] = $tempiface['if'];
2803
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2804
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2805
				$count++;
2806
			}
2807
			// Maximum /31 is is x.y.z.254/31
2808
			if ($count > 122) {
2809
				break;
2810
			}
2811
		}
2812
		unset($count);
2813
	}
2814

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

    
2820
	// Check for PPPoE periodic reset request
2821
	if ($type == "pppoe") {
2822
		if (!empty($ppp['pppoe-reset-type'])) {
2823
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2824
		} else {
2825
			interface_setup_pppoe_reset_file($ppp['if']);
2826
		}
2827
	}
2828
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2829
	$i = 0;
2830
	while ($i < 10) {
2831
		if (does_interface_exist($ppp['if'], true)) {
2832
			break;
2833
		}
2834
		sleep(3);
2835
		$i++;
2836
	}
2837

    
2838
	/* Remove all temporary bogon IPv4 addresses */
2839
	if (is_array($tempaddr)) {
2840
		foreach ($tempaddr as $tempiface) {
2841
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2842
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2843
			}
2844
		}
2845
		unset ($tempaddr);
2846
	}
2847

    
2848
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2849
	/* We should be able to launch the right version for each modem */
2850
	/* We can also guess the mondev from the manufacturer */
2851
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2852
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2853
	foreach ($ports as $port) {
2854
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2855
			$mondev = substr(basename($port), 0, -1);
2856
			$devlist = glob("/dev/{$mondev}?");
2857
			$mondev = basename(end($devlist));
2858
		}
2859
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2860
			$mondev = substr(basename($port), 0, -1) . "1";
2861
		}
2862
		if ($mondev != '') {
2863
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2864
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2865
		}
2866
	}
2867

    
2868
	return 1;
2869
}
2870

    
2871
function interfaces_sync_setup() {
2872
	global $g, $config;
2873

    
2874
	if (isset($config['system']['developerspew'])) {
2875
		$mt = microtime();
2876
		echo "interfaces_sync_setup() being called $mt\n";
2877
	}
2878

    
2879
	if (platform_booting()) {
2880
		echo gettext("Configuring CARP settings...");
2881
		mute_kernel_msgs();
2882
	}
2883

    
2884
	/* suck in configuration items */
2885
	if ($config['hasync']) {
2886
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2887
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2888
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2889
	}
2890

    
2891
	set_sysctl(array(
2892
		"net.inet.carp.preempt" => "1",
2893
		"net.inet.carp.log" => "1")
2894
	);
2895

    
2896
	if (!empty($pfsyncinterface)) {
2897
		$carp_sync_int = get_real_interface($pfsyncinterface);
2898
	}
2899

    
2900
	/* setup pfsync interface */
2901
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2902
		if (is_ipaddr($pfsyncpeerip)) {
2903
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2904
		} else {
2905
			$syncpeer = "-syncpeer";
2906
		}
2907

    
2908
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} " .
2909
		    "{$syncpeer} up");
2910
		mwexec("/sbin/ifconfig pfsync0 -defer");
2911

    
2912
		/*
2913
		 * XXX: Handle an issue with pfsync(4) and carp(4). In a
2914
		 * cluster carp will come up before pfsync(4) has updated and
2915
		 * so will cause issues for existing sessions.
2916
		 */
2917
		log_error(gettext("waiting for pfsync..."));
2918

    
2919
		$i = 0;
2920
		do {
2921
			sleep(1);
2922
			$_gb = exec('/sbin/ifconfig pfsync0 | ' .
2923
			    '/usr/bin/grep -q "syncok: 0" 2>/dev/null', $output,
2924
			    $rc);
2925
			$i++;
2926
		} while ($rc != 0 && $i <= 30);
2927

    
2928
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2929
		log_error(gettext("Configuring CARP settings finalize..."));
2930
	} else {
2931
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down");
2932
	}
2933

    
2934
	$carplist = get_configured_vip_list('all', VIP_CARP);
2935
	if (is_array($carplist) && count($carplist) > 0) {
2936
		set_single_sysctl("net.inet.carp.allow", "1");
2937
	} else {
2938
		set_single_sysctl("net.inet.carp.allow", "0");
2939
	}
2940

    
2941
	if (platform_booting()) {
2942
		unmute_kernel_msgs();
2943
		echo gettext("done.") . "\n";
2944
	}
2945
}
2946

    
2947
function interface_proxyarp_configure($interface = "") {
2948
	global $config, $g;
2949
	if (isset($config['system']['developerspew'])) {
2950
		$mt = microtime();
2951
		echo "interface_proxyarp_configure() being called $mt\n";
2952
	}
2953

    
2954
	/* kill any running choparp */
2955
	if (empty($interface)) {
2956
		killbyname("choparp");
2957
	} else {
2958
		$vipif = get_real_interface($interface);
2959
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2960
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2961
		}
2962
	}
2963

    
2964
	$paa = array();
2965
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2966

    
2967
		/* group by interface */
2968
		foreach ($config['virtualip']['vip'] as $vipent) {
2969
			if ($vipent['mode'] === "proxyarp") {
2970
				if ($vipent['interface']) {
2971
					$proxyif = $vipent['interface'];
2972
				} else {
2973
					$proxyif = "wan";
2974
				}
2975

    
2976
				if (!empty($interface) && $interface != $proxyif) {
2977
					continue;
2978
				}
2979

    
2980
				if (!is_array($paa[$proxyif])) {
2981
					$paa[$proxyif] = array();
2982
				}
2983

    
2984
				$paa[$proxyif][] = $vipent;
2985
			}
2986
		}
2987
	}
2988

    
2989
	if (!empty($interface)) {
2990
		if (is_array($paa[$interface])) {
2991
			$paaifip = get_interface_ip($interface);
2992
			if (!is_ipaddr($paaifip)) {
2993
				return;
2994
			}
2995
			$vipif = get_real_interface($interface);
2996
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2997
			$args .= $vipif . " auto";
2998
			foreach ($paa[$interface] as $paent) {
2999
				if (isset($paent['subnet'])) {
3000
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
3001
				} elseif (isset($paent['range'])) {
3002
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
3003
				}
3004
			}
3005
			mwexec_bg("/usr/local/sbin/choparp " . $args);
3006
		}
3007
	} elseif (count($paa) > 0) {
3008
		foreach ($paa as $paif => $paents) {
3009
			$paaifip = get_interface_ip($paif);
3010
			if (!is_ipaddr($paaifip)) {
3011
				continue;
3012
			}
3013
			$vipif = get_real_interface($paif);
3014
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
3015
			$args .= $vipif . " auto";
3016
			foreach ($paents as $paent) {
3017
				if (isset($paent['subnet'])) {
3018
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
3019
				} elseif (isset($paent['range'])) {
3020
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
3021
				}
3022
			}
3023
			mwexec_bg("/usr/local/sbin/choparp " . $args);
3024
		}
3025
	}
3026
}
3027

    
3028
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
3029
	global $g, $config;
3030

    
3031
	if (is_array($config['virtualip']['vip'])) {
3032
		foreach ($config['virtualip']['vip'] as $vip) {
3033

    
3034
			$iface = $vip['interface'];
3035
			if (substr($iface, 0, 4) == "_vip")
3036
				$iface = get_configured_vip_interface($vip['interface']);
3037
			if ($iface != $interface)
3038
				continue;
3039
			if ($type == VIP_CARP) {
3040
				if ($vip['mode'] != "carp")
3041
					continue;
3042
			} elseif ($type == VIP_IPALIAS) {
3043
				if ($vip['mode'] != "ipalias")
3044
					continue;
3045
			} else {
3046
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
3047
					continue;
3048
			}
3049

    
3050
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
3051
				interface_vip_bring_down($vip);
3052
			elseif ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
3053
				interface_vip_bring_down($vip);
3054
			elseif ($inet == "all")
3055
				interface_vip_bring_down($vip);
3056
		}
3057
	}
3058
}
3059

    
3060
function interfaces_vips_configure($interface = "") {
3061
	global $g, $config;
3062
	if (isset($config['system']['developerspew'])) {
3063
		$mt = microtime();
3064
		echo "interfaces_vips_configure() being called $mt\n";
3065
	}
3066

    
3067
	if (!is_array($config['virtualip']['vip'])) {
3068
		return;
3069
	}
3070

    
3071
	$carp_setuped = false;
3072
	$anyproxyarp = false;
3073
	foreach ($config['virtualip']['vip'] as $vip) {
3074
		if ($interface <> "" &&
3075
		    get_root_interface($vip['interface']) <> $interface) {
3076
			continue;
3077
		}
3078
		switch ($vip['mode']) {
3079
			case "proxyarp":
3080
				/*
3081
				 * nothing it is handled on
3082
				 * interface_proxyarp_configure()
3083
				 */
3084
				$anyproxyarp = true;
3085
				break;
3086
			case "ipalias":
3087
				interface_ipalias_configure($vip);
3088
				break;
3089
			case "carp":
3090
				if ($carp_setuped == false) {
3091
					$carp_setuped = true;
3092
				}
3093
				interface_carp_configure($vip);
3094
				break;
3095
		}
3096
	}
3097
	if ($carp_setuped == true) {
3098
		interfaces_sync_setup();
3099
	}
3100
	if ($anyproxyarp == true) {
3101
		interface_proxyarp_configure();
3102
	}
3103
}
3104

    
3105
function interface_ipalias_configure(&$vip) {
3106
	global $config;
3107

    
3108
	$gateway = '';
3109
	if ($vip['mode'] != 'ipalias') {
3110
		return;
3111
	}
3112

    
3113
	$realif = get_real_interface("_vip{$vip['uniqid']}");
3114
	if ($realif != "lo0") {
3115
		$if = convert_real_interface_to_friendly_interface_name($realif);
3116
		if (!isset($config['interfaces'][$if]) ||
3117
		    !isset($config['interfaces'][$if]['enable'])) {
3118
			return;
3119
		}
3120
		if (is_pseudo_interface($realif)) {
3121
			if (is_ipaddrv4($vip['subnet'])) {
3122
				$gateway = get_interface_gateway($if);
3123
			} else {
3124
				$gateway = get_interface_gateway_v6($if);
3125
			}
3126
		}
3127
	}
3128

    
3129
	$af = 'inet';
3130
	if (is_ipaddrv6($vip['subnet'])) {
3131
		$af = 'inet6';
3132
	}
3133
	$iface = $vip['interface'];
3134
	$vhid = '';
3135
	if (substr($vip['interface'], 0, 4) == "_vip") {
3136
		$carpvip = get_configured_vip($vip['interface']);
3137
		$iface = $carpvip['interface'];
3138
		$vhid = "vhid {$carpvip['vhid']}";
3139
	}
3140
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$gateway} {$vhid}");
3141
	unset($iface, $af, $realif, $carpvip, $vhid, $gateway);
3142
}
3143

    
3144
function interface_carp_configure(&$vip, $maintenancemode_only = false, $ipalias_reload = false) {
3145
	global $config, $g;
3146
	if (isset($config['system']['developerspew'])) {
3147
		$mt = microtime();
3148
		echo "interface_carp_configure() being called $mt\n";
3149
	}
3150

    
3151
	if ($vip['mode'] != "carp") {
3152
		return;
3153
	}
3154

    
3155
	$realif = get_real_interface($vip['interface']);
3156
	if (!does_interface_exist($realif)) {
3157
		file_notice("CARP", sprintf(gettext(
3158
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
3159
		    $vip['subnet']), "Firewall: Virtual IP", "");
3160
		return;
3161
	}
3162
	if ($realif != "lo0") {
3163
		if (!isset($config['interfaces'][$vip['interface']]) ||
3164
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
3165
			return;
3166
		}
3167
	}
3168

    
3169
	$vip_password = $vip['password'];
3170
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3171
	    $vip_password)));
3172
	if ($vip['password'] != "") {
3173
		$password = " pass {$vip_password}";
3174
	}
3175

    
3176
	$advbase = "";
3177
	if (!empty($vip['advbase'])) {
3178
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3179
	}
3180

    
3181
	$carp_maintenancemode = isset(
3182
	    $config["virtualip_carp_maintenancemode"]);
3183
	if ($carp_maintenancemode) {
3184
		$advskew = "advskew 254";
3185
	} else {
3186
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3187
	}
3188

    
3189
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) .
3190
	    " {$advskew} {$advbase} {$password}");
3191

    
3192
	if (!$maintenancemode_only) {
3193
		if (is_ipaddrv4($vip['subnet'])) {
3194
			mwexec("/sbin/ifconfig {$realif} " .
3195
			    escapeshellarg($vip['subnet']) . "/" .
3196
			    escapeshellarg($vip['subnet_bits']) .
3197
			    " alias vhid " . escapeshellarg($vip['vhid']));
3198
		} elseif (is_ipaddrv6($vip['subnet'])) {
3199
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3200
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3201
			    escapeshellarg($vip['subnet_bits']) .
3202
			    " alias vhid " . escapeshellarg($vip['vhid']));
3203
		}
3204
	}
3205

    
3206
	/* reconfigure stacked IP Aliases after CARP VIP changes
3207
	 * see https://redmine.pfsense.org/issues/12227
3208
	 * and https://redmine.pfsense.org/issues/12961 */
3209
	if ($ipalias_reload) {
3210
		foreach ($config['virtualip']['vip'] as $viface) {
3211
			if (($viface['mode'] == 'ipalias') &&
3212
			    (get_root_interface($viface['interface']) == $vip['interface'])) { 
3213
				interface_vip_bring_down($viface);
3214
				interface_ipalias_configure($viface);
3215
			}
3216
		}
3217
	}
3218

    
3219
	return $realif;
3220
}
3221

    
3222
function interface_wireless_clone($realif, $wlcfg) {
3223
	global $config, $g;
3224
	/*   Check to see if interface has been cloned as of yet.
3225
	 *   If it has not been cloned then go ahead and clone it.
3226
	 */
3227
	$needs_clone = false;
3228
	if (is_array($wlcfg['wireless'])) {
3229
		$wlcfg_mode = $wlcfg['wireless']['mode'];
3230
	} else {
3231
		$wlcfg_mode = $wlcfg['mode'];
3232
	}
3233
	switch ($wlcfg_mode) {
3234
		case "hostap":
3235
			$mode = "wlanmode hostap";
3236
			break;
3237
		case "adhoc":
3238
			$mode = "wlanmode adhoc";
3239
			break;
3240
		default:
3241
			$mode = "";
3242
			break;
3243
	}
3244
	$baseif = interface_get_wireless_base($wlcfg['if']);
3245
	if (does_interface_exist($realif)) {
3246
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
3247
		$ifconfig_str = implode($output);
3248
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
3249
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
3250
			$needs_clone = true;
3251
		}
3252
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
3253
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
3254
			$needs_clone = true;
3255
		}
3256
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3257
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3258
			$needs_clone = true;
3259
		}
3260
	} else {
3261
		$needs_clone = true;
3262
	}
3263

    
3264
	if ($needs_clone == true) {
3265
		/* remove previous instance if it exists */
3266
		if (does_interface_exist($realif)) {
3267
			pfSense_interface_destroy($realif);
3268

    
3269
			/* Invalidate cache */
3270
			get_interface_arr(true);
3271
		}
3272

    
3273
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3274
		// Create the new wlan interface. FreeBSD returns the new interface name.
3275
		// example:  wlan2
3276
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3277
		if ($ret <> 0) {
3278
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3279
			return false;
3280
		}
3281
		$newif = trim($out[0]);
3282
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3283
		pfSense_interface_rename($newif, $realif);
3284
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3285
	}
3286
	return true;
3287
}
3288

    
3289
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3290
	global $config, $g;
3291

    
3292
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3293
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3294
				 'regdomain', 'regcountry', 'reglocation');
3295

    
3296
	if (!is_interface_wireless($ifcfg['if'])) {
3297
		return;
3298
	}
3299

    
3300
	$baseif = interface_get_wireless_base($ifcfg['if']);
3301

    
3302
	// Sync shared settings for assigned clones
3303
	$iflist = get_configured_interface_list(true);
3304
	foreach ($iflist as $if) {
3305
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
3306
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
3307
				foreach ($shared_settings as $setting) {
3308
					if ($sync_changes) {
3309
						if (isset($ifcfg['wireless'][$setting])) {
3310
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
3311
						} elseif (isset($config['interfaces'][$if]['wireless'][$setting])) {
3312
							unset($config['interfaces'][$if]['wireless'][$setting]);
3313
						}
3314
					} else {
3315
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3316
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
3317
						} elseif (isset($ifcfg['wireless'][$setting])) {
3318
							unset($ifcfg['wireless'][$setting]);
3319
						}
3320
					}
3321
				}
3322
				if (!$sync_changes) {
3323
					break;
3324
				}
3325
			}
3326
		}
3327
	}
3328

    
3329
	// Read or write settings at shared area
3330
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3331
		foreach ($shared_settings as $setting) {
3332
			if ($sync_changes) {
3333
				if (isset($ifcfg['wireless'][$setting])) {
3334
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3335
				} elseif (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3336
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3337
				}
3338
			} elseif (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3339
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3340
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3341
				} elseif (isset($ifcfg['wireless'][$setting])) {
3342
					unset($ifcfg['wireless'][$setting]);
3343
				}
3344
			}
3345
		}
3346
	}
3347

    
3348
	// Sync the mode on the clone creation page with the configured mode on the interface
3349
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3350
		foreach ($config['wireless']['clone'] as &$clone) {
3351
			if ($clone['cloneif'] == $ifcfg['if']) {
3352
				if ($sync_changes) {
3353
					$clone['mode'] = $ifcfg['wireless']['mode'];
3354
				} else {
3355
					$ifcfg['wireless']['mode'] = $clone['mode'];
3356
				}
3357
				break;
3358
			}
3359
		}
3360
		unset($clone);
3361
	}
3362
}
3363

    
3364
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3365
	global $config, $g;
3366

    
3367
	/*    open up a shell script that will be used to output the commands.
3368
	 *    since wireless is changing a lot, these series of commands are fragile
3369
	 *    and will sometimes need to be verified by a operator by executing the command
3370
	 *    and returning the output of the command to the developers for inspection.  please
3371
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3372
	 */
3373

    
3374
	// Remove script file
3375
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3376

    
3377
	// Clone wireless nic if needed.
3378
	interface_wireless_clone($if, $wl);
3379

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

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

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

    
3389
	/* set values for /path/program */
3390
	if (file_exists("/usr/local/sbin/hostapd")) {
3391
		$hostapd = "/usr/local/sbin/hostapd";
3392
	} else {
3393
		$hostapd = "/usr/sbin/hostapd";
3394
	}
3395
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3396
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3397
	} else {
3398
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3399
	}
3400
	$ifconfig = "/sbin/ifconfig";
3401
	$sysctl = "/sbin/sysctl";
3402
	$sysctl_args = "-q";
3403
	$killall = "/usr/bin/killall";
3404

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

    
3407
	$wlcmd = array();
3408
	$wl_sysctl = array();
3409
	/* Set a/b/g standard */
3410
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3411
	/* skip mode entirely for "auto" */
3412
	if ($wlcfg['standard'] != "auto") {
3413
		$wlcmd[] = "mode " . escapeshellarg($standard);
3414
	}
3415

    
3416
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3417
	 * to prevent massive packet loss under certain conditions. */
3418
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3419
		$wlcmd[] = "-ampdu";
3420
	}
3421

    
3422
	/* Set ssid */
3423
	if ($wlcfg['ssid']) {
3424
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3425
	}
3426

    
3427
	/* Set 802.11g protection mode */
3428
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3429

    
3430
	/* set wireless channel value */
3431
	if (isset($wlcfg['channel'])) {
3432
		if ($wlcfg['channel'] == "0") {
3433
			$wlcmd[] = "channel any";
3434
		} else {
3435
			if ($wlcfg['channel_width'] != "0") {
3436
				$channel_width = ":" . $wlcfg['channel_width'];
3437
			} else {
3438
				$channel_width = '';
3439
			}
3440
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3441
		}
3442
	}
3443

    
3444
	/* Set antenna diversity value */
3445
	if (isset($wlcfg['diversity'])) {
3446
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3447
	}
3448

    
3449
	/* Set txantenna value */
3450
	if (isset($wlcfg['txantenna'])) {
3451
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3452
	}
3453

    
3454
	/* Set rxantenna value */
3455
	if (isset($wlcfg['rxantenna'])) {
3456
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3457
	}
3458

    
3459
	/* set Distance value */
3460
	if ($wlcfg['distance']) {
3461
		$distance = escapeshellarg($wlcfg['distance']);
3462
	}
3463

    
3464
	/* Set wireless hostap mode */
3465
	if ($wlcfg['mode'] == "hostap") {
3466
		$wlcmd[] = "mediaopt hostap";
3467
	} else {
3468
		$wlcmd[] = "-mediaopt hostap";
3469
	}
3470

    
3471
	/* Set wireless adhoc mode */
3472
	if ($wlcfg['mode'] == "adhoc") {
3473
		$wlcmd[] = "mediaopt adhoc";
3474
	} else {
3475
		$wlcmd[] = "-mediaopt adhoc";
3476
	}
3477

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

    
3480
	/* handle hide ssid option */
3481
	if (isset($wlcfg['hidessid']['enable'])) {
3482
		$wlcmd[] = "hidessid";
3483
	} else {
3484
		$wlcmd[] = "-hidessid";
3485
	}
3486

    
3487
	/* handle pureg (802.11g) only option */
3488
	if (isset($wlcfg['pureg']['enable'])) {
3489
		$wlcmd[] = "mode 11g pureg";
3490
	} else {
3491
		$wlcmd[] = "-pureg";
3492
	}
3493

    
3494
	/* handle puren (802.11n) only option */
3495
	if (isset($wlcfg['puren']['enable'])) {
3496
		$wlcmd[] = "puren";
3497
	} else {
3498
		$wlcmd[] = "-puren";
3499
	}
3500

    
3501
	/* enable apbridge option */
3502
	if (isset($wlcfg['apbridge']['enable'])) {
3503
		$wlcmd[] = "apbridge";
3504
	} else {
3505
		$wlcmd[] = "-apbridge";
3506
	}
3507

    
3508
	/* handle turbo option */
3509
	if (isset($wlcfg['turbo']['enable'])) {
3510
		$wlcmd[] = "mediaopt turbo";
3511
	} else {
3512
		$wlcmd[] = "-mediaopt turbo";
3513
	}
3514

    
3515
	/* handle txpower setting */
3516
	// or don't. this has issues at the moment.
3517
	/*
3518
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3519
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3520
	}*/
3521

    
3522
	/* handle wme option */
3523
	if (isset($wlcfg['wme']['enable'])) {
3524
		$wlcmd[] = "wme";
3525
	} else {
3526
		$wlcmd[] = "-wme";
3527
	}
3528

    
3529
	/* Enable wpa if it's configured. No WEP support anymore. */
3530
	if (isset($wlcfg['wpa']['enable'])) {
3531
		$wlcmd[] = "authmode wpa wepmode off ";
3532
	} else {
3533
		$wlcmd[] = "authmode open wepmode off ";
3534
	}
3535

    
3536
	kill_hostapd($if);
3537
	mwexec(kill_wpasupplicant("{$if}"));
3538

    
3539
	$wpa_supplicant_file = "{$g['varetc_path']}/wpa_supplicant_{$if}.";
3540
	$hostapd_conf = "{$g['varetc_path']}/hostapd_{$if}.conf";
3541

    
3542
	unlink_if_exists("{$wpa_supplicant_file}*");
3543
	unlink_if_exists($hostapd_conf);
3544

    
3545
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3546

    
3547
	switch ($wlcfg['mode']) {
3548
		case 'bss':
3549
			if (isset($wlcfg['wpa']['enable'])) {
3550
				$wpa .= <<<EOD
3551
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3552
ctrl_interface_group=0
3553
ap_scan=1
3554
#fast_reauth=1
3555
network={
3556
ssid="{$wlcfg['ssid']}"
3557
scan_ssid=1
3558
priority=5
3559
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3560
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3561
group={$wlcfg['wpa']['wpa_pairwise']}
3562

    
3563
EOD;
3564
				if ($wlcfg['wpa']['wpa_key_mgmt'] == 'WPA-EAP') {
3565
					if (($wlcfg['wpa']['wpa_eap_client_mode'] == 'PEAP') ||
3566
					    ($wlcfg['wpa']['wpa_eap_client_mode'] == 'TTLS')) {
3567
						if ($wlcfg['wpa']['wpa_eap_inner_auth'] == 'MSCHAPV2') {
3568
							$wpa .= "phase1=\"peaplabel=0\"\n";
3569
						}
3570
						$wpa .= "phase2=\"auth={$wlcfg['wpa']['wpa_eap_inner_auth']}\"\n";
3571
						$wpa .= "identity=\"{$wlcfg['wpa']['wpa_eap_inner_id']}\"\n";
3572
						$eappass = base64_decode($wlcfg['wpa']['wpa_eap_inner_password']);
3573
						$wpa .= "password=\"{$eappass}\"\n";
3574
					}
3575
					if (strstr($wlcfg['wpa']['wpa_eap_client_mode'], 'TLS')) { 
3576
						$cert = lookup_cert($wlcfg['wpa']['wpa_eap_cert']);
3577
						@file_put_contents($wpa_supplicant_file . "crt", base64_decode($cert['crt']) . "\n" .
3578
						    ca_chain($cert)); 
3579
						@file_put_contents($wpa_supplicant_file . "key", base64_decode($cert['prv'])); 
3580
						@chmod($wpa_supplicant_crt, 0600);
3581
						@chmod($wpa_supplicant_key, 0600);
3582
						$wpa .= "client_cert=\"{$wpa_supplicant_crt}\"\n";
3583
						$wpa .= "private_key=\"{$wpa_supplicant_key}\"\n";
3584
					}
3585
					$ca = lookup_ca($wlcfg['wpa']['wpa_eap_ca']);
3586
					@file_put_contents($wpa_supplicant_file . "ca", base64_decode($ca['crt']) . "\n" .
3587
					    ca_chain($ca)); 
3588
					$wpa .= "ca_cert=\"{$wpa_supplicant_ca}\"\n";
3589
					$wpa .= "eap={$wlcfg['wpa']['wpa_eap_client_mode']}\n";
3590
				} else {
3591
					$wpa .= "psk=\"{$wlcfg['wpa']['passphrase']}\"\n";
3592
				}
3593
				$wpa .= "}\n";
3594

    
3595
				@file_put_contents($wpa_supplicant_file . "conf", $wpa);
3596
				unset($wpa);
3597
			}
3598
			break;
3599
		case 'hostap':
3600
			if (!empty($wlcfg['wpa']['passphrase'])) {
3601
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3602
			} else {
3603
				$wpa_passphrase = "";
3604
			}
3605
			if (isset($wlcfg['wpa']['enable'])) {
3606
				$wpa .= <<<EOD
3607
interface={$if}
3608
driver=bsd
3609
logger_syslog=-1
3610
logger_syslog_level=0
3611
logger_stdout=-1
3612
logger_stdout_level=0
3613
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3614
ctrl_interface={$g['varrun_path']}/hostapd
3615
ctrl_interface_group=wheel
3616
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3617
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3618
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3619
ssid={$wlcfg['ssid']}
3620
debug={$wlcfg['wpa']['debug_mode']}
3621
wpa={$wlcfg['wpa']['wpa_mode']}
3622
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3623
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3624
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3625
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3626
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3627
{$wpa_passphrase}
3628

    
3629
EOD;
3630

    
3631
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3632
					$wpa .= <<<EOD
3633
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3634
rsn_preauth=1
3635
rsn_preauth_interfaces={$if}
3636

    
3637
EOD;
3638
				}
3639
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3640
					$wpa .= "ieee8021x=1\n";
3641

    
3642
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3643
						$auth_server_port = "1812";
3644
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3645
							$auth_server_port = intval($wlcfg['auth_server_port']);
3646
						}
3647
						$wpa .= <<<EOD
3648

    
3649
auth_server_addr={$wlcfg['auth_server_addr']}
3650
auth_server_port={$auth_server_port}
3651
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3652

    
3653
EOD;
3654
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3655
							$auth_server_port2 = "1812";
3656
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3657
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3658
							}
3659

    
3660
							$wpa .= <<<EOD
3661
auth_server_addr={$wlcfg['auth_server_addr2']}
3662
auth_server_port={$auth_server_port2}
3663
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3664

    
3665
EOD;
3666
						}
3667
					}
3668
				}
3669

    
3670
				@file_put_contents($hostapd_conf, $wpa);
3671
				unset($wpa);
3672
			}
3673
			break;
3674
	}
3675

    
3676
	/*
3677
	 *    all variables are set, lets start up everything
3678
	 */
3679

    
3680
	$baseif = interface_get_wireless_base($if);
3681
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3682
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3683

    
3684
	/* set sysctls for the wireless interface */
3685
	if (!empty($wl_sysctl)) {
3686
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3687
		foreach ($wl_sysctl as $wl_sysctl_line) {
3688
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3689
		}
3690
	}
3691

    
3692
	/* set ack timers according to users preference (if he/she has any) */
3693
	if ($distance) {
3694
		fwrite($fd_set, "# Enable ATH distance settings\n");
3695
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3696
	}
3697

    
3698
	if (isset($wlcfg['wpa']['enable'])) {
3699
		if ($wlcfg['mode'] == "bss") {
3700
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3701
		}
3702
		if ($wlcfg['mode'] == "hostap") {
3703
			/* add line to script to restore old mac to make hostapd happy */
3704
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3705
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3706
				$if_curmac = get_interface_mac($if);
3707
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3708
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3709
						" link " . escapeshellarg($if_oldmac) . "\n");
3710
				}
3711
			}
3712

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

    
3715
			/* add line to script to restore spoofed mac after running hostapd */
3716
			if ($wl['spoofmac']) {
3717
				$if_curmac = get_interface_mac($if);
3718
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3719
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3720
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3721
				}
3722
			}
3723
		}
3724
	}
3725

    
3726
	fclose($fd_set);
3727

    
3728
	/* Making sure regulatory settings have actually changed
3729
	 * before applying, because changing them requires bringing
3730
	 * down all wireless networks on the interface. */
3731
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3732
	$ifconfig_str = implode($output);
3733
	unset($output);
3734
	$reg_changing = false;
3735

    
3736
	/* special case for the debug country code */
3737
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3738
		$reg_changing = true;
3739
	} elseif ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3740
		$reg_changing = true;
3741
	} elseif ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3742
		$reg_changing = true;
3743
	} elseif ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3744
		$reg_changing = true;
3745
	} elseif ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3746
		$reg_changing = true;
3747
	}
3748

    
3749
	if ($reg_changing) {
3750
		/* set regulatory domain */
3751
		if ($wlcfg['regdomain']) {
3752
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3753
		}
3754

    
3755
		/* set country */
3756
		if ($wlcfg['regcountry']) {
3757
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3758
		}
3759

    
3760
		/* set location */
3761
		if ($wlcfg['reglocation']) {
3762
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3763
		}
3764

    
3765
		$wlregcmd_args = implode(" ", $wlregcmd);
3766

    
3767
		/* build a complete list of the wireless clones for this interface */
3768
		$clone_list = array();
3769
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3770
			$clone_list[] = interface_get_wireless_clone($baseif);
3771
		}
3772
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3773
			foreach ($config['wireless']['clone'] as $clone) {
3774
				if ($clone['if'] == $baseif) {
3775
					$clone_list[] = $clone['cloneif'];
3776
				}
3777
			}
3778
		}
3779

    
3780
		/* find which clones are up and bring them down */
3781
		$clones_up = array();
3782
		foreach ($clone_list as $clone_if) {
3783
			$clone_status = pfSense_get_interface_addresses($clone_if);
3784
			if ($clone_status['status'] == 'up') {
3785
				$clones_up[] = $clone_if;
3786
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3787
			}
3788
		}
3789

    
3790
		/* apply the regulatory settings */
3791
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3792
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3793

    
3794
		/* bring the clones back up that were previously up */
3795
		foreach ($clones_up as $clone_if) {
3796
			interfaces_bring_up($clone_if);
3797

    
3798
			/*
3799
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3800
			 * is in infrastructure mode, and WPA is enabled.
3801
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3802
			 */
3803
			if ($clone_if != $if) {
3804
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3805
				if ((!empty($friendly_if)) &&
3806
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3807
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3808
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3809
				}
3810
			}
3811
		}
3812
	}
3813

    
3814
	/* The mode must be specified in a separate command before ifconfig
3815
	 * will allow the mode and channel at the same time in the next.
3816
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3817
	 */
3818
	if ($wlcfg['mode'] == "hostap") {
3819
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3820
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3821
	}
3822

    
3823
	/* configure wireless */
3824
	$wlcmd_args = implode(" ", $wlcmd);
3825
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args);
3826
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3827
	/* Bring the interface up only after setting up all the other parameters. */
3828
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up");
3829
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3830
	fclose($wlan_setup_log);
3831

    
3832
	unset($wlcmd_args, $wlcmd);
3833

    
3834

    
3835
	sleep(1);
3836
	/* execute hostapd and wpa_supplicant if required in shell */
3837
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3838

    
3839
	return 0;
3840

    
3841
}
3842

    
3843
function kill_hostapd($interface) {
3844
	global $g;
3845

    
3846
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3847
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3848
	}
3849
}
3850

    
3851
function kill_wpasupplicant($interface) {
3852
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3853
}
3854

    
3855
function find_dhclient_process($interface) {
3856
	if ($interface) {
3857
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3858
	} else {
3859
		$pid = 0;
3860
	}
3861

    
3862
	return intval($pid);
3863
}
3864

    
3865
function kill_dhclient_process($interface) {
3866
	if (empty($interface) || !does_interface_exist($interface)) {
3867
		return;
3868
	}
3869

    
3870
	$i = 0;
3871
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3872
		/* 3rd time make it die for sure */
3873
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3874
		posix_kill($pid, $sig);
3875
		sleep(1);
3876
		$i++;
3877
	}
3878
	unset($i);
3879
}
3880

    
3881
function find_dhcp6c_process() {
3882
	global $g;
3883

    
3884
	if (isvalidpid("{$g['varrun_path']}/dhcp6c.pid")) {
3885
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c.pid"), " \n");
3886
	} else {
3887
		return(false);
3888
	}
3889

    
3890
	return intval($pid);
3891
}
3892

    
3893
function kill_dhcp6client_process($force, $release = false) {
3894
	global $g;
3895

    
3896
	$i = 0;
3897

    
3898
	/*
3899
	Beware of the following: Reason, the interface may be down, but
3900
	dhcp6c may still be running, it just complains it cannot send
3901
	and carries on. Commented out as will stop the call to kill.
3902

    
3903
	if (empty($interface) || !does_interface_exist($interface)) {
3904
		return;
3905
	}
3906
	*/
3907

    
3908
	/*********** Notes on signals for dhcp6c and this function *************
3909

    
3910
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3911
	a release and waiting for the response that never comes.
3912
	So we need to tell it that the interface is down and to just die quickly
3913
	otherwise a new client may launch and we have duplicate proceses.
3914
	In this case use SIGUSR1.
3915

    
3916
	If we want to exit normally obeying the no release flag then use SIGTERM.
3917
	If we want to exit with a release overiding the no release flag then
3918
	use SIGUSR2.
3919

    
3920
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3921
	exit quickly without sending release signals.
3922

    
3923
	If $Force is set to false and $release is also set to false dhcp6c will
3924
	follow the no-release flag.
3925

    
3926
	If $Force is set to false and $release is true then dhcp6c will send a
3927
	release regardless of the no-release flag.
3928
	***********************************************************************/
3929

    
3930
	if ($force == true) {
3931
		$psig=SIGUSR1;
3932
	} elseif ($release == false) {
3933
		$psig=SIGTERM;
3934
	} else {
3935
		$psig=SIGUSR2;
3936
	}
3937

    
3938
	while ((($pid = find_dhcp6c_process()) != 0) && ($i < 3)) {
3939
		/* 3rd time make it die for sure */
3940
		$sig = ($i == 2 ? SIGKILL : $psig);
3941
		posix_kill($pid, $sig);
3942
		sleep(1);
3943
		$i++;
3944
	}
3945
	/* Clear the RTSOLD script created lock & tidy up */
3946
	unlink_if_exists("/tmp/dhcp6c_lock");
3947
	unlink_if_exists("{$g['varrun_path']}/dhcp6c.pid"); // just in case!
3948
}
3949
function reset_dhcp6client_process() {
3950

    
3951
	$pid = find_dhcp6c_process();
3952

    
3953
	if($pid != 0) {
3954
		posix_kill($pid, SIGHUP);
3955
	}
3956
}
3957

    
3958
function run_dhcp6client_process($interfaces, $debugOption, $noreleaseOption) {
3959
	global $g;
3960

    
3961
	/*
3962
	 * Only run this if the lock does not exist. In theory the lock being
3963
	 * there in this mode means the user has selected dhcp6withoutRA while
3964
	 * a session is active in the other mode.
3965
	 *
3966
	 * It should not happen as the process should have been killed and the
3967
	 * lock deleted.
3968
	 */
3969

    
3970
	if (!file_exists("/tmp/dhcp6c_lock")) {
3971
		kill_dhcp6client_process(true);
3972
		/* Lock it to avoid multiple runs */
3973
		touch("/tmp/dhcp6c_lock");
3974
		mwexec("/usr/local/sbin/dhcp6c {$debugOptions} " .
3975
		    "{$noreleaseOption} " .
3976
		    "-c {$g['varetc_path']}/dhcp6c.conf " .
3977
		    "-p {$g['varrun_path']}/dhcp6c.pid " .
3978
		    implode(' ', $interfaces));
3979
		log_error(sprintf(gettext(
3980
		    "Starting DHCP6 client for interfaces %s in DHCP6 without RA mode"),
3981
		    implode(',', $interfaces)));
3982
	}
3983
}
3984

    
3985
function interface_virtual_create($interface, $gateways_status = false) {
3986
	global $config;
3987

    
3988
	/* Fetch gateway status if not passed */
3989
	if (!is_array($gateways_status)) {
3990
		$gateways_status = return_gateways_status(true);
3991
	}
3992

    
3993
	if (interface_is_vlan($interface) != NULL) {
3994
		interface_vlan_configure(interface_is_vlan($interface));
3995
	} elseif (substr($interface, 0, 3) == "gre") {
3996
		interfaces_tunnel_configure(0, $interface, 'gre');
3997
	} elseif (substr($interface, 0, 3) == "gif") {
3998
		interfaces_tunnel_configure(0, $interface, 'gif');
3999
	} elseif (substr($interface, 0, 5) == "ovpns") {
4000
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
4001
			foreach ($config['openvpn']['openvpn-server'] as $server) {
4002
				if ($interface == "ovpns{$server['vpnid']}") {
4003
					if (!function_exists('openvpn_resync')) {
4004
						require_once('openvpn.inc');
4005
					}
4006
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
4007
					openvpn_resync('server', $server);
4008
				}
4009
			}
4010
			unset($server);
4011
		}
4012
	} elseif (substr($interface, 0, 5) == "ovpnc") {
4013
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
4014
			foreach ($config['openvpn']['openvpn-client'] as $client) {
4015
				if ($interface == "ovpnc{$client['vpnid']}") {
4016
					if (!function_exists('openvpn_resync')) {
4017
						require_once('openvpn.inc');
4018
					}
4019
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
4020
					openvpn_resync('client', $client);
4021
				}
4022
			}
4023
			unset($client);
4024
		}
4025
	} elseif (substr($interface, 0, 5) == "ipsec") {
4026
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
4027
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
4028
				if ($ph1ent['disabled']) {
4029
					continue;
4030
				}
4031
				interface_ipsec_vti_configure($ph1ent, $gateways_status);
4032
			}
4033
		}
4034
	} elseif (substr($interface, 0, 4) == "lagg") {
4035
		interfaces_lagg_configure($interface);
4036
	} elseif (substr($interface, 0, 6) == "bridge") {
4037
		interfaces_bridge_configure(0, $interface);
4038
	}
4039
}
4040

    
4041
function interface_vlan_mtu_configured($iface) {
4042
	global $config;
4043

    
4044
	$mtu = 0;
4045
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
4046
		foreach ($config['vlans']['vlan'] as $vlan) {
4047

    
4048
			if ($vlan['vlanif'] != $iface)
4049
				continue;
4050

    
4051
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4052
			$parentinf = convert_real_interface_to_friendly_interface_name($vlan['if']);
4053
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
4054
				/* VLAN MTU */
4055
				$mtu = $config['interfaces'][$assignedport]['mtu'];
4056
			} elseif (!empty($config['interfaces'][$parentinf]['mtu'])) {
4057
				/* Parent MTU */
4058
				$mtu = $config['interfaces'][$parentinf]['mtu'];
4059
			}
4060
		}
4061
	}
4062

    
4063
	return $mtu;
4064
}
4065

    
4066
function interface_mtu_wanted_for_pppoe($realif) {
4067
	global $config;
4068

    
4069
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
4070
		return 0;
4071

    
4072
	$mtu = 0;
4073
	foreach ($config['ppps']['ppp'] as $ppp) {
4074
		if ($ppp['type'] != "pppoe") {
4075
			continue;
4076
		}
4077

    
4078
		$mtus = array();
4079
		if (!empty($ppp['mtu'])) {
4080
			$mtus = explode(',', $ppp['mtu']);
4081
		}
4082
		$ports = explode(',', $ppp['ports']);
4083

    
4084
		foreach ($ports as $pid => $port) {
4085
			$parentifa = get_parent_interface($port);
4086
			$parentif = $parentifa[0];
4087
			if ($parentif != $realif)
4088
				continue;
4089

    
4090
			// there is an MTU configured on the port in question
4091
			if (!empty($mtus[$pid])) {
4092
				$mtu = intval($mtus[$pid]) + 8;
4093
			// or use the MTU configured on the interface ...
4094
			} elseif (is_array($config['interfaces'])) {
4095
				foreach ($config['interfaces'] as $interface) {
4096
					if ($interface['if'] == $ppp['if'] &&
4097
					    !empty($interface['mtu'])) {
4098
						$mtu = intval($interface['mtu']) + 8;
4099
						break;
4100
					}
4101
				}
4102
			}
4103
		}
4104
	}
4105

    
4106
	return $mtu;
4107
}
4108

    
4109
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
4110
	global $config, $g;
4111
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
4112
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
4113

    
4114
	$wancfg = $config['interfaces'][$interface];
4115

    
4116
	if (!isset($wancfg['enable'])) {
4117
		return;
4118
	}
4119

    
4120
	$realif = get_real_interface($interface);
4121
	$realhwif_array = get_parent_interface($interface);
4122
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
4123
	$realhwif = $realhwif_array[0];
4124

    
4125
	$mac_if_cfg = $wancfg;
4126
	if (interface_is_vlan($realif)) {
4127
		$mac_if = convert_real_interface_to_friendly_interface_name(
4128
		    $realhwif);
4129
		if (is_array($config['interfaces'][$mac_if])) {
4130
			$mac_if_cfg = $config['interfaces'][$mac_if];
4131
		} else {
4132
			$mac_if = $interface;
4133
		}
4134
	}
4135

    
4136
	if (!platform_booting() && (substr($realif, 0, 4) != "ovpn") && (substr($realif, 0, 5) != "ipsec")) {
4137
		/* remove all IPv4 and IPv6 addresses */
4138
		$tmpifaces = pfSense_getall_interface_addresses($realif);
4139
		if (is_array($tmpifaces)) {
4140
			foreach ($tmpifaces as $tmpiface) {
4141
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
4142
					if (!is_linklocal($tmpiface)) {
4143
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
4144
					}
4145
				} elseif (strstr($tmpiface, "fe80::1:1")) {
4146
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 fe80::1:1 -alias");
4147
				} else {
4148
					if (is_subnetv4($tmpiface)) {
4149
						$tmpip = explode('/', $tmpiface);
4150
						$tmpip = $tmpip[0];
4151
					} else {
4152
						$tmpip = $tmpiface;
4153
					}
4154
					pfSense_interface_deladdress($realif, $tmpip);
4155
				}
4156
			}
4157
		}
4158

    
4159
		/* only bring down the interface when both v4 and v6 are set to NONE */
4160
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4161
			interface_bring_down($interface);
4162
		}
4163
	}
4164

    
4165
	$interface_to_check = $realif;
4166
	if (interface_isppp_type($interface)) {
4167
		$interface_to_check = $realhwif;
4168
	}
4169

    
4170
	/* Need to check that the interface exists or not in the case where its coming back from disabled state see #3270 */
4171
	if (!platform_booting() && (in_array(substr($realif, 0, 3), array("gre", "gif")) ||
4172
	    !does_interface_exist($interface_to_check))) {
4173
		interface_virtual_create($interface_to_check);
4174
	}
4175

    
4176
	/* Disable Accepting router advertisements unless specifically requested */
4177
	if ($g['debug']) {
4178
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
4179
	}
4180
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
4181
	{
4182
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
4183
	}
4184
	/* wireless configuration? */
4185
	if (is_array($wancfg['wireless']) && !$linkupevent) {
4186
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
4187
	}
4188

    
4189
	$current_mac = get_interface_mac($realhwif);
4190
	$vendor_mac = get_interface_vendor_mac($realhwif);
4191

    
4192
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4193
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4194

    
4195
		interface_set_macaddr($realhwif, $mac_addr);
4196

    
4197
		/* Regenerate link-local address on MAC change.
4198
		 *
4199
		 * Some network devices respond to a DHCPv6 Solicit message only when
4200
		 * the IPv6 source address is consistent with what they expect.
4201
		 *
4202
		 * See https://redmine.pfsense.org/issues/12794 */
4203
		if ($mac_addr != $current_mac) {
4204
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 ifdisabled");
4205
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 " . get_interface_linklocal($interface) . " delete");
4206
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -ifdisabled");
4207
		}
4208
	} else {
4209
		/*
4210
		 * this is not a valid mac address.  generate a
4211
		 * temporary mac address so the machine can get online.
4212
		 */
4213
		echo gettext("Generating new MAC address.");
4214
		$random_mac = generate_random_mac_address();
4215
		interface_set_macaddr($realhwif, $random_mac);
4216
		$config['interfaces'][$mac_if]['spoofmac'] = $random_mac;
4217
		write_config(sprintf(gettext('The invalid MAC address ' .
4218
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
4219
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
4220
		file_notice("MAC Address altered", sprintf(gettext('The ' .
4221
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
4222
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
4223
		    $random_mac), "Interfaces");
4224
	}
4225

    
4226
	/* media */
4227
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4228
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4229
		if ($wancfg['media']) {
4230
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4231
		}
4232
		if ($wancfg['mediaopt']) {
4233
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4234
		}
4235
		mwexec($cmd);
4236
	}
4237

    
4238
	/* Apply hw offloading policies as configured */
4239
	enable_hardware_offloading($interface);
4240

    
4241
	/* invalidate interface/ip/sn cache */
4242
	get_interface_arr(true);
4243
	unset($interface_ip_arr_cache[$realif]);
4244
	unset($interface_sn_arr_cache[$realif]);
4245
	unset($interface_ipv6_arr_cache[$realif]);
4246
	unset($interface_snv6_arr_cache[$realif]);
4247

    
4248
	$tunnelif = substr($realif, 0, 3);
4249

    
4250
	$mtuif = $realif;
4251
	$mtuhwif = $realhwif;
4252

    
4253
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4254
	if (interface_isppp_type($interface)) {
4255
		$mtuif = $realhwif;
4256
		$mtuhwif_array = get_parent_interface($mtuif);
4257
		$mtuhwif = $mtuhwif_array[0];
4258
	}
4259

    
4260
	$wantedmtu = 0;
4261
	if (is_array($config['interfaces'])) {
4262
		foreach ($config['interfaces'] as $tmpinterface) {
4263
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4264
				$wantedmtu = $tmpinterface['mtu'];
4265
				break;
4266
			}
4267
		}
4268
	}
4269

    
4270
	/* MTU is not specified for interface, try the pppoe settings. */
4271
	if ($wantedmtu == 0) {
4272
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4273
	}
4274
	if (($wantedmtu == 0) && (interface_is_vlan($mtuif) != NULL) && interface_isppp_type($interface)) {
4275
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4276
	}
4277
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4278
		/* set MTU to 1400 for GRE over IPsec */
4279
		if (is_greipsec($mtuif)) {
4280
			$wantedmtu = 1400;
4281
		} else {
4282
			$wantedmtu = 1476;
4283
		}
4284
	}
4285
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4286
		$wantedmtu = 1280;
4287
	}
4288

    
4289
	/* Set the MTU to 1500 if no explicit MTU configured. */
4290
	if ($wantedmtu == 0) {
4291
		$wantedmtu = 1500; /* Default */
4292
	}
4293

    
4294
	if (interface_is_vlan($mtuif) != NULL) {
4295
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4296
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
4297
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
4298
			if ($wancfg['mtu'] > $parentmtu) {
4299
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4300
			}
4301
		}
4302

    
4303
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4304

    
4305
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4306
			$configuredmtu = $parentmtu;
4307
		if ($configuredmtu != 0)
4308
			$mtu = $configuredmtu;
4309
		else
4310
			$mtu = $wantedmtu;
4311

    
4312
		/* Set the parent MTU. */
4313
		if (get_interface_mtu($mtuhwif) < $mtu)
4314
			set_interface_mtu($mtuhwif, $mtu);
4315
		/* Set the VLAN MTU. */
4316
		if (get_interface_mtu($mtuif) != $mtu)
4317
			set_interface_mtu($mtuif, $mtu);
4318
	} elseif (substr($mtuif, 0, 4) == 'lagg') {
4319
		/* LAGG interface must be destroyed and re-created to change MTU */
4320
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4321
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
4322
				foreach ($config['laggs']['lagg'] as $lagg) {
4323
					if ($lagg['laggif'] == $mtuif) {
4324
						interface_lagg_configure($lagg);
4325
						break;
4326
					}
4327
				}
4328
			}
4329
		}
4330
	} else {
4331
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4332
			pfSense_interface_mtu($mtuif, $wantedmtu);
4333
			set_ipv6routes_mtu($mtuif, $wantedmtu);
4334
		}
4335
	}
4336
	/* XXX: What about gre/gif/.. ? */
4337

    
4338
	if (does_interface_exist($wancfg['if'])) {
4339
		interfaces_bring_up($wancfg['if']);
4340
	}
4341

    
4342
	switch ($wancfg['ipaddr']) {
4343
		case 'dhcp':
4344
			interface_dhcp_configure($interface);
4345
			break;
4346
		case 'pppoe':
4347
		case 'l2tp':
4348
		case 'pptp':
4349
		case 'ppp':
4350
			interface_ppps_configure($interface);
4351
			break;
4352
		default:
4353
			/* XXX: Kludge for now related to #3280 */
4354
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips", "l2t"))) {
4355
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4356
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4357
				}
4358
			}
4359
			break;
4360
	}
4361

    
4362
	switch ($wancfg['ipaddrv6']) {
4363
		case 'slaac':
4364
		case 'dhcp6':
4365
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4366
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4367
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4368
			log_error(gettext("calling interface_dhcpv6_configure."));
4369
			if ((($wancfg['ipaddrv6'] == 'dhcp6') && !isset($wancfg['dhcp6usev4iface'])) ||
4370
			    (($wancfg['ipaddrv6'] == 'slaac') && !isset($wancfg['slaacusev4iface'])) ||
4371
			    !interface_isppp_type($interface)) {
4372
				interface_dhcpv6_configure($interface, $wancfg);
4373
			}
4374
			break;
4375
		case '6rd':
4376
			interface_6rd_configure($interface, $wancfg);
4377
			break;
4378
		case '6to4':
4379
			interface_6to4_configure($interface, $wancfg);
4380
			break;
4381
		case 'track6':
4382
			interface_track6_configure($interface, $wancfg, $linkupevent);
4383
			break;
4384
		default:
4385
			/* XXX: Kludge for now related to #3280 */
4386
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips", "l2t"))) {
4387
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4388
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4389
					// FIXME: Add IPv6 Support to the pfSense module
4390
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4391
				}
4392
			}
4393
			break;
4394
	}
4395

    
4396
	if (!platform_booting()) {
4397
		link_interface_to_vips($interface, "update");
4398

    
4399
		if ($tunnelif != 'gre') {
4400
			$gre = link_interface_to_tunnelif($interface, 'gre');
4401
			array_walk($gre, 'interface_gre_configure');
4402
		}
4403

    
4404
		if ($tunnelif != 'gif') {
4405
			$gif = link_interface_to_tunnelif($interface, 'gif');
4406
			array_walk($gif, 'interface_gif_configure');
4407
		}
4408

    
4409
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4410
			unset($bridgetmp);
4411
			$bridgetmp = link_interface_to_bridge($interface);
4412
			if (!empty($bridgetmp)) {
4413
				interface_bridge_add_member($bridgetmp, $realif);
4414
			}
4415
		}
4416

    
4417
		$grouptmp = link_interface_to_group($interface);
4418
		if (!empty($grouptmp)) {
4419
			array_walk($grouptmp, 'interface_group_add_member');
4420
		}
4421

    
4422
		if ($interface == "lan") {
4423
			/* make new hosts file */
4424
			system_hosts_generate();
4425
		}
4426

    
4427
		if ($reloadall == true) {
4428

    
4429
			/* reconfigure static routes (kernel may have deleted them) */
4430
			system_routing_configure($interface);
4431

    
4432
			/* reload ipsec tunnels */
4433
			send_event("service reload ipsecdns");
4434

    
4435
			if (isset($config['dnsmasq']['enable'])) {
4436
				services_dnsmasq_configure();
4437
			}
4438

    
4439
			if (isset($config['unbound']['enable'])) {
4440
				services_unbound_configure();
4441
			}
4442

    
4443
			/* update dyndns */
4444
			send_event("service reload dyndns {$interface}");
4445
		}
4446
	} 
4447

    
4448
	if (!platform_booting() && (substr($realif, 0, 5) == 'l2tps')) {
4449
		vpn_l2tp_configure();
4450
	};
4451

    
4452
	if (!empty($wancfg['descr'])) {
4453
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4454
	};
4455

    
4456
	interfaces_staticarp_configure($interface);
4457
	return 0;
4458
}
4459

    
4460
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4461
	global $config, $g;
4462

    
4463
	if (!is_array($wancfg)) {
4464
		return;
4465
	}
4466

    
4467
	if (!isset($wancfg['enable'])) {
4468
		return;
4469
	}
4470

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

    
4476
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4477
	$realif = get_real_interface($interface);
4478
	$linklocal = find_interface_ipv6_ll($realif, true);
4479
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4480
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4481
	}
4482

    
4483
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4484
	if (!isset($trackcfg['enable'])) {
4485
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4486
		return;
4487
	}
4488

    
4489
	switch ($trackcfg['ipaddrv6']) {
4490
		case "6to4":
4491
			if ($g['debug']) {
4492
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4493
			}
4494
			interface_track6_6to4_configure($interface, $wancfg);
4495
			break;
4496
		case "6rd":
4497
			if ($g['debug']) {
4498
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4499
			}
4500
			interface_track6_6rd_configure($interface, $wancfg);
4501
			break;
4502
		case "dhcp6":
4503
			if ($linkupevent == true) {
4504
				/*
4505
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4506
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4507
				 *
4508
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4509
				 */
4510
				$pidv6 = find_dhcp6c_process();
4511
				if ($pidv6) {
4512
					posix_kill($pidv6, SIGHUP);
4513
				}
4514
			}
4515
			break;
4516
	}
4517

    
4518
	if ($linkupevent == false && !platform_booting()) {
4519
		if (!function_exists('services_dhcpd_configure')) {
4520
			require_once("services.inc");
4521
		}
4522

    
4523
		/* restart dns servers (defering dhcpd reload) */
4524
		if (isset($config['unbound']['enable'])) {
4525
			services_unbound_configure(false);
4526
		}
4527
		if (isset($config['dnsmasq']['enable'])) {
4528
			services_dnsmasq_configure(false);
4529
		}
4530

    
4531
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4532
		services_dhcpd_configure("inet6");
4533
	}
4534

    
4535
	return 0;
4536
}
4537

    
4538
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4539
	global $config, $g;
4540
	global $interface_ipv6_arr_cache;
4541
	global $interface_snv6_arr_cache;
4542

    
4543
	if (!is_array($lancfg)) {
4544
		return;
4545
	}
4546

    
4547
	/* If the interface is not configured via another, exit */
4548
	if (empty($lancfg['track6-interface'])) {
4549
		return;
4550
	}
4551

    
4552
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4553
	if (empty($wancfg)) {
4554
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4555
		return;
4556
	}
4557

    
4558
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4559
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4560
		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']));
4561
		return;
4562
	}
4563
	$hexwanv4 = return_hex_ipv4($ip4address);
4564

    
4565
	/* create the long prefix notation for math, save the prefix length */
4566
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4567
	$rd6prefixlen = $rd6prefix[1];
4568
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4569

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

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

    
4578
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4579
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4580
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4581
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4582
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4583
	/* fill the rest out with zeros */
4584
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4585

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

    
4589
	$lanif = get_real_interface($interface);
4590
	$oip = find_interface_ipv6($lanif);
4591
	if (is_ipaddrv6($oip)) {
4592
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4593
	}
4594
	unset($interface_ipv6_arr_cache[$lanif]);
4595
	unset($interface_snv6_arr_cache[$lanif]);
4596
	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));
4597
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4598

    
4599
	return 0;
4600
}
4601

    
4602
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4603
	global $config, $g;
4604
	global $interface_ipv6_arr_cache;
4605
	global $interface_snv6_arr_cache;
4606

    
4607
	if (!is_array($lancfg)) {
4608
		return;
4609
	}
4610

    
4611
	/* If the interface is not configured via another, exit */
4612
	if (empty($lancfg['track6-interface'])) {
4613
		return;
4614
	}
4615

    
4616
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4617
	if (empty($wancfg)) {
4618
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4619
		return;
4620
	}
4621

    
4622
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4623
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4624
		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']));
4625
		return;
4626
	}
4627
	$hexwanv4 = return_hex_ipv4($ip4address);
4628

    
4629
	/* create the long prefix notation for math, save the prefix length */
4630
	$sixto4prefix = "2002::";
4631
	$sixto4prefixlen = 16;
4632
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4633

    
4634
	/* binary presentation of the prefix for all 128 bits. */
4635
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4636

    
4637
	/* just save the left prefix length bits */
4638
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4639
	/* add the v4 address */
4640
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4641
	/* add the custom prefix id */
4642
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4643
	/* fill the rest out with zeros */
4644
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4645

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

    
4649
	$lanif = get_real_interface($interface);
4650
	$oip = find_interface_ipv6($lanif);
4651
	if (is_ipaddrv6($oip)) {
4652
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4653
	}
4654
	unset($interface_ipv6_arr_cache[$lanif]);
4655
	unset($interface_snv6_arr_cache[$lanif]);
4656
	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));
4657
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4658

    
4659
	return 0;
4660
}
4661

    
4662
function interface_6rd_configure($interface = "wan", $wancfg) {
4663
	global $config, $g;
4664

    
4665
	/* because this is a tunnel interface we can only function
4666
	 *	with a public IPv4 address on the interface */
4667

    
4668
	if (!is_array($wancfg)) {
4669
		return;
4670
	}
4671

    
4672
	if (!is_module_loaded('if_stf.ko')) {
4673
		mwexec('/sbin/kldload if_stf.ko');
4674
	}
4675

    
4676
	$wanif = get_real_interface($interface);
4677
	$ip4address = find_interface_ip($wanif);
4678
	if (!is_ipaddrv4($ip4address)) {
4679
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4680
		return false;
4681
	}
4682
	$hexwanv4 = return_hex_ipv4($ip4address);
4683

    
4684
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4685
		$wancfg['prefix-6rd-v4plen'] = 0;
4686
	}
4687

    
4688
	/* create the long prefix notation for math, save the prefix length */
4689
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4690
	$rd6prefixlen = $rd6prefix[1];
4691
	$brgw = explode('.', $wancfg['gateway-6rd']);
4692
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4693
	$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);
4694
	if (strlen($rd6brgw) < 128) {
4695
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4696
	}
4697
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4698
	unset($brgw);
4699
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4700

    
4701
	/* binary presentation of the prefix for all 128 bits. */
4702
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4703

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

    
4711
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4712
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4713

    
4714

    
4715
	/* XXX: need to extend to support variable prefix size for v4 */
4716
	$stfiface = "{$interface}_stf";
4717
	if (does_interface_exist($stfiface)) {
4718
		pfSense_interface_destroy($stfiface);
4719
	}
4720
	$tmpstfiface = pfSense_interface_create2("stf");
4721
	pfSense_interface_rename($tmpstfiface, $stfiface);
4722
	pfSense_interface_flags($stfiface, IFF_LINK2);
4723
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4724
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4725
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4726
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4727
	}
4728
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4729
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4730
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4731
	} elseif ($parentmtu > 1300) {
4732
		set_interface_mtu($stfiface, $parentmtu - 20);
4733
	}
4734
	if ($g['debug']) {
4735
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4736
	}
4737

    
4738
	/* write out a default router file */
4739
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4740
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4741
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4742

    
4743
	$ip4gateway = get_interface_gateway($interface);
4744
	if (is_ipaddrv4($ip4gateway)) {
4745
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4746
	}
4747

    
4748
	/* configure dependent interfaces */
4749
	if (!platform_booting()) {
4750
		link_interface_to_track6($interface, "update");
4751
	}
4752

    
4753
	return 0;
4754
}
4755

    
4756
function interface_6to4_configure($interface = "wan", $wancfg) {
4757
	global $config, $g;
4758

    
4759
	/* because this is a tunnel interface we can only function
4760
	 *	with a public IPv4 address on the interface */
4761

    
4762
	if (!is_array($wancfg)) {
4763
		return;
4764
	}
4765

    
4766
	$wanif = get_real_interface($interface);
4767
	$ip4address = find_interface_ip($wanif);
4768
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4769
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4770
		return false;
4771
	}
4772

    
4773
	/* create the long prefix notation for math, save the prefix length */
4774
	$stfprefixlen = 16;
4775
	$stfprefix = Net_IPv6::uncompress("2002::");
4776
	$stfarr = explode(":", $stfprefix);
4777
	$v4prefixlen = "0";
4778

    
4779
	/* we need the hex form of the interface IPv4 address */
4780
	$ip4arr = explode(".", $ip4address);
4781
	$hexwanv4 = "";
4782
	foreach ($ip4arr as $octet) {
4783
		$hexwanv4 .= sprintf("%02x", $octet);
4784
	}
4785

    
4786
	/* we need the hex form of the broker IPv4 address */
4787
	$ip4arr = explode(".", "192.88.99.1");
4788
	$hexbrv4 = "";
4789
	foreach ($ip4arr as $octet) {
4790
		$hexbrv4 .= sprintf("%02x", $octet);
4791
	}
4792

    
4793
	/* binary presentation of the prefix for all 128 bits. */
4794
	$stfprefixbin = "";
4795
	foreach ($stfarr as $element) {
4796
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4797
	}
4798
	/* just save the left prefix length bits */
4799
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4800

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

    
4805
	/* for the local subnet too. */
4806
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4807
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4808

    
4809
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4810
	$stfbrarr = array();
4811
	$stfbrbinarr = array();
4812
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4813
	foreach ($stfbrbinarr as $bin) {
4814
		$stfbrarr[] = dechex(bindec($bin));
4815
	}
4816
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4817

    
4818
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4819
	$stflanarr = array();
4820
	$stflanbinarr = array();
4821
	$stflanbinarr = str_split($stflanbin, 16);
4822
	foreach ($stflanbinarr as $bin) {
4823
		$stflanarr[] = dechex(bindec($bin));
4824
	}
4825
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4826
	$stflanarr[7] = 1;
4827
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4828

    
4829
	/* setup the stf interface */
4830
	if (!is_module_loaded("if_stf")) {
4831
		mwexec("/sbin/kldload if_stf.ko");
4832
	}
4833
	$stfiface = "{$interface}_stf";
4834
	if (does_interface_exist($stfiface)) {
4835
		pfSense_interface_destroy($stfiface);
4836
	}
4837
	$tmpstfiface = pfSense_interface_create2("stf");
4838
	pfSense_interface_rename($tmpstfiface, $stfiface);
4839
	pfSense_interface_flags($stfiface, IFF_LINK2);
4840
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4841

    
4842
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4843
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4844
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4845
	} elseif ($parentmtu > 1300) {
4846
		set_interface_mtu($stfiface, $parentmtu - 20);
4847
	}
4848
	if ($g['debug']) {
4849
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4850
	}
4851

    
4852
	/* write out a default router file */
4853
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4854
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4855
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4856

    
4857
	$ip4gateway = get_interface_gateway($interface);
4858
	if (is_ipaddrv4($ip4gateway)) {
4859
		route_add_or_change("192.88.99.1", $ip4gateway);
4860
	}
4861

    
4862
	if (!platform_booting()) {
4863
		link_interface_to_track6($interface, "update");
4864
	}
4865

    
4866
	return 0;
4867
}
4868

    
4869
function interface_dhcpv6_configure($ifconf = "wan", $ifcfg, $destroy = false) {
4870
	global $config, $g;
4871

    
4872
	$dhcp6cconf = "";
4873
	$id = "0";
4874
	$dhcp6cinterfaces = array();
4875
	$dhcp6cifs_descr = array();
4876
	$dhcp6crealifs = array();
4877
	$debugOption = "-d";
4878
	$noreleaseOption = "";
4879

    
4880
	if (!empty($config['system']['global-v6duid'])) {
4881
		// Write the DUID file
4882
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4883
		    log_error(gettext("Failed to write user DUID file!"));
4884
		}
4885
	}
4886

    
4887
	foreach ($config['interfaces'] as $interface => $wancfg) {
4888
		$wanif = get_real_interface($interface, "inet6");
4889

    
4890
		if (($ifconf == $interface) && $destroy) {
4891
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
4892
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh");
4893
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$wanif}_script.sh");
4894
			continue;
4895
		}
4896

    
4897
		if (!isset($wancfg['enable']) || (($ifconf == $interface) && $destroy) ||
4898
		    (($wancfg['ipaddrv6'] != 'dhcp6') && ($wancfg['ipaddrv6'] != 'slaac'))) {
4899
			continue;
4900
		}
4901

    
4902
		$dhcp6cinterfaces[$interface] = $wancfg;
4903

    
4904
		if (isset($config['system']['dhcp6debug'])) {
4905
			$debugOption = "-D";
4906
		}
4907
		if (isset($config['system']['dhcp6norelease'])) {
4908
			$noreleaseOption = "-n";
4909
		}
4910

    
4911
		/* accept router advertisements for this interface                 */
4912
		/* Moved to early in the function as sometimes interface not ready */
4913
		/* RTSOLD fails as interface does not accept .....                 */
4914

    
4915
		log_error("Accept router advertisements on interface {$wanif} ");
4916
		mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4917

    
4918
		if ($wancfg['adv_dhcp6_config_file_override']) {
4919
			// DHCP6 Config File Override
4920
			$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4921
		} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4922
			// DHCP6 Config File Advanced
4923
			$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4924
		} else {
4925
			// DHCP6 Config File Basic
4926
			$dhcp6cconf .= "interface {$wanif} {\n";
4927

    
4928
			/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4929
			if ($wancfg['ipaddrv6'] == "slaac") {
4930
				$dhcp6cconf .= "\tinformation-only;\n";
4931
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4932
				$dhcp6cconf .= "\trequest domain-name;\n";
4933
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4934
				$dhcp6cconf .= "};\n";
4935
			} else {
4936
				$trackiflist = array();
4937
				$iflist = link_interface_to_track6($interface);
4938
				foreach ($iflist as $ifname => $ifcfg) {
4939
					if (is_numeric($ifcfg['track6-prefix-id'])) {
4940
						$trackiflist[$ifname] = $ifcfg;
4941
					}
4942
				}
4943

    
4944
				/* skip address request if this is set */
4945
				if (!isset($wancfg['dhcp6prefixonly'])) {
4946
					$dhcp6cconf .= "\tsend ia-na {$id};\t# request stateful address\n";
4947
				}
4948
				if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4949
					$dhcp6cconf .= "\tsend ia-pd {$id};\t# request prefix delegation\n";
4950
				}
4951

    
4952
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4953
				$dhcp6cconf .= "\trequest domain-name;\n";
4954

    
4955
				/*
4956
				 * dhcp6c will run different scripts depending on
4957
				 * whether dhcpwithoutra is set or unset.
4958
				 */
4959
				if (isset($wancfg['dhcp6withoutra'])) {
4960
					$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4961
				} else {
4962
					$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4963
				}
4964
				$dhcp6cconf .= "};\n";
4965

    
4966
				if (!isset($wancfg['dhcp6prefixonly'])) {
4967
					$dhcp6cconf .= "id-assoc na {$id} { };\n";
4968
				}
4969

    
4970
				if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4971
					/* Setup the prefix delegation */
4972
					$dhcp6cconf .= "id-assoc pd {$id} {\n";
4973
					$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4974
					if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4975
						$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4976
					}
4977
					foreach ($trackiflist as $friendly => $ifcfg) {
4978
						if ($g['debug']) {
4979
							log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4980
						}
4981
						$realif = get_real_interface($friendly);
4982
						$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4983
						$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4984
						$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4985
						$dhcp6cconf .= "\t};\n";
4986
					}
4987
					unset($preflen, $iflist, $ifcfg, $ifname);
4988
					$dhcp6cconf .= "};\n\n";
4989
				}
4990
				unset($trackiflist);
4991
			}
4992
			$id++;
4993
		}
4994

    
4995
		/*************** Script Debug Logging ***************************
4996
		Both dhcp6 scripts now have a logging message built in.
4997
		These logging messages ONLY appear if dhcp6c debug logging is set.
4998
		The logging messages appear in the dhcp section of the logs,
4999
		not in system.
5000

    
5001
		These scripts now also take advantage of the REASON= env vars
5002
		supplied by dhcp6c.
5003
		****************************************************************/
5004

    
5005
		/* Script create for dhcp6withoutRA mode */
5006
		/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
5007
		$dhcp6cscriptwithoutra = "#!/bin/sh\n";
5008
		$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
5009
		$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
5010
		$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
5011
		$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
5012
		// Need to pass params to  the final script
5013
		$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
5014
		$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
5015
		$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
5016
		$dhcp6cscriptwithoutra .= "case \$REASON in\n";
5017
		$dhcp6cscriptwithoutra .= "REQUEST)\n";
5018
		$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
5019
		$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -M {$g['varetc_path']}/rtsold_{$wanif}_script.sh -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
5020
		if ($debugOption == '-D') {
5021
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rtsold\"\n";
5022
		}
5023
		$dhcp6cscriptwithoutra .= ";;\n";
5024
		$dhcp6cscriptwithoutra .= "REBIND)\n";
5025
		if ($debugOption == '-D') {
5026
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5027
		}
5028
		$dhcp6cscriptwithoutra .= ";;\n";
5029
		if (isset($wancfg['dhcp6norelease'])) {
5030
			$dhcp6cscriptwithoutra .= "EXIT)\n";
5031
		} else {
5032
			$dhcp6cscriptwithoutra .= "RELEASE)\n";
5033
		}
5034
		if ($debugOption == '-D') {
5035
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
5036
		}
5037
		$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5038
		$dhcp6cscriptwithoutra .= ";;\n";
5039
		$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
5040
		if ($debugOption == '-D') {
5041
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5042
		}
5043
		$dhcp6cscriptwithoutra .= "esac\n";
5044
		if (!@file_put_contents(
5045
		    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
5046
		    $dhcp6cscriptwithoutra)) {
5047
			printf("Error: cannot open " .
5048
			    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
5049
			    "interface_dhcpv6_configure() for writing.\n");
5050
			unset($dhcp6cscriptwithoutra);
5051
			return 1;
5052
		}
5053

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

    
5056
		/*
5057
		 * Dual mode wan_dhcp6c script with variations depending on node
5058
		 * dhcp6 will run the wan ipv6 configure
5059
		 */
5060
		$dhcp6cscript  = "#!/bin/sh\n";
5061
		$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
5062
		if (!isset($wancfg['dhcp6withoutra'])) {
5063
			$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
5064
			$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
5065
			$dhcp6cscript .= "case \$REASON in\n";
5066
			$dhcp6cscript .= "REBIND)\n";
5067
			if ($debugOption == '-D') {
5068
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5069
			}
5070
			$dhcp6cscript .= ";;\n";
5071
			$dhcp6cscript .= "REQUEST|";
5072
			if (isset($wancfg['dhcp6norelease'])) {
5073
				$dhcp6cscript .= "EXIT)\n";
5074
			} else {
5075
				$dhcp6cscript .= "RELEASE)\n";
5076
			}
5077
			if ($debugOption == '-D') {
5078
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c RELEASE, REQUEST or EXIT on {$wanif} running rc.newwanipv6\"\n";
5079
			}
5080
			$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5081
			$dhcp6cscript .= ";;\n";
5082
			$dhcp6cscript .= "RENEW|INFO)\n";
5083
			if ($debugOption == '-D') {
5084
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5085
			}
5086
			$dhcp6cscript .= "esac\n";
5087
			$rtsold_ra_ifs[] = $wanif;
5088
		} else {
5089
			// Need to get the parameters from the dhcp6cwithoutRA run
5090
			$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
5091
			$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
5092
			$dhcp6cscript .= "/bin/sleep 1\n";
5093
			$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5094
		}
5095

    
5096
		/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5097
		if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
5098
			printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
5099
			unset($dhcp6cscript);
5100
			return 1;
5101
		}
5102
		unset($dhcp6cscript);
5103
		@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
5104
	}
5105

    
5106
	if (!empty($dhcp6cinterfaces)) {
5107
		/* wide-dhcp6c works for now. */
5108
		if (!@file_put_contents("{$g['varetc_path']}/dhcp6c.conf", $dhcp6cconf)) {
5109
			printf("Error: cannot open dhcp6c.conf in interface_dhcpv6_configure() for writing.\n");
5110
			return 1;
5111
		}
5112
		foreach ($dhcp6cinterfaces as $interface => $wancfg) {
5113
			$dhcp6cifs_descr[] = $interface . '(' . $wancfg['if'] . ')';
5114
			$dhcp6crealifs[] = $wancfg['if'];
5115
		}
5116
		$dhcp6cdescr = implode(',', $dhcp6cifs_descr);
5117
		$dhcp6cifs = implode(' ', $dhcp6crealifs);
5118
		foreach ($dhcp6cinterfaces as $interface => $wancfg) {
5119
			$wanif = get_real_interface($interface, "inet6");
5120

    
5121
			$rtsoldscript_header = <<<EOD
5122
#!/bin/sh
5123
# This shell script launches dhcp6c and configured gateways for this interface.
5124
if [ -n "\$2" ]; then
5125
	if [ -n "$(echo \$2 | /usr/bin/grep '^fe80')" ]; then
5126
		echo \$2\%{$wanif} > {$g['tmp_path']}/{$wanif}_routerv6
5127
		/bin/rm -f {$g['tmp_path']}/{$wanif}_routerv6.last
5128
		echo \$2\%{$wanif} > {$g['tmp_path']}/{$wanif}_defaultgwv6
5129
	else
5130
		echo \$2 > {$g['tmp_path']}/{$wanif}_routerv6
5131
		/bin/rm -f {$g['tmp_path']}/{$wanif}_routerv6.last
5132
		echo \$2 > {$g['tmp_path']}/{$wanif}_defaultgwv6
5133
	fi
5134
	/usr/bin/logger -t rtsold "Received RA specifying route \$2 for interface {$interface}({$wanif})"
5135
fi
5136

    
5137
EOD;
5138

    
5139
			/* non ipoe Process */
5140
			if (!isset($wancfg['dhcp6withoutra'])) {
5141
				/*
5142
				 * We only want this script to run once, and if it runs twice
5143
				 * then do not launch dhcp6c again, this only happens if
5144
				 * dhcpwithoutra is not set.
5145
				 *
5146
				 * Check for a lock file, trying to prevent multiple instances
5147
				 * of dhcp6c being launched
5148
				 */
5149
				$rtsoldscript = $rtsoldscript_header;
5150
				$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_lock ]; then\n";
5151
				/*
5152
				 * Create the lock file, trying to prevent multiple instances
5153
				 * of dhcp6c being launched
5154
				 */
5155
				$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_lock\n";
5156
				$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c.pid ]; then\n";
5157
				$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c.pid\n";
5158
				$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c.pid\n";
5159
				$rtsoldscript .= "\t\t/bin/sleep 1\n";
5160
				$rtsoldscript .= "\tfi\n";
5161
				$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
5162
				    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c.conf " .
5163
				    "-p {$g['varrun_path']}/dhcp6c.pid {$dhcp6cifs}\n";
5164
				$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interfaces {$dhcp6cdescr}\"\n";
5165
				$rtsoldscript .= "else\n";
5166
				$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
5167
				$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c.pid\")\n";
5168
				$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
5169
				$rtsoldscript .= "fi\n";
5170
			} else {
5171
				/*
5172
				 * The script needs to run in dhcp6withoutra mode as RA may
5173
				 * not have been received, or there can be a delay with
5174
				 * certain ISPs
5175
				 */
5176
				$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
5177
				$rtsoldscript .= "/bin/sleep 1\n";
5178
			}
5179

    
5180
			/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5181
			if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
5182
				printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
5183
				return 1;
5184
			}
5185
			unset($rtsoldscript);
5186
			@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
5187
		}
5188

    
5189
		$realif = get_real_interface($ifconf, "inet6");
5190
		if (isvalidpid("{$g['varrun_path']}/rtsold_{$realif}.pid")) {
5191
			killbypid("{$g['varrun_path']}/rtsold_{$realif}.pid");
5192
			log_error("Killing running rtsold process");
5193
			sleep(2);
5194
		}
5195

    
5196
		if (file_exists("{$g['tmp_path']}/dhcp6c_ifs")) {
5197
			$dhcp6crealifs_run = unserialize(file_get_contents("{$g['tmp_path']}/dhcp6c_ifs"));
5198
		} else {
5199
			$dhcp6crealifs_run = array();
5200
		}
5201

    
5202
		if (($dhcp6crealifs != $dhcp6crealifs_run) || $destroy) {
5203
			kill_dhcp6client_process(false);
5204
			run_dhcp6client_process($dhcp6crealifs, $debugOption, $noreleaseOption);
5205
			file_put_contents("{$g['tmp_path']}/dhcp6c_ifs", serialize($dhcp6crealifs));
5206
			$dhcp6c_restarted = true;
5207
			if ($destroy) {
5208
				$track6 = link_interface_to_track6($ifconf);
5209
				if (is_array($track6) && !empty($track6)) {
5210
					/* remove stale track interfaces IP */
5211
					foreach ($track6 as $tr6ifname => $tr6cfg) {
5212
						interface_reconfigure($tr6if, true);
5213
					}
5214
				}
5215
			}
5216
		}
5217

    
5218
		if (isset($ifcfg['dhcp6withoutra']) && !$dhcp6c_restarted) {
5219
			/*
5220
			 * Start dhcp6c here if we don't want to wait for ra - calls
5221
			 * separate function
5222
			 *
5223
			 * In this mode dhcp6c launches rtsold via its script. RTSOLD
5224
			 * will then run the configure on receipt of the RA.
5225
			 *
5226
			 * Already started. interface_dhcpv6_configure() appears to get
5227
			 * called multiple times.
5228
			 *
5229
			 * Taking the interface down or releasing will kill the client.
5230
			 */
5231

    
5232
			/*
5233
			 * If the interface is being brought up, wait for the
5234
			 * interface to configure accept RA before launching.
5235
			 * Otherwise it is not ready to accept and will fail.
5236
			 */
5237
			sleep(3);
5238
			if (file_exists("/tmp/dhcp6c_lock")) {
5239
				reset_dhcp6client_process();
5240
			}
5241
		} elseif (!$destroy) {
5242
			/*
5243
			 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
5244
			 * ( it does not background, it exits! ) It will launch dhcp6c
5245
			 * if dhcpwihtoutra is not set
5246
			 */
5247
			log_error("Starting rtsold process on {$ifconf}({$realif})");
5248
			sleep(2);
5249
			mwexec("/usr/sbin/rtsold -1 " .
5250
			    "-p {$g['varrun_path']}/rtsold_{$realif}.pid " .
5251
			    "-M {$g['varetc_path']}/rtsold_{$realif}_script.sh " .
5252
			    "-O {$g['varetc_path']}/rtsold_{$realif}_script.sh " .
5253
			    $realif);
5254
		}
5255
	} else {
5256
		kill_dhcp6client_process(true);
5257
		unlink_if_exists("{$g['varetc_path']}/dhcp6c.conf");
5258
		unlink_if_exists("{$g['tmp_path']}/dhcp6c_ifs");
5259
	}
5260

    
5261
	/*
5262
	 * NOTE: will be called from rtsold invoked script
5263
	 * link_interface_to_track6($interface, "update");
5264
	 */
5265

    
5266
	return 0;
5267
}
5268

    
5269
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5270
	global $g;
5271

    
5272
	$send_options = "";
5273
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5274
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5275
		foreach ($options as $option) {
5276
			$send_options .= "\tsend " . trim($option) . ";\n";
5277
		}
5278
	}
5279

    
5280
	$request_options = "";
5281
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5282
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5283
		foreach ($options as $option) {
5284
			$request_options .= "\trequest " . trim($option) . ";\n";
5285
		}
5286
	}
5287

    
5288
	$information_only = "";
5289
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5290
		$information_only = "\tinformation-only;\n";
5291
	}
5292

    
5293
	if (isset($wancfg['dhcp6withoutra'])) {
5294
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\";\n";
5295
	} else {
5296
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5297
	}
5298
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5299
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5300
	}
5301

    
5302
	$interface_statement  = "interface";
5303
	$interface_statement .= " {$wanif}";
5304
	$interface_statement .= " {\n";
5305
	$interface_statement .= "$send_options";
5306
	$interface_statement .= "$request_options";
5307
	$interface_statement .= "$information_only";
5308
	$interface_statement .= "$script";
5309
	$interface_statement .= "};\n";
5310

    
5311
	$id_assoc_statement_address = "";
5312
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5313
		$id_assoc_statement_address .= "id-assoc";
5314
		$id_assoc_statement_address .= " na";
5315
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5316
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5317
		}
5318
		$id_assoc_statement_address .= " { ";
5319

    
5320
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5321
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5322
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5323
			$id_assoc_statement_address .= "\n\taddress";
5324
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5325
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5326
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5327
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5328
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5329
			}
5330
			$id_assoc_statement_address .= ";\n";
5331
		}
5332

    
5333
		$id_assoc_statement_address .= "};\n";
5334
	}
5335

    
5336
	$id_assoc_statement_prefix = "";
5337
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5338
		$id_assoc_statement_prefix .= "id-assoc";
5339
		$id_assoc_statement_prefix .= " pd";
5340
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5341
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5342
		}
5343
		$id_assoc_statement_prefix .= " { ";
5344

    
5345
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5346
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5347
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5348
			$id_assoc_statement_prefix .= "\n\tprefix";
5349
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5350
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5351
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5352
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5353
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5354
			}
5355
			$id_assoc_statement_prefix .= ";";
5356
		}
5357

    
5358
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5359
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5360
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5361
			$id_assoc_statement_prefix .= " {$realif}";
5362
			$id_assoc_statement_prefix .= " {\n";
5363
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5364
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5365
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5366
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5367
			}
5368
			$id_assoc_statement_prefix .= "\t};";
5369
		}
5370

    
5371
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5372
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5373
			$id_assoc_statement_prefix .= "\n";
5374
		}
5375

    
5376
		$id_assoc_statement_prefix .= "};\n";
5377
	}
5378

    
5379
	$authentication_statement = "";
5380
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5381
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5382
		$authentication_statement .= "authentication";
5383
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5384
		$authentication_statement .= " {\n";
5385
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5386
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5387
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5388
		}
5389
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5390
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5391
		}
5392
		$authentication_statement .= "};\n";
5393
	}
5394

    
5395
	$key_info_statement = "";
5396
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5397
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5398
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5399
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5400
		$key_info_statement .= "keyinfo";
5401
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5402
		$key_info_statement .= " {\n";
5403
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5404
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5405
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5406
		if (preg_match("/((([0-9]{4}-)?[0-9]{2}[0-9]{2} )?[0-9]{2}:[0-9]{2})||(foreever)/", $wancfg['adv_dhcp6_key_info_statement_expire'])) {
5407
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5408
		}
5409
		$key_info_statement .= "};\n";
5410
	}
5411

    
5412
	$dhcp6cconf  = $interface_statement;
5413
	$dhcp6cconf .= $id_assoc_statement_address;
5414
	$dhcp6cconf .= $id_assoc_statement_prefix;
5415
	$dhcp6cconf .= $authentication_statement;
5416
	$dhcp6cconf .= $key_info_statement;
5417

    
5418
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5419

    
5420
	return $dhcp6cconf;
5421
}
5422

    
5423

    
5424
function DHCP6_Config_File_Override($wancfg, $wanif) {
5425

    
5426
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5427

    
5428
	if ($dhcp6cconf === false) {
5429
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5430
		return '';
5431
	} else {
5432
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5433
	}
5434
}
5435

    
5436

    
5437
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5438

    
5439
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5440

    
5441
	return $dhcp6cconf;
5442
}
5443

    
5444

    
5445
function interface_dhcp_configure($interface = "wan") {
5446
	global $config, $g, $vlanprio_values;
5447

    
5448
	$ifcfg = $config['interfaces'][$interface];
5449
	if (empty($ifcfg)) {
5450
		$ifcfg = array();
5451
	}
5452

    
5453
	$dhclientconf_vlantag = "";
5454
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5455
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5456
	}
5457

    
5458
	/* generate dhclient_wan.conf */
5459
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5460
	if (!$fd) {
5461
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5462
		return 1;
5463
	}
5464

    
5465
	if ($ifcfg['dhcphostname']) {
5466
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5467
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5468
	} else {
5469
		$dhclientconf_hostname = "";
5470
	}
5471

    
5472
	$realif = get_real_interface($interface);
5473
	if (empty($realif)) {
5474
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5475
		return 0;
5476
	}
5477
	$dhclientconf = "";
5478

    
5479
	$dhclientconf .= <<<EOD
5480
interface "{$realif}" {
5481
	supersede interface-mtu 0;
5482
	timeout 60;
5483
	retry 15;
5484
	select-timeout 0;
5485
	initial-interval 1;
5486
	{$dhclientconf_vlantag}
5487
	{$dhclientconf_hostname}
5488
	script "/usr/local/sbin/pfSense-dhclient-script";
5489
EOD;
5490

    
5491
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5492
		$dhclientconf .= <<<EOD
5493

    
5494
	reject {$ifcfg['dhcprejectfrom']};
5495
EOD;
5496
	}
5497
	$dhclientconf .= <<<EOD
5498

    
5499
}
5500

    
5501
EOD;
5502

    
5503
	// DHCP Config File Advanced
5504
	if ($ifcfg['adv_dhcp_config_advanced']) {
5505
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5506
	}
5507

    
5508
	if (is_ipaddr($ifcfg['alias-address'])) {
5509
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5510
		$dhclientconf .= <<<EOD
5511
alias {
5512
	interface "{$realif}";
5513
	fixed-address {$ifcfg['alias-address']};
5514
	option subnet-mask {$subnetmask};
5515
}
5516

    
5517
EOD;
5518
	}
5519

    
5520
	// DHCP Config File Override
5521
	if ($ifcfg['adv_dhcp_config_file_override']) {
5522
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5523
	}
5524

    
5525
	fwrite($fd, $dhclientconf);
5526
	fclose($fd);
5527

    
5528
	/* bring wan interface up before starting dhclient */
5529
	if ($realif) {
5530
		interfaces_bring_up($realif);
5531
	}
5532

    
5533
	/* Make sure dhclient is not running */
5534
	kill_dhclient_process($realif);
5535

    
5536
	/* fire up dhclient */
5537
	mwexec("/sbin/dhclient -c {$g['varetc_path']}/dhclient_{$interface}.conf {$realif} > {$g['tmp_path']}/{$realif}_output 2> {$g['tmp_path']}/{$realif}_error_output");
5538

    
5539
	return 0;
5540
}
5541

    
5542
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5543

    
5544
	$hostname = "";
5545
	if ($ifcfg['dhcphostname'] != '') {
5546
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5547
	}
5548

    
5549
	/* DHCP Protocol Timings */
5550
	$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");
5551
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5552
		$pt_variable = "{$Protocol_Timing}";
5553
		${$pt_variable} = "";
5554
		if ($ifcfg[$Protocol_Timing] != "") {
5555
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5556
		}
5557
	}
5558

    
5559
	$send_options = "";
5560
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5561
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5562
		foreach ($options as $option) {
5563
			$send_options .= "\tsend " . trim($option) . ";\n";
5564
		}
5565
	}
5566

    
5567
	$request_options = "";
5568
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5569
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5570
	}
5571

    
5572
	$required_options = "";
5573
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5574
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5575
	}
5576

    
5577
	$option_modifiers = "";
5578
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5579
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5580
		foreach ($modifiers as $modifier) {
5581
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5582
		}
5583
	}
5584

    
5585
	$dhclientconf  = "interface \"{$realif}\" {\n";
5586
	$dhclientconf .= "\n";
5587
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5588
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5589
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5590
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5591
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5592
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5593
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5594
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5595
	$dhclientconf .= "\n";
5596
	$dhclientconf .= "# DHCP Protocol Options\n";
5597
	$dhclientconf .= "{$hostname}";
5598
	$dhclientconf .= "{$send_options}";
5599
	$dhclientconf .= "{$request_options}";
5600
	$dhclientconf .= "{$required_options}";
5601
	$dhclientconf .= "{$option_modifiers}";
5602
	$dhclientconf .= "\n";
5603
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5604
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5605
	}
5606
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5607
	$dhclientconf .= "}\n";
5608

    
5609
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5610

    
5611
	return $dhclientconf;
5612
}
5613

    
5614
function DHCP_Config_Option_Split($option_string) {
5615
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5616
	return $matches ? $matches[0] : [];
5617
}
5618

    
5619
function DHCP_Config_File_Override($ifcfg, $realif) {
5620

    
5621
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5622

    
5623
	if ($dhclientconf === false) {
5624
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5625
		return '';
5626
	} else {
5627
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5628
	}
5629
}
5630

    
5631

    
5632
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5633

    
5634
	/* Apply Interface Substitutions */
5635
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5636

    
5637
	/* Apply Hostname Substitutions */
5638
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5639

    
5640
	/* Arrays of MAC Address Types, Cases, Delimiters */
5641
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5642
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5643
	$various_mac_cases      = array("U", "L");
5644
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5645

    
5646
	/* Apply MAC Address Substitutions */
5647
	foreach ($various_mac_types as $various_mac_type) {
5648
		foreach ($various_mac_cases as $various_mac_case) {
5649
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5650

    
5651
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5652
				if ($res !== false) {
5653

    
5654
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5655
					if ("$various_mac_case" == "U") {
5656
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5657
					}
5658
					if ("$various_mac_case" == "L") {
5659
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5660
					}
5661

    
5662
					if ("$various_mac_type" == "mac_addr_hex") {
5663
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5664
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5665
						$dhcpclientconf_mac_hex = "";
5666
						$delimiter = "";
5667
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5668
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5669
							$delimiter = ":";
5670
						}
5671
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5672
					}
5673

    
5674
					/* MAC Address Delimiter Substitutions */
5675
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5676

    
5677
					/* Apply MAC Address Substitutions */
5678
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5679
				}
5680
			}
5681
		}
5682
	}
5683

    
5684
	return $dhclientconf;
5685
}
5686

    
5687
function interfaces_group_setup() {
5688
	global $config;
5689

    
5690
	if (!isset($config['ifgroups']['ifgroupentry']) ||
5691
	    !is_array($config['ifgroups']['ifgroupentry'])) {
5692
		return;
5693
	}
5694

    
5695
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5696
		interface_group_setup($groupar);
5697
	}
5698

    
5699
	return;
5700
}
5701

    
5702
function interface_group_setup(&$groupname /* The parameter is an array */) {
5703
	global $config;
5704

    
5705
	if (!is_array($groupname)) {
5706
		return;
5707
	}
5708
	$members = explode(" ", $groupname['members']);
5709
	foreach ($members as $ifs) {
5710
		$realif = get_real_interface($ifs);
5711
		if ($realif && does_interface_exist($realif)) {
5712
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5713
		}
5714
	}
5715

    
5716
	return;
5717
}
5718

    
5719
function is_interface_group($if) {
5720
	global $config;
5721

    
5722
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5723
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5724
			if ($groupentry['ifname'] === $if) {
5725
				return true;
5726
			}
5727
		}
5728
	}
5729

    
5730
	return false;
5731
}
5732

    
5733
function interface_group_add_member($interface, $groupname) {
5734
	$interface = get_real_interface($interface);
5735
	if (does_interface_exist($interface)) {
5736
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5737
	}
5738
}
5739

    
5740
/* COMPAT Function */
5741
function convert_friendly_interface_to_real_interface_name($interface) {
5742
	return get_real_interface($interface);
5743
}
5744

    
5745
/* COMPAT Function */
5746
function get_real_wan_interface($interface = "wan") {
5747
	return get_real_interface($interface);
5748
}
5749

    
5750
/* COMPAT Function */
5751
function get_current_wan_address($interface = "wan") {
5752
	return get_interface_ip($interface);
5753
}
5754

    
5755
/*
5756
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5757
 */
5758
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5759
	global $config;
5760

    
5761
	/* XXX: For speed reasons reference directly the interface array */
5762
	init_config_arr(array('interfaces'));
5763
	$ifdescrs = &$config['interfaces'];
5764
	//$ifdescrs = get_configured_interface_list(true);
5765

    
5766
	foreach ($ifdescrs as $if => $ifname) {
5767
		if ($if == $interface || $ifname['if'] == $interface) {
5768
			return $if;
5769
		}
5770

    
5771
		if (get_real_interface($if) == $interface) {
5772
			return $if;
5773
		}
5774

    
5775
		if ($checkparent == false) {
5776
			continue;
5777
		}
5778

    
5779
		$int = get_parent_interface($if, true);
5780
		if (is_array($int)) {
5781
			foreach ($int as $iface) {
5782
				if ($iface == $interface) {
5783
					return $if;
5784
				}
5785
			}
5786
		}
5787
	}
5788

    
5789
	if ($interface == "enc0") {
5790
		return 'IPsec';
5791
	}
5792
}
5793

    
5794
/* attempt to resolve interface to friendly descr */
5795
function convert_friendly_interface_to_friendly_descr($interface) {
5796
	global $config;
5797

    
5798
	switch ($interface) {
5799
		case "l2tp":
5800
			$ifdesc = "L2TP";
5801
			break;
5802
		case "pptp":
5803
			$ifdesc = "PPTP";
5804
			break;
5805
		case "pppoe":
5806
			$ifdesc = "PPPoE";
5807
			break;
5808
		case "openvpn":
5809
			$ifdesc = "OpenVPN";
5810
			break;
5811
		case "lo0":
5812
			$ifdesc = "Loopback";
5813
			break;
5814
		case "enc0":
5815
		case "ipsec":
5816
		case "IPsec":
5817
			$ifdesc = "IPsec";
5818
			break;
5819
		default:
5820
			if (isset($config['interfaces'][$interface])) {
5821
				if (empty($config['interfaces'][$interface]['descr'])) {
5822
					$ifdesc = strtoupper($interface);
5823
				} else {
5824
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5825
				}
5826
				break;
5827
			} elseif (substr($interface, 0, 4) == '_vip') {
5828
				if (is_array($config['virtualip']['vip'])) {
5829
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5830
						if (($vip['mode'] == "carp") || ($vip['mode'] == "ipalias")) {
5831
							if ($interface == "_vip{$vip['uniqid']}") {
5832
								$descr = $vip['subnet'];
5833
								if (!empty($vip['vhid'])) {
5834
									$descr .= " (vhid {$vip['vhid']})";
5835
								}
5836
								if (!empty($vip['descr'])) {
5837
									$descr .= " - " .$vip['descr'];
5838
								}
5839
								return $descr;
5840
							}
5841
						}
5842
					}
5843
				}
5844
			} elseif (substr($interface, 0, 5) == '_lloc') {
5845
				return get_interface_linklocal($interface);
5846
			} else {
5847
				if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5848
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5849
						if ($ifgen['ifname'] === $interface) {
5850
							return $ifgen['ifname'];
5851
						}
5852
					}
5853
				}
5854

    
5855
				/* if list */
5856
				$ifdescrs = get_configured_interface_with_descr(true);
5857
				foreach ($ifdescrs as $if => $ifname) {
5858
					if ($if == $interface || $ifname == $interface) {
5859
						return $ifname;
5860
					}
5861
				}
5862
			}
5863
			break;
5864
	}
5865

    
5866
	return $ifdesc;
5867
}
5868

    
5869
function convert_real_interface_to_friendly_descr($interface) {
5870

    
5871
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5872

    
5873
	if (!empty($ifdesc)) {
5874
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5875
	}
5876

    
5877
	return $interface;
5878
}
5879

    
5880
/*
5881
 *  get_parent_interface($interface):
5882
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5883
 *				or virtual interface (i.e. vlan)
5884
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5885
 *			-- returns $interface passed in if $interface parent is not found
5886
 *			-- returns empty array if an invalid interface is passed
5887
 *	(Only handles ppps and vlans now.)
5888
 */
5889
function get_parent_interface($interface, $avoidrecurse = false) {
5890
	global $config;
5891

    
5892
	$parents = array();
5893
	//Check that we got a valid interface passed
5894
	$realif = get_real_interface($interface);
5895
	if ($realif == NULL) {
5896
		return $parents;
5897
	}
5898

    
5899
	// If we got a real interface, find it's friendly assigned name
5900
	if ($interface == $realif && $avoidrecurse == false) {
5901
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5902
	}
5903

    
5904
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5905
		$ifcfg = $config['interfaces'][$interface];
5906
		switch ($ifcfg['ipaddr']) {
5907
			case "ppp":
5908
			case "pppoe":
5909
			case "pptp":
5910
			case "l2tp":
5911
				if (empty($parents)) {
5912
					if (is_array($config['ppps']['ppp'])) {
5913
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5914
							if ($ifcfg['if'] == $ppp['if']) {
5915
								$ports = explode(',', $ppp['ports']);
5916
								foreach ($ports as $pid => $parent_if) {
5917
									$parents[$pid] = get_real_interface($parent_if);
5918
								}
5919
								break;
5920
							}
5921
						}
5922
					}
5923
				}
5924
				break;
5925
			case "dhcp":
5926
			case "static":
5927
			default:
5928
				// Handle _vlans
5929
				$vlan = interface_is_vlan($ifcfg['if']);
5930
				if ($vlan != NULL) {
5931
					$parents[0] = $vlan['if'];
5932
				}
5933
				break;
5934
		}
5935
	}
5936

    
5937
	if (empty($parents)) {
5938
		// Handle _vlans not assigned to an interface
5939
		$vlan = interface_is_vlan($realif);
5940
		if ($vlan != NULL) {
5941
			$parents[0] = $vlan['if'];
5942
		}
5943
	}
5944

    
5945
	if (empty($parents)) {
5946
		/* Handle LAGGs. */
5947
		$lagg = interface_is_type($realif, 'lagg');
5948
		if ($lagg != NULL && isset($lagg['members'])) {
5949
			$parents = explode(",", $lagg['members']);
5950
		}
5951
	}
5952

    
5953
	if (empty($parents)) {
5954
		$parents[0] = $realif;
5955
	}
5956

    
5957
	return $parents;
5958
}
5959

    
5960
/*
5961
 *  get_parent_physical_interface($interface):
5962
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5963
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5964
 */
5965
function get_parent_physical_interface($interface) {
5966
	global $config;
5967

    
5968
	$realif = get_parent_interface($interface);
5969

    
5970
	if (substr($realif[0], 0, 4) == "lagg") {
5971
		foreach ($config['laggs']['lagg'] as $lagg) {
5972
			if ($realif[0] == $lagg['laggif']) {
5973
				return explode(",", $lagg['members']);
5974
			}
5975
		}
5976
	} else {
5977
		return $realif;
5978
	}
5979
}
5980

    
5981
function interface_is_wireless_clone($wlif) {
5982
	if (!stristr($wlif, "_wlan")) {
5983
		return false;
5984
	} else {
5985
		return true;
5986
	}
5987
}
5988

    
5989
function interface_get_wireless_base($wlif) {
5990
	if (!stristr($wlif, "_wlan")) {
5991
		return $wlif;
5992
	} else {
5993
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5994
	}
5995
}
5996

    
5997
function interface_get_wireless_clone($wlif) {
5998
	if (!stristr($wlif, "_wlan")) {
5999
		return $wlif . "_wlan0";
6000
	} else {
6001
		return $wlif;
6002
	}
6003
}
6004

    
6005
function interface_list_wireless() {
6006
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
6007

    
6008
	$result = array();
6009
	foreach ($portlist as $port) {
6010
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
6011
			continue;
6012
		}
6013

    
6014
		$desc = $port . " ( " . get_single_sysctl(
6015
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
6016

    
6017
		$result[] = array(
6018
		    "if" => $port,
6019
		    "descr" => $desc
6020
		);
6021
	}
6022

    
6023
	return $result;
6024
}
6025

    
6026
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
6027
	global $config, $g;
6028

    
6029
	$wanif = NULL;
6030

    
6031
	switch ($interface) {
6032
		case "l2tp":
6033
			$wanif = "l2tp";
6034
			break;
6035
		case "pptp":
6036
			$wanif = "pptp";
6037
			break;
6038
		case "pppoe":
6039
			$wanif = "pppoe";
6040
			break;
6041
		case "openvpn":
6042
			$wanif = "openvpn";
6043
			break;
6044
		case "IPsec":
6045
		case "ipsec":
6046
		case "enc0":
6047
			$wanif = "enc0";
6048
			break;
6049
		case "ppp":
6050
			$wanif = "ppp";
6051
			break;
6052
		default:
6053
			if (substr($interface, 0, 4) == '_vip') {
6054
				$wanif = get_configured_vip_interface($interface);
6055
				if (!empty($wanif)) {
6056
					$wanif = get_real_interface($wanif);
6057
				}
6058
				break;
6059
			} elseif (substr($interface, 0, 5) == '_lloc') {
6060
				$interface = substr($interface, 5);
6061
			} elseif (interface_is_vlan($interface) != NULL ||
6062
			    does_interface_exist($interface, $flush)) {
6063
				/*
6064
				 * If a real interface was already passed simply
6065
				 * pass the real interface back.  This encourages
6066
				 * the usage of this function in more cases so that
6067
				 * we can combine logic for more flexibility.
6068
				 */
6069
				$wanif = $interface;
6070
				break;
6071
			}
6072

    
6073
			if (empty($config['interfaces'][$interface])) {
6074
				break;
6075
			}
6076

    
6077
			$cfg = &$config['interfaces'][$interface];
6078

    
6079
			if ($family == "inet6") {
6080
				switch ($cfg['ipaddrv6']) {
6081
					case "6rd":
6082
					case "6to4":
6083
						$wanif = "{$interface}_stf";
6084
						break;
6085
					case 'pppoe':
6086
					case 'ppp':
6087
					case 'l2tp':
6088
					case 'pptp':
6089
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6090
							$wanif = interface_get_wireless_clone($cfg['if']);
6091
						} else {
6092
							$wanif = $cfg['if'];
6093
						}
6094
						break;
6095
					default:
6096
						switch ($cfg['ipaddr']) {
6097
							case 'pppoe':
6098
							case 'ppp':
6099
							case 'l2tp':
6100
							case 'pptp':
6101
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
6102
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) ||
6103
								    isset($cfg['ipv6usev4iface']) || isset($cfg['slaacusev4iface'])) {
6104
									$wanif = $cfg['if'];
6105
								} else {
6106
									$parents = get_parent_interface($interface);
6107
									if (!empty($parents[0])) {
6108
										$wanif = $parents[0];
6109
									} else {
6110
										$wanif = $cfg['if'];
6111
									}
6112
								}
6113
								break;
6114
							default:
6115
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6116
									$wanif = interface_get_wireless_clone($cfg['if']);
6117
								} else {
6118
									$wanif = $cfg['if'];
6119
								}
6120
								break;
6121
						}
6122
						break;
6123
				}
6124
			} else {
6125
				// Wireless cloned NIC support (FreeBSD 8+)
6126
				// interface name format: $parentnic_wlanparentnic#
6127
				// example: ath0_wlan0
6128
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6129
					$wanif = interface_get_wireless_clone($cfg['if']);
6130
				} else {
6131
					$wanif = $cfg['if'];
6132
				}
6133
			}
6134
			break;
6135
	}
6136

    
6137
	return $wanif;
6138
}
6139

    
6140
/* Guess the physical interface by providing a IP address */
6141
function guess_interface_from_ip($ipaddress) {
6142

    
6143
	if (!is_ipaddr($ipaddress)) {
6144
		return false;
6145
	}
6146

    
6147
	$route = route_get($ipaddress, '', true);
6148
	if (empty($route)) {
6149
		return false;
6150
	}
6151

    
6152
	if (!empty($route[0]['interface-name'])) {
6153
		return $route[0]['interface-name'];
6154
	}
6155

    
6156
	return false;
6157
}
6158

    
6159
/*
6160
 * find_ip_interface($ip): return the interface where an ip is defined
6161
 *   (or if $bits is specified, where an IP within the subnet is defined)
6162
 */
6163
function find_ip_interface($ip, $bits = null) {
6164
	if (!is_ipaddr($ip)) {
6165
		return false;
6166
	}
6167

    
6168
	$isv6ip = is_ipaddrv6($ip);
6169

    
6170
	/* if list */
6171
	$ifdescrs = get_configured_interface_list();
6172

    
6173
	foreach ($ifdescrs as $ifdescr => $ifname) {
6174
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
6175
		if (is_null($ifip)) {
6176
			continue;
6177
		}
6178
		if (is_null($bits)) {
6179
			if ($ip == $ifip) {
6180
				$int = get_real_interface($ifname);
6181
				return $int;
6182
			}
6183
		} else {
6184
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
6185
				$int = get_real_interface($ifname);
6186
				return $int;
6187
			}
6188
		}
6189
	}
6190

    
6191
	return false;
6192
}
6193

    
6194
/*
6195
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6196
 *   (or if $bits is specified, where an IP within the subnet is found)
6197
 */
6198
function find_virtual_ip_alias($ip, $bits = null) {
6199
	global $config;
6200

    
6201
	if (!is_array($config['virtualip']['vip'])) {
6202
		return false;
6203
	}
6204
	if (!is_ipaddr($ip)) {
6205
		return false;
6206
	}
6207

    
6208
	$isv6ip = is_ipaddrv6($ip);
6209

    
6210
	foreach ($config['virtualip']['vip'] as $vip) {
6211
		if ($vip['mode'] === "ipalias") {
6212
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
6213
				continue;
6214
			}
6215
			if (is_null($bits)) {
6216
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
6217
					return $vip;
6218
				}
6219
			} else {
6220
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
6221
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
6222
					return $vip;
6223
				}
6224
			}
6225
		}
6226
	}
6227
	return false;
6228
}
6229

    
6230
function link_interface_to_track6($int, $action = "") {
6231
	global $config;
6232

    
6233
	if (empty($int)) {
6234
		return;
6235
	}
6236

    
6237
	if (is_array($config['interfaces'])) {
6238
		$list = array();
6239
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
6240
			if (!isset($ifcfg['enable'])) {
6241
				continue;
6242
			}
6243
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
6244
				if ($action == "update") {
6245
					interface_track6_configure($ifname, $ifcfg);
6246
				} elseif ($action == "") {
6247
					$list[$ifname] = $ifcfg;
6248
				}
6249
			}
6250
		}
6251
		return $list;
6252
	}
6253
}
6254

    
6255
function interface_find_child_cfgmtu($realiface) {
6256
	global $config;
6257

    
6258
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6259
	$vlans = link_interface_to_vlans($realiface);
6260
	$qinqs = link_interface_to_qinqs($realiface);
6261
	$bridge = link_interface_to_bridge($realiface);
6262
	$gifs = link_interface_to_tunnelif($interface, 'gif');
6263
	$gres = link_interface_to_tunnelif($interface, 'gre');
6264

    
6265
	$mtu = 0;
6266
	if (is_array($vlans)) {
6267
		foreach ($vlans as $vlan) {
6268
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
6269
			if (empty($ifass)) {
6270
				continue;
6271
			}
6272
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6273
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6274
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6275
				}
6276
			}
6277
		}
6278
	}
6279
	if (is_array($qinqs)) {
6280
		foreach ($qinqs as $qinq) {
6281
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
6282
			if (empty($ifass)) {
6283
				continue;
6284
			}
6285
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6286
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6287
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6288
				}
6289
			}
6290
		}
6291
	}
6292
	foreach ($gifs as $gif) {
6293
		$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
6294
		if (empty($ifass)) {
6295
			continue;
6296
		}
6297
		if (!empty($config['interfaces'][$ifass]['mtu'])) {
6298
			if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6299
				$mtu = intval($config['interfaces'][$ifass]['mtu']);
6300
			}
6301
		}
6302
	}
6303
	foreach ($gres as $gre) {
6304
		$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
6305
		if (empty($ifass)) {
6306
			continue;
6307
		}
6308
		if (!empty($config['interfaces'][$ifass]['mtu'])) {
6309
			if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6310
				$mtu = intval($config['interfaces'][$ifass]['mtu']);
6311
			}
6312
		}
6313
	}
6314
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
6315
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
6316
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6317
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
6318
		}
6319
	}
6320
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
6321

    
6322
	return $mtu;
6323
}
6324

    
6325
function link_interface_to_vlans($int, $action = "") {
6326
	global $config;
6327

    
6328
	if (empty($int)) {
6329
		return;
6330
	}
6331

    
6332
	if (is_array($config['vlans']['vlan'])) {
6333
		$ifaces = array();
6334
		foreach ($config['vlans']['vlan'] as $vlan) {
6335
			if ($int == $vlan['if']) {
6336
				if ($action == "update") {
6337
					interfaces_bring_up($int);
6338
				} else {
6339
					$ifaces[$vlan['tag']] = $vlan;
6340
				}
6341
			}
6342
		}
6343
		if (!empty($ifaces)) {
6344
			return $ifaces;
6345
		}
6346
	}
6347
}
6348

    
6349
function link_interface_to_qinqs($int, $action = "") {
6350
	global $config;
6351

    
6352
	if (empty($int)) {
6353
		return;
6354
	}
6355

    
6356
	if (is_array($config['qinqs']['qinqentry'])) {
6357
		$ifaces = array();
6358
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
6359
			if ($int == $qinq['if']) {
6360
				if ($action == "update") {
6361
					interfaces_bring_up($int);
6362
				} else {
6363
					$ifaces[$qinq['tag']] = $qinq;
6364
				}
6365
			}
6366
		}
6367
		if (!empty($ifaces)) {
6368
			return $ifaces;
6369
		}
6370
	}
6371
}
6372

    
6373
function link_interface_to_vips($int, $action = "", $vhid = '') {
6374
	global $config;
6375

    
6376
	$updatevips = false;
6377
	if (is_array($config['virtualip']['vip'])) {
6378
		$result = array();
6379
		foreach ($config['virtualip']['vip'] as $vip) {
6380
			if (substr($vip['interface'], 0, 4) == "_vip") {
6381
				$iface = get_configured_vip_interface($vip['interface']);
6382
			} else {
6383
				$iface = $vip['interface'];
6384
			}
6385
			if ($int != $iface) {
6386
				continue;
6387
			}
6388
			if ($action == "update") {
6389
				$updatevips = true;
6390
			} else {
6391
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
6392
				    substr($vip['interface'], 0, 4) == "_vip") {
6393
					$result[] = $vip;
6394
				}
6395
			}
6396
		}
6397
		if ($updatevips === true) {
6398
			interfaces_vips_configure($int);
6399
		}
6400
		return $result;
6401
	}
6402

    
6403
	return NULL;
6404
}
6405

    
6406
/****f* interfaces/link_interface_to_bridge
6407
 * NAME
6408
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6409
 * INPUTS
6410
 *   $ip
6411
 * RESULT
6412
 *   bridge[0-99]
6413
 ******/
6414
function link_interface_to_bridge($int) {
6415
	global $config;
6416

    
6417
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6418
		foreach ($config['bridges']['bridged'] as $bridge) {
6419
			if (in_array($int, explode(',', $bridge['members']))) {
6420
				return "{$bridge['bridgeif']}";
6421
			}
6422
		}
6423
	}
6424
}
6425

    
6426
function link_interface_to_lagg($int) {
6427
	global $config;
6428

    
6429
	if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
6430
		foreach ($config['laggs']['lagg'] as $lagg) {
6431
			if (in_array($int, explode(',', $lagg['members']))) {
6432
				return "{$lagg['laggif']}";
6433
			}
6434
		}
6435
	}
6436
}
6437

    
6438
function link_interface_to_group($int) {
6439
	global $config;
6440

    
6441
	$result = array();
6442

    
6443
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6444
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6445
			if (in_array($int, explode(" ", $group['members']))) {
6446
				$result[$group['ifname']] = $int;
6447
			}
6448
		}
6449
	}
6450

    
6451
	return $result;
6452
}
6453

    
6454
function link_interface_to_tunnelif($interface, $type, $remote = 'any') {
6455
	global $config;
6456

    
6457
	$result = array();
6458

    
6459
	if (empty($interface)) {
6460
		return $result;
6461
	}
6462

    
6463
	if (!in_array($type, array('gre', 'gif'))) {
6464
		return $result;
6465
	}
6466

    
6467
	if (is_array($config["{$type}s"][$type])) {
6468
		foreach ($config["{$type}s"][$type] as $tunnel) {
6469
			if (($tunnel['if'] == $interface) && (($remote == 'any') ||
6470
			    (is_ipaddrv4($tunnel['remote-addr']) && ($remote == 'inet')) ||
6471
			    (is_ipaddrv6($tunnel['remote-addr']) && ($remote == 'inet6')))) { 
6472
				$result[] = $tunnel;
6473
			}
6474
		}
6475
	}
6476

    
6477
	return $result;
6478
}
6479

    
6480
function link_interface_to_ppp_tunnelif($interface) {
6481
	global $config;
6482

    
6483
	$result = array();
6484

    
6485
	if (empty($interface)) {
6486
		return $result;
6487
	}
6488

    
6489
	init_config_arr(array('ppps', 'ppp'));
6490
	if (!empty($config['ppps']['ppp'])) {
6491
		$realif = get_real_interface($interface);
6492
		foreach ($config['ppps']['ppp'] as $ppp) {
6493
			if (($ppp['ports'] == $realif) && in_array($ppp['type'], array('l2tp', 'pptp'))) { 
6494
				$result[] = $ppp;
6495
			}
6496
		}
6497
	}
6498

    
6499
	return $result;
6500
}
6501

    
6502
/*
6503
 * find_interface_ip($interface): return the interface ip (first found)
6504
 */
6505
function find_interface_ip($interface, $flush = false) {
6506
	global $interface_ip_arr_cache;
6507
	global $interface_sn_arr_cache;
6508

    
6509
	$interface = str_replace("\n", "", $interface);
6510

    
6511
	if (!does_interface_exist($interface)) {
6512
		return;
6513
	}
6514

    
6515
	/* Setup IP cache */
6516
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6517
		if (file_exists("/var/db/${interface}_ip")) {
6518
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6519
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6520
			foreach ($ifaddrs as $ifaddr) {
6521
				list($ip, $mask) = explode("/", $ifaddr);
6522
				if ($ip == $ifip) {
6523
					$interface_ip_arr_cache[$interface] = $ip;
6524
					$interface_sn_arr_cache[$interface] = $mask;
6525
					break;
6526
				}
6527
			}
6528
		}
6529
		if (!isset($interface_ip_arr_cache[$interface])) {
6530
			$ifinfo = pfSense_get_interface_addresses($interface);
6531
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6532
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6533
		}
6534
	}
6535

    
6536
	return $interface_ip_arr_cache[$interface];
6537
}
6538

    
6539
/*
6540
 * find_interface_ipv6($interface): return the interface ip (first found)
6541
 */
6542
function find_interface_ipv6($interface, $flush = false) {
6543
	global $interface_ipv6_arr_cache;
6544
	global $interface_snv6_arr_cache;
6545
	global $config;
6546

    
6547
	$interface = trim($interface);
6548
	$interface = get_real_interface($interface);
6549

    
6550
	if (!does_interface_exist($interface)) {
6551
		return;
6552
	}
6553

    
6554
	/* Setup IP cache */
6555
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6556
		$ifinfo = pfSense_get_interface_addresses($interface);
6557
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6558
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6559
	}
6560

    
6561
	return $interface_ipv6_arr_cache[$interface];
6562
}
6563

    
6564
/*
6565
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6566
 */
6567
function find_interface_ipv6_ll($interface, $flush = false) {
6568
	global $interface_llv6_arr_cache;
6569
	global $config;
6570

    
6571
	$interface = str_replace("\n", "", $interface);
6572

    
6573
	if (!does_interface_exist($interface)) {
6574
		return;
6575
	}
6576

    
6577
	/* Setup IP cache */
6578
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6579
		$ifinfo = pfSense_getall_interface_addresses($interface);
6580
		foreach ($ifinfo as $line) {
6581
			if (strstr($line, ":")) {
6582
				$parts = explode("/", $line);
6583
				if (is_linklocal($parts[0])) {
6584
					$ifinfo['linklocal'] = $parts[0];
6585
				}
6586
			}
6587
		}
6588
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6589
	}
6590
	return $interface_llv6_arr_cache[$interface];
6591
}
6592

    
6593
function find_interface_subnet($interface, $flush = false) {
6594
	global $interface_sn_arr_cache;
6595
	global $interface_ip_arr_cache;
6596

    
6597
	$interface = str_replace("\n", "", $interface);
6598
	if (does_interface_exist($interface) == false) {
6599
		return;
6600
	}
6601

    
6602
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6603
		$ifinfo = pfSense_get_interface_addresses($interface);
6604
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6605
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6606
	}
6607

    
6608
	return $interface_sn_arr_cache[$interface];
6609
}
6610

    
6611
function find_interface_subnetv6($interface, $flush = false) {
6612
	global $interface_snv6_arr_cache;
6613
	global $interface_ipv6_arr_cache;
6614

    
6615
	$interface = str_replace("\n", "", $interface);
6616
	if (does_interface_exist($interface) == false) {
6617
		return;
6618
	}
6619

    
6620
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6621
		$ifinfo = pfSense_get_interface_addresses($interface);
6622
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6623
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6624
	}
6625

    
6626
	return $interface_snv6_arr_cache[$interface];
6627
}
6628

    
6629
function ip_in_interface_alias_subnet($interface, $ipalias) {
6630
	global $config;
6631

    
6632
	if (empty($interface) || !is_ipaddr($ipalias)) {
6633
		return false;
6634
	}
6635
	if (is_array($config['virtualip']['vip'])) {
6636
		foreach ($config['virtualip']['vip'] as $vip) {
6637
			switch ($vip['mode']) {
6638
				case "ipalias":
6639
					if ($vip['interface'] <> $interface) {
6640
						break;
6641
					}
6642
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6643
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6644
						return true;
6645
					}
6646
					break;
6647
			}
6648
		}
6649
	}
6650

    
6651
	return false;
6652
}
6653

    
6654
function get_possible_listen_ips($include_ipv6_link_local=false) {
6655

    
6656
	$interfaces = get_configured_interface_with_descr();
6657
	foreach ($interfaces as $iface => $ifacename) {
6658
		if ($include_ipv6_link_local) {
6659
			/* This is to avoid going though added ll below */
6660
			if (substr($iface, 0, 5) == '_lloc') {
6661
				continue;
6662
			}
6663
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6664
			if (!empty($llip)) {
6665
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6666
			}
6667
		}
6668
	}
6669
	$viplist = get_configured_vip_list();
6670
	foreach ($viplist as $vip => $address) {
6671
		$interfaces[$vip] = $address;
6672
		if (get_vip_descr($address)) {
6673
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6674
		}
6675
	}
6676

    
6677
	$interfaces['lo0'] = 'Localhost';
6678

    
6679
	return $interfaces;
6680
}
6681

    
6682
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6683
	global $config;
6684

    
6685
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6686
	foreach (array('server', 'client') as $mode) {
6687
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6688
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6689
				if (!isset($setting['disable'])) {
6690
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6691
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6692
				}
6693
			}
6694
		}
6695
	}
6696

    
6697
	init_config_arr(array('ipsec', 'phase1'));
6698
	foreach ($config['ipsec']['phase1'] as $p1) {
6699
		if ($p1['disabled']) {
6700
			continue;
6701
		}
6702
		if (ipsec_vti($p1)) {
6703
			$vtiiflist = interface_ipsec_vti_list_p1($p1);
6704
			if (!empty($vtiiflist)) {
6705
				$sourceips = array_merge($sourceips, $vtiiflist);
6706
			}
6707
		}
6708
	}
6709
	return $sourceips;
6710
}
6711

    
6712
function get_interface_ip($interface = "wan", $gateways_status = false) {
6713
	global $config;
6714

    
6715
	if (substr($interface, 0, 4) == '_vip') {
6716
		return get_configured_vip_ipv4($interface);
6717
	} elseif (substr($interface, 0, 5) == '_lloc') {
6718
		/* No link-local address for v4. */
6719
		return null;
6720
	}
6721

    
6722
	$realif = get_failover_interface($interface, 'inet', $gateways_status);
6723
	if (!$realif) {
6724
		return null;
6725
	}
6726

    
6727
	if (substr($realif, 0, 4) == '_vip') {
6728
		return get_configured_vip_ipv4($realif);
6729
	} elseif (substr($realif, 0, 5) == '_lloc') {
6730
		/* No link-local address for v4. */
6731
		return null;
6732
	}
6733

    
6734
	if (is_array($config['interfaces'][$interface]) &&
6735
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6736
		return ($config['interfaces'][$interface]['ipaddr']);
6737
	}
6738

    
6739
	/*
6740
	 * Beaware that find_interface_ip() is our last option, it will
6741
	 * return the first IP it find on interface, not necessarily the
6742
	 * main IP address.
6743
	 */
6744
	$curip = find_interface_ip($realif);
6745
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6746
		return $curip;
6747
	} else {
6748
		return null;
6749
	}
6750
}
6751

    
6752
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false, $gateways_status = false) {
6753
	global $config;
6754

    
6755
	if (substr($interface, 0, 4) == '_vip') {
6756
		return get_configured_vip_ipv6($interface);
6757
	} elseif (substr($interface, 0, 5) == '_lloc') {
6758
		return get_interface_linklocal($interface);
6759
	}
6760

    
6761
	$realif = get_failover_interface($interface, 'inet6', $gateways_status);
6762
	if (!$realif) {
6763
		return null;
6764
	}
6765

    
6766
	if (substr($realif, 0, 4) == '_vip') {
6767
		return get_configured_vip_ipv6($realif);
6768
	} elseif (substr($realif, 0, 5) == '_lloc') {
6769
		return get_interface_linklocal($realif);
6770
	}
6771

    
6772
	if (is_array($config['interfaces'][$interface])) {
6773
		switch ($config['interfaces'][$interface]['ipaddr']) {
6774
			case 'pppoe':
6775
			case 'l2tp':
6776
			case 'pptp':
6777
			case 'ppp':
6778
				if (($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') ||
6779
				    ($config['interfaces'][$interface]['ipaddrv6'] == 'slaac')) {
6780
					$realif = get_real_interface($interface, 'inet6', false);
6781
				}
6782
				break;
6783
		}
6784
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6785
			return ($config['interfaces'][$interface]['ipaddrv6']);
6786
		}
6787
	}
6788

    
6789
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6790
	$checkif = is_array($config['interfaces'][$interface]) ? $interface : convert_real_interface_to_friendly_interface_name($interface);
6791
	if (is_array($config['interfaces'][$checkif]) && ($config['interfaces'][$checkif]['ipaddrv6'] == 'track6')) { 
6792
		$curip = get_interface_track6ip($checkif);
6793
		if ($curip) {
6794
			return $curip[0];
6795
		}
6796
	}
6797

    
6798
	/*
6799
	 * Beaware that find_interface_ip() is our last option, it will
6800
	 * return the first IP it find on interface, not necessarily the
6801
	 * main IP address.
6802
	 */
6803
	$curip = find_interface_ipv6($realif, $flush);
6804
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6805
		return $curip;
6806
	} else {
6807
		/*
6808
		 * NOTE: On the case when only the prefix is requested,
6809
		 * the communication on WAN will be done over link-local.
6810
		 */
6811
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6812
			$curip = find_interface_ipv6_ll($realif, $flush);
6813
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6814
				return $curip;
6815
			}
6816
		}
6817
	}
6818
	return null;
6819
}
6820

    
6821
function get_interface_linklocal($interface = "wan") {
6822

    
6823
	$realif = get_failover_interface($interface, 'inet6');
6824
	if (!$realif) {
6825
		return null;
6826
	}
6827

    
6828
	if (substr($interface, 0, 4) == '_vip') {
6829
		$realif = get_real_interface($interface);
6830
	} elseif (substr($interface, 0, 5) == '_lloc') {
6831
		$realif = get_real_interface(substr($interface, 5));
6832
	}
6833

    
6834
	$curip = find_interface_ipv6_ll($realif);
6835
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6836
		return $curip;
6837
	} else {
6838
		return null;
6839
	}
6840
}
6841

    
6842
function get_interface_track6ip($interface = "wan") {
6843
	$realif = get_real_interface($interface);
6844
	$vips = get_configured_vip_list('inet6');
6845

    
6846
	foreach (pfSense_getall_interface_addresses($realif) as $ifaddr) {
6847
		list($ip, $bits) = explode("/", $ifaddr);
6848
		$ip = text_to_compressed_ip6($ip);
6849
		if (is_ipaddrv6($ip) && !is_linklocal($ip)) {
6850
			if (is_array($vips) && !empty($vips)) {
6851
				foreach ($vips as $vip) {
6852
					if ($ip == text_to_compressed_ip6($vip)) {
6853
						continue 2;
6854
					}
6855
				}
6856
			}
6857
			return array($ip, $bits);
6858
		}
6859
	}
6860
	return false;
6861
}
6862

    
6863
function get_interface_subnet($interface = "wan") {
6864
	global $config;
6865

    
6866
	if (substr($interface, 0, 4) == '_vip') {
6867
		return (get_configured_vip_subnetv4($interface));
6868
	}
6869

    
6870
	if (is_array($config['interfaces'][$interface]) &&
6871
	    !empty($config['interfaces'][$interface]['subnet']) &&
6872
	    is_ipaddrv4($config['interfaces'][$interface]['ipaddr'])) {
6873
		return ($config['interfaces'][$interface]['subnet']);
6874
	}
6875

    
6876
	$realif = get_real_interface($interface);
6877
	if (!$realif) {
6878
		return (NULL);
6879
	}
6880

    
6881
	$cursn = find_interface_subnet($realif);
6882
	if (!empty($cursn)) {
6883
		return ($cursn);
6884
	}
6885

    
6886
	return (NULL);
6887
}
6888

    
6889
function get_interface_subnetv6($interface = "wan") {
6890
	global $config;
6891

    
6892
	if (substr($interface, 0, 4) == '_vip') {
6893
		return (get_configured_vip_subnetv6($interface));
6894
	} elseif (substr($interface, 0, 5) == '_lloc') {
6895
		$interface = substr($interface, 5);
6896
	}
6897

    
6898
	if (is_array($config['interfaces'][$interface]) &&
6899
	    !empty($config['interfaces'][$interface]['subnetv6']) &&
6900
	    is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6901
		return ($config['interfaces'][$interface]['subnetv6']);
6902
	}
6903

    
6904
	$realif = get_real_interface($interface, 'inet6');
6905
	if (!$realif) {
6906
		return (NULL);
6907
	}
6908

    
6909
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6910
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6911
		$curip = get_interface_track6ip($interface);
6912
		if ($curip) {
6913
			return $curip[1];
6914
		}
6915
	}
6916

    
6917
	$cursn = find_interface_subnetv6($realif);
6918
	if (!empty($cursn)) {
6919
		return ($cursn);
6920
	}
6921

    
6922
	return (NULL);
6923
}
6924

    
6925
/* return outside interfaces with a gateway */
6926
function get_interfaces_with_gateway() {
6927
	global $config;
6928

    
6929
	$ints = array();
6930

    
6931
	/* loop interfaces, check config for outbound */
6932
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6933
		switch ($ifname['ipaddr']) {
6934
			case "dhcp":
6935
			case "pppoe":
6936
			case "pptp":
6937
			case "l2tp":
6938
			case "ppp":
6939
				$ints[$ifdescr] = $ifdescr;
6940
				break;
6941
			default:
6942
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6943
				    !empty($ifname['gateway'])) {
6944
					$ints[$ifdescr] = $ifdescr;
6945
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6946
				    !empty($ifname['gateway'])) {
6947
					$ints[$ifdescr] = $ifdescr;
6948
				}
6949

    
6950
				break;
6951
		}
6952
	}
6953
	return $ints;
6954
}
6955

    
6956
/* return true if interface has a gateway */
6957
function interface_has_gateway($friendly) {
6958
	global $config;
6959

    
6960
	if (!empty($config['interfaces'][$friendly])) {
6961
		$ifname = &$config['interfaces'][$friendly];
6962
		switch ($ifname['ipaddr']) {
6963
			case "dhcp":
6964
				/* see https://redmine.pfsense.org/issues/5135 */
6965
				if (get_interface_gateway($friendly)) {
6966
					return true;
6967
				}
6968
				break;
6969
			case "pppoe":
6970
			case "pptp":
6971
			case "l2tp":
6972
			case "ppp":
6973
				return true;
6974
				break;
6975
			default:
6976
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6977
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6978
					return true;
6979
				}
6980
				$tunnelif = substr($ifname['if'], 0, 3);
6981
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6982
					if (find_interface_ip($ifname['if'])) {
6983
						return true;
6984
					}
6985
				}
6986
				if (!empty($ifname['gateway'])) {
6987
					return true;
6988
				}
6989
				break;
6990
		}
6991
	}
6992

    
6993
	return false;
6994
}
6995

    
6996
/* return true if interface has a gateway */
6997
function interface_has_gatewayv6($friendly) {
6998
	global $config;
6999

    
7000
	if (!empty($config['interfaces'][$friendly])) {
7001
		$ifname = &$config['interfaces'][$friendly];
7002
		switch ($ifname['ipaddrv6']) {
7003
			case "slaac":
7004
			case "dhcp6":
7005
			case "6to4":
7006
			case "6rd":
7007
				return true;
7008
				break;
7009
			default:
7010
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
7011
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
7012
					return true;
7013
				}
7014
				$tunnelif = substr($ifname['if'], 0, 3);
7015
				if ($tunnelif == "gif" || $tunnelif == "gre") {
7016
					if (find_interface_ipv6($ifname['if'])) {
7017
						return true;
7018
					}
7019
				}
7020
				if (!empty($ifname['gatewayv6'])) {
7021
					return true;
7022
				}
7023
				break;
7024
		}
7025
	}
7026

    
7027
	return false;
7028
}
7029

    
7030
/****f* interfaces/is_altq_capable
7031
 * NAME
7032
 *   is_altq_capable - Test if interface is capable of using ALTQ
7033
 * INPUTS
7034
 *   $int            - string containing interface name
7035
 * RESULT
7036
 *   boolean         - true or false
7037
 ******/
7038

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

    
7054
	$int_family = remove_ifindex($int);
7055

    
7056
	if (in_array($int_family, $capable)) {
7057
		return true;
7058
	} elseif (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
7059
		return true;
7060
	} elseif (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
7061
		return true;
7062
	} elseif (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
7063
		return true;
7064
	} else {
7065
		return false;
7066
	}
7067
}
7068

    
7069
/****f* interfaces/is_interface_wireless
7070
 * NAME
7071
 *   is_interface_wireless - Returns if an interface is wireless
7072
 * RESULT
7073
 *   $tmp       - Returns if an interface is wireless
7074
 ******/
7075
function is_interface_wireless($interface) {
7076
	global $config, $g;
7077

    
7078
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
7079
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
7080
		if (preg_match($g['wireless_regex'], $interface)) {
7081
			if (isset($config['interfaces'][$friendly])) {
7082
				$config['interfaces'][$friendly]['wireless'] = array();
7083
			}
7084
			return true;
7085
		}
7086
		return false;
7087
	} else {
7088
		return true;
7089
	}
7090
}
7091

    
7092
function get_wireless_modes($interface) {
7093
	/* return wireless modes and channels */
7094
	$wireless_modes = array();
7095

    
7096
	$cloned_interface = get_real_interface($interface);
7097

    
7098
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7099
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
7100
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\n\" \$3 }'";
7101
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
7102

    
7103
		$interface_channels = "";
7104
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7105
		$interface_channel_count = count($interface_channels);
7106

    
7107
		$c = 0;
7108
		while ($c < $interface_channel_count) {
7109
			$channel_line = explode(",", $interface_channels["$c"]);
7110
			$wireless_mode = trim($channel_line[0]);
7111
			$wireless_channel = trim($channel_line[1]);
7112
			if (trim($wireless_mode) != "") {
7113
				/* if we only have 11g also set 11b channels */
7114
				if ($wireless_mode == "11g") {
7115
					if (!isset($wireless_modes["11b"])) {
7116
						$wireless_modes["11b"] = array();
7117
					}
7118
				} elseif ($wireless_mode == "11g ht") {
7119
					if (!isset($wireless_modes["11b"])) {
7120
						$wireless_modes["11b"] = array();
7121
					}
7122
					if (!isset($wireless_modes["11g"])) {
7123
						$wireless_modes["11g"] = array();
7124
					}
7125
					$wireless_mode = "11ng";
7126
				} elseif ($wireless_mode == "11a ht") {
7127
					if (!isset($wireless_modes["11a"])) {
7128
						$wireless_modes["11a"] = array();
7129
					}
7130
					$wireless_mode = "11na";
7131
				}
7132
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
7133
			}
7134
			$c++;
7135
		}
7136
	}
7137
	return($wireless_modes);
7138
}
7139

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

    
7145
		$interface_channels = "";
7146
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7147
		return $interface_channels;
7148
}
7149

    
7150
/* return wireless HT modes */
7151
function get_wireless_ht_modes($interface) {
7152
	$wireless_hts_supported = array(0 => gettext('Auto'));
7153

    
7154
	$cloned_interface = get_real_interface($interface);
7155

    
7156
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7157
		$interface_channels = get_wireless_channels($cloned_interface);
7158

    
7159
		foreach ($interface_channels as $channel) {
7160
			$channel_line = explode(",", $channel);
7161
			$wireless_ht = trim($channel_line[1]);
7162
			if (!empty($wireless_ht)) {
7163
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
7164
			}
7165
		}
7166
	}
7167
	return($wireless_hts_supported);
7168
}
7169

    
7170
/* return wireless HT by channel/standard */
7171
function get_wireless_ht_list($interface) {
7172
	$wireless_hts = array();
7173

    
7174
	$cloned_interface = get_real_interface($interface);
7175

    
7176
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7177
		$interface_channels = get_wireless_channels($cloned_interface);
7178
		$interface_channel_count = count($interface_channels);
7179

    
7180
		$c = 0;
7181
		while ($c < $interface_channel_count) {
7182
			$channel_line = explode(",", $interface_channels["$c"]);
7183
			$wireless_mode = trim($channel_line[0]);
7184
			$wireless_ht = trim($channel_line[1]);
7185
			$wireless_channel = trim($channel_line[2]);
7186
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
7187
				if ($wireless_mode == "11g") {
7188
					if (!isset($wireless_modes["11g"])) {
7189
						$wireless_hts["11g"] = array();
7190
					}
7191
					$wireless_mode = "11ng";
7192
				} elseif ($wireless_mode == "11a") {
7193
					if (!isset($wireless_modes["11a"])) {
7194
						$wireless_hts["11a"] = array();
7195
					}
7196
					$wireless_mode = "11na";
7197
				}
7198
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
7199
			}
7200
			$c++;
7201
		}
7202
	}
7203
	return($wireless_hts);
7204
}
7205

    
7206
/* return channel numbers, frequency, max txpower, and max regulation txpower */
7207
function get_wireless_channel_info($interface) {
7208
	$wireless_channels = array();
7209

    
7210
	$cloned_interface = get_real_interface($interface);
7211

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

    
7217
		$interface_channels = "";
7218
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7219

    
7220
		foreach ($interface_channels as $channel_line) {
7221
			$channel_line = explode(",", $channel_line);
7222
			if (!isset($wireless_channels[$channel_line[0]])) {
7223
				$wireless_channels[$channel_line[0]] = $channel_line;
7224
			}
7225
		}
7226
	}
7227
	return($wireless_channels);
7228
}
7229

    
7230
function set_interface_mtu($interface, $mtu) {
7231

    
7232
	/* LAGG interface must be destroyed and re-created to change MTU */
7233
	if ((substr($interface, 0, 4) == 'lagg') &&
7234
	    (!strstr($interface, "."))) {
7235
		if (isset($config['laggs']['lagg']) &&
7236
		    is_array($config['laggs']['lagg'])) {
7237
			foreach ($config['laggs']['lagg'] as $lagg) {
7238
				if ($lagg['laggif'] == $interface) {
7239
					interface_lagg_configure($lagg);
7240
					break;
7241
				}
7242
			}
7243
		}
7244
	} else {
7245
		pfSense_interface_mtu($interface, $mtu);
7246
		set_ipv6routes_mtu($interface, $mtu);
7247
	}
7248
}
7249

    
7250
/****f* interfaces/get_interface_mtu
7251
 * NAME
7252
 *   get_interface_mtu - Return the mtu of an interface
7253
 * RESULT
7254
 *   $tmp       - Returns the mtu of an interface
7255
 ******/
7256
function get_interface_mtu($interface) {
7257
	$mtu = pfSense_interface_getmtu($interface);
7258
	return $mtu['mtu'];
7259
}
7260

    
7261
function get_interface_mac($interface) {
7262
	$macinfo = pfSense_get_interface_addresses($interface);
7263
	return $macinfo["macaddr"];
7264
}
7265

    
7266
function get_interface_vendor_mac($interface) {
7267
	global $config, $g;
7268

    
7269
	$macinfo = pfSense_get_interface_addresses($interface);
7270
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7271
	    "00:00:00:00:00:00") {
7272
		return ($macinfo["hwaddr"]);
7273
	}
7274

    
7275
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7276
	if (file_exists($hwaddr_file)) {
7277
		$macaddr = trim(file_get_contents($hwaddr_file));
7278
		if (is_macaddr($macaddr)) {
7279
			return ($macaddr);
7280
		}
7281
	} elseif (is_macaddr($macinfo['macaddr'])) {
7282
		/* Save original macaddress to be restored when necessary */
7283
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7284
	}
7285

    
7286
	return (NULL);
7287
}
7288

    
7289
/****f* pfsense-utils/generate_random_mac_address
7290
 * NAME
7291
 *   generate_random_mac - generates a random mac address
7292
 * INPUTS
7293
 *   none
7294
 * RESULT
7295
 *   $mac - a random mac address
7296
 ******/
7297
function generate_random_mac_address() {
7298
	$mac = "02";
7299
	for ($x = 0; $x < 5; $x++) {
7300
		$mac .= ":" . dechex(rand(16, 255));
7301
	}
7302
	return $mac;
7303
}
7304

    
7305
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7306
	global $g;
7307

    
7308
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7309

    
7310
	if (!empty($iface) && !empty($pppif)) {
7311
		$cron_cmd = <<<EOD
7312
#!/bin/sh
7313
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7314
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7315

    
7316
EOD;
7317

    
7318
		@file_put_contents($cron_file, $cron_cmd);
7319
		chmod($cron_file, 0755);
7320
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7321
	} else {
7322
		unlink_if_exists($cron_file);
7323
	}
7324
}
7325

    
7326
function get_interface_default_mtu($type = "ethernet") {
7327
	switch ($type) {
7328
		case "gre":
7329
			return 1476;
7330
			break;
7331
		case "gif":
7332
			return 1280;
7333
			break;
7334
		case "tun":
7335
		case "vlan":
7336
		case "tap":
7337
		case "ethernet":
7338
		default:
7339
			return 1500;
7340
			break;
7341
	}
7342

    
7343
	/* Never reached */
7344
	return 1500;
7345
}
7346

    
7347
function get_vip_descr($ipaddress) {
7348
	global $config;
7349

    
7350
	foreach ($config['virtualip']['vip'] as $vip) {
7351
		if ($vip['subnet'] == $ipaddress) {
7352
			return ($vip['descr']);
7353
		}
7354
	}
7355
	return "";
7356
}
7357

    
7358
function interfaces_staticarp_configure($if) {
7359
	global $config, $g;
7360
	if (isset($config['system']['developerspew'])) {
7361
		$mt = microtime();
7362
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7363
	}
7364

    
7365
	$ifcfg = $config['interfaces'][$if];
7366

    
7367
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
7368
		return 0;
7369
	}
7370

    
7371
	/* Enable staticarp, if enabled */
7372
	if (isset($config['dhcpd'][$if]['staticarp'])) {
7373
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7374
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7375
	} else {
7376
		/*
7377
		 * Interfaces do not have staticarp enabled by default
7378
		 * Let's not disable staticarp on freshly created interfaces
7379
		 */
7380
		if (!platform_booting()) {
7381
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7382
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7383
		}
7384
	}
7385

    
7386
	/* Enable static arp entries */
7387
	if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
7388
		foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
7389
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7390
				continue;
7391
			}
7392
			if (isset($config['dhcpd'][$if]['staticarp']) || isset($arpent['arp_table_static_entry'])) {
7393
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7394
			}
7395
		}
7396
	}
7397

    
7398
	return 0;
7399
}
7400

    
7401
function get_failover_interface($interface, $family = "all", $gateways_status = false) {
7402
	global $config;
7403

    
7404
	/* shortcut to get_real_interface if we find it in the config */
7405
	if (is_array($config['interfaces'][$interface])) {
7406
		return get_real_interface($interface, $family);
7407
	}
7408

    
7409
	/* compare against gateway groups */
7410
	$a_groups = return_gateway_groups_array(true, $gateways_status);
7411
	if (is_array($a_groups[$interface])) {
7412
		/* we found a gateway group, fetch the interface or vip */
7413
		if (!empty($a_groups[$interface][0]['vip'])) {
7414
			return $a_groups[$interface][0]['vip'];
7415
		} else {
7416
			return $a_groups[$interface][0]['int'];
7417
		}
7418
	}
7419
	/* fall through to get_real_interface */
7420
	/* XXX: Really needed? */
7421
	return get_real_interface($interface, $family);
7422
}
7423

    
7424
/****f* interfaces/interface_has_dhcp
7425
 * NAME
7426
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7427
 * INPUTS
7428
 *   interface or gateway group name
7429
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7430
 * RESULT
7431
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7432
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7433
 ******/
7434
function interface_has_dhcp($interface, $family = 4) {
7435
	global $config;
7436

    
7437
	if ($config['interfaces'][$interface]) {
7438
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
7439
			return true;
7440
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
7441
			return true;
7442
		} else {
7443
			return false;
7444
		}
7445
	}
7446

    
7447
	if (!is_array($config['gateways']['gateway_group'])) {
7448
		return false;
7449
	}
7450

    
7451
	if ($family == 6) {
7452
		$dhcp_string = "_DHCP6";
7453
	} else {
7454
		$dhcp_string = "_DHCP";
7455
	}
7456

    
7457
	foreach ($config['gateways']['gateway_group'] as $group) {
7458
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7459
			continue;
7460
		}
7461
		foreach ($group['item'] as $item) {
7462
			$item_data = explode("|", $item);
7463
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7464
				return true;
7465
			}
7466
		}
7467
	}
7468

    
7469
	return false;
7470
}
7471

    
7472
function remove_ifindex($ifname) {
7473
	return preg_replace("/[0-9]+$/", "", $ifname);
7474
}
7475

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

    
7479
	$viplist = get_configured_vip_list($family, $type);
7480
	foreach ($viplist as $vip => $address) {
7481
		$interfaces[$vip] = $address;
7482
		if ($type = VIP_CARP) {
7483
			$vip = get_configured_vip($vipid);
7484
			if (isset($vip) && is_array($vip) ) {
7485
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7486
			}
7487
		}
7488
		if (get_vip_descr($address)) {
7489
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
7490
		}
7491
	}
7492
	return $interfaces;
7493
}
7494

    
7495
function return_gateway_groups_array_with_descr() {
7496
	$interfaces = array();
7497
	$grouplist = return_gateway_groups_array();
7498
	foreach ($grouplist as $name => $group) {
7499
		if ($group[0]['vip'] != "") {
7500
			$vipif = $group[0]['vip'];
7501
		} else {
7502
			$vipif = $group[0]['int'];
7503
		}
7504

    
7505
		$interfaces[$name] = "GW Group {$name}";
7506
	}
7507
	return $interfaces;
7508
}
7509

    
7510
function get_serial_ports($short=false) {
7511
	$linklist = array();
7512
	if (!is_dir("/var/spool/lock")) {
7513
		mwexec("/bin/mkdir -p /var/spool/lock");
7514
	}
7515
	$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);
7516
	foreach ($serialports as $port) {
7517
		$port = trim($port);
7518
		$port = ($short) ? basename($port) : $port;
7519
		$linklist[$port] = $port;
7520
	}
7521
	return $linklist;
7522
}
7523

    
7524
function get_interface_ports() {
7525
	global $config;
7526
	$linklist = array();
7527
	$portlist = get_interface_list();
7528
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7529
		foreach ($config['vlans']['vlan'] as $vlan) {
7530
			$portlist[$vlan['vlanif']] = $vlan;
7531
		}
7532
	}
7533

    
7534
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7535
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7536
			$members = explode(" ", $qinq['members']);
7537
			foreach ($members as $mem) {
7538
				$qentry = $qinq['vlanif'] . "." . $mem;
7539
				$portlist[$qentry] = $qentry;
7540
			}
7541
		}
7542
	}
7543

    
7544
	foreach ($portlist as $ifn => $ifinfo) {
7545
		$string = "";
7546
		if (is_array($ifinfo)) {
7547
			$string .= $ifn;
7548
			if ($ifinfo['mac']) {
7549
				$string .= " ({$ifinfo['mac']})";
7550
			}
7551
			if ($ifinfo['friendly']) {
7552
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7553
			} elseif ($ifinfo['descr']) {
7554
				$string .= " - {$ifinfo['descr']}";
7555
			}
7556
		} else {
7557
			$string .= $ifinfo;
7558
		}
7559

    
7560
		$linklist[$ifn] = $string;
7561
	}
7562
	return $linklist;
7563
}
7564

    
7565
function build_ppps_link_list() {
7566
	global $pconfig;
7567

    
7568
	$linklist = array('list' => array(), 'selected' => array());
7569

    
7570
	if ($pconfig['type'] == 'ppp') {
7571
		$linklist['list'] = get_serial_ports();
7572
	} else {
7573
		$iflist = get_interface_ports();
7574

    
7575
		$viplist = array();
7576
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7577
		foreach ($carplist as $vid => $vaddr) {
7578
			$vip = get_configured_vip($vid);
7579
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7580
		}
7581

    
7582
		$linklist['list'] = array_merge($iflist, $viplist);
7583

    
7584
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7585
		$lagglist = get_lagg_interface_list();
7586
		foreach ($lagglist as $laggif => $lagg) {
7587
			/* LAGG members cannot be assigned */
7588
			$laggmembers = explode(',', $lagg['members']);
7589
			foreach ($laggmembers as $lagm) {
7590
				if (isset($linklist['list'][$lagm])) {
7591
					unset($linklist['list'][$lagm]);
7592
				}
7593
			}
7594
		}
7595
	}
7596

    
7597
	$selected_ports = array();
7598
	if (is_array($pconfig['interfaces'])) {
7599
		$selected_ports = $pconfig['interfaces'];
7600
	} elseif (!empty($pconfig['interfaces'])) {
7601
		$selected_ports = explode(',', $pconfig['interfaces']);
7602
	}
7603
	foreach ($selected_ports as $port) {
7604
		if (isset($linklist['list'][$port])) {
7605
			array_push($linklist['selected'], $port);
7606
		}
7607
	}
7608
	return($linklist);
7609
}
7610

    
7611
function create_interface_list($open = false) {
7612
	global $config;
7613

    
7614
	$iflist = array();
7615

    
7616
	// add group interfaces
7617
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7618
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7619
			if ($open || have_ruleint_access($ifgen['ifname'])) {
7620
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7621
			}
7622
		}
7623
	}
7624

    
7625
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7626
		if ($open || have_ruleint_access($ifent)) {
7627
			$iflist[$ifent] = $ifdesc;
7628
		}
7629
	}
7630

    
7631
	if ($config['l2tp']['mode'] == "server" && ($open || have_ruleint_access("l2tp"))) {
7632
		$iflist['l2tp'] = gettext('L2TP VPN');
7633
	}
7634

    
7635
	if (is_pppoe_server_enabled() && ($open || have_ruleint_access("pppoe"))) {
7636
		$iflist['pppoe'] = gettext("PPPoE Server");
7637
	}
7638

    
7639
	// add ipsec interfaces
7640
	if (ipsec_enabled() && ($open || have_ruleint_access("enc0"))) {
7641
		$iflist["enc0"] = gettext("IPsec");
7642
	}
7643

    
7644
	// add openvpn/tun interfaces
7645
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7646
		$iflist["openvpn"] = gettext("OpenVPN");
7647
	}
7648

    
7649
	return($iflist);
7650
}
7651

    
7652
function is_pseudo_interface($inf, $tap=true) {
7653
	global $config;
7654
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7655
	foreach ($psifs as $pif) {
7656
		if (substr($inf, 0, strlen($pif)) == $pif) {
7657
			if (($pif == 'ovpn') && $tap) {
7658
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7659
				$type = ($m[1] == 'c') ? 'client' : 'server';
7660
				foreach ($config['openvpn']['openvpn-'.$type] as $ovpn) {
7661
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7662
						return false;
7663
					} elseif ($ovpn['vpnid'] == $m[2]) {
7664
						return true;
7665
					}
7666
				}
7667
			} else {
7668
				return true;
7669
			}
7670
		}
7671
	}
7672
	return false;
7673
}
7674

    
7675
function is_stf_interface($inf) {
7676
	global $config;
7677

    
7678
	if (is_array($config['interfaces'][$inf]) &&
7679
	    (($config['interfaces'][$inf]['ipaddrv6'] == '6rd') ||
7680
	    ($config['interfaces'][$inf]['ipaddrv6'] == '6to4'))) {
7681
	    return true;
7682
	}
7683

    
7684
	return false;
7685
}
7686

    
7687
function restart_interface_services($interface, $ipv6type = "") {
7688
	global $config;
7689

    
7690
	services_unbound_configure(true, $interface);
7691

    
7692
	services_igmpproxy_configure($interface);
7693
	services_snmpd_configure($interface);
7694
	vpn_l2tp_configure($interface);
7695

    
7696
	if (substr($realif, 0, 4) != "ovpn") {
7697
		openvpn_resync_all($interface);
7698
	}
7699
	ipsec_force_reload($interface);
7700

    
7701
	/* restart RADVD to announce correct IPv6 prefix
7702
	 * see https://redmine.pfsense.org/issues/12604 */ 
7703
	if ((($ipv6type == "staticv6") || ($ipv6type == "track6")) &&
7704
	    is_array($config['dhcpdv6'][$interface]) &&
7705
	    isset($config['dhcpdv6'][$interface]['ramode']) &&
7706
	    ($config['dhcpdv6'][$interface]['ramode'] != "disabled")) {
7707
		services_radvd_configure();
7708
	}
7709

    
7710
	if (isset($config['dhcpd'][$interface]['enable']) ||
7711
	    isset($config['dhcpdv6'][$interface]['enable'])) {
7712
		services_dhcpd_configure();
7713
	}
7714

    
7715
	init_config_arr(array('syslog'));
7716
	if (isset($config['syslog']['enable']) && ($interface == $config['syslog']['sourceip'])) {
7717
		system_syslogd_start();
7718
	}
7719
}
7720

    
7721
?>
(22-22/61)