Project

General

Profile

Download (219 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-2020 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

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

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

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

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

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

    
61
	return true;
62
}
63

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

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

    
75
	return $interface_arr_cache;
76
}
77

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

    
85
	if (!$interface) {
86
		return false;
87
	}
88

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

    
97
/*
98
 * does_vip_exist($vip): return true or false if a vip is
99
 * configured.
100
 */
101
function does_vip_exist($vip) {
102
	global $config;
103

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

    
108

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

    
124
	$ifacedata = pfSense_getall_interface_addresses($realif);
125

    
126
	if (is_subnetv6("{$vip['subnet']}/{$vip['subnet_bits']}")) {	
127
		$comparevip = text_to_compressed_ip6("{$vip['subnet']}/{$vip['subnet_bits']}");
128
	} else {
129
		$comparevip = "{$vip['subnet']}/{$vip['subnet_bits']}";
130
	}
131

    
132
	foreach ($ifacedata as $vipips) {
133
		if ($vipips == $comparevip) {
134
			return true;
135
		}
136
	}
137

    
138
	return false;
139
}
140

    
141
function interface_netgraph_needed($interface = "wan") {
142
	global $config;
143

    
144
	$found = false;
145
	if (!empty($config['l2tp']) &&
146
	    $config['l2tp']['mode'] == "server") {
147
		$found = true;
148
	}
149
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
150
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
151
			if ($pppoe['mode'] != "server") {
152
				continue;
153
			}
154
			if ($pppoe['interface'] == $interface) {
155
				$found = true;
156
				break;
157
			}
158
		}
159
	}
160
	if ($found == false) {
161
		$found = interface_isppp_type($interface);
162
	}
163

    
164
	if ($found == false) {
165
		$realif = get_real_interface($interface);
166
		init_config_arr(array('ppps', 'ppp'));
167
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
168
			$ports = explode(',', $ppp['ports']);
169
			foreach ($ports as $pid => $port) {
170
				$port = get_real_interface($port);
171
				if ($realif == $port) {
172
					$found = true;
173
					break;
174
				}
175
				/* Find the parent interfaces of the vlans in the MLPPP configs
176
				* there should be only one element in the array here
177
				* -- this could be better . . . */
178
				$parent_if = get_parent_interface($port);
179
				if ($realif == $parent_if[0]) {
180
					$found = true;
181
					break;
182
				}
183
			}
184
		}
185
	}
186

    
187
	if ($found == false) {
188
		$realif = get_real_interface($interface);
189
		pfSense_ngctl_detach("{$realif}:", $realif);
190
	}
191
	/* NOTE: We make sure for this on interface_ppps_configure()
192
	 *	no need to do it here again.
193
	 *	else
194
	 *		pfSense_ngctl_attach(".", $realif);
195
	 */
196
}
197

    
198
function interfaces_loopback_configure() {
199
	global $g;
200

    
201
	if (platform_booting()) {
202
		echo gettext("Configuring loopback interface...");
203
	}
204
	pfSense_interface_setaddress("lo0", "127.0.0.1");
205
	interfaces_bring_up("lo0");
206
	if (platform_booting()) {
207
		echo gettext("done.") . "\n";
208
	}
209
	return 0;
210
}
211

    
212
function vlan_valid_tag($tag = NULL) {
213

    
214
	if ($tag == NULL || empty($tag) ||
215
	    !is_numericint($tag) || intval($tag) < 1 || intval($tag) > 4094) {
216
		return (false);
217
	}
218
	return (true);
219
}
220

    
221
function qinq_inuse($qinq = NULL, $inqtag = NULL) {
222
        global $config;
223

    
224
	if ($qinq == NULL || $inqtag == NULL ||
225
	    !is_array($qinq) || !vlan_valid_tag($inqtag)) {
226
		return (false);
227
	}
228

    
229
        $iflist = get_configured_interface_list(true);
230
        foreach ($iflist as $if) {
231
                if ($config['interfaces'][$if]['if'] == qinq_interface($qinq, $inqtag)) {
232
                        return (true);
233
                }
234
        }
235

    
236
        return (false);
237
}
238

    
239
function qinq_interface($qinq = NULL, $inqtag = NULL) {
240

    
241
	if ($qinq == NULL || $inqtag == NULL || !is_array($qinq) ||
242
	    !isset($qinq['if']) || !isset($qinq['tag']) ||
243
	    !vlan_valid_tag($qinq['tag']) || !vlan_valid_tag($inqtag)) {
244
		return (NULL);
245
	}
246
	return ("{$qinq['if']}.{$qinq['tag']}.{$inqtag}");
247
}
248

    
249
function interface_is_qinq($if = NULL) {
250
	global $config;
251

    
252
	if ($if == NULL || empty($if) || !is_array($config['qinqs']['qinqentry'])) {
253
		return (NULL);
254
	}
255

    
256
	/* Check basic format. */
257
	list($qinqif, $vlantag, $inqtag) = explode(".", $if);
258
	if (empty($qinqif) || empty($vlantag) || empty($inqtag) ||
259
	    !vlan_valid_tag($vlantag) || !vlan_valid_tag($inqtag)) {
260
		return (NULL);
261
	}
262

    
263
	foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
264
		if ("{$qinqif}.{$vlantag}" != $qinq['vlanif']) {
265
			continue;
266
		}
267
		if (empty($qinq['members'])) {
268
			continue;
269
		}
270
		foreach (explode(" ", $qinq['members']) as $tag) {
271
			if ($if == qinq_interface($qinq, $tag)) {
272
				return ($qinq);
273
			}
274
		}
275
	}
276

    
277
	return (NULL);
278
}
279

    
280
function vlan_inuse($vlan) {
281
	global $config;
282

    
283
	if ($vlan == NULL || !is_array($vlan)) {
284
		return (false);
285
	}
286

    
287
	$iflist = get_configured_interface_list(true);
288
	foreach ($iflist as $if) {
289
		if ($config['interfaces'][$if]['if'] == $vlan['vlanif']) {
290
			return (true);
291
		}
292
	}
293

    
294
	return (false);
295
}
296

    
297
function interface_is_vlan($if = NULL) {
298
	global $config;
299

    
300
	if ($if == NULL || empty($if) || is_array($if)) {
301
		return (NULL);
302
	}
303

    
304
	/* Check basic format. */
305
	list($vlanif, $vlantag) = explode(".", $if);
306
	if (empty($vlanif) || empty($vlantag) || !vlan_valid_tag($vlantag)) {
307
		return (NULL);
308
	}
309

    
310
	/* Find the VLAN interface. */
311
	if (isset($config['vlans']['vlan']) && is_array($config['vlans']['vlan'])) {
312
		foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
313
			if ($if == $vlan['vlanif']) {
314
				return ($vlan);
315
			}
316
		}
317
	}
318

    
319
	/* Check for the first level tag in QinQ interfaces. */
320
	if (isset($config['qinqs']['qinqentry']) && is_array($config['qinqs']['qinqentry'])) {
321
		foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
322
			if ($if == $qinq['vlanif']) {
323
				return ($qinq);
324
			}
325
		}
326
	}
327

    
328
	return (NULL);
329
}
330

    
331
function vlan_interface($vlan = NULL) {
332
	if ($vlan == NULL || !is_array($vlan) || !isset($vlan['if']) ||
333
	    !isset($vlan['tag']) || !vlan_valid_tag($vlan['tag'])) {
334
		return (NULL);
335
	}
336
	return ("{$vlan['if']}.{$vlan['tag']}");
337
}
338

    
339
function interface_set_macaddr($interface, $mac_addr) {
340
	if (empty($mac_addr) || !is_macaddr($mac_addr)) {
341
		return;
342
	}
343

    
344
	$current_mac = get_interface_mac($interface);
345

    
346
	/*
347
	 * Don't try to reapply the MAC if it's already applied.
348
	 * When ifconfig link is used, it cycles the interface down/up, which
349
	 * triggers the interface config again, which attempts to apply the
350
	 * MAC again, which cycles the link again...
351
	 */
352
	if ($mac_addr != $current_mac) {
353
		mwexec("/sbin/ifconfig " . escapeshellarg($interface) .
354
		    " link " . escapeshellarg($mac_addr));
355
	}
356
}
357

    
358
function interface_is_parent($if, $parent_check) {
359

    
360
	$parent_array = get_parent_interface($if);
361
	if (count($parent_array) > 1) {
362
		$parent = $parent_array;
363
	} else {
364
		$parent = $parent_array[0];
365
	}
366
	if (is_array($parent)) {
367
		foreach ($parent as $parentif) {
368
			if (strcasecmp($parent_check, $parentif) == 0) {
369
				return (TRUE);
370
			}
371
		}
372
	} else {
373
		$realif = get_real_interface($parent);
374
		if (strcasecmp($parent_check, $realif) == 0) {
375
			return (TRUE);
376
		}
377
	}
378
	return (FALSE);
379
}
380

    
381
function interface_has_clones($if) {
382
	global $config;
383

    
384
	/* Check LAGGs. */
385
	if (isset($config['laggs']) && isset($config['laggs']['lagg']) &&
386
	    is_array($config['laggs']['lagg'])) {
387
		foreach ($config['laggs']['lagg'] as $lagg) {
388
			if (interface_is_parent($lagg['laggif'], $if)) {
389
				return (TRUE);
390
			}
391
		}
392
	}
393
	/* Check VLANs. */
394
	if (isset($config['vlans']) && isset($config['vlans']['vlan']) &&
395
	    is_array($config['vlans']['vlan'])) {
396
		foreach ($config['vlans']['vlan'] as $vlan) {
397
			if (interface_is_parent($vlan['if'], $if)) {
398
				return (TRUE);
399
			}
400
		}
401
	}
402
	/* Check bridges. */
403
	if (isset($config['bridges']) && isset($config['bridges']['bridged']) &&
404
	    is_array($config['bridges']['bridged'])) {
405
		foreach ($config['bridges']['bridged'] as $bridge) {
406
			$members = explode(',', $bridge['members']);
407
			foreach ($members as $member) {
408
				if (interface_is_parent($member, $if)) {
409
					return (TRUE);
410
				}
411
			}
412
		}
413
	}
414

    
415
	return (FALSE);
416
}
417

    
418
function interfaces_vlan_configure($parentif = "") {
419
	global $config, $g;
420
	if (platform_booting()) {
421
		echo gettext("Configuring VLAN interfaces...");
422
	}
423
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
424
		foreach ($config['vlans']['vlan'] as $vlan) {
425
			if (empty($vlan['vlanif'])) {
426
				$vlan['vlanif'] = vlan_interface($vlan);
427
			}
428
			if (!empty($parentif) && ($parentif != $vlan['if'])) {
429
				continue;
430
			}
431

    
432
			/* XXX: Maybe we should report any errors?! */
433
			interface_vlan_configure($vlan, false);
434
		}
435
	}
436

    
437
	/* Invalidate cache */
438
	get_interface_arr(true);
439

    
440
	if (platform_booting()) {
441
		echo gettext("done.") . "\n";
442
	}
443
}
444

    
445
function interface_vlan_configure(&$vlan, $flush = true) {
446
	global $config, $g;
447

    
448
	if (!is_array($vlan)) {
449
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
450
		return(NULL);
451
	}
452
	$if = $vlan['if'];
453
	if (empty($if)) {
454
		log_error(gettext("interface_vlan_configure called with if undefined."));
455
		return(NULL);
456
	}
457

    
458
	$vlanif = empty($vlan['vlanif']) ? vlan_interface($vlan) : $vlan['vlanif'];
459
	if ($vlanif == NULL) {
460
		log_error(gettext("vlan_interface called with if undefined var."));
461
		return(NULL);
462
	}
463
	$tag = $vlan['tag'];
464
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
465

    
466
	/* make sure the parent interface is up */
467
	interfaces_bring_up($if);
468
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
469
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
470

    
471
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
472
		pfSense_interface_destroy($vlanif);
473
	}
474

    
475
	$tmpvlanif = pfSense_interface_create("vlan");
476
	pfSense_interface_rename($tmpvlanif, $vlanif);
477
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
478

    
479
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
480

    
481
	interfaces_bring_up($vlanif);
482

    
483
	/* invalidate interface cache */
484
	if ($flush) {
485
		get_interface_arr(true);
486
	}
487

    
488
	/* configure interface if assigned */
489
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
490
	if ($assignedif) {
491
		if (isset($config['interfaces'][$assignedif]['enable'])) {
492
			interface_configure($assignedif, true);
493
		}
494
	}
495

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

    
499
	if (interface_vlan_mtu_configured($vlanif)) {
500
		set_interface_mtu($vlanif, interface_vlan_mtu_configured($vlanif));
501
	}
502

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

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

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

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

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

    
595
	return $vlanif;
596
}
597

    
598
function interfaces_qinq_configure() {
599
	global $config, $g;
600
	if (platform_booting()) {
601
		echo gettext("Configuring QinQ interfaces...");
602
	}
603
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
604
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
605
			/* XXX: Maybe we should report any errors?! */
606
			interface_qinq_configure($qinq, NULL, false);
607
		}
608
	}
609

    
610
	/* Invalidate cache */
611
	get_interface_arr(true);
612

    
613
	if (platform_booting()) {
614
		echo gettext("done.") . "\n";
615
	}
616
}
617

    
618
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr, $flush = true) {
619
	global $config, $g;
620

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

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

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

    
647
	/* invalidate interface cache */
648
	if ($flush) {
649
		get_interface_arr(true);
650
	}
651

    
652
	return $vlanif;
653
}
654

    
655
function interfaces_create_wireless_clones() {
656
	global $config, $g;
657

    
658
	if (platform_booting()) {
659
		echo gettext("Creating wireless clone interfaces...");
660
	}
661

    
662
	$iflist = get_configured_interface_list();
663

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

    
671
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
672
		foreach ($config['wireless']['clone'] as $clone) {
673
			if (empty($clone['cloneif'])) {
674
				continue;
675
			}
676
			if (does_interface_exist($clone['cloneif'])) {
677
				continue;
678
			}
679
			/* XXX: Maybe we should report any errors?! */
680
			interface_wireless_clone($clone['cloneif'], $clone);
681
		}
682
	}
683
	if (platform_booting()) {
684
		echo gettext("done.") . "\n";
685
	}
686

    
687
}
688

    
689
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
690
	global $config;
691

    
692
	$i = 0;
693
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
694
		foreach ($config['bridges']['bridged'] as $bridge) {
695
			if (empty($bridge['bridgeif'])) {
696
				$bridge['bridgeif'] = "bridge{$i}";
697
			}
698
			if (!empty($realif) && ($realif != $bridge['bridgeif'])) {
699
				continue;
700
			}
701
			$ifname = false;
702
			foreach ($config['interfaces'] as $intname => $intpar) {
703
				if ($intpar['if'] == $bridge['bridgeif']) {
704
					$ifname = $intname;
705
					break;
706
				}
707
			}
708

    
709
			if (($checkmember == 1) && $ifname &&
710
			    ($config['interfaces'][$ifname]['ipaddrv6'] == "track6")) {
711
				continue;
712
			} elseif (($checkmember == 2) && !$ifname) {
713
				continue;
714
			}
715

    
716
			/* XXX: Maybe we should report any errors?! */
717
			interface_bridge_configure($bridge, $checkmember,
718
			    false);
719
			$i++;
720
		}
721

    
722
		/* Invalidate cache */
723
		get_interface_arr(true);
724
	}
725
}
726

    
727
function interface_bridge_configure(&$bridge, $checkmember = 0, $flush = true) {
728
	global $config, $g;
729

    
730
	if (!is_array($bridge)) {
731
		return;
732
	}
733

    
734
	if (empty($bridge['members'])) {
735
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
736
		return;
737
	}
738

    
739
	$members = explode(',', $bridge['members']);
740
	if (!count($members)) {
741
		return;
742
	}
743

    
744
	/* Calculate smaller mtu and enforce it */
745
	$smallermtu = 0;
746
	$foundgif = false;
747
	foreach ($members as $member) {
748
		$realif = get_real_interface($member);
749
		$mtu = get_interface_mtu($realif);
750
		if (substr($realif, 0, 3) == "gif") {
751
			$foundgif = true;
752
			if ($checkmember == 1) {
753
				return;
754
			}
755
			if ($mtu <= 1500) {
756
				continue;
757
			}
758
		}
759
		if ($smallermtu == 0 && !empty($mtu)) {
760
			$smallermtu = $mtu;
761
		} else if (!empty($mtu) && $mtu < $smallermtu) {
762
			$smallermtu = $mtu;
763
		}
764
	}
765
	if ($foundgif == false && $checkmember == 2) {
766
		return;
767
	}
768

    
769
	/* Just in case anything is not working well */
770
	if ($smallermtu == 0) {
771
		$smallermtu = 1500;
772
	}
773

    
774
	if (!empty($bridge['bridgeif'])) {
775
		pfSense_interface_destroy($bridge['bridgeif']);
776
		pfSense_interface_create($bridge['bridgeif']);
777
		$bridgeif = escapeshellarg($bridge['bridgeif']);
778
	} else {
779
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
780
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
781
		$bridgeif = pfSense_interface_create("bridge");
782
		$bridge['bridgeif'] = $bridgeif;
783
	}
784

    
785
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
786
	if ($bridgemtu > $smallermtu) {
787
		$smallermtu = $bridgemtu;
788
	}
789

    
790
	$checklist = get_configured_interface_list();
791

    
792
	/* Add interfaces to bridge */
793
	foreach ($members as $member) {
794
		if (empty($checklist[$member])) {
795
			continue;
796
		}
797
		$realif = get_real_interface($member);
798
		if (!$realif) {
799
			log_error(gettext("realif not defined in interfaces bridge - up"));
800
			continue;
801
		}
802
		/* make sure the parent interface is up */
803
		pfSense_interface_mtu($realif, $smallermtu);
804
		interfaces_bring_up($realif);
805
		enable_hardware_offloading($member);
806
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
807
	}
808

    
809
	if (isset($bridge['enablestp'])) {
810
		interface_bridge_configure_stp($bridge);
811
	}
812

    
813
	interface_bridge_configure_advanced($bridge);
814

    
815
	interface_bridge_configure_ip6linklocal($bridge);
816

    
817
	if ($flush) {
818
		get_interface_arr(true);
819
	}
820

    
821
	if ($bridge['bridgeif']) {
822
		interfaces_bring_up($bridge['bridgeif']);
823
	} else {
824
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
825
	}
826
}
827

    
828
function interface_bridge_configure_stp($bridge) {
829
	if (isset($bridge['enablestp'])) {
830
		$bridgeif = trim($bridge['bridgeif']);
831
		/* configure spanning tree proto */
832
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
833

    
834
		if (!empty($bridge['stp'])) {
835
			$stpifs = explode(',', $bridge['stp']);
836
			foreach ($stpifs as $stpif) {
837
				$realif = get_real_interface($stpif);
838
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
839
			}
840
		}
841
		if (!empty($bridge['maxage'])) {
842
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
843
		}
844
		if (!empty($bridge['fwdelay'])) {
845
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
846
		}
847
		if (!empty($bridge['hellotime'])) {
848
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
849
		}
850
		if (!empty($bridge['priority'])) {
851
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
852
		}
853
		if (!empty($bridge['holdcnt'])) {
854
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
855
		}
856
		if (!empty($bridge['ifpriority'])) {
857
			$pconfig = explode(",", $bridge['ifpriority']);
858
			$ifpriority = array();
859
			foreach ($pconfig as $cfg) {
860
				$embcfg = explode_assoc(":", $cfg);
861
				foreach ($embcfg as $key => $value) {
862
					$ifpriority[$key] = $value;
863
				}
864
			}
865
			foreach ($ifpriority as $key => $value) {
866
				$realif = get_real_interface($key);
867
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
868
			}
869
		}
870
		if (!empty($bridge['ifpathcost'])) {
871
			$pconfig = explode(",", $bridge['ifpathcost']);
872
			$ifpathcost = array();
873
			foreach ($pconfig as $cfg) {
874
				$embcfg = explode_assoc(":", $cfg);
875
				foreach ($embcfg as $key => $value) {
876
					$ifpathcost[$key] = $value;
877
				}
878
			}
879
			foreach ($ifpathcost as $key => $value) {
880
				$realif = get_real_interface($key);
881
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
882
			}
883
		}
884
	}
885
}
886

    
887
function interface_bridge_configure_advanced($bridge) {
888
	$bridgeif = trim($bridge['bridgeif']);
889

    
890
	if ($bridge['maxaddr'] <> "") {
891
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
892
	}
893
	if ($bridge['timeout'] <> "") {
894
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
895
	}
896
	if (!empty($bridge['span'])) {
897
		$spanifs = explode(",", $bridge['span']);
898
		foreach ($spanifs as $spanif) {
899
			$realif = get_real_interface($spanif);
900
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
901
		}
902
	}
903
	if (!empty($bridge['edge'])) {
904
		$edgeifs = explode(',', $bridge['edge']);
905
		foreach ($edgeifs as $edgeif) {
906
			$realif = get_real_interface($edgeif);
907
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
908
		}
909
	}
910
	if (!empty($bridge['autoedge'])) {
911
		$edgeifs = explode(',', $bridge['autoedge']);
912
		foreach ($edgeifs as $edgeif) {
913
			$realif = get_real_interface($edgeif);
914
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
915
		}
916
	}
917
	if (!empty($bridge['ptp'])) {
918
		$ptpifs = explode(',', $bridge['ptp']);
919
		foreach ($ptpifs as $ptpif) {
920
			$realif = get_real_interface($ptpif);
921
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
922
		}
923
	}
924
	if (!empty($bridge['autoptp'])) {
925
		$ptpifs = explode(',', $bridge['autoptp']);
926
		foreach ($ptpifs as $ptpif) {
927
			$realif = get_real_interface($ptpif);
928
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
929
		}
930
	}
931
	if (!empty($bridge['static'])) {
932
		$stickyifs = explode(',', $bridge['static']);
933
		foreach ($stickyifs as $stickyif) {
934
			$realif = get_real_interface($stickyif);
935
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
936
		}
937
	}
938
	if (!empty($bridge['private'])) {
939
		$privateifs = explode(',', $bridge['private']);
940
		foreach ($privateifs as $privateif) {
941
			$realif = get_real_interface($privateif);
942
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
943
		}
944
	}
945
}
946

    
947
function interface_bridge_configure_ip6linklocal($bridge) {
948
	$bridgeif = trim($bridge['bridgeif']);
949

    
950
	$members = explode(',', $bridge['members']);
951
	if (!count($members)) {
952
		return;
953
	}
954

    
955
	$auto_linklocal = isset($bridge['ip6linklocal']);
956
	$bridgeop = $auto_linklocal ? '' : '-';
957
	$memberop = $auto_linklocal ? '-' : '';
958

    
959
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
960
	foreach ($members as $member) {
961
		$realif = get_real_interface($member);
962
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
963
	}
964
}
965

    
966
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
967
	global $config;
968

    
969
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
970
		return;
971
	}
972

    
973
	if ($flagsapplied == false) {
974
		$mtu = get_interface_mtu($bridgeif);
975
		$mtum = get_interface_mtu($interface);
976
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
977
			pfSense_interface_mtu($interface, $mtu);
978
		}
979

    
980
		hardware_offloading_applyflags($interface);
981
		interfaces_bring_up($interface);
982
	}
983

    
984
	pfSense_bridge_add_member($bridgeif, $interface);
985
	if (is_array($config['bridges']['bridged'])) {
986
		foreach ($config['bridges']['bridged'] as $bridge) {
987
			if ($bridgeif == $bridge['bridgeif']) {
988
				interface_bridge_configure_stp($bridge);
989
				interface_bridge_configure_advanced($bridge);
990
			}
991
		}
992
	}
993
}
994

    
995
function interfaces_lagg_configure($realif = "") {
996
	global $config, $g;
997
	if (platform_booting()) {
998
		echo gettext("Configuring LAGG interfaces...");
999
	}
1000
	$i = 0;
1001
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
1002
		foreach ($config['laggs']['lagg'] as $lagg) {
1003
			if (empty($lagg['laggif'])) {
1004
				$lagg['laggif'] = "lagg{$i}";
1005
			}
1006
			if (!empty($realif) && $realif != $lagg['laggif']) {
1007
				continue;
1008
			}
1009
			/* XXX: Maybe we should report any errors?! */
1010
			interface_lagg_configure($lagg, false);
1011
			$i++;
1012
		}
1013

    
1014
		/* Invalidate cache */
1015
		get_interface_arr(true);
1016
	}
1017
	if (platform_booting()) {
1018
		echo gettext("done.") . "\n";
1019
	}
1020
}
1021

    
1022
function interface_lagg_configure($lagg, $flush = true) {
1023
	global $config, $g;
1024

    
1025
	if (!is_array($lagg)) {
1026
		return -1;
1027
	}
1028

    
1029
	$members = explode(',', $lagg['members']);
1030
	if (!count($members)) {
1031
		return -1;
1032
	}
1033

    
1034
	if (platform_booting() || !(empty($lagg['laggif']))) {
1035
		pfSense_interface_destroy($lagg['laggif']);
1036
		pfSense_interface_create($lagg['laggif']);
1037
		$laggif = $lagg['laggif'];
1038
	} else {
1039
		$laggif = pfSense_interface_create("lagg");
1040
	}
1041

    
1042
	/* Check if MTU was defined for this lagg interface */
1043
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
1044
	if ($lagg_mtu == 0 &&
1045
	    is_array($config['interfaces'])) {
1046
		foreach ($config['interfaces'] as $tmpinterface) {
1047
			if ($tmpinterface['if'] == $lagg['laggif'] &&
1048
			    !empty($tmpinterface['mtu'])) {
1049
				$lagg_mtu = $tmpinterface['mtu'];
1050
				break;
1051
			}
1052
		}
1053
	}
1054

    
1055
	/* Just in case anything is not working well */
1056
	if ($lagg_mtu == 0) {
1057
		$lagg_mtu = 1500;
1058
	}
1059

    
1060
	// put failover master interface on top of list
1061
	if (($lagg['proto'] == 'failover') && isset($lagg['failovermaster']) &&
1062
	    ($lagg['failovermaster'] != 'auto')) {
1063
		unset($members[array_search($lagg['failovermaster'], $members)]);
1064
		$members = array_merge(array($lagg['failovermaster']), $members);
1065
	}
1066

    
1067
	if (($lagg['proto'] == 'lacp') && isset($lagg['lacptimeout']) &&
1068
	    ($lagg['lacptimeout'] != 'slow')) {
1069
		$lacptimeout = 'lacp_fast_timeout';
1070
	} else {
1071
		$lacptimeout = '';
1072
	}
1073

    
1074
	foreach ($members as $member) {
1075
		if (!does_interface_exist($member)) {
1076
			continue;
1077
		}
1078

    
1079
		/* make sure the parent interface is up */
1080
		pfSense_interface_mtu($member, $lagg_mtu);
1081
		interfaces_bring_up($member);
1082
		hardware_offloading_applyflags($member);
1083

    
1084
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
1085
		$laggif = str_replace("\0", "", $laggif);
1086
		$member = str_replace("\0", "", $member);
1087
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
1088
	}
1089

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

    
1092
	if ($flush) {
1093
		get_interface_arr(true);
1094
	}
1095

    
1096
	interfaces_bring_up($laggif);
1097

    
1098
	return $laggif;
1099
}
1100

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

    
1105
	if (!is_array($gre)) {
1106
		return -1;
1107
	}
1108

    
1109
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1110
	if (!interface_is_vlan($realif)) {
1111
		$realif = get_real_interface($gre['if']);
1112
	}
1113
	$realifip = get_interface_ip($gre['if']);
1114
	$realifip6 = get_interface_ipv6($gre['if']);
1115

    
1116
	/* make sure the parent interface is up */
1117
	interfaces_bring_up($realif);
1118

    
1119
	if (platform_booting() || !(empty($gre['greif']))) {
1120
		pfSense_interface_destroy($gre['greif']);
1121
		pfSense_interface_create($gre['greif']);
1122
		$greif = $gre['greif'];
1123
	} else {
1124
		$greif = pfSense_interface_create("gre");
1125
	}
1126

    
1127
	$tunnel_type = '';
1128
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1129
		$tunnel_type = 'v4';
1130
	}
1131
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1132
		$tunnel_type .= 'v6';
1133
	}
1134

    
1135
	/* Do not change the order here for more see gre(4) NOTES section. */
1136
	if (is_ipaddrv6($gre['remote-addr'])) {
1137
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1138
	} else {
1139
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1140
	}
1141
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1142
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1143
	}
1144
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1145
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1146
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr6']) . " " . escapeshellarg($gre['tunnel-remote-addr6']) . " prefixlen 128");
1147
	}
1148

    
1149
	$parentif = get_real_interface($gre['if']);
1150
	if ($parentif) {
1151
		interfaces_bring_up($parentif);
1152
	} else {
1153
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1154
	}
1155

    
1156
	if (isset($gre['link1'])) {
1157
		if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1158
			mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1159
		}
1160
		if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1161
			mwexec("/sbin/route -6 add " . escapeshellarg($gre['tunnel-remote-addr6']) . "/" . escapeshellarg($gre['tunnel-remote-net6']) . " " . escapeshellarg($gre['tunnel-local-addr6']));
1162
		}
1163
	}
1164
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1165
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1166
	}
1167
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1168
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr6']);
1169
	}
1170

    
1171
	if ($flush) {
1172
		get_interface_arr(true);
1173
	}
1174

    
1175
	interfaces_bring_up($greif);
1176

    
1177
	return $greif;
1178
}
1179

    
1180
function interface_is_type($if = NULL, $type) {
1181
	global $config;
1182
	switch ($type) {
1183
		case "gre":
1184
			$list = 'gres';
1185
			$entry = 'gre';
1186
			$entif = 'greif';
1187
			break;
1188
		case "gif":
1189
			$list = 'gifs';
1190
			$entry = 'gif';
1191
			$entif = 'gifif';
1192
			break;
1193
		case "lagg":
1194
			$list = 'laggs';
1195
			$entry = 'lagg';
1196
			$entif = 'laggif';
1197
			break;
1198
		case "vxlan":
1199
			$list = 'vxlans';
1200
			$entry = 'vxlan';
1201
			$entif = 'vxlanif';
1202
			break;
1203
		default:
1204
			break;
1205
	}
1206

    
1207
	if (!isset($config[$list][$entry]) || !is_array($config[$list][$entry])) {
1208
		return (NULL);
1209
	}
1210

    
1211
	foreach ($config[$list][$entry] as $ent) {
1212
		if ($ent[$entif] == $if) {
1213
			return ($ent);
1214
		}
1215
	}
1216
	return (NULL);
1217
}
1218

    
1219
function is_greipsec($if) {
1220
	global $config;
1221

    
1222
	if (ipsec_enabled() && is_array($config['gres']) && 
1223
	    is_array($config['gres']['gre']) &&
1224
	    is_array($config['ipsec']['phase2'])) {
1225
		foreach ($config['gres']['gre'] as $gre) {
1226
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
1227
				foreach ($config['ipsec']['phase2'] as $ph2ent) {
1228
					if (($ph1ent['ikeid'] == $ph2ent['ikeid']) && ($ph2ent['mode'] == 'transport') && 
1229
					    !isset($ph1ent['disabled']) && !isset($ph2ent['disabled']) && 
1230
					    ($ph1ent['interface'] == $gre['if']) && ($gre['greif'] == $if) &&
1231
					    ($ph1ent['remote-gateway'] == $gre['remote-addr'])) {
1232
						    return true;
1233
					}
1234
				}
1235
			}
1236
		}
1237
	}
1238
	return false;
1239
}
1240

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

    
1245
	if (!is_array($gif)) {
1246
		return -1;
1247
	}
1248

    
1249
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1250
	if (!interface_is_vlan($realif)) {
1251
		$realif = get_real_interface($gif['if']);
1252
	}
1253
	$ipaddr = get_interface_ip($gif['if']);
1254

    
1255
	if (is_ipaddrv4($gif['remote-addr'])) {
1256
		if (is_ipaddrv4($ipaddr)) {
1257
			$realifip = $ipaddr;
1258
		} else {
1259
			$realifip = get_interface_ip($gif['if']);
1260
		}
1261
		$realifgw = get_interface_gateway($gif['if']);
1262
	} else if (is_ipaddrv6($gif['remote-addr'])) {
1263
		if (is_ipaddrv6($ipaddr)) {
1264
			$realifip = $ipaddr;
1265
		} else {
1266
			$realifip = get_interface_ipv6($gif['if']);
1267
		}
1268
		$realifgw = get_interface_gateway_v6($gif['if']);
1269
	}
1270
	/* make sure the parent interface is up */
1271
	$parentif = get_real_interface($gif['if']);
1272
	if ($parentif) {
1273
		interfaces_bring_up($parentif);
1274
	} else {
1275
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gif_configure()"));
1276
	}
1277

    
1278
	if (platform_booting() || !(empty($gif['gifif']))) {
1279
		pfSense_interface_destroy($gif['gifif']);
1280
		pfSense_interface_create($gif['gifif']);
1281
		$gifif = $gif['gifif'];
1282
	} else {
1283
		$gifif = pfSense_interface_create("gif");
1284
	}
1285

    
1286
	/* Do not change the order here for more see gif(4) NOTES section. */
1287
	if (is_ipaddrv6($gif['remote-addr'])) {
1288
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1289
	} else {
1290
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1291
	}
1292
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1293
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1294
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1295
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1296
	} else {
1297
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1298
	}
1299
	if (isset($gif['link1'])) {
1300
		pfSense_interface_flags($gifif, IFF_LINK1);
1301
	}
1302
	if (isset($gif['link2'])) {
1303
		pfSense_interface_flags($gifif, IFF_LINK2);
1304
	}
1305
	if ($gifif) {
1306
		interfaces_bring_up($gifif);
1307
		$gifmtu = "";
1308
		$currentgifmtu = get_interface_mtu($gifif);
1309
		foreach ($config['interfaces'] as $tmpinterface) {
1310
			if ($tmpinterface['if'] == $gifif) {
1311
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1312
					$gifmtu = $tmpinterface['mtu'];
1313
				}
1314
			}
1315
		}
1316
		if (is_numericint($gifmtu)) {
1317
			if ($gifmtu != $currentgifmtu) {
1318
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1319
			}
1320
		}
1321
	} else {
1322
		log_error(gettext("could not bring gifif up -- variable not defined"));
1323
	}
1324

    
1325
	if (!platform_booting()) {
1326
		$iflist = get_configured_interface_list();
1327
		foreach ($iflist as $ifname) {
1328
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1329
				if (get_interface_gateway($ifname)) {
1330
					system_routing_configure($ifname);
1331
					break;
1332
				}
1333
				if (get_interface_gateway_v6($ifname)) {
1334
					system_routing_configure($ifname);
1335
					break;
1336
				}
1337
			}
1338
		}
1339
	}
1340

    
1341

    
1342
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1343
		file_put_contents("{$g['tmp_path']}/{$gifif}_router",
1344
		    $gif['tunnel-remote-addr']);
1345
	} else if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1346
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6",
1347
		    $gif['tunnel-remote-addr']);
1348
	}
1349

    
1350
	route_add_or_change($gif['remote-addr'], $realifgw);
1351

    
1352
	if ($flush) {
1353
		get_interface_arr(true);
1354
	}
1355

    
1356
	interfaces_bring_up($gifif);
1357

    
1358
	return $gifif;
1359
}
1360

    
1361
/*
1362
 * $ipsecifnum = get_ipsecifnum($ikeid, $idx);
1363
 * locates and returns an ipsecifnum in the config.
1364
 */
1365
function get_ipsecifnum($ikeid, $idx) {
1366
	global $config;
1367

    
1368
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1369
	foreach ($config['ipsec']['vtimaps']['item'] as $vtimap) {
1370
		if (($vtimap['reqid'] == $ikeid) &&
1371
		    ($vtimap['index'] == $idx)) {
1372
			return $vtimap['ifnum'];
1373
		}
1374
	}
1375

    
1376
	return false;
1377
}
1378
	
1379
function ipsec_create_vtimap($ikeid, $idx) {
1380
	global $config;
1381

    
1382
	if ((($ikeid < 33) && ($idx < 10)) || (($ikeid < 10) && ($idx < 100))) {
1383
		$oldformat = "{$ikeid}00{$idx}";
1384
		return array(
1385
			"reqid" => $ikeid,
1386
			"index" => $idx,
1387
			"ifnum" => $oldformat
1388
		);
1389
	}
1390

    
1391
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1392

    
1393
	if (count($config['ipsec']['vtimaps']['item']) == 0) {
1394
		return array(
1395
			"reqid" => $ikeid,
1396
			"index" => $idx,
1397
			"ifnum" => 1
1398
		);
1399
	}
1400

    
1401
	$assigned = array_column($config['ipsec']['vtimaps']['item'], 'ifnum');
1402
	asort($assigned, SORT_NUMERIC);
1403
	$new = 1;
1404
	foreach($assigned as $ipsecifnum) {
1405
		if ($ipsecifnum != $new) {
1406
			return array(
1407
				"reqid" => $ikeid,
1408
				"index" => $idx,
1409
				"ifnum" => $new
1410
			);
1411
		}
1412
		if ($new <= 32767) {
1413
			$new++;
1414
		} else {
1415
			log_error(gettext("All 32767 ipsec interface numbers " .
1416
			    "have been assigned!"));
1417
			return(NULL);
1418
		}
1419
	}
1420
}
1421

    
1422
function ipsec_del_vtimap($phase2) {
1423
	global $config;
1424

    
1425
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1426

    
1427
	if (count($config['ipsec']['vtimaps']['item']) == 0) {
1428
		return;
1429
	}
1430

    
1431
	$a_vtimaps = &$config['ipsec']['vtimaps']['item'];
1432
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1433
	$last = '';
1434
	foreach ($a_vtimaps as $id => $vtimap) {
1435
		if ($vtimap['reqid'] == $phase1['ikeid']) {
1436
			$last = $id;
1437
		}
1438
	}
1439
	if (!is_numeric($last)) {
1440
		return false;
1441
	}
1442

    
1443
	$vtisubnet_spec = ipsec_vti($phase1, true);
1444
	if (($phase1['iketype'] == 'ikev1') || isset($phase1['splitconn']) ||
1445
	    (count($vtisubnet_spec) == 1)) {
1446
		unset($a_vtimaps[$last]);
1447
		return true;
1448
	}
1449
}
1450

    
1451
/* NOTE: $vxlankey is not used but useful for passing this function to array_walk. */
1452
function interface_vxlan_configure(&$vxlan, $vxlankey = "", $flush = true) {
1453
	global $config, $g;
1454

    
1455
	if (!is_array($vxlan)) {
1456
		return -1;
1457
	}
1458

    
1459
	$realif = convert_friendly_interface_to_real_interface_name($vxlan['if']);
1460
	if (!interface_is_vlan($realif)) {
1461
		$realif = get_real_interface($vxlan['if']);
1462
	}
1463
	$realifip = get_interface_ip($vxlan['if']);
1464
	$realifip6 = get_interface_ipv6($vxlan['if']);
1465

    
1466
	/* make sure the parent interface is up */
1467
	if ($realif) {
1468
		interfaces_bring_up($realif);
1469
	} else {
1470
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_vxlan_configure()"));
1471
	}
1472

    
1473
	/* Interface is defined */
1474
	if (!empty($vxlan['vxlanif'])) {
1475
		if (!platform_booting()) {
1476
			/*
1477
			 * Calling this after boot implies we are editing an
1478
			 * existing interface so destroy it first
1479
			 */
1480
			pfSense_interface_destroy($vxlan['vxlanif']);
1481
		}
1482
		/* Create the interfaces at boot */
1483
		pfSense_interface_create($vxlan['vxlanif']);
1484
		$vxlanif = $vxlan['vxlanif'];
1485
	} else {
1486
		/*
1487
		 * The interface is undefined, we are creating a new one. Next
1488
		 * interface name is returned
1489
		 */
1490
		$vxlanif = pfSense_interface_create("vxlan");
1491
	}
1492

    
1493
	$ifconfigcmd = "/sbin/ifconfig " . escapeshellarg($vxlanif) .
1494
	    " vxlanid " .  escapeshellarg($vxlan['vxlanid']);
1495

    
1496
	if (is_mcast($vxlan['remote-addr'])) {
1497
		$ifconfigcmd .= " vxlangroup " .
1498
		    escapeshellarg($vxlan['remote-addr']) . " vxlandev " .
1499
		    escapeshellarg($realif);
1500
	} else {
1501
		$ifconfigcmd .= " vxlanremote " .
1502
		    escapeshellarg($vxlan['remote-addr']);
1503
	}
1504

    
1505
	if (is_ipaddrv6($vxlan['remote-addr']) && $realifip6) {
1506
		$ifconfigcmd .= " vxlanlocal " . escapeshellarg($realifip6);
1507
	} elseif (is_ipaddrv4($vxlan['remote-addr']) && $realifip) {
1508
		$ifconfigcmd .= " vxlanlocal " . escapeshellarg($realifip);
1509
	} else {
1510
		return;
1511
	}
1512

    
1513
	if (!empty($vxlan['vxlanlocalport'])) {
1514
		$ifconfigcmd .= " vxlanlocalport " . escapeshellarg($vxlan['vxlanlocalport']);
1515
	}
1516

    
1517
	if (!empty($vxlan['vxlanremoteport'])) {
1518
		$ifconfigcmd .= " vxlanremoteport " . escapeshellarg($vxlan['vxlanremoteport']);
1519
	}
1520

    
1521
	if (!empty($vxlan['vxlanttl'])) {
1522
		$ifconfigcmd .= " vxlanttl " . escapeshellarg($vxlan['vxlanttl']);
1523
	}
1524

    
1525
	if (isset($vxlan['vxlanlearn'])) {
1526
		$ifconfigcmd .= " vxlanlearn ";
1527
	} else {
1528
		$ifconfigcmd .= " -vxlanlearn ";
1529
	}
1530

    
1531
	mwexec($ifconfigcmd);
1532

    
1533
	if ($flush) {
1534
		get_interface_arr(true);
1535
	}
1536

    
1537
	interfaces_bring_up($vxlanif);
1538

    
1539
	return $vxlanif;
1540
}
1541

    
1542
function interfaces_tunnel_configure($checkparent = 0, $realif = "", $type = "") {
1543
	global $config;
1544

    
1545
	if (!in_array($type, array('gre', 'gif', 'vxlan'))) {
1546
		return;
1547
	}
1548

    
1549
	if (is_array($config["{$type}s"][$type]) && count($config["{$type}s"][$type])) {
1550
		foreach ($config["{$type}s"][$type] as $i => $tunnel) {
1551
			if (empty($tunnel["{$type}if"])) {
1552
				$tunnel["{$type}if"] = $type . $i;
1553
			}
1554
			if (!empty($realif) && $realif != $tunnel["{$type}if"]) {
1555
				continue;
1556
			}
1557

    
1558
			if ($checkparent == 1) {
1559
				if (substr($tunnel['if'], 0, 4) == '_vip') {
1560
					continue;
1561
				}
1562
				if (substr($tunnel['if'], 0, 5) == '_lloc') {
1563
					continue;
1564
				}
1565
				if (!empty($config['interfaces'][$tunnel['if']]) &&
1566
				    $config['interfaces'][$tunnel['if']]['ipaddrv6'] == "track6") {
1567
					continue;
1568
				}
1569
			}
1570
			else if ($checkparent == 2) {
1571
				if ((substr($tunnel['if'], 0, 4) != '_vip' &&
1572
				    substr($tunnel['if'], 0, 5) != '_lloc') &&
1573
				    (empty($config['interfaces'][$tunnel['if']]) ||
1574
				    $config['interfaces'][$tunnel['if']]['ipaddrv6'] != "track6")) {
1575
					continue;
1576
				}
1577
			}
1578
			if ($type == 'gif') {
1579
				interface_gif_configure($tunnel, "", false);
1580
			} elseif ($type == 'gre') {
1581
				interface_gre_configure($tunnel, "", false);
1582
			} elseif ($type == 'vxlan') {
1583
				interface_vxlan_configure($tunnel, "", false);
1584
			}
1585
		}
1586

    
1587
		/* Invalidate cache */
1588
		get_interface_arr(true);
1589
	}
1590
}
1591

    
1592
/* Build a list of IPsec interfaces */
1593
function interface_ipsec_vti_list_p1($ph1ent) {
1594
	global $config;
1595
	$iface_list = array();
1596

    
1597
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1598
		return $iface_list;
1599
	}
1600

    
1601
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1602
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1603
		return $iface_list;
1604
	}
1605

    
1606
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1607
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1608
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1609
			$iface_list["ipsec".get_ipsecifnum($ph1ent['ikeid'], $idx)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1610
		}
1611
	} else {
1612
		/* For IKEv2, only create one interface with additional addresses as aliases */
1613
		$iface_list["ipsec".get_ipsecifnum($ph1ent['ikeid'], 0)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1614
	}
1615
	return $iface_list;
1616
}
1617
function interface_ipsec_vti_list_all() {
1618
	global $config;
1619
	$iface_list = array();
1620
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1621
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1622
			if ($ph1ent['disabled']) {
1623
				continue;
1624
			}
1625
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1626
		}
1627
	}
1628
	return $iface_list;
1629
}
1630

    
1631
function is_interface_ipsec_vti_assigned($phase2) {
1632
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1633
	$vti_interface = null;
1634
	$vtisubnet_spec = ipsec_vti($phase1, true);
1635
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1636
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1637
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1638
			foreach ($vtisubnet_spec as $idx => $vtisub) {
1639
				/* Is this for this P2? */
1640
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1641
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1642
					$vti_interface = "ipsec".get_ipsecifnum($phase1['ikeid'], $idx);
1643
				}
1644
			}
1645
		} else {
1646
			$vti_interface = "ipsec".get_ipsecifnum($phase1['ikeid'], 0);
1647
		}
1648
	}
1649
	/* Check if this interface is assigned */
1650
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1651
}
1652
function interface_ipsec_vti_configure($ph1ent) {
1653
	global $config;
1654

    
1655
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1656
		return false;
1657
	}
1658

    
1659
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1660
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1661
		return false;
1662
	}
1663

    
1664
	$left_spec = ipsec_get_phase1_src($ph1ent);
1665
	$right_spec = $ph1ent['remote-gateway'];
1666

    
1667
	$iface_addrs = array();
1668

    
1669
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1670
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1671
		/* Form a single interface for each P2 entry */
1672
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1673
			$ipsecifnum = get_ipsecifnum($ph1ent['ikeid'], $idx);
1674
			if (!is_array($iface_addrs[$ipsecifnum])) {
1675
				$iface_addrs[$ipsecifnum] = array();
1676
			}
1677
			$vtisub['alias'] = "";
1678
			$iface_addrs[$ipsecifnum][] = $vtisub;
1679
		}
1680
	} else {
1681
		/* For IKEv2, only create one interface with additional addresses as aliases */
1682
		$ipsecifnum = get_ipsecifnum($ph1ent['ikeid'], 0);
1683
		if (!is_array($iface_addrs[$ipsecifnum])) {
1684
			$iface_addrs[$ipsecifnum] = array();
1685
		}
1686
		$have_v4 = false;
1687
		$have_v6 = false;
1688
		foreach ($vtisubnet_spec as $vtisub) {
1689
			// Alias stuff
1690
			$vtisub['alias'] = "";
1691
			if (is_ipaddrv6($vtisub['left'])) {
1692
				if ($have_v6) {
1693
					$vtisub['alias'] = " alias";
1694
				}
1695
				$have_v6 = true;
1696
			} else {
1697
				if ($have_v4) {
1698
					$vtisub['alias'] = " alias";
1699
				}
1700
				$have_v4 = true;
1701
			}
1702
			$iface_addrs[$ipsecifnum][] = $vtisub;
1703
		}
1704
	}
1705

    
1706
	foreach ($iface_addrs as $ipsecifnum => $addrs) {
1707
		$ipsecif = "ipsec{$ipsecifnum}";
1708
		if (!is_array($addrs)) {
1709
			continue;
1710
		}
1711
		// Create IPsec interface
1712
		if (does_interface_exist($ipsecif)) {
1713
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy");
1714
		}
1715
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum));
1716

    
1717
		/* Apply the outer tunnel addresses to the interface */
1718
		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
1719
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up");
1720

    
1721
		/* Loop through all of the addresses for this interface and apply them as needed */
1722
		foreach ($addrs as $addr) {
1723
			// apply interface addresses
1724
			if (is_v6($addr['left'])) {
1725
				$inet = "inet6";
1726
				$gwtype = "v6";
1727
				$right = '';
1728
			} else {
1729
				$inet = "inet";
1730
				$gwtype = "";
1731
				$right = escapeshellarg($addr['right']);
1732
			}
1733

    
1734
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias']);
1735
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1736
			if (empty($addr['alias'])) {
1737
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1738
			}
1739
		}
1740
		/* Check/set the MTU if the user configured a custom value.
1741
		 * https://redmine.pfsense.org/issues/9111 */
1742
		$currentvtimtu = get_interface_mtu($ipsecif);
1743
		foreach ($config['interfaces'] as $tmpinterface) {
1744
			if ($tmpinterface['if'] == $ipsecif) {
1745
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1746
					$vtimtu = $tmpinterface['mtu'];
1747
				}
1748
			}
1749
		}
1750
		if (is_numericint($vtimtu)) {
1751
			if ($vtimtu != $currentvtimtu) {
1752
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1753
			}
1754
		}
1755
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1756
	}
1757
}
1758

    
1759
function interfaces_ipsec_vti_configure() {
1760
	global $config;
1761
	if (platform_booting()) {
1762
		echo gettext("Configuring IPsec VTI interfaces...");
1763
	}
1764
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1765
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1766
			if ($ph1ent['disabled']) {
1767
				continue;
1768
			}
1769
			interface_ipsec_vti_configure($ph1ent);
1770
		}
1771
	}
1772
	if (platform_booting()) {
1773
		echo gettext("done.") . "\n";
1774
	}
1775
}
1776

    
1777
function interfaces_configure() {
1778
	global $config, $g;
1779

    
1780
	/* Set up our loopback interface */
1781
	interfaces_loopback_configure();
1782

    
1783
	/* create the unconfigured wireless clones */
1784
	interfaces_create_wireless_clones();
1785

    
1786
	/* set up LAGG virtual interfaces */
1787
	interfaces_lagg_configure();
1788

    
1789
	/* set up VLAN virtual interfaces */
1790
	interfaces_vlan_configure();
1791

    
1792
	interfaces_qinq_configure();
1793

    
1794
	/* set up IPsec VTI interfaces */
1795
	interfaces_ipsec_vti_configure();
1796

    
1797
	$iflist = get_configured_interface_with_descr();
1798
	$delayed_list = array();
1799
	$bridge_list = array();
1800
	$track6_list = array();
1801

    
1802
	/* This is needed to speedup interfaces on bootup. */
1803
	$reload = false;
1804
	if (!platform_booting()) {
1805
		$reload = true;
1806
	}
1807

    
1808
	foreach ($iflist as $if => $ifname) {
1809
		$realif = $config['interfaces'][$if]['if'];
1810
		if (strstr($realif, "bridge")) {
1811
			$bridge_list[$if] = $ifname;
1812
		} else if (strstr($realif, "gre")) {
1813
			$delayed_list[$if] = $ifname;
1814
		} else if (strstr($realif, "gif")) {
1815
			$delayed_list[$if] = $ifname;
1816
		} else if (strstr($realif, "vxlan")) {
1817
			$delayed_list[$if] = $ifname;
1818
		} else if (strstr($realif, "ovpn")) {
1819
			//echo "Delaying OpenVPN interface configuration...done.\n";
1820
			continue;
1821
		} else if (strstr($realif, "ipsec")) {
1822
			continue;
1823
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1824
			$track6_list[$if] = $ifname;
1825
		} else {
1826
			if (platform_booting()) {
1827
				printf(gettext("Configuring %s interface..."), $ifname);
1828
			}
1829

    
1830
			if ($g['debug']) {
1831
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1832
			}
1833
			interface_configure($if, $reload);
1834
			if (platform_booting()) {
1835
				echo gettext("done.") . "\n";
1836
			}
1837
		}
1838
	}
1839

    
1840
	/*
1841
	 * NOTE: The following function parameter consists of
1842
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1843
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1844
	 */
1845

    
1846
	/* set up GRE virtual interfaces */
1847
	interfaces_tunnel_configure(1,'','gre');
1848

    
1849
	/* set up GIF virtual interfaces */
1850
	interfaces_tunnel_configure(1,'','gif');
1851

    
1852
	/* set up VXLAN virtual interfaces */
1853
	interfaces_tunnel_configure(1,'','vxlan');
1854

    
1855
	/* set up BRIDGe virtual interfaces */
1856
	interfaces_bridge_configure(1);
1857

    
1858
	foreach ($track6_list as $if => $ifname) {
1859
		if (platform_booting()) {
1860
			printf(gettext("Configuring %s interface..."), $ifname);
1861
		}
1862
		if ($g['debug']) {
1863
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1864
		}
1865

    
1866
		interface_configure($if, $reload);
1867

    
1868
		if (platform_booting()) {
1869
			echo gettext("done.") . "\n";
1870
		}
1871
	}
1872

    
1873
	/* bring up vip interfaces */
1874
	interfaces_vips_configure();
1875

    
1876
	/* set up GRE virtual interfaces */
1877
	interfaces_tunnel_configure(2,'','gre');
1878

    
1879
	/* set up GIF virtual interfaces */
1880
	interfaces_tunnel_configure(2,'','gif');
1881

    
1882
	/* set up VXLAN virtual interfaces */
1883
	interfaces_tunnel_configure(2,'','vxlan');
1884

    
1885
	foreach ($delayed_list as $if => $ifname) {
1886
		if (platform_booting()) {
1887
			printf(gettext("Configuring %s interface..."), $ifname);
1888
		}
1889
		if ($g['debug']) {
1890
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1891
		}
1892

    
1893
		interface_configure($if, $reload);
1894

    
1895
		if (platform_booting()) {
1896
			echo gettext("done.") . "\n";
1897
		}
1898
	}
1899

    
1900
	/* set up BRIDGe virtual interfaces */
1901
	interfaces_bridge_configure(2);
1902

    
1903
	foreach ($bridge_list as $if => $ifname) {
1904
		if (platform_booting()) {
1905
			printf(gettext("Configuring %s interface..."), $ifname);
1906
		}
1907
		if ($g['debug']) {
1908
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1909
		}
1910

    
1911
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1912
		// redmine #3997
1913
		interface_reconfigure($if, $reload);
1914
		interfaces_vips_configure($if);
1915

    
1916
		if (platform_booting()) {
1917
			echo gettext("done.") . "\n";
1918
		}
1919
	}
1920

    
1921
	/* configure interface groups */
1922
	interfaces_group_setup();
1923

    
1924
	if (!platform_booting()) {
1925
		/* reconfigure static routes (kernel may have deleted them) */
1926
		system_routing_configure();
1927

    
1928
		/* reload IPsec tunnels */
1929
		ipsec_configure();
1930

    
1931
		/* restart dns servers (defering dhcpd reload) */
1932
		if (isset($config['dnsmasq']['enable'])) {
1933
			services_dnsmasq_configure(false);
1934
		}
1935
		if (isset($config['unbound']['enable'])) {
1936
			services_unbound_configure(false);
1937
		}
1938

    
1939
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1940
		services_dhcpd_configure();
1941
	}
1942

    
1943
	return 0;
1944
}
1945

    
1946
function interface_reconfigure($interface = "wan", $reloadall = false) {
1947
	interface_bring_down($interface);
1948
	interface_configure($interface, $reloadall);
1949
}
1950

    
1951
function interface_vip_bring_down($vip) {
1952
	global $g;
1953

    
1954
	$vipif = get_real_interface($vip['interface']);
1955
	switch ($vip['mode']) {
1956
		case "proxyarp":
1957
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1958
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1959
			}
1960
			break;
1961
		case "ipalias":
1962
			if (does_interface_exist($vipif)) {
1963
				if (is_ipaddrv6($vip['subnet'])) {
1964
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1965
				} else {
1966
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1967
				}
1968
			}
1969
			break;
1970
		case "carp":
1971
			/* XXX: Is enough to delete ip address? */
1972
			if (does_interface_exist($vipif)) {
1973
				if (is_ipaddrv6($vip['subnet'])) {
1974
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1975
				} else {
1976
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1977
				}
1978
			}
1979
			break;
1980
	}
1981
}
1982

    
1983
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1984
	global $config, $g;
1985

    
1986
	if (!isset($config['interfaces'][$interface])) {
1987
		return;
1988
	}
1989

    
1990
	if ($g['debug']) {
1991
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1992
	}
1993

    
1994
	/*
1995
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1996
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1997
	 * Keep this in mind while doing changes here!
1998
	 */
1999
	if ($ifacecfg === false) {
2000
		$ifcfg = $config['interfaces'][$interface];
2001
		$ppps = $config['ppps']['ppp'];
2002
		$realif = get_real_interface($interface);
2003
		$realifv6 = get_real_interface($interface, "inet6", true);
2004
	} elseif (!is_array($ifacecfg)) {
2005
		log_error(gettext("Wrong parameters used during interface_bring_down"));
2006
		$ifcfg = $config['interfaces'][$interface];
2007
		$ppps = $config['ppps']['ppp'];
2008
		$realif = get_real_interface($interface);
2009
		$realifv6 = get_real_interface($interface, "inet6", true);
2010
	} else {
2011
		$ifcfg = $ifacecfg['ifcfg'];
2012
		$ppps = $ifacecfg['ppps'];
2013
		if (isset($ifacecfg['ifcfg']['realif'])) {
2014
			$realif = $ifacecfg['ifcfg']['realif'];
2015
			/* XXX: Any better way? */
2016
			$realifv6 = $realif;
2017
		} else {
2018
			$realif = get_real_interface($interface);
2019
			$realifv6 = get_real_interface($interface, "inet6", true);
2020
		}
2021
	}
2022

    
2023
	switch ($ifcfg['ipaddr']) {
2024
		case "ppp":
2025
		case "pppoe":
2026
		case "pptp":
2027
		case "l2tp":
2028
			if (is_array($ppps) && count($ppps)) {
2029
				foreach ($ppps as $pppid => $ppp) {
2030
					if ($realif == $ppp['if']) {
2031
						if (isset($ppp['ondemand']) && !$destroy) {
2032
							send_event("interface reconfigure {$interface}");
2033
							break;
2034
						}
2035
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
2036
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
2037
							sleep(2);
2038
						}
2039
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
2040
						break;
2041
					}
2042
				}
2043
			}
2044
			break;
2045
		case "dhcp":
2046
			kill_dhclient_process($realif);
2047
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
2048
			if (does_interface_exist("$realif")) {
2049
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
2050
				interface_vip_cleanup($interface, "inet4");
2051
				if ($destroy == true) {
2052
					pfSense_interface_flags($realif, -IFF_UP);
2053
				}
2054
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2055
			}
2056
			break;
2057
		default:
2058
			if (does_interface_exist("$realif")) {
2059
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
2060
				interface_vip_cleanup($interface, "inet4");
2061
				if ($destroy == true) {
2062
					pfSense_interface_flags($realif, -IFF_UP);
2063
				}
2064
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2065
			}
2066
			break;
2067
	}
2068

    
2069
	$track6 = array();
2070
	switch ($ifcfg['ipaddrv6']) {
2071
		case "slaac":
2072
		case "dhcp6":
2073
			kill_dhcp6client_process($realif, $destroy, false);
2074
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
2075
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
2076
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh");
2077
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
2078
			if (does_interface_exist($realifv6)) {
2079
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 -accept_rtadv");
2080
				$ip6 = find_interface_ipv6($realifv6);
2081
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
2082
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
2083
				}
2084
				interface_vip_cleanup($interface, "inet6");
2085
				if ($destroy == true) {
2086
					pfSense_interface_flags($realif, -IFF_UP);
2087
				}
2088
			}
2089
			$track6 = link_interface_to_track6($interface);
2090
			break;
2091
		case "6rd":
2092
		case "6to4":
2093
			$realif = "{$interface}_stf";
2094
			if (does_interface_exist("$realif")) {
2095
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
2096
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
2097
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
2098
					$destroy = true;
2099
				} else {
2100
					/* get_interface_ipv6() returns empty value if interface is being disabled */
2101
					$ip6 = get_interface_ipv6($interface);
2102
					if (is_ipaddrv6($ip6)) {
2103
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2104
					}
2105
				}
2106
				interface_vip_cleanup($interface, "inet6");
2107
				if ($destroy == true) {
2108
					pfSense_interface_flags($realif, -IFF_UP);
2109
				}
2110
			}
2111
			$track6 = link_interface_to_track6($interface);
2112
			break;
2113
		default:
2114
			if (does_interface_exist("$realif")) {
2115
				$ip6 = get_interface_ipv6($interface);
2116
				if (is_ipaddrv6($ip6)) {
2117
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2118
				}
2119
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
2120
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
2121
				}
2122
				interface_vip_cleanup($interface, "inet6");
2123
				if ($destroy == true) {
2124
					pfSense_interface_flags($realif, -IFF_UP);
2125
				}
2126
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2127
			}
2128
			$track6 = link_interface_to_track6($interface);
2129
			break;
2130
	}
2131

    
2132
	if (!empty($track6) && is_array($track6)) {
2133
		if (!function_exists('services_dhcpd_configure')) {
2134
			require_once('services.inc');
2135
		}
2136
		/* Bring down radvd and dhcp6 on these interfaces */
2137
		services_dhcpd_configure('inet6', $track6);
2138
	}
2139

    
2140
	$old_router = '';
2141
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
2142
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
2143
	}
2144

    
2145
	/* remove interface up file if it exists */
2146
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
2147
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
2148
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
2149
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
2150
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
2151
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
2152
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
2153

    
2154
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
2155
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
2156
	if (is_array($ifcfg['wireless'])) {
2157
		kill_hostapd($realif);
2158
		mwexec(kill_wpasupplicant($realif));
2159
	}
2160

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

    
2165
			/* Invalidate cache */
2166
			get_interface_arr(true);
2167
		}
2168
	}
2169

    
2170
	return;
2171
}
2172

    
2173
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
2174
	global $config;
2175
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
2176
		unset($config["virtualip_carp_maintenancemode"]);
2177
		write_config("Leave CARP maintenance mode");
2178
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
2179
		$config["virtualip_carp_maintenancemode"] = true;
2180
		write_config(gettext("Enter CARP maintenance mode"));
2181
	}
2182
	init_config_arr(array('virtualip', 'vip'));
2183
	$viparr = &$config['virtualip']['vip'];
2184

    
2185
	if (is_array($viparr)) {
2186
		foreach ($viparr as $vip) {
2187
			if ($vip['mode'] == "carp") {
2188
				interface_carp_configure($vip, true);
2189
			}
2190
		}
2191
	}
2192
}
2193

    
2194
function interface_wait_tentative($interface, $timeout = 10) {
2195
	if (!does_interface_exist($interface)) {
2196
		return false;
2197
	}
2198

    
2199
	$time = 0;
2200
	while ($time <= $timeout) {
2201
		$if = pfSense_get_interface_addresses($interface);
2202
		if (!isset($if['tentative'])) {
2203
			return true;
2204
		}
2205
		sleep(1);
2206
		$time++;
2207
	}
2208

    
2209
	return false;
2210
}
2211

    
2212
function interface_isppp_type($interface) {
2213
	global $config;
2214

    
2215
	if (!is_array($config['interfaces'][$interface])) {
2216
		return false;
2217
	}
2218

    
2219
	switch ($config['interfaces'][$interface]['ipaddr']) {
2220
		case 'pptp':
2221
		case 'l2tp':
2222
		case 'pppoe':
2223
		case 'ppp':
2224
			return true;
2225
			break;
2226
		default:
2227
			return false;
2228
			break;
2229
	}
2230
}
2231

    
2232
function interfaces_ptpid_used($ptpid) {
2233
	global $config;
2234

    
2235
	if (is_array($config['ppps']['ppp'])) {
2236
		foreach ($config['ppps']['ppp'] as & $settings) {
2237
			if ($ptpid == $settings['ptpid']) {
2238
				return true;
2239
			}
2240
		}
2241
	}
2242

    
2243
	return false;
2244
}
2245

    
2246
function interfaces_ptpid_next() {
2247

    
2248
	$ptpid = 0;
2249
	while (interfaces_ptpid_used($ptpid)) {
2250
		$ptpid++;
2251
	}
2252

    
2253
	return $ptpid;
2254
}
2255

    
2256
function getMPDCRONSettings($pppif) {
2257
	global $config;
2258

    
2259
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2260
	if (is_array($config['cron']['item'])) {
2261
		foreach ($config['cron']['item'] as $i => $item) {
2262
			if (stripos($item['command'], $cron_cmd_file) !== false) {
2263
				return array("ID" => $i, "ITEM" => $item);
2264
			}
2265
		}
2266
	}
2267

    
2268
	return NULL;
2269
}
2270

    
2271
function handle_pppoe_reset($post_array) {
2272
	global $config, $g;
2273

    
2274
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2275
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2276

    
2277
	if (!is_array($config['cron']['item'])) {
2278
		$config['cron']['item'] = array();
2279
	}
2280

    
2281
	$itemhash = getMPDCRONSettings($pppif);
2282

    
2283
	// reset cron items if necessary and return
2284
	if (empty($post_array['pppoe-reset-type'])) {
2285
		if (isset($itemhash)) {
2286
			unset($config['cron']['item'][$itemhash['ID']]);
2287
		}
2288
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2289
		return;
2290
	}
2291

    
2292
	if (empty($itemhash)) {
2293
		$itemhash = array();
2294
	}
2295
	$item = array();
2296
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2297
		$item['minute'] = $post_array['pppoe_resetminute'];
2298
		$item['hour'] = $post_array['pppoe_resethour'];
2299
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2300
			$date = explode("/", $post_array['pppoe_resetdate']);
2301
			$item['mday'] = $date[1];
2302
			$item['month'] = $date[0];
2303
		} else {
2304
			$item['mday'] = "*";
2305
			$item['month'] = "*";
2306
		}
2307
		$item['wday'] = "*";
2308
		$item['who'] = "root";
2309
		$item['command'] = $cron_cmd_file;
2310
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2311
		switch ($post_array['pppoe_pr_preset_val']) {
2312
			case "monthly":
2313
				$item['minute'] = "0";
2314
				$item['hour'] = "0";
2315
				$item['mday'] = "1";
2316
				$item['month'] = "*";
2317
				$item['wday'] = "*";
2318
				break;
2319
			case "weekly":
2320
				$item['minute'] = "0";
2321
				$item['hour'] = "0";
2322
				$item['mday'] = "*";
2323
				$item['month'] = "*";
2324
				$item['wday'] = "0";
2325
				break;
2326
			case "daily":
2327
				$item['minute'] = "0";
2328
				$item['hour'] = "0";
2329
				$item['mday'] = "*";
2330
				$item['month'] = "*";
2331
				$item['wday'] = "*";
2332
				break;
2333
			case "hourly":
2334
				$item['minute'] = "0";
2335
				$item['hour'] = "*";
2336
				$item['mday'] = "*";
2337
				$item['month'] = "*";
2338
				$item['wday'] = "*";
2339
				break;
2340
		} // end switch
2341
		$item['who'] = "root";
2342
		$item['command'] = $cron_cmd_file;
2343
	}
2344
	if (empty($item)) {
2345
		return;
2346
	}
2347
	if (isset($itemhash['ID'])) {
2348
		$config['cron']['item'][$itemhash['ID']] = $item;
2349
	} else {
2350
		$config['cron']['item'][] = $item;
2351
	}
2352
}
2353

    
2354
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2355
	global $config;
2356
	$ppp_list = array();
2357
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2358
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2359
			$ports = explode(",", $ppp['ports']);
2360
			foreach($ports as $port) {
2361
				foreach($triggerinterfaces as $vip) {
2362
					if ($port == "_vip{$vip['uniqid']}") {
2363
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2364
						$ppp_list[$if] = 1;
2365
					}
2366
				}
2367
			}
2368
		}
2369
	}
2370
	foreach($ppp_list as $pppif => $dummy) {
2371
		interface_ppps_configure($pppif);
2372
	}
2373
}
2374

    
2375
/*
2376
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2377
 * It writes the mpd config file to /var/etc every time the link is opened.
2378
 */
2379
function interface_ppps_configure($interface) {
2380
	global $config, $g;
2381

    
2382
	/* Return for unassigned interfaces. This is a minimum requirement. */
2383
	if (empty($config['interfaces'][$interface])) {
2384
		return 0;
2385
	}
2386
	$ifcfg = $config['interfaces'][$interface];
2387
	if (!isset($ifcfg['enable'])) {
2388
		return 0;
2389
	}
2390

    
2391
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2392
	if (!is_dir("/var/spool/lock")) {
2393
		mkdir("/var/spool/lock", 0777, true);
2394
	}
2395
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2396
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2397
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2398
	}
2399

    
2400
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2401
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2402
			if ($ifcfg['if'] == $ppp['if']) {
2403
				break;
2404
			}
2405
		}
2406
	}
2407
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2408
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2409
		return 0;
2410
	}
2411
	$pppif = $ifcfg['if'];
2412
	if ($ppp['type'] == "ppp") {
2413
		$type = "modem";
2414
	} else {
2415
		$type = $ppp['type'];
2416
	}
2417
	$upper_type = strtoupper($ppp['type']);
2418

    
2419
	$confports = explode(',', $ppp['ports']);
2420
	if ($type == "modem") {
2421
		$ports = $confports;
2422
	} else {
2423
		$ports = array();
2424
		foreach ($confports as $pid => $port) {
2425
			if (strstr($port, "_vip")) {
2426
				if (get_carp_interface_status($port) != "MASTER") {
2427
					continue;
2428
				}
2429
			}
2430
			$ports[$pid] = get_real_interface($port);
2431
			if (empty($ports[$pid])) {
2432
				return 0;
2433
			}
2434
		}
2435
	}
2436
	$localips = explode(',', $ppp['localip']);
2437
	$gateways = explode(',', $ppp['gateway']);
2438
	$subnets = explode(',', $ppp['subnet']);
2439

    
2440
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2441
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2442
	 */
2443
	foreach ($ports as $pid => $port) {
2444
		switch ($ppp['type']) {
2445
			case "pppoe":
2446
				/* Bring the parent interface up */
2447
				interfaces_bring_up($port);
2448
				pfSense_ngctl_attach(".", $port);
2449
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2450
				$ngif = str_replace(".", "_", $port);
2451
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2452
				break;
2453
			case "pptp":
2454
			case "l2tp":
2455
				/* configure interface */
2456
				if (is_ipaddr($localips[$pid])) {
2457
					// Manually configure interface IP/subnet
2458
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2459
					interfaces_bring_up($port);
2460
				} else if (empty($localips[$pid])) {
2461
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2462
				}
2463

    
2464
				if (!is_ipaddr($localips[$pid])) {
2465
					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));
2466
					$localips[$pid] = "0.0.0.0";
2467
				}
2468
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2469
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2470
				}
2471
				if (!is_ipaddr($gateways[$pid])) {
2472
					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));
2473
					return 0;
2474
				}
2475
				pfSense_ngctl_attach(".", $port);
2476
				break;
2477
			case "ppp":
2478
				if (!file_exists("{$port}")) {
2479
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2480
					return 0;
2481
				}
2482
				break;
2483
			default:
2484
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2485
				break;
2486
		}
2487
	}
2488

    
2489
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2490
	    (is_array($ports) && count($ports) > 1)) {
2491
		$multilink = "enable";
2492
	} else {
2493
		$multilink = "disable";
2494
	}
2495

    
2496
	if ($type == "modem") {
2497
		if (is_ipaddr($ppp['localip'])) {
2498
			$localip = $ppp['localip'];
2499
		} else {
2500
			$localip = '0.0.0.0';
2501
		}
2502

    
2503
		if (is_ipaddr($ppp['gateway'])) {
2504
			$gateway = $ppp['gateway'];
2505
		} else {
2506
			$gateway = "10.64.64.{$pppid}";
2507
		}
2508
		$ranges = "{$localip}/0 {$gateway}/0";
2509

    
2510
		if (empty($ppp['apnum'])) {
2511
			$ppp['apnum'] = 1;
2512
		}
2513
	} else {
2514
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2515
	}
2516

    
2517
	if (isset($ppp['ondemand'])) {
2518
		$ondemand = "enable";
2519
	} else {
2520
		$ondemand = "disable";
2521
	}
2522
	if (!isset($ppp['idletimeout'])) {
2523
		$ppp['idletimeout'] = 0;
2524
	}
2525

    
2526
	if (empty($ppp['username']) && $type == "modem") {
2527
		$ppp['username'] = "user";
2528
		$ppp['password'] = "none";
2529
	}
2530
	if (empty($ppp['password']) && $type == "modem") {
2531
		$passwd = "none";
2532
	} else {
2533
		$passwd = base64_decode($ppp['password']);
2534
	}
2535

    
2536
	$bandwidths = explode(',', $ppp['bandwidth']);
2537
	$defaultmtu = "1492";
2538
	if (!empty($ifcfg['mtu'])) {
2539
		$defaultmtu = intval($ifcfg['mtu']);
2540
	}
2541
	if (isset($ppp['mtu'])) {
2542
		$mtus = explode(',', $ppp['mtu']);
2543
	}
2544
	if (isset($ppp['mru'])) {
2545
		$mrus = explode(',', $ppp['mru']);
2546
	}
2547
	if (isset($ppp['mrru'])) {
2548
		$mrrus = explode(',', $ppp['mrru']);
2549
	}
2550
	if (!empty($ifcfg['ipaddrv6'])) {
2551
		$ipv6cp = "set bundle enable ipv6cp";
2552
	}
2553

    
2554
	// Construct the mpd.conf file
2555
	$mpdconf = <<<EOD
2556
startup:
2557
	# configure the console
2558
	set console close
2559
	# configure the web server
2560
	set web close
2561

    
2562
default:
2563
{$ppp['type']}client:
2564
	create bundle static {$interface}
2565
	{$ipv6cp}
2566
	set iface name {$pppif}
2567

    
2568
EOD;
2569
	$setdefaultgw = false;
2570
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2571
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2572
	if ($defgw4['interface'] == $interface) {
2573
		$setdefaultgw = true;
2574
	}
2575

    
2576
/* Omit this, we maintain the default route by other means, and it causes problems with
2577
 * default gateway switching. See redmine #1837 for original issue
2578
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2579
 * edge case. redmine #6495 open to address.
2580
 */
2581
	if ($setdefaultgw == true) {
2582
		$mpdconf .= <<<EOD
2583
	set iface route default
2584

    
2585
EOD;
2586
	}
2587

    
2588
	$mpdconf .= <<<EOD
2589
	set iface {$ondemand} on-demand
2590
	set iface idle {$ppp['idletimeout']}
2591

    
2592
EOD;
2593

    
2594
	if (isset($ppp['ondemand'])) {
2595
		$mpdconf .= <<<EOD
2596
	set iface addrs 10.10.1.1 10.10.1.2
2597

    
2598
EOD;
2599
	}
2600

    
2601
	if (isset($ppp['mtu-override']) &&
2602
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2603
		/* Find the smaller MTU set on ports */
2604
		$mtu = $defaultmtu;
2605
		foreach ($ports as $pid => $port) {
2606
			if (empty($mtus[$pid])) {
2607
				$mtus[$pid] = $defaultmtu;
2608
			}
2609
			if ($type == "pppoe") {
2610
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2611
					$mtus[$pid] = get_interface_mtu($port) - 8;
2612
				}
2613
			}
2614
			if ($mtu > $mtus[$pid]) {
2615
				$mtu = $mtus[$pid];
2616
			}
2617
		}
2618
		$mpdconf .= <<<EOD
2619
	set iface mtu {$mtu} override
2620

    
2621
EOD;
2622
	}
2623

    
2624
	if (isset($ppp['tcpmssfix'])) {
2625
		$tcpmss = "disable";
2626
	} else {
2627
		$tcpmss = "enable";
2628
	}
2629
	$mpdconf .= <<<EOD
2630
	set iface {$tcpmss} tcpmssfix
2631

    
2632
EOD;
2633

    
2634
	$mpdconf .= <<<EOD
2635
	set iface up-script /usr/local/sbin/ppp-linkup
2636
	set iface down-script /usr/local/sbin/ppp-linkdown
2637
	set ipcp ranges {$ranges}
2638

    
2639
EOD;
2640
	if (isset($ppp['vjcomp'])) {
2641
		$mpdconf .= <<<EOD
2642
	set ipcp no vjcomp
2643

    
2644
EOD;
2645
	}
2646

    
2647
	if (isset($config['system']['dnsallowoverride'])) {
2648
		$mpdconf .= <<<EOD
2649
	set ipcp enable req-pri-dns
2650
	set ipcp enable req-sec-dns
2651

    
2652
EOD;
2653
	}
2654

    
2655
	if (!isset($ppp['verbose_log'])) {
2656
		$mpdconf .= <<<EOD
2657
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2658

    
2659
EOD;
2660
	}
2661

    
2662
	foreach ($ports as $pid => $port) {
2663
		$port = get_real_interface($port);
2664
		$mpdconf .= <<<EOD
2665

    
2666
	create link static {$interface}_link{$pid} {$type}
2667
	set link action bundle {$interface}
2668
	set link {$multilink} multilink
2669
	set link keep-alive 10 60
2670
	set link max-redial 0
2671

    
2672
EOD;
2673
		if (isset($ppp['shortseq'])) {
2674
			$mpdconf .= <<<EOD
2675
	set link no shortseq
2676

    
2677
EOD;
2678
		}
2679

    
2680
		if (isset($ppp['acfcomp'])) {
2681
			$mpdconf .= <<<EOD
2682
	set link no acfcomp
2683

    
2684
EOD;
2685
		}
2686

    
2687
		if (isset($ppp['protocomp'])) {
2688
			$mpdconf .= <<<EOD
2689
	set link no protocomp
2690

    
2691
EOD;
2692
		}
2693

    
2694
		$mpdconf .= <<<EOD
2695
	set link disable chap pap
2696
	set link accept chap pap eap
2697
	set link disable incoming
2698

    
2699
EOD;
2700

    
2701

    
2702
		if (!empty($bandwidths[$pid])) {
2703
			$mpdconf .= <<<EOD
2704
	set link bandwidth {$bandwidths[$pid]}
2705

    
2706
EOD;
2707
		}
2708

    
2709
		if (empty($mtus[$pid])) {
2710
			$mtus[$pid] = $defaultmtu;
2711
		}
2712
		if ($type == "pppoe") {
2713
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2714
				$mtus[$pid] = get_interface_mtu($port) - 8;
2715
			}
2716
		}
2717
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2718
		    !isset($ppp['mtu-override']) &&
2719
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2720
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2721
			$mpdconf .= <<<EOD
2722
	set link mtu {$mtus[$pid]}
2723

    
2724
EOD;
2725
		}
2726

    
2727
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2728
		    !isset($ppp['mtu-override']) &&
2729
		    !empty($mrus[$pid])) {
2730
			$mpdconf .= <<<EOD
2731
	set link mru {$mrus[$pid]}
2732

    
2733
EOD;
2734
		}
2735

    
2736
		if (!empty($mrrus[$pid])) {
2737
			$mpdconf .= <<<EOD
2738
	set link mrru {$mrrus[$pid]}
2739

    
2740
EOD;
2741
		}
2742

    
2743
		$mpdconf .= <<<EOD
2744
	set auth authname "{$ppp['username']}"
2745
	set auth password {$passwd}
2746

    
2747
EOD;
2748
		if ($type == "modem") {
2749
			$mpdconf .= <<<EOD
2750
	set modem device {$ppp['ports']}
2751
	set modem script DialPeer
2752
	set modem idle-script Ringback
2753
	set modem watch -cd
2754
	set modem var \$DialPrefix "DT"
2755
	set modem var \$Telephone "{$ppp['phone']}"
2756

    
2757
EOD;
2758
		}
2759
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2760
			$mpdconf .= <<<EOD
2761
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2762

    
2763
EOD;
2764
		}
2765
		if (isset($ppp['initstr']) && $type == "modem") {
2766
			$initstr = base64_decode($ppp['initstr']);
2767
			$mpdconf .= <<<EOD
2768
	set modem var \$InitString "{$initstr}"
2769

    
2770
EOD;
2771
		}
2772
		if (isset($ppp['simpin']) && $type == "modem") {
2773
			if ($ppp['pin-wait'] == "") {
2774
				$ppp['pin-wait'] = 0;
2775
			}
2776
			$mpdconf .= <<<EOD
2777
	set modem var \$SimPin "{$ppp['simpin']}"
2778
	set modem var \$PinWait "{$ppp['pin-wait']}"
2779

    
2780
EOD;
2781
		}
2782
		if (isset($ppp['apn']) && $type == "modem") {
2783
			$mpdconf .= <<<EOD
2784
	set modem var \$APN "{$ppp['apn']}"
2785
	set modem var \$APNum "{$ppp['apnum']}"
2786

    
2787
EOD;
2788
		}
2789
		if ($type == "pppoe") {
2790
			$hostuniq = '';
2791
			if (!empty($ppp['hostuniq'])) {
2792
				if (preg_match('/^0x[a-fA-F0-9]+$/', $ppp['hostuniq'])) {
2793
					$hostuniq = strtolower($ppp['hostuniq']) .'|';
2794
				} elseif (preg_match('/^[a-zA-Z0-9]+$/i', $ppp['hostuniq'])) {
2795
					$hostuniq = '0x' . bin2hex($ppp['hostuniq']) . '|';
2796
				}
2797
			}
2798
			// Send a null service name if none is set.
2799
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2800
			$mpdconf .= <<<EOD
2801
	set pppoe service "{$hostuniq}{$provider}"
2802

    
2803
EOD;
2804
		}
2805
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2806
			$mpdconf .= <<<EOD
2807
	set pppoe max-payload {$mtus[$pid]}
2808

    
2809
EOD;
2810
		}
2811
		if ($type == "pppoe") {
2812
			$mpdconf .= <<<EOD
2813
	set pppoe iface {$port}
2814

    
2815
EOD;
2816
		}
2817

    
2818
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2819
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2820
			$mpdconf .= <<<EOD
2821
	set l2tp secret "{$secret}"
2822

    
2823
EOD;
2824
		}
2825

    
2826
		if (($type == "pptp") || ($type == "l2tp")) {
2827
			$mpdconf .= <<<EOD
2828
	set {$type} self {$localips[$pid]}
2829
	set {$type} peer {$gateways[$pid]}
2830

    
2831
EOD;
2832
		}
2833

    
2834
		$mpdconf .= "\topen\n";
2835
	} //end foreach ($port)
2836

    
2837

    
2838
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2839
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2840
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2841
	} else {
2842
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2843
		if (!$fd) {
2844
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2845
			return 0;
2846
		}
2847
		// Write out mpd_ppp.conf
2848
		fwrite($fd, $mpdconf);
2849
		fclose($fd);
2850
		unset($mpdconf);
2851
	}
2852

    
2853
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2854
	if (isset($ppp['uptime'])) {
2855
		if (!file_exists("/conf/{$pppif}.log")) {
2856
			file_put_contents("/conf/{$pppif}.log", '');
2857
		}
2858
	} else {
2859
		if (file_exists("/conf/{$pppif}.log")) {
2860
			@unlink("/conf/{$pppif}.log");
2861
		}
2862
	}
2863

    
2864
	/* clean up old lock files */
2865
	foreach ($ports as $port) {
2866
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2867
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2868
		}
2869
	}
2870

    
2871
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2872
	/* random IPv6 interface identifier during boot. More details at */
2873
	/* https://forum.netgate.com/post/592474 */
2874
	if (platform_booting() && is_array($config['interfaces'])) {
2875
		$count = 0;
2876
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2877
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2878
				$tempaddr[$count]['if'] = $tempiface['if'];
2879
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2880
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2881
				$count++;
2882
			}
2883
			// Maximum /31 is is x.y.z.254/31
2884
			if ($count > 122) {
2885
				break;
2886
			}
2887
		}
2888
		unset($count);
2889
	}
2890

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

    
2896
	// Check for PPPoE periodic reset request
2897
	if ($type == "pppoe") {
2898
		if (!empty($ppp['pppoe-reset-type'])) {
2899
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2900
		} else {
2901
			interface_setup_pppoe_reset_file($ppp['if']);
2902
		}
2903
	}
2904
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2905
	$i = 0;
2906
	while ($i < 10) {
2907
		if (does_interface_exist($ppp['if'], true)) {
2908
			break;
2909
		}
2910
		sleep(3);
2911
		$i++;
2912
	}
2913

    
2914
	/* Remove all temporary bogon IPv4 addresses */
2915
	if (is_array($tempaddr)) {
2916
		foreach ($tempaddr as $tempiface) {
2917
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2918
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2919
			}
2920
		}
2921
		unset ($tempaddr);
2922
	}
2923

    
2924
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2925
	/* We should be able to launch the right version for each modem */
2926
	/* We can also guess the mondev from the manufacturer */
2927
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2928
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2929
	foreach ($ports as $port) {
2930
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2931
			$mondev = substr(basename($port), 0, -1);
2932
			$devlist = glob("/dev/{$mondev}?");
2933
			$mondev = basename(end($devlist));
2934
		}
2935
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2936
			$mondev = substr(basename($port), 0, -1) . "1";
2937
		}
2938
		if ($mondev != '') {
2939
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2940
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2941
		}
2942
	}
2943

    
2944
	return 1;
2945
}
2946

    
2947
function interfaces_sync_setup() {
2948
	global $g, $config;
2949

    
2950
	if (isset($config['system']['developerspew'])) {
2951
		$mt = microtime();
2952
		echo "interfaces_sync_setup() being called $mt\n";
2953
	}
2954

    
2955
	if (platform_booting()) {
2956
		echo gettext("Configuring CARP settings...");
2957
		mute_kernel_msgs();
2958
	}
2959

    
2960
	/* suck in configuration items */
2961
	if ($config['hasync']) {
2962
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2963
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2964
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2965
	} else {
2966
		unset($pfsyncinterface);
2967
		unset($pfsyncenabled);
2968
	}
2969

    
2970
	set_sysctl(array(
2971
		"net.inet.carp.preempt" => "1",
2972
		"net.inet.carp.log" => "1")
2973
	);
2974

    
2975
	if (!empty($pfsyncinterface)) {
2976
		$carp_sync_int = get_real_interface($pfsyncinterface);
2977
	} else {
2978
		unset($carp_sync_int);
2979
	}
2980

    
2981
	/* setup pfsync interface */
2982
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2983
		if (is_ipaddr($pfsyncpeerip)) {
2984
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2985
		} else {
2986
			$syncpeer = "-syncpeer";
2987
		}
2988

    
2989
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} " .
2990
		    "{$syncpeer} up");
2991
		mwexec("/sbin/ifconfig pfsync0 -defer");
2992

    
2993
		/*
2994
		 * XXX: Handle an issue with pfsync(4) and carp(4). In a
2995
		 * cluster carp will come up before pfsync(4) has updated and
2996
		 * so will cause issues for existing sessions.
2997
		 */
2998
		log_error(gettext("waiting for pfsync..."));
2999

    
3000
		$i = 0;
3001
		do {
3002
			sleep(1);
3003
			$_gb = exec('/sbin/ifconfig pfsync0 | ' .
3004
			    '/usr/bin/grep -q "syncok: 0" 2>/dev/null', $output,
3005
			    $rc);
3006
			$i++;
3007
		} while ($rc != 0 && $i <= 30);
3008

    
3009
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
3010
		log_error(gettext("Configuring CARP settings finalize..."));
3011
	} else {
3012
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down");
3013
	}
3014

    
3015
	$carplist = get_configured_vip_list('all', VIP_CARP);
3016
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
3017
		set_single_sysctl("net.inet.carp.allow", "1");
3018
	} else {
3019
		set_single_sysctl("net.inet.carp.allow", "0");
3020
	}
3021

    
3022
	if (platform_booting()) {
3023
		unmute_kernel_msgs();
3024
		echo gettext("done.") . "\n";
3025
	}
3026
}
3027

    
3028
function interface_proxyarp_configure($interface = "") {
3029
	global $config, $g;
3030
	if (isset($config['system']['developerspew'])) {
3031
		$mt = microtime();
3032
		echo "interface_proxyarp_configure() being called $mt\n";
3033
	}
3034

    
3035
	/* kill any running choparp */
3036
	if (empty($interface)) {
3037
		killbyname("choparp");
3038
	} else {
3039
		$vipif = get_real_interface($interface);
3040
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
3041
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
3042
		}
3043
	}
3044

    
3045
	$paa = array();
3046
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
3047

    
3048
		/* group by interface */
3049
		foreach ($config['virtualip']['vip'] as $vipent) {
3050
			if ($vipent['mode'] === "proxyarp") {
3051
				if ($vipent['interface']) {
3052
					$proxyif = $vipent['interface'];
3053
				} else {
3054
					$proxyif = "wan";
3055
				}
3056

    
3057
				if (!empty($interface) && $interface != $proxyif) {
3058
					continue;
3059
				}
3060

    
3061
				if (!is_array($paa[$proxyif])) {
3062
					$paa[$proxyif] = array();
3063
				}
3064

    
3065
				$paa[$proxyif][] = $vipent;
3066
			}
3067
		}
3068
	}
3069

    
3070
	if (!empty($interface)) {
3071
		if (is_array($paa[$interface])) {
3072
			$paaifip = get_interface_ip($interface);
3073
			if (!is_ipaddr($paaifip)) {
3074
				return;
3075
			}
3076
			$vipif = get_real_interface($interface);
3077
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
3078
			$args .= $vipif . " auto";
3079
			foreach ($paa[$interface] as $paent) {
3080
				if (isset($paent['subnet'])) {
3081
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
3082
				} else if (isset($paent['range'])) {
3083
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
3084
				}
3085
			}
3086
			mwexec_bg("/usr/local/sbin/choparp " . $args);
3087
		}
3088
	} else if (count($paa) > 0) {
3089
		foreach ($paa as $paif => $paents) {
3090
			$paaifip = get_interface_ip($paif);
3091
			if (!is_ipaddr($paaifip)) {
3092
				continue;
3093
			}
3094
			$vipif = get_real_interface($paif);
3095
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
3096
			$args .= $vipif . " auto";
3097
			foreach ($paents as $paent) {
3098
				if (isset($paent['subnet'])) {
3099
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
3100
				} else if (isset($paent['range'])) {
3101
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
3102
				}
3103
			}
3104
			mwexec_bg("/usr/local/sbin/choparp " . $args);
3105
		}
3106
	}
3107
}
3108

    
3109
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
3110
	global $g, $config;
3111

    
3112
	if (is_array($config['virtualip']['vip'])) {
3113
		foreach ($config['virtualip']['vip'] as $vip) {
3114

    
3115
			$iface = $vip['interface'];
3116
			if (substr($iface, 0, 4) == "_vip")
3117
				$iface = get_configured_vip_interface($vip['interface']);
3118
			if ($iface != $interface)
3119
				continue;
3120
			if ($type == VIP_CARP) {
3121
				if ($vip['mode'] != "carp")
3122
					continue;
3123
			} elseif ($type == VIP_IPALIAS) {
3124
				if ($vip['mode'] != "ipalias")
3125
					continue;
3126
			} else {
3127
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
3128
					continue;
3129
			}
3130

    
3131
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
3132
				interface_vip_bring_down($vip);
3133
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
3134
				interface_vip_bring_down($vip);
3135
			else if ($inet == "all")
3136
				interface_vip_bring_down($vip);
3137
		}
3138
	}
3139
}
3140

    
3141
function interfaces_vips_configure($interface = "") {
3142
	global $g, $config;
3143
	if (isset($config['system']['developerspew'])) {
3144
		$mt = microtime();
3145
		echo "interfaces_vips_configure() being called $mt\n";
3146
	}
3147
	$paa = array();
3148
	if (is_array($config['virtualip']['vip'])) {
3149
		$carp_setuped = false;
3150
		$anyproxyarp = false;
3151
		foreach ($config['virtualip']['vip'] as $vip) {
3152
			if ($interface <> "" && get_root_interface($vip['interface']) <> $interface) {
3153
				continue;
3154
			}
3155
			switch ($vip['mode']) {
3156
				case "proxyarp":
3157
					/* nothing it is handled on interface_proxyarp_configure() */
3158
					$anyproxyarp = true;
3159
					break;
3160
				case "ipalias":
3161
					interface_ipalias_configure($vip);
3162
					break;
3163
				case "carp":
3164
					if ($carp_setuped == false) {
3165
						$carp_setuped = true;
3166
					}
3167
					interface_carp_configure($vip);
3168
					break;
3169
			}
3170
		}
3171
		if ($carp_setuped == true) {
3172
			interfaces_sync_setup();
3173
		}
3174
		if ($anyproxyarp == true) {
3175
			interface_proxyarp_configure();
3176
		}
3177
	}
3178
}
3179

    
3180
function interface_ipalias_configure(&$vip) {
3181
	global $config;
3182

    
3183
	$gateway = '';
3184
	if ($vip['mode'] != 'ipalias') {
3185
		return;
3186
	}
3187

    
3188
	$realif = get_real_interface("_vip{$vip['uniqid']}");
3189
	if ($realif != "lo0") {
3190
		$if = convert_real_interface_to_friendly_interface_name($realif);
3191
		if (!isset($config['interfaces'][$if]) ||
3192
		    !isset($config['interfaces'][$if]['enable'])) {
3193
			return;
3194
		}
3195
		if (is_pseudo_interface($realif)) {
3196
			if (is_ipaddrv4($vip['subnet'])) {
3197
				$gateway = get_interface_gateway($if);
3198
			} else {
3199
				$gateway = get_interface_gateway_v6($if);
3200
			}
3201
		}
3202
	}
3203

    
3204
	$af = 'inet';
3205
	if (is_ipaddrv6($vip['subnet'])) {
3206
		$af = 'inet6';
3207
	}
3208
	$iface = $vip['interface'];
3209
	$vhid = '';
3210
	if (substr($vip['interface'], 0, 4) == "_vip") {
3211
		$carpvip = get_configured_vip($vip['interface']);
3212
		$iface = $carpvip['interface'];
3213
		$vhid = "vhid {$carpvip['vhid']}";
3214
	}
3215
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$gateway} {$vhid}");
3216
	unset($iface, $af, $realif, $carpvip, $vhid, $gateway);
3217
}
3218

    
3219
function interface_carp_configure(&$vip, $maintenancemode_only = false) {
3220
	global $config, $g;
3221
	if (isset($config['system']['developerspew'])) {
3222
		$mt = microtime();
3223
		echo "interface_carp_configure() being called $mt\n";
3224
	}
3225

    
3226
	if ($vip['mode'] != "carp") {
3227
		return;
3228
	}
3229

    
3230
	$realif = get_real_interface($vip['interface']);
3231
	if (!does_interface_exist($realif)) {
3232
		file_notice("CARP", sprintf(gettext(
3233
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
3234
		    $vip['subnet']), "Firewall: Virtual IP", "");
3235
		return;
3236
	}
3237
	if ($realif != "lo0") {
3238
		if (!isset($config['interfaces'][$vip['interface']]) ||
3239
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
3240
			return;
3241
		}
3242
	}
3243

    
3244
	$vip_password = $vip['password'];
3245
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3246
	    $vip_password)));
3247
	if ($vip['password'] != "") {
3248
		$password = " pass {$vip_password}";
3249
	}
3250

    
3251
	$advbase = "";
3252
	if (!empty($vip['advbase'])) {
3253
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3254
	}
3255

    
3256
	$carp_maintenancemode = isset(
3257
	    $config["virtualip_carp_maintenancemode"]);
3258
	if ($carp_maintenancemode) {
3259
		$advskew = "advskew 254";
3260
	} else {
3261
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3262
	}
3263

    
3264
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) .
3265
	    " {$advskew} {$advbase} {$password}");
3266

    
3267
	if (!$maintenancemode_only) {
3268
		if (is_ipaddrv4($vip['subnet'])) {
3269
			mwexec("/sbin/ifconfig {$realif} " .
3270
			    escapeshellarg($vip['subnet']) . "/" .
3271
			    escapeshellarg($vip['subnet_bits']) .
3272
			    " alias vhid " . escapeshellarg($vip['vhid']));
3273
		} else if (is_ipaddrv6($vip['subnet'])) {
3274
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3275
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3276
			    escapeshellarg($vip['subnet_bits']) .
3277
			    " alias vhid " . escapeshellarg($vip['vhid']));
3278
		}
3279
	}
3280

    
3281
	return $realif;
3282
}
3283

    
3284
function interface_wireless_clone($realif, $wlcfg) {
3285
	global $config, $g;
3286
	/*   Check to see if interface has been cloned as of yet.
3287
	 *   If it has not been cloned then go ahead and clone it.
3288
	 */
3289
	$needs_clone = false;
3290
	if (is_array($wlcfg['wireless'])) {
3291
		$wlcfg_mode = $wlcfg['wireless']['mode'];
3292
	} else {
3293
		$wlcfg_mode = $wlcfg['mode'];
3294
	}
3295
	switch ($wlcfg_mode) {
3296
		case "hostap":
3297
			$mode = "wlanmode hostap";
3298
			break;
3299
		case "adhoc":
3300
			$mode = "wlanmode adhoc";
3301
			break;
3302
		default:
3303
			$mode = "";
3304
			break;
3305
	}
3306
	$baseif = interface_get_wireless_base($wlcfg['if']);
3307
	if (does_interface_exist($realif)) {
3308
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
3309
		$ifconfig_str = implode($output);
3310
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
3311
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
3312
			$needs_clone = true;
3313
		}
3314
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
3315
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
3316
			$needs_clone = true;
3317
		}
3318
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3319
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3320
			$needs_clone = true;
3321
		}
3322
	} else {
3323
		$needs_clone = true;
3324
	}
3325

    
3326
	if ($needs_clone == true) {
3327
		/* remove previous instance if it exists */
3328
		if (does_interface_exist($realif)) {
3329
			pfSense_interface_destroy($realif);
3330

    
3331
			/* Invalidate cache */
3332
			get_interface_arr(true);
3333
		}
3334

    
3335
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3336
		// Create the new wlan interface. FreeBSD returns the new interface name.
3337
		// example:  wlan2
3338
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3339
		if ($ret <> 0) {
3340
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3341
			return false;
3342
		}
3343
		$newif = trim($out[0]);
3344
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3345
		pfSense_interface_rename($newif, $realif);
3346
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3347
	}
3348
	return true;
3349
}
3350

    
3351
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3352
	global $config, $g;
3353

    
3354
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3355
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3356
				 'regdomain', 'regcountry', 'reglocation');
3357

    
3358
	if (!is_interface_wireless($ifcfg['if'])) {
3359
		return;
3360
	}
3361

    
3362
	$baseif = interface_get_wireless_base($ifcfg['if']);
3363

    
3364
	// Sync shared settings for assigned clones
3365
	$iflist = get_configured_interface_list(true);
3366
	foreach ($iflist as $if) {
3367
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
3368
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
3369
				foreach ($shared_settings as $setting) {
3370
					if ($sync_changes) {
3371
						if (isset($ifcfg['wireless'][$setting])) {
3372
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
3373
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3374
							unset($config['interfaces'][$if]['wireless'][$setting]);
3375
						}
3376
					} else {
3377
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3378
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
3379
						} else if (isset($ifcfg['wireless'][$setting])) {
3380
							unset($ifcfg['wireless'][$setting]);
3381
						}
3382
					}
3383
				}
3384
				if (!$sync_changes) {
3385
					break;
3386
				}
3387
			}
3388
		}
3389
	}
3390

    
3391
	// Read or write settings at shared area
3392
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3393
		foreach ($shared_settings as $setting) {
3394
			if ($sync_changes) {
3395
				if (isset($ifcfg['wireless'][$setting])) {
3396
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3397
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3398
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3399
				}
3400
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3401
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3402
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3403
				} else if (isset($ifcfg['wireless'][$setting])) {
3404
					unset($ifcfg['wireless'][$setting]);
3405
				}
3406
			}
3407
		}
3408
	}
3409

    
3410
	// Sync the mode on the clone creation page with the configured mode on the interface
3411
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3412
		foreach ($config['wireless']['clone'] as &$clone) {
3413
			if ($clone['cloneif'] == $ifcfg['if']) {
3414
				if ($sync_changes) {
3415
					$clone['mode'] = $ifcfg['wireless']['mode'];
3416
				} else {
3417
					$ifcfg['wireless']['mode'] = $clone['mode'];
3418
				}
3419
				break;
3420
			}
3421
		}
3422
		unset($clone);
3423
	}
3424
}
3425

    
3426
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3427
	global $config, $g;
3428

    
3429
	/*    open up a shell script that will be used to output the commands.
3430
	 *    since wireless is changing a lot, these series of commands are fragile
3431
	 *    and will sometimes need to be verified by a operator by executing the command
3432
	 *    and returning the output of the command to the developers for inspection.  please
3433
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3434
	 */
3435

    
3436
	// Remove script file
3437
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3438

    
3439
	// Clone wireless nic if needed.
3440
	interface_wireless_clone($if, $wl);
3441

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

    
3445
	$fd_set = fopen("{$g['tmp_path']}/{$if}_setup.sh", "w");
3446
	fwrite($fd_set, "#!/bin/sh\n");
3447
	fwrite($fd_set, "# {$g['product_name']} wireless configuration script.\n\n");
3448

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

    
3451
	/* set values for /path/program */
3452
	if (file_exists("/usr/local/sbin/hostapd")) {
3453
		$hostapd = "/usr/local/sbin/hostapd";
3454
	} else {
3455
		$hostapd = "/usr/sbin/hostapd";
3456
	}
3457
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3458
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3459
	} else {
3460
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3461
	}
3462
	$ifconfig = "/sbin/ifconfig";
3463
	$sysctl = "/sbin/sysctl";
3464
	$sysctl_args = "-q";
3465
	$killall = "/usr/bin/killall";
3466

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

    
3469
	$wlcmd = array();
3470
	$wl_sysctl = array();
3471
	/* Set a/b/g standard */
3472
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3473
	/* skip mode entirely for "auto" */
3474
	if ($wlcfg['standard'] != "auto") {
3475
		$wlcmd[] = "mode " . escapeshellarg($standard);
3476
	}
3477

    
3478
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3479
	 * to prevent massive packet loss under certain conditions. */
3480
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3481
		$wlcmd[] = "-ampdu";
3482
	}
3483

    
3484
	/* Set ssid */
3485
	if ($wlcfg['ssid']) {
3486
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3487
	}
3488

    
3489
	/* Set 802.11g protection mode */
3490
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3491

    
3492
	/* set wireless channel value */
3493
	if (isset($wlcfg['channel'])) {
3494
		if ($wlcfg['channel'] == "0") {
3495
			$wlcmd[] = "channel any";
3496
		} else {
3497
			if ($wlcfg['channel_width'] != "0") {
3498
				$channel_width = ":" . $wlcfg['channel_width'];
3499
			} else {
3500
				$channel_width = '';
3501
			}
3502
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3503
		}
3504
	}
3505

    
3506
	/* Set antenna diversity value */
3507
	if (isset($wlcfg['diversity'])) {
3508
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3509
	}
3510

    
3511
	/* Set txantenna value */
3512
	if (isset($wlcfg['txantenna'])) {
3513
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3514
	}
3515

    
3516
	/* Set rxantenna value */
3517
	if (isset($wlcfg['rxantenna'])) {
3518
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3519
	}
3520

    
3521
	/* set Distance value */
3522
	if ($wlcfg['distance']) {
3523
		$distance = escapeshellarg($wlcfg['distance']);
3524
	}
3525

    
3526
	/* Set wireless hostap mode */
3527
	if ($wlcfg['mode'] == "hostap") {
3528
		$wlcmd[] = "mediaopt hostap";
3529
	} else {
3530
		$wlcmd[] = "-mediaopt hostap";
3531
	}
3532

    
3533
	/* Set wireless adhoc mode */
3534
	if ($wlcfg['mode'] == "adhoc") {
3535
		$wlcmd[] = "mediaopt adhoc";
3536
	} else {
3537
		$wlcmd[] = "-mediaopt adhoc";
3538
	}
3539

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

    
3542
	/* handle hide ssid option */
3543
	if (isset($wlcfg['hidessid']['enable'])) {
3544
		$wlcmd[] = "hidessid";
3545
	} else {
3546
		$wlcmd[] = "-hidessid";
3547
	}
3548

    
3549
	/* handle pureg (802.11g) only option */
3550
	if (isset($wlcfg['pureg']['enable'])) {
3551
		$wlcmd[] = "mode 11g pureg";
3552
	} else {
3553
		$wlcmd[] = "-pureg";
3554
	}
3555

    
3556
	/* handle puren (802.11n) only option */
3557
	if (isset($wlcfg['puren']['enable'])) {
3558
		$wlcmd[] = "puren";
3559
	} else {
3560
		$wlcmd[] = "-puren";
3561
	}
3562

    
3563
	/* enable apbridge option */
3564
	if (isset($wlcfg['apbridge']['enable'])) {
3565
		$wlcmd[] = "apbridge";
3566
	} else {
3567
		$wlcmd[] = "-apbridge";
3568
	}
3569

    
3570
	/* handle turbo option */
3571
	if (isset($wlcfg['turbo']['enable'])) {
3572
		$wlcmd[] = "mediaopt turbo";
3573
	} else {
3574
		$wlcmd[] = "-mediaopt turbo";
3575
	}
3576

    
3577
	/* handle txpower setting */
3578
	// or don't. this has issues at the moment.
3579
	/*
3580
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3581
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3582
	}*/
3583

    
3584
	/* handle wme option */
3585
	if (isset($wlcfg['wme']['enable'])) {
3586
		$wlcmd[] = "wme";
3587
	} else {
3588
		$wlcmd[] = "-wme";
3589
	}
3590

    
3591
	/* Enable wpa if it's configured. No WEP support anymore. */
3592
	if (isset($wlcfg['wpa']['enable'])) {
3593
		$wlcmd[] = "authmode wpa wepmode off ";
3594
	} else {
3595
		$wlcmd[] = "authmode open wepmode off ";
3596
	}
3597

    
3598
	kill_hostapd($if);
3599
	mwexec(kill_wpasupplicant("{$if}"));
3600

    
3601
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3602

    
3603
	switch ($wlcfg['mode']) {
3604
		case 'bss':
3605
			if (isset($wlcfg['wpa']['enable'])) {
3606
				$wpa .= <<<EOD
3607
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3608
ctrl_interface_group=0
3609
ap_scan=1
3610
#fast_reauth=1
3611
network={
3612
ssid="{$wlcfg['ssid']}"
3613
scan_ssid=1
3614
priority=5
3615
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3616
psk="{$wlcfg['wpa']['passphrase']}"
3617
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3618
group={$wlcfg['wpa']['wpa_pairwise']}
3619
}
3620
EOD;
3621

    
3622
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
3623
				unset($wpa);
3624
			}
3625
			break;
3626
		case 'hostap':
3627
			if (!empty($wlcfg['wpa']['passphrase'])) {
3628
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3629
			} else {
3630
				$wpa_passphrase = "";
3631
			}
3632
			if (isset($wlcfg['wpa']['enable'])) {
3633
				$wpa .= <<<EOD
3634
interface={$if}
3635
driver=bsd
3636
logger_syslog=-1
3637
logger_syslog_level=0
3638
logger_stdout=-1
3639
logger_stdout_level=0
3640
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3641
ctrl_interface={$g['varrun_path']}/hostapd
3642
ctrl_interface_group=wheel
3643
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3644
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3645
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3646
ssid={$wlcfg['ssid']}
3647
debug={$wlcfg['wpa']['debug_mode']}
3648
wpa={$wlcfg['wpa']['wpa_mode']}
3649
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3650
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3651
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3652
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3653
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3654
{$wpa_passphrase}
3655

    
3656
EOD;
3657

    
3658
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3659
					$wpa .= <<<EOD
3660
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3661
rsn_preauth=1
3662
rsn_preauth_interfaces={$if}
3663

    
3664
EOD;
3665
				}
3666
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3667
					$wpa .= "ieee8021x=1\n";
3668

    
3669
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3670
						$auth_server_port = "1812";
3671
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3672
							$auth_server_port = intval($wlcfg['auth_server_port']);
3673
						}
3674
						$wpa .= <<<EOD
3675

    
3676
auth_server_addr={$wlcfg['auth_server_addr']}
3677
auth_server_port={$auth_server_port}
3678
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3679

    
3680
EOD;
3681
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3682
							$auth_server_port2 = "1812";
3683
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3684
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3685
							}
3686

    
3687
							$wpa .= <<<EOD
3688
auth_server_addr={$wlcfg['auth_server_addr2']}
3689
auth_server_port={$auth_server_port2}
3690
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3691

    
3692
EOD;
3693
						}
3694
					}
3695
				}
3696

    
3697
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3698
				unset($wpa);
3699
			}
3700
			break;
3701
	}
3702

    
3703
	/*
3704
	 *    all variables are set, lets start up everything
3705
	 */
3706

    
3707
	$baseif = interface_get_wireless_base($if);
3708
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3709
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3710

    
3711
	/* set sysctls for the wireless interface */
3712
	if (!empty($wl_sysctl)) {
3713
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3714
		foreach ($wl_sysctl as $wl_sysctl_line) {
3715
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3716
		}
3717
	}
3718

    
3719
	/* set ack timers according to users preference (if he/she has any) */
3720
	if ($distance) {
3721
		fwrite($fd_set, "# Enable ATH distance settings\n");
3722
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3723
	}
3724

    
3725
	if (isset($wlcfg['wpa']['enable'])) {
3726
		if ($wlcfg['mode'] == "bss") {
3727
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3728
		}
3729
		if ($wlcfg['mode'] == "hostap") {
3730
			/* add line to script to restore old mac to make hostapd happy */
3731
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3732
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3733
				$if_curmac = get_interface_mac($if);
3734
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3735
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3736
						" link " . escapeshellarg($if_oldmac) . "\n");
3737
				}
3738
			}
3739

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

    
3742
			/* add line to script to restore spoofed mac after running hostapd */
3743
			if ($wl['spoofmac']) {
3744
				$if_curmac = get_interface_mac($if);
3745
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3746
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3747
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3748
				}
3749
			}
3750
		}
3751
	}
3752

    
3753
	fclose($fd_set);
3754

    
3755
	/* Making sure regulatory settings have actually changed
3756
	 * before applying, because changing them requires bringing
3757
	 * down all wireless networks on the interface. */
3758
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3759
	$ifconfig_str = implode($output);
3760
	unset($output);
3761
	$reg_changing = false;
3762

    
3763
	/* special case for the debug country code */
3764
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3765
		$reg_changing = true;
3766
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3767
		$reg_changing = true;
3768
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3769
		$reg_changing = true;
3770
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3771
		$reg_changing = true;
3772
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3773
		$reg_changing = true;
3774
	}
3775

    
3776
	if ($reg_changing) {
3777
		/* set regulatory domain */
3778
		if ($wlcfg['regdomain']) {
3779
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3780
		}
3781

    
3782
		/* set country */
3783
		if ($wlcfg['regcountry']) {
3784
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3785
		}
3786

    
3787
		/* set location */
3788
		if ($wlcfg['reglocation']) {
3789
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3790
		}
3791

    
3792
		$wlregcmd_args = implode(" ", $wlregcmd);
3793

    
3794
		/* build a complete list of the wireless clones for this interface */
3795
		$clone_list = array();
3796
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3797
			$clone_list[] = interface_get_wireless_clone($baseif);
3798
		}
3799
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3800
			foreach ($config['wireless']['clone'] as $clone) {
3801
				if ($clone['if'] == $baseif) {
3802
					$clone_list[] = $clone['cloneif'];
3803
				}
3804
			}
3805
		}
3806

    
3807
		/* find which clones are up and bring them down */
3808
		$clones_up = array();
3809
		foreach ($clone_list as $clone_if) {
3810
			$clone_status = pfSense_get_interface_addresses($clone_if);
3811
			if ($clone_status['status'] == 'up') {
3812
				$clones_up[] = $clone_if;
3813
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3814
			}
3815
		}
3816

    
3817
		/* apply the regulatory settings */
3818
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3819
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3820

    
3821
		/* bring the clones back up that were previously up */
3822
		foreach ($clones_up as $clone_if) {
3823
			interfaces_bring_up($clone_if);
3824

    
3825
			/*
3826
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3827
			 * is in infrastructure mode, and WPA is enabled.
3828
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3829
			 */
3830
			if ($clone_if != $if) {
3831
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3832
				if ((!empty($friendly_if)) &&
3833
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3834
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3835
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3836
				}
3837
			}
3838
		}
3839
	}
3840

    
3841
	/* The mode must be specified in a separate command before ifconfig
3842
	 * will allow the mode and channel at the same time in the next.
3843
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3844
	 */
3845
	if ($wlcfg['mode'] == "hostap") {
3846
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3847
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3848
	}
3849

    
3850
	/* configure wireless */
3851
	$wlcmd_args = implode(" ", $wlcmd);
3852
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args);
3853
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3854
	/* Bring the interface up only after setting up all the other parameters. */
3855
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up");
3856
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3857
	fclose($wlan_setup_log);
3858

    
3859
	unset($wlcmd_args, $wlcmd);
3860

    
3861

    
3862
	sleep(1);
3863
	/* execute hostapd and wpa_supplicant if required in shell */
3864
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3865

    
3866
	return 0;
3867

    
3868
}
3869

    
3870
function kill_hostapd($interface) {
3871
	global $g;
3872

    
3873
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3874
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3875
	}
3876
}
3877

    
3878
function kill_wpasupplicant($interface) {
3879
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3880
}
3881

    
3882
function find_dhclient_process($interface) {
3883
	if ($interface) {
3884
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3885
	} else {
3886
		$pid = 0;
3887
	}
3888

    
3889
	return intval($pid);
3890
}
3891

    
3892
function kill_dhclient_process($interface) {
3893
	if (empty($interface) || !does_interface_exist($interface)) {
3894
		return;
3895
	}
3896

    
3897
	$i = 0;
3898
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3899
		/* 3rd time make it die for sure */
3900
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3901
		posix_kill($pid, $sig);
3902
		sleep(1);
3903
		$i++;
3904
	}
3905
	unset($i);
3906
}
3907

    
3908
function find_dhcp6c_process($interface) {
3909
	global $g;
3910

    
3911
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3912
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3913
	} else {
3914
		return(false);
3915
	}
3916

    
3917
	return intval($pid);
3918
}
3919

    
3920
function kill_dhcp6client_process($interface, $force, $release = false) {
3921
	global $g;
3922

    
3923
	$i = 0;
3924

    
3925
	/*
3926
	Beware of the following: Reason, the interface may be down, but
3927
	dhcp6c may still be running, it just complains it cannot send
3928
	and carries on. Commented out as will stop the call to kill.
3929

    
3930
	if (empty($interface) || !does_interface_exist($interface)) {
3931
		return;
3932
	}
3933
	*/
3934

    
3935
	/*********** Notes on signals for dhcp6c and this function *************
3936

    
3937
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3938
	a release and waiting for the response that never comes.
3939
	So we need to tell it that the interface is down and to just die quickly
3940
	otherwise a new client may launch and we have duplicate proceses.
3941
	In this case use SIGUSR1.
3942

    
3943
	If we want to exit normally obeying the no release flag then use SIGTERM.
3944
	If we want to exit with a release overiding the no release flag then
3945
	use SIGUSR2.
3946

    
3947
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3948
	exit quickly without sending release signals.
3949

    
3950
	If $Force is set to false and $release is also set to false dhcp6c will
3951
	follow the no-release flag.
3952

    
3953
	If $Force is set to false and $release is true then dhcp6c will send a
3954
	release regardless of the no-release flag.
3955
	***********************************************************************/
3956

    
3957
	if ($force == true) {
3958
		$psig=SIGUSR1;
3959
	} else if ($release == false) {
3960
		$psig=SIGTERM;
3961
	} else {
3962
		$psig=SIGUSR2;
3963
	}
3964

    
3965
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3966
		/* 3rd time make it die for sure */
3967
		$sig = ($i == 2 ? SIGKILL : $psig);
3968
		posix_kill($pid, $sig);
3969
		sleep(1);
3970
		$i++;
3971
	}
3972
	/* Clear the RTSOLD script created lock & tidy up */
3973
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3974
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
3975
}
3976
function reset_dhcp6client_process($interface) {
3977

    
3978
	$pid = find_dhcp6c_process($interface);
3979

    
3980
	if($pid != 0) {
3981
		posix_kill($pid, SIGHUP);
3982
	}
3983
}
3984

    
3985
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3986
	global $g;
3987

    
3988
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3989
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3990

    
3991
	/*
3992
	 * Only run this if the lock does not exist. In theory the lock being
3993
	 * there in this mode means the user has selected dhcp6withoutRA while
3994
	 * a session is active in the other mode.
3995
	 *
3996
	 * It should not happen as the process should have been killed and the
3997
	 * lock deleted.
3998
	 */
3999

    
4000
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
4001
		kill_dhcp6client_process($interface, true);
4002
		/* Lock it to avoid multiple runs */
4003
		touch("/tmp/dhcp6c_{$interface}_lock");
4004
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
4005
		    "{$noreleaseOption} " .
4006
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
4007
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
4008
		    $interface);
4009
		log_error(sprintf(gettext(
4010
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
4011
		    $interface));
4012
	}
4013
}
4014

    
4015
function interface_virtual_create($interface) {
4016
	global $config;
4017

    
4018
	if (interface_is_vlan($interface) != NULL) {
4019
		interface_vlan_configure(interface_is_vlan($interface));
4020
	} else if (substr($interface, 0, 3) == "gre") {
4021
		interfaces_tunnel_configure(0, $interface, 'gre');
4022
	} else if (substr($interface, 0, 3) == "gif") {
4023
		interfaces_tunnel_configure(0, $interface, 'gif');
4024
	} else if (substr($interface, 0, 5) == "ovpns") {
4025
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
4026
			foreach ($config['openvpn']['openvpn-server'] as $server) {
4027
				if ($interface == "ovpns{$server['vpnid']}") {
4028
					if (!function_exists('openvpn_resync')) {
4029
						require_once('openvpn.inc');
4030
					}
4031
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
4032
					openvpn_resync('server', $server);
4033
				}
4034
			}
4035
			unset($server);
4036
		}
4037
	} else if (substr($interface, 0, 5) == "ovpnc") {
4038
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
4039
			foreach ($config['openvpn']['openvpn-client'] as $client) {
4040
				if ($interface == "ovpnc{$client['vpnid']}") {
4041
					if (!function_exists('openvpn_resync')) {
4042
						require_once('openvpn.inc');
4043
					}
4044
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
4045
					openvpn_resync('client', $client);
4046
				}
4047
			}
4048
			unset($client);
4049
		}
4050
	} else if (substr($interface, 0, 5) == "ipsec") {
4051
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
4052
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
4053
				if ($ph1ent['disabled']) {
4054
					continue;
4055
				}
4056
				if ($interface == "ipsec{$ph1ent['ikeid']}") {
4057
					interface_ipsec_vti_configure($ph1ent);
4058
				}
4059
			}
4060
		}
4061
	} else if (substr($interface, 0, 4) == "lagg") {
4062
		interfaces_lagg_configure($interface);
4063
	} else if (substr($interface, 0, 6) == "bridge") {
4064
		interfaces_bridge_configure(0, $interface);
4065
	}
4066
}
4067

    
4068
function interface_vlan_mtu_configured($iface) {
4069
	global $config;
4070

    
4071
	$mtu = 0;
4072
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
4073
		foreach ($config['vlans']['vlan'] as $vlan) {
4074

    
4075
			if ($vlan['vlanif'] != $iface)
4076
				continue;
4077

    
4078
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4079
			$parentinf = convert_real_interface_to_friendly_interface_name($vlan['if']);
4080
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
4081
				/* VLAN MTU */
4082
				$mtu = $config['interfaces'][$assignedport]['mtu'];
4083
			} elseif (!empty($config['interfaces'][$parentinf]['mtu'])) {
4084
				/* Parent MTU */
4085
				$mtu = $config['interfaces'][$parentinf]['mtu'];
4086
			}
4087
		}
4088
	}
4089

    
4090
	return $mtu;
4091
}
4092

    
4093
function interface_mtu_wanted_for_pppoe($realif) {
4094
	global $config;
4095

    
4096
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
4097
		return 0;
4098

    
4099
	$mtu = 0;
4100
	foreach ($config['ppps']['ppp'] as $ppp) {
4101
		if ($ppp['type'] != "pppoe") {
4102
			continue;
4103
		}
4104

    
4105
		$mtus = array();
4106
		if (!empty($ppp['mtu'])) {
4107
			$mtus = explode(',', $ppp['mtu']);
4108
		}
4109
		$ports = explode(',', $ppp['ports']);
4110

    
4111
		foreach ($ports as $pid => $port) {
4112
			$parentifa = get_parent_interface($port);
4113
			$parentif = $parentifa[0];
4114
			if ($parentif != $realif)
4115
				continue;
4116

    
4117
			// there is an MTU configured on the port in question
4118
			if (!empty($mtus[$pid])) {
4119
				$mtu = intval($mtus[$pid]) + 8;
4120
			// or use the MTU configured on the interface ...
4121
			} elseif (is_array($config['interfaces'])) {
4122
				foreach ($config['interfaces'] as $interface) {
4123
					if ($interface['if'] == $ppp['if'] &&
4124
					    !empty($interface['mtu'])) {
4125
						$mtu = intval($interface['mtu']) + 8;
4126
						break;
4127
					}
4128
				}
4129
			}
4130
		}
4131
	}
4132

    
4133
	return $mtu;
4134
}
4135

    
4136
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
4137
	global $config, $g;
4138
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
4139
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
4140

    
4141
	$wancfg = $config['interfaces'][$interface];
4142

    
4143
	if (!isset($wancfg['enable'])) {
4144
		return;
4145
	}
4146

    
4147
	$realif = get_real_interface($interface);
4148
	$realhwif_array = get_parent_interface($interface);
4149
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
4150
	$realhwif = $realhwif_array[0];
4151

    
4152
	$mac_if_cfg = $wancfg;
4153
	if (interface_is_vlan($realif)) {
4154
		$mac_if = convert_real_interface_to_friendly_interface_name(
4155
		    $realhwif);
4156
		if (is_array($config['interfaces'][$mac_if])) {
4157
			$mac_if_cfg = $config['interfaces'][$mac_if];
4158
		} else {
4159
			$mac_if = $interface;
4160
		}
4161
	}
4162

    
4163
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn") && !(substr($realif, 0, 5) == "ipsec")) {
4164
		/* remove all IPv4 and IPv6 addresses */
4165
		$tmpifaces = pfSense_getall_interface_addresses($realif);
4166
		if (is_array($tmpifaces)) {
4167
			foreach ($tmpifaces as $tmpiface) {
4168
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
4169
					if (!is_linklocal($tmpiface)) {
4170
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
4171
					}
4172
				} elseif (strstr($tmpiface, "fe80::1:1")) {
4173
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 fe80::1:1 -alias");
4174
				} else {
4175
					if (is_subnetv4($tmpiface)) {
4176
						$tmpip = explode('/', $tmpiface);
4177
						$tmpip = $tmpip[0];
4178
					} else {
4179
						$tmpip = $tmpiface;
4180
					}
4181
					pfSense_interface_deladdress($realif, $tmpip);
4182
				}
4183
			}
4184
		}
4185

    
4186
		/* only bring down the interface when both v4 and v6 are set to NONE */
4187
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4188
			interface_bring_down($interface);
4189
		}
4190
	}
4191

    
4192
	$interface_to_check = $realif;
4193
	if (interface_isppp_type($interface)) {
4194
		$interface_to_check = $realhwif;
4195
	}
4196

    
4197
	/* Need to check that the interface exists or not in the case where its coming back from disabled state see #3270 */
4198
	if (!platform_booting() && (in_array(substr($realif, 0, 3), array("gre", "gif", "ips")) || !does_interface_exist($interface_to_check))) {
4199
		interface_virtual_create($interface_to_check);
4200
	}
4201

    
4202
	/* Disable Accepting router advertisements unless specifically requested */
4203
	if ($g['debug']) {
4204
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
4205
	}
4206
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
4207
	{
4208
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
4209
	}
4210
	/* wireless configuration? */
4211
	if (is_array($wancfg['wireless']) && !$linkupevent) {
4212
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
4213
	}
4214

    
4215
	$current_mac = get_interface_mac($realhwif);
4216
	$vendor_mac = get_interface_vendor_mac($realhwif);
4217

    
4218
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4219
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4220

    
4221
		interface_set_macaddr($realhwif, $mac_addr);
4222
	} else {
4223
		/*
4224
		 * this is not a valid mac address.  generate a
4225
		 * temporary mac address so the machine can get online.
4226
		 */
4227
		echo gettext("Generating new MAC address.");
4228
		$random_mac = generate_random_mac_address();
4229
		interface_set_macaddr($realhwif, $random_mac);
4230
		$config['interfaces'][$mac_if]['spoofmac'] = $random_mac;
4231
		write_config(sprintf(gettext('The invalid MAC address ' .
4232
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
4233
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
4234
		file_notice("MAC Address altered", sprintf(gettext('The ' .
4235
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
4236
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
4237
		    $random_mac), "Interfaces");
4238
	}
4239

    
4240
	/* media */
4241
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4242
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4243
		if ($wancfg['media']) {
4244
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4245
		}
4246
		if ($wancfg['mediaopt']) {
4247
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4248
		}
4249
		mwexec($cmd);
4250
	}
4251

    
4252
	/* Apply hw offloading policies as configured */
4253
	enable_hardware_offloading($interface);
4254

    
4255
	/* invalidate interface/ip/sn cache */
4256
	get_interface_arr(true);
4257
	unset($interface_ip_arr_cache[$realif]);
4258
	unset($interface_sn_arr_cache[$realif]);
4259
	unset($interface_ipv6_arr_cache[$realif]);
4260
	unset($interface_snv6_arr_cache[$realif]);
4261

    
4262
	$tunnelif = substr($realif, 0, 3);
4263

    
4264
	$mtuif = $realif;
4265
	$mtuhwif = $realhwif;
4266

    
4267
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4268
	if (interface_isppp_type($interface)) {
4269
		$mtuif = $realhwif;
4270
		$mtuhwif_array = get_parent_interface($mtuif);
4271
		$mtuhwif = $mtuhwif_array[0];
4272
	}
4273

    
4274
	$wantedmtu = 0;
4275
	if (is_array($config['interfaces'])) {
4276
		foreach ($config['interfaces'] as $tmpinterface) {
4277
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4278
				$wantedmtu = $tmpinterface['mtu'];
4279
				break;
4280
			}
4281
		}
4282
	}
4283

    
4284
	/* MTU is not specified for interface, try the pppoe settings. */
4285
	if ($wantedmtu == 0) {
4286
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4287
	}
4288
	if (($wantedmtu == 0) && (interface_is_vlan($mtuif) != NULL) && interface_isppp_type($interface)) {
4289
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4290
	}
4291
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4292
		/* set MTU to 1400 for GRE over IPsec */
4293
		if (is_greipsec($mtuif)) {
4294
			$wantedmtu = 1400;
4295
		} else {
4296
			$wantedmtu = 1476;
4297
		}
4298
	}
4299
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4300
		$wantedmtu = 1280;
4301
	}
4302
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'vxlan')) {
4303
		$wantedmtu = 1450;
4304
	}
4305

    
4306
	/* Set the MTU to 1500 if no explicit MTU configured. */
4307
	if ($wantedmtu == 0) {
4308
		$wantedmtu = 1500; /* Default */
4309
	}
4310

    
4311
	if (interface_is_vlan($mtuif) != NULL) {
4312
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4313
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
4314
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
4315
			if ($wancfg['mtu'] > $parentmtu) {
4316
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4317
			}
4318
		}
4319

    
4320
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4321

    
4322
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4323
			$configuredmtu = $parentmtu;
4324
		if ($configuredmtu != 0)
4325
			$mtu = $configuredmtu;
4326
		else
4327
			$mtu = $wantedmtu;
4328

    
4329
		/* Set the parent MTU. */
4330
		if (get_interface_mtu($mtuhwif) < $mtu)
4331
			set_interface_mtu($mtuhwif, $mtu);
4332
		/* Set the VLAN MTU. */
4333
		if (get_interface_mtu($mtuif) != $mtu)
4334
			set_interface_mtu($mtuif, $mtu);
4335
	} else if (substr($mtuif, 0, 4) == 'lagg') {
4336
		/* LAGG interface must be destroyed and re-created to change MTU */
4337
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4338
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
4339
				foreach ($config['laggs']['lagg'] as $lagg) {
4340
					if ($lagg['laggif'] == $mtuif) {
4341
						interface_lagg_configure($lagg);
4342
						break;
4343
					}
4344
				}
4345
			}
4346
		}
4347
	} else {
4348
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4349
			pfSense_interface_mtu($mtuif, $wantedmtu);
4350
			set_ipv6routes_mtu($mtuif, $wantedmtu);
4351
		}
4352
	}
4353
	/* XXX: What about gre/gif/.. ? */
4354

    
4355
	if (does_interface_exist($wancfg['if'])) {
4356
		interfaces_bring_up($wancfg['if']);
4357
	}
4358

    
4359
	switch ($wancfg['ipaddr']) {
4360
		case 'dhcp':
4361
			interface_dhcp_configure($interface);
4362
			break;
4363
		case 'pppoe':
4364
		case 'l2tp':
4365
		case 'pptp':
4366
		case 'ppp':
4367
			interface_ppps_configure($interface);
4368
			break;
4369
		default:
4370
			/* XXX: Kludge for now related to #3280 */
4371
			if (!in_array($tunnelif, array("gif", "gre", "vxlan", "ovp", "ips"))) {
4372
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4373
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4374
				}
4375
			}
4376
			break;
4377
	}
4378

    
4379
	switch ($wancfg['ipaddrv6']) {
4380
		case 'slaac':
4381
		case 'dhcp6':
4382
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4383
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4384
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4385
			/* Remove the check file. Should not be there but just in case */
4386
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
4387
			log_error(gettext("calling interface_dhcpv6_configure."));
4388
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
4389
				interface_dhcpv6_configure($interface, $wancfg);
4390
			}
4391
			break;
4392
		case '6rd':
4393
			interface_6rd_configure($interface, $wancfg);
4394
			break;
4395
		case '6to4':
4396
			interface_6to4_configure($interface, $wancfg);
4397
			break;
4398
		case 'track6':
4399
			interface_track6_configure($interface, $wancfg, $linkupevent);
4400
			break;
4401
		default:
4402
			/* XXX: Kludge for now related to #3280 */
4403
			if (!in_array($tunnelif, array("gif", "gre", "vxlan", "ovp", "ips"))) {
4404
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4405
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4406
					// FIXME: Add IPv6 Support to the pfSense module
4407
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4408
				}
4409
			}
4410
			break;
4411
	}
4412

    
4413
	interface_netgraph_needed($interface);
4414

    
4415
	if (!platform_booting()) {
4416
		link_interface_to_vips($interface, "update");
4417

    
4418
		if ($tunnelif != 'gre') {
4419
			unset($gre);
4420
			$gre = link_interface_to_tunnelif($interface, 'gre');
4421
			if (!empty($gre)) {
4422
				array_walk($gre, 'interface_gre_configure');
4423
			}
4424
		}
4425

    
4426
		if ($tunnelif != 'gif') {
4427
			unset($gif);
4428
			$gif = link_interface_to_tunnelif($interface, 'gif');
4429
			if (!empty($gif)) {
4430
				array_walk($gif, 'interface_gif_configure');
4431
			}
4432
		}
4433

    
4434
		if ($tunnelif != 'vxlan') {
4435
			unset($vxlan);
4436
			$vxlan = link_interface_to_tunnelif($interface, 'vxlan');
4437
			if (!empty($vxlan)) {
4438
				array_walk($vxlan, 'interface_vxlan_configure');
4439
			}
4440
		}
4441

    
4442
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4443
			unset($bridgetmp);
4444
			$bridgetmp = link_interface_to_bridge($interface);
4445
			if (!empty($bridgetmp)) {
4446
				interface_bridge_add_member($bridgetmp, $realif);
4447
			}
4448
		}
4449

    
4450
		$grouptmp = link_interface_to_group($interface);
4451
		if (!empty($grouptmp)) {
4452
			array_walk($grouptmp, 'interface_group_add_member');
4453
		}
4454

    
4455
		if ($interface == "lan") {
4456
			/* make new hosts file */
4457
			system_hosts_generate();
4458
		}
4459

    
4460
		if ($reloadall == true) {
4461

    
4462
			/* reconfigure static routes (kernel may have deleted them) */
4463
			system_routing_configure($interface);
4464

    
4465
			/* reload ipsec tunnels */
4466
			send_event("service reload ipsecdns");
4467

    
4468
			if (isset($config['dnsmasq']['enable'])) {
4469
				services_dnsmasq_configure();
4470
			}
4471

    
4472
			if (isset($config['unbound']['enable'])) {
4473
				services_unbound_configure();
4474
			}
4475

    
4476
			/* update dyndns */
4477
			send_event("service reload dyndns {$interface}");
4478

    
4479
			/* reload captive portal */
4480
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4481
				require_once('captiveportal.inc');
4482
			}
4483
			captiveportal_init_rules_byinterface($interface);
4484
		}
4485
	}
4486

    
4487
	if (!empty($wancfg['descr'])) {
4488
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4489
	};
4490

    
4491
	interfaces_staticarp_configure($interface);
4492
	return 0;
4493
}
4494

    
4495
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4496
	global $config, $g;
4497

    
4498
	if (!is_array($wancfg)) {
4499
		return;
4500
	}
4501

    
4502
	if (!isset($wancfg['enable'])) {
4503
		return;
4504
	}
4505

    
4506
	/* If the interface is not configured via another, exit */
4507
	if (empty($wancfg['track6-interface'])) {
4508
		return;
4509
	}
4510

    
4511
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4512
	$realif = get_real_interface($interface);
4513
	$linklocal = find_interface_ipv6_ll($realif, true);
4514
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4515
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4516
	}
4517

    
4518
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4519
	if (!isset($trackcfg['enable'])) {
4520
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4521
		return;
4522
	}
4523

    
4524
	switch ($trackcfg['ipaddrv6']) {
4525
		case "6to4":
4526
			if ($g['debug']) {
4527
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4528
			}
4529
			interface_track6_6to4_configure($interface, $wancfg);
4530
			break;
4531
		case "6rd":
4532
			if ($g['debug']) {
4533
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4534
			}
4535
			interface_track6_6rd_configure($interface, $wancfg);
4536
			break;
4537
		case "dhcp6":
4538
			if ($linkupevent == true) {
4539
				/*
4540
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4541
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4542
				 *
4543
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4544
				 */
4545
				$parentrealif = get_real_interface($wancfg['track6-interface']);
4546
				$pidv6 = find_dhcp6c_process($parentrealif);
4547
				if ($pidv6) {
4548
					posix_kill($pidv6, SIGHUP);
4549
				}
4550
			}
4551
			break;
4552
	}
4553

    
4554
	if ($linkupevent == false && !platform_booting()) {
4555
		if (!function_exists('services_dhcpd_configure')) {
4556
			require_once("services.inc");
4557
		}
4558

    
4559
		/* restart dns servers (defering dhcpd reload) */
4560
		if (isset($config['unbound']['enable'])) {
4561
			services_unbound_configure(false);
4562
		}
4563
		if (isset($config['dnsmasq']['enable'])) {
4564
			services_dnsmasq_configure(false);
4565
		}
4566

    
4567
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4568
		services_dhcpd_configure("inet6");
4569
	}
4570

    
4571
	return 0;
4572
}
4573

    
4574
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4575
	global $config, $g;
4576
	global $interface_ipv6_arr_cache;
4577
	global $interface_snv6_arr_cache;
4578

    
4579
	if (!is_array($lancfg)) {
4580
		return;
4581
	}
4582

    
4583
	/* If the interface is not configured via another, exit */
4584
	if (empty($lancfg['track6-interface'])) {
4585
		return;
4586
	}
4587

    
4588
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4589
	if (empty($wancfg)) {
4590
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4591
		return;
4592
	}
4593

    
4594
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4595
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4596
		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']));
4597
		return;
4598
	}
4599
	$hexwanv4 = return_hex_ipv4($ip4address);
4600

    
4601
	/* create the long prefix notation for math, save the prefix length */
4602
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4603
	$rd6prefixlen = $rd6prefix[1];
4604
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4605

    
4606
	/* binary presentation of the prefix for all 128 bits. */
4607
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4608

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

    
4614
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4615
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4616
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4617
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4618
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4619
	/* fill the rest out with zeros */
4620
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4621

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

    
4625
	$lanif = get_real_interface($interface);
4626
	$oip = find_interface_ipv6($lanif);
4627
	if (is_ipaddrv6($oip)) {
4628
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4629
	}
4630
	unset($interface_ipv6_arr_cache[$lanif]);
4631
	unset($interface_snv6_arr_cache[$lanif]);
4632
	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));
4633
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4634

    
4635
	return 0;
4636
}
4637

    
4638
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4639
	global $config, $g;
4640
	global $interface_ipv6_arr_cache;
4641
	global $interface_snv6_arr_cache;
4642

    
4643
	if (!is_array($lancfg)) {
4644
		return;
4645
	}
4646

    
4647
	/* If the interface is not configured via another, exit */
4648
	if (empty($lancfg['track6-interface'])) {
4649
		return;
4650
	}
4651

    
4652
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4653
	if (empty($wancfg)) {
4654
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4655
		return;
4656
	}
4657

    
4658
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4659
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4660
		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']));
4661
		return;
4662
	}
4663
	$hexwanv4 = return_hex_ipv4($ip4address);
4664

    
4665
	/* create the long prefix notation for math, save the prefix length */
4666
	$sixto4prefix = "2002::";
4667
	$sixto4prefixlen = 16;
4668
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4669

    
4670
	/* binary presentation of the prefix for all 128 bits. */
4671
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4672

    
4673
	/* just save the left prefix length bits */
4674
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4675
	/* add the v4 address */
4676
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4677
	/* add the custom prefix id */
4678
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4679
	/* fill the rest out with zeros */
4680
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4681

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

    
4685
	$lanif = get_real_interface($interface);
4686
	$oip = find_interface_ipv6($lanif);
4687
	if (is_ipaddrv6($oip)) {
4688
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4689
	}
4690
	unset($interface_ipv6_arr_cache[$lanif]);
4691
	unset($interface_snv6_arr_cache[$lanif]);
4692
	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));
4693
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4694

    
4695
	return 0;
4696
}
4697

    
4698
function interface_6rd_configure($interface = "wan", $wancfg) {
4699
	global $config, $g;
4700

    
4701
	/* because this is a tunnel interface we can only function
4702
	 *	with a public IPv4 address on the interface */
4703

    
4704
	if (!is_array($wancfg)) {
4705
		return;
4706
	}
4707

    
4708
	if (!is_module_loaded('if_stf.ko')) {
4709
		mwexec('/sbin/kldload if_stf.ko');
4710
	}
4711

    
4712
	$wanif = get_real_interface($interface);
4713
	$ip4address = find_interface_ip($wanif);
4714
	if (!is_ipaddrv4($ip4address)) {
4715
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4716
		return false;
4717
	}
4718
	$hexwanv4 = return_hex_ipv4($ip4address);
4719

    
4720
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4721
		$wancfg['prefix-6rd-v4plen'] = 0;
4722
	}
4723

    
4724
	/* create the long prefix notation for math, save the prefix length */
4725
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4726
	$rd6prefixlen = $rd6prefix[1];
4727
	$brgw = explode('.', $wancfg['gateway-6rd']);
4728
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4729
	$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);
4730
	if (strlen($rd6brgw) < 128) {
4731
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4732
	}
4733
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4734
	unset($brgw);
4735
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4736

    
4737
	/* binary presentation of the prefix for all 128 bits. */
4738
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4739

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

    
4747
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4748
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4749

    
4750

    
4751
	/* XXX: need to extend to support variable prefix size for v4 */
4752
	$stfiface = "{$interface}_stf";
4753
	if (does_interface_exist($stfiface)) {
4754
		pfSense_interface_destroy($stfiface);
4755
	}
4756
	$tmpstfiface = pfSense_interface_create("stf");
4757
	pfSense_interface_rename($tmpstfiface, $stfiface);
4758
	pfSense_interface_flags($stfiface, IFF_LINK2);
4759
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4760
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4761
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4762
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4763
	}
4764
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4765
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4766
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4767
	} elseif ($parentmtu > 1300) {
4768
		set_interface_mtu($stfiface, $parentmtu - 20);
4769
	}
4770
	if ($g['debug']) {
4771
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4772
	}
4773

    
4774
	/* write out a default router file */
4775
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4776
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4777

    
4778
	$ip4gateway = get_interface_gateway($interface);
4779
	if (is_ipaddrv4($ip4gateway)) {
4780
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4781
	}
4782

    
4783
	/* configure dependent interfaces */
4784
	if (!platform_booting()) {
4785
		link_interface_to_track6($interface, "update");
4786
	}
4787

    
4788
	return 0;
4789
}
4790

    
4791
function interface_6to4_configure($interface = "wan", $wancfg) {
4792
	global $config, $g;
4793

    
4794
	/* because this is a tunnel interface we can only function
4795
	 *	with a public IPv4 address on the interface */
4796

    
4797
	if (!is_array($wancfg)) {
4798
		return;
4799
	}
4800

    
4801
	$wanif = get_real_interface($interface);
4802
	$ip4address = find_interface_ip($wanif);
4803
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4804
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4805
		return false;
4806
	}
4807

    
4808
	/* create the long prefix notation for math, save the prefix length */
4809
	$stfprefixlen = 16;
4810
	$stfprefix = Net_IPv6::uncompress("2002::");
4811
	$stfarr = explode(":", $stfprefix);
4812
	$v4prefixlen = "0";
4813

    
4814
	/* we need the hex form of the interface IPv4 address */
4815
	$ip4arr = explode(".", $ip4address);
4816
	$hexwanv4 = "";
4817
	foreach ($ip4arr as $octet) {
4818
		$hexwanv4 .= sprintf("%02x", $octet);
4819
	}
4820

    
4821
	/* we need the hex form of the broker IPv4 address */
4822
	$ip4arr = explode(".", "192.88.99.1");
4823
	$hexbrv4 = "";
4824
	foreach ($ip4arr as $octet) {
4825
		$hexbrv4 .= sprintf("%02x", $octet);
4826
	}
4827

    
4828
	/* binary presentation of the prefix for all 128 bits. */
4829
	$stfprefixbin = "";
4830
	foreach ($stfarr as $element) {
4831
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4832
	}
4833
	/* just save the left prefix length bits */
4834
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4835

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

    
4840
	/* for the local subnet too. */
4841
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4842
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4843

    
4844
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4845
	$stfbrarr = array();
4846
	$stfbrbinarr = array();
4847
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4848
	foreach ($stfbrbinarr as $bin) {
4849
		$stfbrarr[] = dechex(bindec($bin));
4850
	}
4851
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4852

    
4853
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4854
	$stflanarr = array();
4855
	$stflanbinarr = array();
4856
	$stflanbinarr = str_split($stflanbin, 16);
4857
	foreach ($stflanbinarr as $bin) {
4858
		$stflanarr[] = dechex(bindec($bin));
4859
	}
4860
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4861
	$stflanarr[7] = 1;
4862
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4863

    
4864
	/* setup the stf interface */
4865
	if (!is_module_loaded("if_stf")) {
4866
		mwexec("/sbin/kldload if_stf.ko");
4867
	}
4868
	$stfiface = "{$interface}_stf";
4869
	if (does_interface_exist($stfiface)) {
4870
		pfSense_interface_destroy($stfiface);
4871
	}
4872
	$tmpstfiface = pfSense_interface_create("stf");
4873
	pfSense_interface_rename($tmpstfiface, $stfiface);
4874
	pfSense_interface_flags($stfiface, IFF_LINK2);
4875
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4876

    
4877
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4878
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4879
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4880
	} elseif ($parentmtu > 1300) {
4881
		set_interface_mtu($stfiface, $parentmtu - 20);
4882
	}
4883
	if ($g['debug']) {
4884
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4885
	}
4886

    
4887
	/* write out a default router file */
4888
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4889
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4890

    
4891
	$ip4gateway = get_interface_gateway($interface);
4892
	if (is_ipaddrv4($ip4gateway)) {
4893
		route_add_or_change("192.88.99.1", $ip4gateway);
4894
	}
4895

    
4896
	if (!platform_booting()) {
4897
		link_interface_to_track6($interface, "update");
4898
	}
4899

    
4900
	return 0;
4901
}
4902

    
4903
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4904
	global $config, $g;
4905

    
4906
	if (!is_array($wancfg)) {
4907
		return;
4908
	}
4909

    
4910
	$wanif = get_real_interface($interface, "inet6");
4911
	$dhcp6cconf = "";
4912

    
4913
	if (!empty($config['system']['global-v6duid'])) {
4914
		// Write the DUID file
4915
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4916
		    log_error(gettext("Failed to write user DUID file!"));
4917
		}
4918
	}
4919

    
4920
	/* accept router advertisements for this interface                 */
4921
	/* Moved to early in the function as sometimes interface not ready */
4922
	/* RTSOLD fails as interface does not accept .....                 */
4923

    
4924
	log_error("Accept router advertisements on interface {$wanif} ");
4925
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4926

    
4927
	if ($wancfg['adv_dhcp6_config_file_override']) {
4928
		// DHCP6 Config File Override
4929
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4930
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4931
		// DHCP6 Config File Advanced
4932
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4933
	} else {
4934
		// DHCP6 Config File Basic
4935
		$dhcp6cconf .= "interface {$wanif} {\n";
4936

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

    
4953
			/* skip address request if this is set */
4954
			if (!isset($wancfg['dhcp6prefixonly'])) {
4955
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4956
			}
4957
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4958
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4959
			}
4960

    
4961
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4962
			$dhcp6cconf .= "\trequest domain-name;\n";
4963

    
4964
			/*
4965
			 * dhcp6c will run different scripts depending on
4966
			 * whether dhcpwithoutra is set or unset.
4967
			 */
4968
			if (isset($wancfg['dhcp6withoutra'])) {
4969
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4970
			} else {
4971
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4972
			}
4973
			$dhcp6cconf .= "};\n";
4974

    
4975
			if (!isset($wancfg['dhcp6prefixonly'])) {
4976
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4977
			}
4978

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

    
5003
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
5004
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
5005

    
5006
	/* wide-dhcp6c works for now. */
5007
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
5008
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
5009
		unset($dhcp6cconf);
5010
		return 1;
5011
	}
5012
	unset($dhcp6cconf);
5013

    
5014
	/*************** Script Debug Logging ***************************
5015
	Both dhcp6 scripts now have a logging message built in.
5016
	These logging messages ONLY appear if dhcp6c debug logging is set.
5017
	The logging messages appear in the dhcp section of the logs,
5018
	not in system.
5019

    
5020
	These scripts now also take advantage of the REASON= env vars
5021
	supplied by dhcp6c.
5022
	****************************************************************/
5023

    
5024
	/* Script create for dhcp6withoutRA mode */
5025
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
5026
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
5027
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
5028
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
5029
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
5030
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
5031
	// Need to pass params to  the final script
5032
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
5033
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
5034
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
5035
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
5036
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
5037
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
5038
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
5039
	if ($debugOption == '-D') {
5040
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rtsold\"\n";
5041
	}
5042
	$dhcp6cscriptwithoutra .= ";;\n";
5043
	$dhcp6cscriptwithoutra .= "REBIND)\n";
5044
	if ($debugOption == '-D') {
5045
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5046
	}
5047
	$dhcp6cscriptwithoutra .= ";;\n";
5048
	if (isset($wancfg['dhcp6norelease'])) {
5049
		$dhcp6cscriptwithoutra .= "EXIT)\n";
5050
	} else {
5051
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
5052
	}
5053
	if ($debugOption == '-D') {
5054
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
5055
	}
5056
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5057
	$dhcp6cscriptwithoutra .= ";;\n";
5058
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
5059
	if ($debugOption == '-D') {
5060
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5061
	}
5062
	$dhcp6cscriptwithoutra .= "esac\n";
5063
	if (!@file_put_contents(
5064
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
5065
	    $dhcp6cscriptwithoutra)) {
5066
		printf("Error: cannot open " .
5067
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
5068
		    "interface_dhcpv6_configure() for writing.\n");
5069
		unset($dhcp6cscriptwithoutra);
5070
		return 1;
5071
	}
5072

    
5073
	unset($dhcp6cscriptwithoutra);
5074
	@chmod(
5075
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
5076
	    0755);
5077

    
5078
	/*
5079
	 * Dual mode wan_dhcp6c script with variations depending on node
5080
	 * dhcp6 will run the wan ipv6 configure
5081
	 */
5082
	$dhcp6cscript  = "#!/bin/sh\n";
5083
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
5084
	if (!isset($wancfg['dhcp6withoutra'])) {
5085
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
5086
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
5087
		$dhcp6cscript .= "case \$REASON in\n";
5088
		$dhcp6cscript .= "REBIND)\n";
5089
		if ($debugOption == '-D') {
5090
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5091
		}
5092
		$dhcp6cscript .= ";;\n";
5093
		if (isset($wancfg['dhcp6norelease'])) {
5094
			$dhcp6cscript .= "EXIT)\n";
5095
		} else {
5096
			$dhcp6cscript .= "RELEASE)\n";
5097
		}
5098
		if ($debugOption == '-D') {
5099
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
5100
		}
5101
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5102
		$dhcp6cscript .= ";;\n";
5103
		$dhcp6cscript .= "RENEW|REQUEST|INFO)\n";
5104
		if ($debugOption == '-D') {
5105
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5106
		}
5107
		$dhcp6cscript .= "esac\n";
5108
	} else {
5109
		// Need to get the parameters from the dhcp6cwithoutRA run
5110
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
5111
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
5112
		$dhcp6cscript .= "/bin/sleep 1\n";
5113
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5114
	}
5115

    
5116
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5117
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
5118
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
5119
		unset($dhcp6cscript);
5120
		return 1;
5121
	}
5122
	unset($dhcp6cscript);
5123
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
5124

    
5125
	$rtsoldscript = "#!/bin/sh\n";
5126
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
5127
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
5128
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
5129
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Received RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
5130

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

    
5179
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
5180
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
5181
		log_error("Killing running rtsold process");
5182
		sleep(2);
5183
	}
5184

    
5185
	if (isset($wancfg['dhcp6withoutra'])) {
5186
		/*
5187
		 * Start dhcp6c here if we don't want to wait for ra - calls
5188
		 * separate function
5189
		 *
5190
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
5191
		 * will then run the configure on receipt of the RA.
5192
		 *
5193
		 * Already started. interface_dhcpv6_configure() appears to get
5194
		 * called multiple times.
5195
		 *
5196
		 * Taking the interface down or releasing will kill the client.
5197
		 */
5198
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
5199
		{
5200
			/*
5201
			 * If the interface is being brought up, wait for the
5202
			 * interface to configure accept RA before launching.
5203
			 * Otherwise it is not ready to accept and will fail.
5204
			 */
5205
			sleep(3);
5206
			run_dhcp6client_process($wanif,$interface,$wancfg);
5207
		}
5208
	} else {
5209
		/*
5210
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
5211
		 * ( it does not background, it exits! ) It will launch dhcp6c
5212
		 * if dhcpwihtoutra is not set
5213
		 */
5214
		log_error("Starting rtsold process");
5215
		sleep(2);
5216
		mwexec("/usr/sbin/rtsold -1 " .
5217
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
5218
		    "-M {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
5219
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
5220
		    $wanif);
5221
	}
5222
	/*
5223
	 * NOTE: will be called from rtsold invoked script
5224
	 * link_interface_to_track6($interface, "update");
5225
	 */
5226

    
5227
	return 0;
5228
}
5229

    
5230
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5231
	global $g;
5232

    
5233
	$send_options = "";
5234
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5235
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5236
		foreach ($options as $option) {
5237
			$send_options .= "\tsend " . trim($option) . ";\n";
5238
		}
5239
	}
5240

    
5241
	$request_options = "";
5242
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5243
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5244
		foreach ($options as $option) {
5245
			$request_options .= "\trequest " . trim($option) . ";\n";
5246
		}
5247
	}
5248

    
5249
	$information_only = "";
5250
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5251
		$information_only = "\tinformation-only;\n";
5252
	}
5253

    
5254
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5255
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5256
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5257
	}
5258

    
5259
	$interface_statement  = "interface";
5260
	$interface_statement .= " {$wanif}";
5261
	$interface_statement .= " {\n";
5262
	$interface_statement .= "$send_options";
5263
	$interface_statement .= "$request_options";
5264
	$interface_statement .= "$information_only";
5265
	$interface_statement .= "$script";
5266
	$interface_statement .= "};\n";
5267

    
5268
	$id_assoc_statement_address = "";
5269
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5270
		$id_assoc_statement_address .= "id-assoc";
5271
		$id_assoc_statement_address .= " na";
5272
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5273
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5274
		}
5275
		$id_assoc_statement_address .= " { ";
5276

    
5277
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5278
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5279
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5280
			$id_assoc_statement_address .= "\n\taddress";
5281
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5282
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5283
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5284
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5285
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5286
			}
5287
			$id_assoc_statement_address .= ";\n";
5288
		}
5289

    
5290
		$id_assoc_statement_address .= "};\n";
5291
	}
5292

    
5293
	$id_assoc_statement_prefix = "";
5294
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5295
		$id_assoc_statement_prefix .= "id-assoc";
5296
		$id_assoc_statement_prefix .= " pd";
5297
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5298
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5299
		}
5300
		$id_assoc_statement_prefix .= " { ";
5301

    
5302
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5303
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5304
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5305
			$id_assoc_statement_prefix .= "\n\tprefix";
5306
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5307
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5308
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5309
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5310
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5311
			}
5312
			$id_assoc_statement_prefix .= ";";
5313
		}
5314

    
5315
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5316
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5317
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5318
			$id_assoc_statement_prefix .= " {$realif}";
5319
			$id_assoc_statement_prefix .= " {\n";
5320
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5321
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5322
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5323
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5324
			}
5325
			$id_assoc_statement_prefix .= "\t};";
5326
		}
5327

    
5328
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5329
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5330
			$id_assoc_statement_prefix .= "\n";
5331
		}
5332

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

    
5336
	$authentication_statement = "";
5337
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5338
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5339
		$authentication_statement .= "authentication";
5340
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5341
		$authentication_statement .= " {\n";
5342
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5343
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5344
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5345
		}
5346
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5347
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5348
		}
5349
		$authentication_statement .= "};\n";
5350
	}
5351

    
5352
	$key_info_statement = "";
5353
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5354
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5355
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5356
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5357
		$key_info_statement .= "keyinfo";
5358
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5359
		$key_info_statement .= " {\n";
5360
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5361
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5362
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5363
		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'])) {
5364
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5365
		}
5366
		$key_info_statement .= "};\n";
5367
	}
5368

    
5369
	$dhcp6cconf  = $interface_statement;
5370
	$dhcp6cconf .= $id_assoc_statement_address;
5371
	$dhcp6cconf .= $id_assoc_statement_prefix;
5372
	$dhcp6cconf .= $authentication_statement;
5373
	$dhcp6cconf .= $key_info_statement;
5374

    
5375
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5376

    
5377
	return $dhcp6cconf;
5378
}
5379

    
5380

    
5381
function DHCP6_Config_File_Override($wancfg, $wanif) {
5382

    
5383
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5384

    
5385
	if ($dhcp6cconf === false) {
5386
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5387
		return '';
5388
	} else {
5389
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5390
	}
5391
}
5392

    
5393

    
5394
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5395

    
5396
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5397

    
5398
	return $dhcp6cconf;
5399
}
5400

    
5401

    
5402
function interface_dhcp_configure($interface = "wan") {
5403
	global $config, $g, $vlanprio_values;
5404

    
5405
	$ifcfg = $config['interfaces'][$interface];
5406
	if (empty($ifcfg)) {
5407
		$ifcfg = array();
5408
	}
5409

    
5410
	$dhclientconf_vlantag = "";
5411
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5412
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5413
	}
5414

    
5415
	/* generate dhclient_wan.conf */
5416
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5417
	if (!$fd) {
5418
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5419
		return 1;
5420
	}
5421

    
5422
	if ($ifcfg['dhcphostname']) {
5423
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5424
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5425
	} else {
5426
		$dhclientconf_hostname = "";
5427
	}
5428

    
5429
	$realif = get_real_interface($interface);
5430
	if (empty($realif)) {
5431
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5432
		return 0;
5433
	}
5434
	$dhclientconf = "";
5435

    
5436
	$dhclientconf .= <<<EOD
5437
interface "{$realif}" {
5438
	supersede interface-mtu 0;
5439
	timeout 60;
5440
	retry 15;
5441
	select-timeout 0;
5442
	initial-interval 1;
5443
	{$dhclientconf_vlantag}
5444
	{$dhclientconf_hostname}
5445
	script "/usr/local/sbin/pfSense-dhclient-script";
5446
EOD;
5447

    
5448
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5449
		$dhclientconf .= <<<EOD
5450

    
5451
	reject {$ifcfg['dhcprejectfrom']};
5452
EOD;
5453
	}
5454
	$dhclientconf .= <<<EOD
5455

    
5456
}
5457

    
5458
EOD;
5459

    
5460
	// DHCP Config File Advanced
5461
	if ($ifcfg['adv_dhcp_config_advanced']) {
5462
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5463
	}
5464

    
5465
	if (is_ipaddr($ifcfg['alias-address'])) {
5466
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5467
		$dhclientconf .= <<<EOD
5468
alias {
5469
	interface "{$realif}";
5470
	fixed-address {$ifcfg['alias-address']};
5471
	option subnet-mask {$subnetmask};
5472
}
5473

    
5474
EOD;
5475
	}
5476

    
5477
	// DHCP Config File Override
5478
	if ($ifcfg['adv_dhcp_config_file_override']) {
5479
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5480
	}
5481

    
5482
	fwrite($fd, $dhclientconf);
5483
	fclose($fd);
5484

    
5485
	/* bring wan interface up before starting dhclient */
5486
	if ($realif) {
5487
		interfaces_bring_up($realif);
5488
	}
5489

    
5490
	/* Make sure dhclient is not running */
5491
	kill_dhclient_process($realif);
5492

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

    
5496
	return 0;
5497
}
5498

    
5499
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5500

    
5501
	$hostname = "";
5502
	if ($ifcfg['dhcphostname'] != '') {
5503
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5504
	}
5505

    
5506
	/* DHCP Protocol Timings */
5507
	$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");
5508
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5509
		$pt_variable = "{$Protocol_Timing}";
5510
		${$pt_variable} = "";
5511
		if ($ifcfg[$Protocol_Timing] != "") {
5512
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5513
		}
5514
	}
5515

    
5516
	$send_options = "";
5517
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5518
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5519
		foreach ($options as $option) {
5520
			$send_options .= "\tsend " . trim($option) . ";\n";
5521
		}
5522
	}
5523

    
5524
	$request_options = "";
5525
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5526
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5527
	}
5528

    
5529
	$required_options = "";
5530
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5531
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5532
	}
5533

    
5534
	$option_modifiers = "";
5535
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5536
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5537
		foreach ($modifiers as $modifier) {
5538
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5539
		}
5540
	}
5541

    
5542
	$dhclientconf  = "interface \"{$realif}\" {\n";
5543
	$dhclientconf .= "\n";
5544
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5545
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5546
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5547
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5548
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5549
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5550
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5551
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5552
	$dhclientconf .= "\n";
5553
	$dhclientconf .= "# DHCP Protocol Options\n";
5554
	$dhclientconf .= "{$hostname}";
5555
	$dhclientconf .= "{$send_options}";
5556
	$dhclientconf .= "{$request_options}";
5557
	$dhclientconf .= "{$required_options}";
5558
	$dhclientconf .= "{$option_modifiers}";
5559
	$dhclientconf .= "\n";
5560
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5561
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5562
	}
5563
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5564
	$dhclientconf .= "}\n";
5565

    
5566
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5567

    
5568
	return $dhclientconf;
5569
}
5570

    
5571
function DHCP_Config_Option_Split($option_string) {
5572
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5573
	return $matches ? $matches[0] : [];
5574
}
5575

    
5576
function DHCP_Config_File_Override($ifcfg, $realif) {
5577

    
5578
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5579

    
5580
	if ($dhclientconf === false) {
5581
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5582
		return '';
5583
	} else {
5584
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5585
	}
5586
}
5587

    
5588

    
5589
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5590

    
5591
	/* Apply Interface Substitutions */
5592
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5593

    
5594
	/* Apply Hostname Substitutions */
5595
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5596

    
5597
	/* Arrays of MAC Address Types, Cases, Delimiters */
5598
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5599
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5600
	$various_mac_cases      = array("U", "L");
5601
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5602

    
5603
	/* Apply MAC Address Substitutions */
5604
	foreach ($various_mac_types as $various_mac_type) {
5605
		foreach ($various_mac_cases as $various_mac_case) {
5606
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5607

    
5608
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5609
				if ($res !== false) {
5610

    
5611
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5612
					if ("$various_mac_case" == "U") {
5613
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5614
					}
5615
					if ("$various_mac_case" == "L") {
5616
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5617
					}
5618

    
5619
					if ("$various_mac_type" == "mac_addr_hex") {
5620
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5621
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5622
						$dhcpclientconf_mac_hex = "";
5623
						$delimiter = "";
5624
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5625
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5626
							$delimiter = ":";
5627
						}
5628
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5629
					}
5630

    
5631
					/* MAC Address Delimiter Substitutions */
5632
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5633

    
5634
					/* Apply MAC Address Substitutions */
5635
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5636
				}
5637
			}
5638
		}
5639
	}
5640

    
5641
	return $dhclientconf;
5642
}
5643

    
5644
function interfaces_group_setup() {
5645
	global $config;
5646

    
5647
	if (!isset($config['ifgroups']['ifgroupentry']) || !is_array($config['ifgroups']['ifgroupentry'])) {
5648
		return;
5649
	}
5650

    
5651
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5652
		interface_group_setup($groupar);
5653
	}
5654

    
5655
	return;
5656
}
5657

    
5658
function interface_group_setup(&$groupname /* The parameter is an array */) {
5659
	global $config;
5660

    
5661
	if (!is_array($groupname)) {
5662
		return;
5663
	}
5664
	$members = explode(" ", $groupname['members']);
5665
	foreach ($members as $ifs) {
5666
		$realif = get_real_interface($ifs);
5667
		if ($realif && does_interface_exist($realif)) {
5668
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5669
		}
5670
	}
5671

    
5672
	return;
5673
}
5674

    
5675
function is_interface_group($if) {
5676
	global $config;
5677

    
5678
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5679
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5680
			if ($groupentry['ifname'] === $if) {
5681
				return true;
5682
			}
5683
		}
5684
	}
5685

    
5686
	return false;
5687
}
5688

    
5689
function interface_group_add_member($interface, $groupname) {
5690
	$interface = get_real_interface($interface);
5691
	if (does_interface_exist($interface)) {
5692
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5693
	}
5694
}
5695

    
5696
/* COMPAT Function */
5697
function convert_friendly_interface_to_real_interface_name($interface) {
5698
	return get_real_interface($interface);
5699
}
5700

    
5701
/* COMPAT Function */
5702
function get_real_wan_interface($interface = "wan") {
5703
	return get_real_interface($interface);
5704
}
5705

    
5706
/* COMPAT Function */
5707
function get_current_wan_address($interface = "wan") {
5708
	return get_interface_ip($interface);
5709
}
5710

    
5711
/*
5712
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5713
 */
5714
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5715
	global $config;
5716

    
5717
	/* XXX: For speed reasons reference directly the interface array */
5718
	init_config_arr(array('interfaces'));
5719
	$ifdescrs = &$config['interfaces'];
5720
	//$ifdescrs = get_configured_interface_list(true);
5721

    
5722
	foreach ($ifdescrs as $if => $ifname) {
5723
		if ($if == $interface || $ifname['if'] == $interface) {
5724
			return $if;
5725
		}
5726

    
5727
		if (get_real_interface($if) == $interface) {
5728
			return $if;
5729
		}
5730

    
5731
		if ($checkparent == false) {
5732
			continue;
5733
		}
5734

    
5735
		$int = get_parent_interface($if, true);
5736
		if (is_array($int)) {
5737
			foreach ($int as $iface) {
5738
				if ($iface == $interface) {
5739
					return $if;
5740
				}
5741
			}
5742
		}
5743
	}
5744

    
5745
	if ($interface == "enc0") {
5746
		return 'IPsec';
5747
	}
5748
}
5749

    
5750
/* attempt to resolve interface to friendly descr */
5751
function convert_friendly_interface_to_friendly_descr($interface) {
5752
	global $config;
5753

    
5754
	switch ($interface) {
5755
		case "l2tp":
5756
			$ifdesc = "L2TP";
5757
			break;
5758
		case "pptp":
5759
			$ifdesc = "PPTP";
5760
			break;
5761
		case "pppoe":
5762
			$ifdesc = "PPPoE";
5763
			break;
5764
		case "openvpn":
5765
			$ifdesc = "OpenVPN";
5766
			break;
5767
		case "lo0":
5768
			$ifdesc = "Loopback";
5769
			break;
5770
		case "enc0":
5771
		case "ipsec":
5772
		case "IPsec":
5773
			$ifdesc = "IPsec";
5774
			break;
5775
		default:
5776
			if (isset($config['interfaces'][$interface])) {
5777
				if (empty($config['interfaces'][$interface]['descr'])) {
5778
					$ifdesc = strtoupper($interface);
5779
				} else {
5780
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5781
				}
5782
				break;
5783
			} else if (substr($interface, 0, 4) == '_vip') {
5784
				if (is_array($config['virtualip']['vip'])) {
5785
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5786
						if ($vip['mode'] == "carp") {
5787
							if ($interface == "_vip{$vip['uniqid']}") {
5788
								$descr = $vip['subnet'];
5789
								$descr .= " (vhid {$vip['vhid']})";
5790
								if (!empty($vip['descr'])) {
5791
									$descr .= " - " .$vip['descr'];
5792
								}
5793
								return $descr;
5794
							}
5795
						}
5796
					}
5797
				}
5798
			} else if (substr($interface, 0, 5) == '_lloc') {
5799
				return get_interface_linklocal($interface);
5800
			} else {
5801
				if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5802
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5803
						if ($ifgen['ifname'] === $interface) {
5804
							return $ifgen['ifname'];
5805
						}
5806
					}
5807
				}
5808

    
5809
				/* if list */
5810
				$ifdescrs = get_configured_interface_with_descr(true);
5811
				foreach ($ifdescrs as $if => $ifname) {
5812
					if ($if == $interface || $ifname == $interface) {
5813
						return $ifname;
5814
					}
5815
				}
5816
			}
5817
			break;
5818
	}
5819

    
5820
	return $ifdesc;
5821
}
5822

    
5823
function convert_real_interface_to_friendly_descr($interface) {
5824

    
5825
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5826

    
5827
	if (!empty($ifdesc)) {
5828
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5829
	}
5830

    
5831
	return $interface;
5832
}
5833

    
5834
/*
5835
 *  get_parent_interface($interface):
5836
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5837
 *				or virtual interface (i.e. vlan)
5838
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5839
 *			-- returns $interface passed in if $interface parent is not found
5840
 *			-- returns empty array if an invalid interface is passed
5841
 *	(Only handles ppps and vlans now.)
5842
 */
5843
function get_parent_interface($interface, $avoidrecurse = false) {
5844
	global $config;
5845

    
5846
	$parents = array();
5847
	//Check that we got a valid interface passed
5848
	$realif = get_real_interface($interface);
5849
	if ($realif == NULL) {
5850
		return $parents;
5851
	}
5852

    
5853
	// If we got a real interface, find it's friendly assigned name
5854
	if ($interface == $realif && $avoidrecurse == false) {
5855
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5856
	}
5857

    
5858
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5859
		$ifcfg = $config['interfaces'][$interface];
5860
		switch ($ifcfg['ipaddr']) {
5861
			case "ppp":
5862
			case "pppoe":
5863
			case "pptp":
5864
			case "l2tp":
5865
				if (empty($parents)) {
5866
					if (is_array($config['ppps']['ppp'])) {
5867
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5868
							if ($ifcfg['if'] == $ppp['if']) {
5869
								$ports = explode(',', $ppp['ports']);
5870
								foreach ($ports as $pid => $parent_if) {
5871
									$parents[$pid] = get_real_interface($parent_if);
5872
								}
5873
								break;
5874
							}
5875
						}
5876
					}
5877
				}
5878
				break;
5879
			case "dhcp":
5880
			case "static":
5881
			default:
5882
				// Handle _vlans
5883
				$vlan = interface_is_vlan($ifcfg['if']);
5884
				if ($vlan != NULL) {
5885
					$parents[0] = $vlan['if'];
5886
				}
5887
				break;
5888
		}
5889
	}
5890

    
5891
	if (empty($parents)) {
5892
		// Handle _vlans not assigned to an interface
5893
		$vlan = interface_is_vlan($realif);
5894
		if ($vlan != NULL) {
5895
			$parents[0] = $vlan['if'];
5896
		}
5897
	}
5898

    
5899
	if (empty($parents)) {
5900
		/* Handle LAGGs. */
5901
		$lagg = interface_is_type($realif, 'lagg');
5902
		if ($lagg != NULL && isset($lagg['members'])) {
5903
			$parents = explode(",", $lagg['members']);
5904
		}
5905
	}
5906

    
5907
	if (empty($parents)) {
5908
		$parents[0] = $realif;
5909
	}
5910

    
5911
	return $parents;
5912
}
5913

    
5914
/*
5915
 *  get_parent_physical_interface($interface):
5916
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5917
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5918
 */
5919
function get_parent_physical_interface($interface) {
5920
	global $config;
5921

    
5922
	$realif = get_parent_interface($interface);
5923

    
5924
	if (substr($realif[0], 0, 4) == "lagg") {
5925
		foreach ($config['laggs']['lagg'] as $lagg) {
5926
			if ($realif[0] == $lagg['laggif']) {
5927
				return explode(",", $lagg['members']);
5928
			}
5929
		}
5930
	} else {
5931
		return $realif;
5932
	}
5933
}
5934

    
5935
function interface_is_wireless_clone($wlif) {
5936
	if (!stristr($wlif, "_wlan")) {
5937
		return false;
5938
	} else {
5939
		return true;
5940
	}
5941
}
5942

    
5943
function interface_get_wireless_base($wlif) {
5944
	if (!stristr($wlif, "_wlan")) {
5945
		return $wlif;
5946
	} else {
5947
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5948
	}
5949
}
5950

    
5951
function interface_get_wireless_clone($wlif) {
5952
	if (!stristr($wlif, "_wlan")) {
5953
		return $wlif . "_wlan0";
5954
	} else {
5955
		return $wlif;
5956
	}
5957
}
5958

    
5959
function interface_list_wireless() {
5960
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5961

    
5962
	$result = array();
5963
	foreach ($portlist as $port) {
5964
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5965
			continue;
5966
		}
5967

    
5968
		$desc = $port . " ( " . get_single_sysctl(
5969
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5970

    
5971
		$result[] = array(
5972
		    "if" => $port,
5973
		    "descr" => $desc
5974
		);
5975
	}
5976

    
5977
	return $result;
5978
}
5979

    
5980
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
5981
	global $config, $g;
5982

    
5983
	$wanif = NULL;
5984

    
5985
	switch ($interface) {
5986
		case "l2tp":
5987
			$wanif = "l2tp";
5988
			break;
5989
		case "pptp":
5990
			$wanif = "pptp";
5991
			break;
5992
		case "pppoe":
5993
			$wanif = "pppoe";
5994
			break;
5995
		case "openvpn":
5996
			$wanif = "openvpn";
5997
			break;
5998
		case "IPsec":
5999
		case "ipsec":
6000
		case "enc0":
6001
			$wanif = "enc0";
6002
			break;
6003
		case "ppp":
6004
			$wanif = "ppp";
6005
			break;
6006
		default:
6007
			if (substr($interface, 0, 4) == '_vip') {
6008
				$wanif = get_configured_vip_interface($interface);
6009
				if (!empty($wanif)) {
6010
					$wanif = get_real_interface($wanif);
6011
				}
6012
				break;
6013
			} else if (substr($interface, 0, 5) == '_lloc') {
6014
				$interface = substr($interface, 5);
6015
			} else if (interface_is_vlan($interface) != NULL ||
6016
			    does_interface_exist($interface, $flush)) {
6017
				/*
6018
				 * If a real interface was already passed simply
6019
				 * pass the real interface back.  This encourages
6020
				 * the usage of this function in more cases so that
6021
				 * we can combine logic for more flexibility.
6022
				 */
6023
				$wanif = $interface;
6024
				break;
6025
			}
6026

    
6027
			if (empty($config['interfaces'][$interface])) {
6028
				break;
6029
			}
6030

    
6031
			$cfg = &$config['interfaces'][$interface];
6032

    
6033
			if ($family == "inet6") {
6034
				switch ($cfg['ipaddrv6']) {
6035
					case "6rd":
6036
					case "6to4":
6037
						$wanif = "{$interface}_stf";
6038
						break;
6039
					case 'pppoe':
6040
					case 'ppp':
6041
					case 'l2tp':
6042
					case 'pptp':
6043
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6044
							$wanif = interface_get_wireless_clone($cfg['if']);
6045
						} else {
6046
							$wanif = $cfg['if'];
6047
						}
6048
						break;
6049
					default:
6050
						switch ($cfg['ipaddr']) {
6051
							case 'pppoe':
6052
							case 'ppp':
6053
							case 'l2tp':
6054
							case 'pptp':
6055
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
6056
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) || 
6057
								    isset($cfg['ipv6usev4iface']) || isset($cfg['slaacusev4iface'])) {
6058
									$wanif = $cfg['if'];
6059
								} else {
6060
									$parents = get_parent_interface($interface);
6061
									if (!empty($parents[0])) {
6062
										$wanif = $parents[0];
6063
									} else {
6064
										$wanif = $cfg['if'];
6065
									}
6066
								}
6067
								break;
6068
							default:
6069
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6070
									$wanif = interface_get_wireless_clone($cfg['if']);
6071
								} else {
6072
									$wanif = $cfg['if'];
6073
								}
6074
								break;
6075
						}
6076
						break;
6077
				}
6078
			} else {
6079
				// Wireless cloned NIC support (FreeBSD 8+)
6080
				// interface name format: $parentnic_wlanparentnic#
6081
				// example: ath0_wlan0
6082
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6083
					$wanif = interface_get_wireless_clone($cfg['if']);
6084
				} else {
6085
					$wanif = $cfg['if'];
6086
				}
6087
			}
6088
			break;
6089
	}
6090

    
6091
	return $wanif;
6092
}
6093

    
6094
/* Guess the physical interface by providing a IP address */
6095
function guess_interface_from_ip($ipaddress) {
6096

    
6097
	if (!is_ipaddr($ipaddress)) {
6098
		return false;
6099
	}
6100

    
6101
	$route = route_get($ipaddress);
6102
	if (empty($route)) {
6103
		return false;
6104
	}
6105

    
6106
	if (!empty($route[0]['interface-name'])) {
6107
		return $route[0]['interface-name'];
6108
	}
6109

    
6110
	return false;
6111
}
6112

    
6113
/*
6114
 * find_ip_interface($ip): return the interface where an ip is defined
6115
 *   (or if $bits is specified, where an IP within the subnet is defined)
6116
 */
6117
function find_ip_interface($ip, $bits = null) {
6118
	if (!is_ipaddr($ip)) {
6119
		return false;
6120
	}
6121

    
6122
	$isv6ip = is_ipaddrv6($ip);
6123

    
6124
	/* if list */
6125
	$ifdescrs = get_configured_interface_list();
6126

    
6127
	foreach ($ifdescrs as $ifdescr => $ifname) {
6128
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
6129
		if (is_null($ifip)) {
6130
			continue;
6131
		}
6132
		if (is_null($bits)) {
6133
			if ($ip == $ifip) {
6134
				$int = get_real_interface($ifname);
6135
				return $int;
6136
			}
6137
		} else {
6138
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
6139
				$int = get_real_interface($ifname);
6140
				return $int;
6141
			}
6142
		}
6143
	}
6144

    
6145
	return false;
6146
}
6147

    
6148
/*
6149
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6150
 *   (or if $bits is specified, where an IP within the subnet is found)
6151
 */
6152
function find_virtual_ip_alias($ip, $bits = null) {
6153
	global $config;
6154

    
6155
	if (!is_array($config['virtualip']['vip'])) {
6156
		return false;
6157
	}
6158
	if (!is_ipaddr($ip)) {
6159
		return false;
6160
	}
6161

    
6162
	$isv6ip = is_ipaddrv6($ip);
6163

    
6164
	foreach ($config['virtualip']['vip'] as $vip) {
6165
		if ($vip['mode'] === "ipalias") {
6166
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
6167
				continue;
6168
			}
6169
			if (is_null($bits)) {
6170
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
6171
					return $vip;
6172
				}
6173
			} else {
6174
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
6175
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
6176
					return $vip;
6177
				}
6178
			}
6179
		}
6180
	}
6181
	return false;
6182
}
6183

    
6184
function link_interface_to_track6($int, $action = "") {
6185
	global $config;
6186

    
6187
	if (empty($int)) {
6188
		return;
6189
	}
6190

    
6191
	if (is_array($config['interfaces'])) {
6192
		$list = array();
6193
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
6194
			if (!isset($ifcfg['enable'])) {
6195
				continue;
6196
			}
6197
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
6198
				if ($action == "update") {
6199
					interface_track6_configure($ifname, $ifcfg);
6200
				} else if ($action == "") {
6201
					$list[$ifname] = $ifcfg;
6202
				}
6203
			}
6204
		}
6205
		return $list;
6206
	}
6207
}
6208

    
6209
function interface_find_child_cfgmtu($realiface) {
6210
	global $config;
6211

    
6212
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6213
	$vlans = link_interface_to_vlans($realiface);
6214
	$qinqs = link_interface_to_qinqs($realiface);
6215
	$bridge = link_interface_to_bridge($realiface);
6216
	if (!empty($interface)) {
6217
		$gifs = link_interface_to_tunnelif($interface, 'gif');
6218
		$gres = link_interface_to_tunnelif($interface, 'gre');
6219
		$vxlans = link_interface_to_tunnelif($interface, 'vxlan');
6220
	} else {
6221
		$gifs = array();
6222
		$gres = array();
6223
		$vxlans = array();
6224
	}
6225

    
6226
	$mtu = 0;
6227
	if (is_array($vlans)) {
6228
		foreach ($vlans as $vlan) {
6229
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
6230
			if (empty($ifass)) {
6231
				continue;
6232
			}
6233
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6234
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6235
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6236
				}
6237
			}
6238
		}
6239
	}
6240
	if (is_array($qinqs)) {
6241
		foreach ($qinqs as $qinq) {
6242
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
6243
			if (empty($ifass)) {
6244
				continue;
6245
			}
6246
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6247
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6248
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6249
				}
6250
			}
6251
		}
6252
	}
6253
	if (is_array($gifs)) {
6254
		foreach ($gifs as $gif) {
6255
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
6256
			if (empty($ifass)) {
6257
				continue;
6258
			}
6259
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6260
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6261
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6262
				}
6263
			}
6264
		}
6265
	}
6266
	if (is_array($gres)) {
6267
		foreach ($gres as $gre) {
6268
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
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($vxlans)) {
6280
		foreach ($vxlans as $vxlan) {
6281
			$ifass = convert_real_interface_to_friendly_interface_name($vxlan['vxlanif']);
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
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
6293
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
6294
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6295
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
6296
		}
6297
	}
6298
	unset($vlans, $bridge, $gifs, $gres, $vxlans, $ifass, $vlan);
6299

    
6300
	return $mtu;
6301
}
6302

    
6303
function link_interface_to_vlans($int, $action = "") {
6304
	global $config;
6305

    
6306
	if (empty($int)) {
6307
		return;
6308
	}
6309

    
6310
	if (is_array($config['vlans']['vlan'])) {
6311
		$ifaces = array();
6312
		foreach ($config['vlans']['vlan'] as $vlan) {
6313
			if ($int == $vlan['if']) {
6314
				if ($action == "update") {
6315
					interfaces_bring_up($int);
6316
				} else {
6317
					$ifaces[$vlan['tag']] = $vlan;
6318
				}
6319
			}
6320
		}
6321
		if (!empty($ifaces)) {
6322
			return $ifaces;
6323
		}
6324
	}
6325
}
6326

    
6327
function link_interface_to_qinqs($int, $action = "") {
6328
	global $config;
6329

    
6330
	if (empty($int)) {
6331
		return;
6332
	}
6333

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

    
6351
function link_interface_to_vips($int, $action = "", $vhid = '') {
6352
	global $config;
6353

    
6354
	$updatevips = false;
6355
	if (is_array($config['virtualip']['vip'])) {
6356
		$result = array();
6357
		foreach ($config['virtualip']['vip'] as $vip) {
6358
			if (substr($vip['interface'], 0, 4) == "_vip") {
6359
				$iface = get_configured_vip_interface($vip['interface']);
6360
			} else {
6361
				$iface = $vip['interface'];
6362
			}
6363
			if ($int != $iface) {
6364
				continue;
6365
			}
6366
			if ($action == "update") {
6367
				$updatevips = true;
6368
			} else {
6369
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
6370
				    substr($vip['interface'], 0, 4) == "_vip") {
6371
					$result[] = $vip;
6372
				}
6373
			}
6374
		}
6375
		if ($updatevips === true) {
6376
			interfaces_vips_configure($int);
6377
		}
6378
		return $result;
6379
	}
6380

    
6381
	return NULL;
6382
}
6383

    
6384
/****f* interfaces/link_interface_to_bridge
6385
 * NAME
6386
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6387
 * INPUTS
6388
 *   $ip
6389
 * RESULT
6390
 *   bridge[0-99]
6391
 ******/
6392
function link_interface_to_bridge($int) {
6393
	global $config;
6394

    
6395
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6396
		foreach ($config['bridges']['bridged'] as $bridge) {
6397
			if (in_array($int, explode(',', $bridge['members']))) {
6398
				return "{$bridge['bridgeif']}";
6399
			}
6400
		}
6401
	}
6402
}
6403

    
6404
function link_interface_to_lagg($int) {
6405
	global $config;
6406

    
6407
	if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
6408
		foreach ($config['laggs']['lagg'] as $lagg) {
6409
			if (in_array($int, explode(',', $lagg['members']))) {
6410
				return "{$lagg['laggif']}";
6411
			}
6412
		}
6413
	}
6414
}
6415

    
6416
function link_interface_to_group($int) {
6417
	global $config;
6418

    
6419
	$result = array();
6420

    
6421
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6422
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6423
			if (in_array($int, explode(" ", $group['members']))) {
6424
				$result[$group['ifname']] = $int;
6425
			}
6426
		}
6427
	}
6428

    
6429
	return $result;
6430
}
6431

    
6432
function link_interface_to_tunnelif($interface, $type) {
6433
	global $config;
6434

    
6435
	if (!in_array($type, array('gre', 'gif', 'vxlan'))) {
6436
		return;
6437
	}
6438

    
6439
	$result = array();
6440

    
6441
	if (is_array($config["{$type}s"][$type])) {
6442
		foreach ($config["{$type}s"][$type] as $tunnel) {
6443
			if ($tunnel['if'] == $interface) {
6444
				$result[] = $tunnel;
6445
			}
6446
		}
6447
	}
6448

    
6449
	return $result;
6450
}
6451

    
6452
/*
6453
 * find_interface_ip($interface): return the interface ip (first found)
6454
 */
6455
function find_interface_ip($interface, $flush = false) {
6456
	global $interface_ip_arr_cache;
6457
	global $interface_sn_arr_cache;
6458

    
6459
	$interface = str_replace("\n", "", $interface);
6460

    
6461
	if (!does_interface_exist($interface)) {
6462
		return;
6463
	}
6464

    
6465
	/* Setup IP cache */
6466
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6467
		if (file_exists("/var/db/${interface}_ip")) {
6468
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6469
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6470
			foreach ($ifaddrs as $ifaddr) {
6471
				list($ip, $mask) = explode("/", $ifaddr);
6472
				if ($ip == $ifip) {
6473
					$interface_ip_arr_cache[$interface] = $ip;
6474
					$interface_sn_arr_cache[$interface] = $mask;
6475
					break;
6476
				}
6477
			}
6478
		}
6479
		if (!isset($interface_ip_arr_cache[$interface])) {
6480
			$ifinfo = pfSense_get_interface_addresses($interface);
6481
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6482
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6483
		}
6484
	}
6485

    
6486
	return $interface_ip_arr_cache[$interface];
6487
}
6488

    
6489
/*
6490
 * find_interface_ipv6($interface): return the interface ip (first found)
6491
 */
6492
function find_interface_ipv6($interface, $flush = false) {
6493
	global $interface_ipv6_arr_cache;
6494
	global $interface_snv6_arr_cache;
6495
	global $config;
6496

    
6497
	$interface = trim($interface);
6498
	$interface = get_real_interface($interface);
6499

    
6500
	if (!does_interface_exist($interface)) {
6501
		return;
6502
	}
6503

    
6504
	/* Setup IP cache */
6505
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6506
		$ifinfo = pfSense_get_interface_addresses($interface);
6507
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6508
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6509
	}
6510

    
6511
	return $interface_ipv6_arr_cache[$interface];
6512
}
6513

    
6514
/*
6515
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6516
 */
6517
function find_interface_ipv6_ll($interface, $flush = false) {
6518
	global $interface_llv6_arr_cache;
6519
	global $config;
6520

    
6521
	$interface = str_replace("\n", "", $interface);
6522

    
6523
	if (!does_interface_exist($interface)) {
6524
		return;
6525
	}
6526

    
6527
	/* Setup IP cache */
6528
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6529
		$ifinfo = pfSense_getall_interface_addresses($interface);
6530
		foreach ($ifinfo as $line) {
6531
			if (strstr($line, ":")) {
6532
				$parts = explode("/", $line);
6533
				if (is_linklocal($parts[0])) {
6534
					$ifinfo['linklocal'] = $parts[0];
6535
				}
6536
			}
6537
		}
6538
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6539
	}
6540
	return $interface_llv6_arr_cache[$interface];
6541
}
6542

    
6543
function find_interface_subnet($interface, $flush = false) {
6544
	global $interface_sn_arr_cache;
6545
	global $interface_ip_arr_cache;
6546

    
6547
	$interface = str_replace("\n", "", $interface);
6548
	if (does_interface_exist($interface) == false) {
6549
		return;
6550
	}
6551

    
6552
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6553
		$ifinfo = pfSense_get_interface_addresses($interface);
6554
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6555
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6556
	}
6557

    
6558
	return $interface_sn_arr_cache[$interface];
6559
}
6560

    
6561
function find_interface_subnetv6($interface, $flush = false) {
6562
	global $interface_snv6_arr_cache;
6563
	global $interface_ipv6_arr_cache;
6564

    
6565
	$interface = str_replace("\n", "", $interface);
6566
	if (does_interface_exist($interface) == false) {
6567
		return;
6568
	}
6569

    
6570
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6571
		$ifinfo = pfSense_get_interface_addresses($interface);
6572
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6573
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6574
	}
6575

    
6576
	return $interface_snv6_arr_cache[$interface];
6577
}
6578

    
6579
function ip_in_interface_alias_subnet($interface, $ipalias) {
6580
	global $config;
6581

    
6582
	if (empty($interface) || !is_ipaddr($ipalias)) {
6583
		return false;
6584
	}
6585
	if (is_array($config['virtualip']['vip'])) {
6586
		foreach ($config['virtualip']['vip'] as $vip) {
6587
			switch ($vip['mode']) {
6588
				case "ipalias":
6589
					if ($vip['interface'] <> $interface) {
6590
						break;
6591
					}
6592
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6593
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6594
						return true;
6595
					}
6596
					break;
6597
			}
6598
		}
6599
	}
6600

    
6601
	return false;
6602
}
6603

    
6604
function get_possible_listen_ips($include_ipv6_link_local=false) {
6605

    
6606
	$interfaces = get_configured_interface_with_descr();
6607
	foreach ($interfaces as $iface => $ifacename) {
6608
		if ($include_ipv6_link_local) {
6609
			/* This is to avoid going though added ll below */
6610
			if (substr($iface, 0, 5) == '_lloc') {
6611
				continue;
6612
			}
6613
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6614
			if (!empty($llip)) {
6615
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6616
			}
6617
		}
6618
	}
6619
	$viplist = get_configured_vip_list();
6620
	foreach ($viplist as $vip => $address) {
6621
		$interfaces[$vip] = $address;
6622
		if (get_vip_descr($address)) {
6623
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6624
		}
6625
	}
6626

    
6627
	$interfaces['lo0'] = 'Localhost';
6628

    
6629
	return $interfaces;
6630
}
6631

    
6632
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6633
	global $config;
6634

    
6635
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6636
	foreach (array('server', 'client') as $mode) {
6637
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6638
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6639
				if (!isset($setting['disable'])) {
6640
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6641
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6642
				}
6643
			}
6644
		}
6645
	}
6646
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
6647
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
6648
			if ($ph1ent['disabled']) {
6649
				continue;
6650
			}
6651
			if (ipsec_vti($ph1ent)) {
6652
				$sourceips_key = "ipsec{$ph1ent['ikeid']}";
6653
				$sourceips[$sourceips_key] = gettext("IPsec VTI") . ": " . htmlspecialchars($ph1ent['descr']);
6654
			}
6655
		}
6656
	}
6657
	return $sourceips;
6658
}
6659

    
6660
function get_interface_ip($interface = "wan") {
6661
	global $config;
6662

    
6663
	if (substr($interface, 0, 4) == '_vip') {
6664
		return get_configured_vip_ipv4($interface);
6665
	} else if (substr($interface, 0, 5) == '_lloc') {
6666
		/* No link-local address for v4. */
6667
		return null;
6668
	}
6669

    
6670
	$realif = get_failover_interface($interface, 'inet');
6671
	if (!$realif) {
6672
		return null;
6673
	}
6674

    
6675
	if (substr($realif, 0, 4) == '_vip') {
6676
		return get_configured_vip_ipv4($realif);
6677
	} else if (substr($realif, 0, 5) == '_lloc') {
6678
		/* No link-local address for v4. */
6679
		return null;
6680
	}
6681

    
6682
	if (is_array($config['interfaces'][$interface]) &&
6683
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6684
		return ($config['interfaces'][$interface]['ipaddr']);
6685
	}
6686

    
6687
	/*
6688
	 * Beaware that find_interface_ip() is our last option, it will
6689
	 * return the first IP it find on interface, not necessarily the
6690
	 * main IP address.
6691
	 */
6692
	$curip = find_interface_ip($realif);
6693
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6694
		return $curip;
6695
	} else {
6696
		return null;
6697
	}
6698
}
6699

    
6700
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6701
	global $config;
6702

    
6703
	if (substr($interface, 0, 4) == '_vip') {
6704
		return get_configured_vip_ipv6($interface);
6705
	} else if (substr($interface, 0, 5) == '_lloc') {
6706
		return get_interface_linklocal($interface);
6707
	}
6708

    
6709
	$realif = get_failover_interface($interface, 'inet6');
6710
	if (!$realif) {
6711
		return null;
6712
	}
6713

    
6714
	if (substr($realif, 0, 4) == '_vip') {
6715
		return get_configured_vip_ipv6($realif);
6716
	} else if (substr($realif, 0, 5) == '_lloc') {
6717
		return get_interface_linklocal($realif);
6718
	}
6719

    
6720
	if (is_array($config['interfaces'][$interface])) {
6721
		switch ($config['interfaces'][$interface]['ipaddr']) {
6722
			case 'pppoe':
6723
			case 'l2tp':
6724
			case 'pptp':
6725
			case 'ppp':
6726
				if (($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') ||
6727
				    ($config['interfaces'][$interface]['ipaddrv6'] == 'slaac')) {
6728
					$realif = get_real_interface($interface, 'inet6', false);
6729
				}
6730
				break;
6731
		}
6732
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6733
			return ($config['interfaces'][$interface]['ipaddrv6']);
6734
		}
6735
	}
6736

    
6737
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6738
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6739
		$curip = get_interface_track6ip($interface);
6740
		if ($curip) {
6741
			return $curip[0];
6742
		}
6743
	}
6744

    
6745
	/*
6746
	 * Beaware that find_interface_ip() is our last option, it will
6747
	 * return the first IP it find on interface, not necessarily the
6748
	 * main IP address.
6749
	 */
6750
	$curip = find_interface_ipv6($realif, $flush);
6751
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6752
		return $curip;
6753
	} else {
6754
		/*
6755
		 * NOTE: On the case when only the prefix is requested,
6756
		 * the communication on WAN will be done over link-local.
6757
		 */
6758
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6759
			$curip = find_interface_ipv6_ll($realif, $flush);
6760
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6761
				return $curip;
6762
			}
6763
		}
6764
	}
6765
	return null;
6766
}
6767

    
6768
function get_interface_linklocal($interface = "wan") {
6769

    
6770
	$realif = get_failover_interface($interface, 'inet6');
6771
	if (!$realif) {
6772
		return null;
6773
	}
6774

    
6775
	if (substr($interface, 0, 4) == '_vip') {
6776
		$realif = get_real_interface($interface);
6777
	} else if (substr($interface, 0, 5) == '_lloc') {
6778
		$realif = get_real_interface(substr($interface, 5));
6779
	}
6780

    
6781
	$curip = find_interface_ipv6_ll($realif);
6782
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6783
		return $curip;
6784
	} else {
6785
		return null;
6786
	}
6787
}
6788

    
6789
function get_interface_track6ip($interface = "wan") {
6790
	$realif = get_real_interface($interface);
6791
	$vips = get_configured_vip_list('inet6');
6792

    
6793
	foreach (pfSense_getall_interface_addresses($realif) as $ifaddr) {
6794
		list($ip, $bits) = explode("/", $ifaddr);
6795
		$ip = text_to_compressed_ip6($ip);
6796
		if (is_ipaddrv6($ip) && !is_linklocal($ip)) {
6797
			if (is_array($vips) && !empty($vips)) {
6798
				foreach ($vips as $vip) {
6799
					if ($ip != text_to_compressed_ip6($vip)) {
6800
						return array($ip, $bits);
6801
					}
6802
				}
6803
			} else {
6804
				return array($ip, $bits);
6805
			}
6806
		}
6807
	}
6808
	return false;
6809
}
6810

    
6811
function get_interface_subnet($interface = "wan") {
6812
	global $config;
6813

    
6814
	if (substr($interface, 0, 4) == '_vip') {
6815
		return (get_configured_vip_subnetv4($interface));
6816
	}
6817

    
6818
	if (is_array($config['interfaces'][$interface]) &&
6819
	    !empty($config['interfaces'][$interface]['subnet']) &&
6820
	    is_ipaddrv4($config['interfaces'][$interface]['ipaddr'])) {
6821
		return ($config['interfaces'][$interface]['subnet']);
6822
	}
6823

    
6824
	$realif = get_real_interface($interface);
6825
	if (!$realif) {
6826
		return (NULL);
6827
	}
6828

    
6829
	$cursn = find_interface_subnet($realif);
6830
	if (!empty($cursn)) {
6831
		return ($cursn);
6832
	}
6833

    
6834
	return (NULL);
6835
}
6836

    
6837
function get_interface_subnetv6($interface = "wan") {
6838
	global $config;
6839

    
6840
	if (substr($interface, 0, 4) == '_vip') {
6841
		return (get_configured_vip_subnetv6($interface));
6842
	} else if (substr($interface, 0, 5) == '_lloc') {
6843
		$interface = substr($interface, 5);
6844
	}
6845

    
6846
	if (is_array($config['interfaces'][$interface]) &&
6847
	    !empty($config['interfaces'][$interface]['subnetv6']) &&
6848
	    is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6849
		return ($config['interfaces'][$interface]['subnetv6']);
6850
	}
6851

    
6852
	$realif = get_real_interface($interface, 'inet6');
6853
	if (!$realif) {
6854
		return (NULL);
6855
	}
6856

    
6857
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6858
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6859
		$curip = get_interface_track6ip($interface);
6860
		if ($curip) {
6861
			return $curip[1];
6862
		}
6863
	}
6864

    
6865
	$cursn = find_interface_subnetv6($realif);
6866
	if (!empty($cursn)) {
6867
		return ($cursn);
6868
	}
6869

    
6870
	return (NULL);
6871
}
6872

    
6873
/* return outside interfaces with a gateway */
6874
function get_interfaces_with_gateway() {
6875
	global $config;
6876

    
6877
	$ints = array();
6878

    
6879
	/* loop interfaces, check config for outbound */
6880
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6881
		switch ($ifname['ipaddr']) {
6882
			case "dhcp":
6883
			case "pppoe":
6884
			case "pptp":
6885
			case "l2tp":
6886
			case "ppp":
6887
				$ints[$ifdescr] = $ifdescr;
6888
				break;
6889
			default:
6890
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6891
				    !empty($ifname['gateway'])) {
6892
					$ints[$ifdescr] = $ifdescr;
6893
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6894
				    !empty($ifname['gateway'])) {
6895
					$ints[$ifdescr] = $ifdescr;
6896
				}
6897

    
6898
				break;
6899
		}
6900
	}
6901
	return $ints;
6902
}
6903

    
6904
/* return true if interface has a gateway */
6905
function interface_has_gateway($friendly) {
6906
	global $config;
6907

    
6908
	if (!empty($config['interfaces'][$friendly])) {
6909
		$ifname = &$config['interfaces'][$friendly];
6910
		switch ($ifname['ipaddr']) {
6911
			case "dhcp":
6912
			case "pppoe":
6913
			case "pptp":
6914
			case "l2tp":
6915
			case "ppp":
6916
				return true;
6917
			break;
6918
			default:
6919
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6920
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6921
					return true;
6922
				}
6923
				$tunnelif = substr($ifname['if'], 0, 3);
6924
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6925
					if (find_interface_ip($ifname['if'])) {
6926
						return true;
6927
					}
6928
				}
6929
				if (!empty($ifname['gateway'])) {
6930
					return true;
6931
				}
6932
			break;
6933
		}
6934
	}
6935

    
6936
	return false;
6937
}
6938

    
6939
/* return true if interface has a gateway */
6940
function interface_has_gatewayv6($friendly) {
6941
	global $config;
6942

    
6943
	if (!empty($config['interfaces'][$friendly])) {
6944
		$ifname = &$config['interfaces'][$friendly];
6945
		switch ($ifname['ipaddrv6']) {
6946
			case "slaac":
6947
			case "dhcp6":
6948
			case "6to4":
6949
			case "6rd":
6950
				return true;
6951
				break;
6952
			default:
6953
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6954
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6955
					return true;
6956
				}
6957
				$tunnelif = substr($ifname['if'], 0, 3);
6958
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6959
					if (find_interface_ipv6($ifname['if'])) {
6960
						return true;
6961
					}
6962
				}
6963
				if (!empty($ifname['gatewayv6'])) {
6964
					return true;
6965
				}
6966
				break;
6967
		}
6968
	}
6969

    
6970
	return false;
6971
}
6972

    
6973
/****f* interfaces/is_altq_capable
6974
 * NAME
6975
 *   is_altq_capable - Test if interface is capable of using ALTQ
6976
 * INPUTS
6977
 *   $int            - string containing interface name
6978
 * RESULT
6979
 *   boolean         - true or false
6980
 ******/
6981

    
6982
function is_altq_capable($int) {
6983
	/* Per:
6984
	 * http://www.freebsd.org/cgi/man.cgi?query=altq&apropos=0&sektion=0&manpath=FreeBSD+11.0-RELEASE&arch=default&format=html
6985
	 * Only the following drivers have ALTQ support
6986
	 * 20150328 - removed wireless drivers - ath, awi, bwn, iwi, ipw, ral, rum, run, wi - for now. redmine #4406
6987
	 */
6988
	$capable = array("ae", "age", "alc", "ale", "an", "aue", "axe", "bce",
6989
			"bfe", "bge", "bnxt", "bridge", "cas", "cpsw", "cxl", "dc", "de",
6990
			"ed", "em", "ep", "epair", "et", "fxp", "gem", "hme", "hn",
6991
			"igb", "ix", "jme", "l2tp", "le", "lem", "msk", "mxge", "my",
6992
			"ndis", "nfe", "ng", "nge", "npe", "nve", "ql", "ovpnc", 
6993
			"ovpns", "ppp", "pppoe", "pptp", "re", "rl", "sf", "sge",
6994
			"sis", "sk", "ste", "stge", "ti", "tun", "txp", "udav",
6995
			"ural", "vge", "vlan", "vmx", "vr", "vte", "vtnet", "xl");
6996

    
6997
	$int_family = remove_ifindex($int);
6998

    
6999
	if (in_array($int_family, $capable)) {
7000
		return true;
7001
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
7002
		return true;
7003
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
7004
		return true;
7005
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
7006
		return true;
7007
	} else {
7008
		return false;
7009
	}
7010
}
7011

    
7012
/****f* interfaces/is_interface_wireless
7013
 * NAME
7014
 *   is_interface_wireless - Returns if an interface is wireless
7015
 * RESULT
7016
 *   $tmp       - Returns if an interface is wireless
7017
 ******/
7018
function is_interface_wireless($interface) {
7019
	global $config, $g;
7020

    
7021
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
7022
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
7023
		if (preg_match($g['wireless_regex'], $interface)) {
7024
			if (isset($config['interfaces'][$friendly])) {
7025
				$config['interfaces'][$friendly]['wireless'] = array();
7026
			}
7027
			return true;
7028
		}
7029
		return false;
7030
	} else {
7031
		return true;
7032
	}
7033
}
7034

    
7035
function get_wireless_modes($interface) {
7036
	/* return wireless modes and channels */
7037
	$wireless_modes = array();
7038

    
7039
	$cloned_interface = get_real_interface($interface);
7040

    
7041
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7042
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
7043
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
7044
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
7045

    
7046
		$interface_channels = "";
7047
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
7048
		$interface_channel_count = count($interface_channels);
7049

    
7050
		$c = 0;
7051
		while ($c < $interface_channel_count) {
7052
			$channel_line = explode(",", $interface_channels["$c"]);
7053
			$wireless_mode = trim($channel_line[0]);
7054
			$wireless_channel = trim($channel_line[1]);
7055
			if (trim($wireless_mode) != "") {
7056
				/* if we only have 11g also set 11b channels */
7057
				if ($wireless_mode == "11g") {
7058
					if (!isset($wireless_modes["11b"])) {
7059
						$wireless_modes["11b"] = array();
7060
					}
7061
				} else if ($wireless_mode == "11g ht") {
7062
					if (!isset($wireless_modes["11b"])) {
7063
						$wireless_modes["11b"] = array();
7064
					}
7065
					if (!isset($wireless_modes["11g"])) {
7066
						$wireless_modes["11g"] = array();
7067
					}
7068
					$wireless_mode = "11ng";
7069
				} else if ($wireless_mode == "11a ht") {
7070
					if (!isset($wireless_modes["11a"])) {
7071
						$wireless_modes["11a"] = array();
7072
					}
7073
					$wireless_mode = "11na";
7074
				}
7075
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
7076
			}
7077
			$c++;
7078
		}
7079
	}
7080
	return($wireless_modes);
7081
}
7082

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

    
7088
		$interface_channels = "";
7089
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7090
		return $interface_channels;
7091
}
7092

    
7093
/* return wireless HT modes */
7094
function get_wireless_ht_modes($interface) {
7095
	$wireless_hts_supported = array(0 => gettext('Auto'));
7096

    
7097
	$cloned_interface = get_real_interface($interface);
7098

    
7099
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7100
		$interface_channels = get_wireless_channels($cloned_interface);
7101

    
7102
		foreach ($interface_channels as $channel) {
7103
			$channel_line = explode(",", $channel);
7104
			$wireless_ht = trim($channel_line[1]);
7105
			if (!empty($wireless_ht)) {
7106
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
7107
			}
7108
		}
7109
	}
7110
	return($wireless_hts_supported);
7111
}
7112

    
7113
/* return wireless HT by channel/standard */
7114
function get_wireless_ht_list($interface) {
7115
	$wireless_hts = array();
7116

    
7117
	$cloned_interface = get_real_interface($interface);
7118

    
7119
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7120
		$interface_channels = get_wireless_channels($cloned_interface);
7121
		$interface_channel_count = count($interface_channels);
7122

    
7123
		$c = 0;
7124
		while ($c < $interface_channel_count) {
7125
			$channel_line = explode(",", $interface_channels["$c"]);
7126
			$wireless_mode = trim($channel_line[0]);
7127
			$wireless_ht = trim($channel_line[1]);
7128
			$wireless_channel = trim($channel_line[2]);
7129
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
7130
				if ($wireless_mode == "11g") {
7131
					if (!isset($wireless_modes["11g"])) {
7132
						$wireless_hts["11g"] = array();
7133
					}
7134
					$wireless_mode = "11ng";
7135
				} elseif ($wireless_mode == "11a") {
7136
					if (!isset($wireless_modes["11a"])) {
7137
						$wireless_hts["11a"] = array();
7138
					}
7139
					$wireless_mode = "11na";
7140
				}
7141
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
7142
			}
7143
			$c++;
7144
		}
7145
	}
7146
	return($wireless_hts);
7147
}
7148

    
7149
/* return channel numbers, frequency, max txpower, and max regulation txpower */
7150
function get_wireless_channel_info($interface) {
7151
	$wireless_channels = array();
7152

    
7153
	$cloned_interface = get_real_interface($interface);
7154

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

    
7160
		$interface_channels = "";
7161
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7162

    
7163
		foreach ($interface_channels as $channel_line) {
7164
			$channel_line = explode(",", $channel_line);
7165
			if (!isset($wireless_channels[$channel_line[0]])) {
7166
				$wireless_channels[$channel_line[0]] = $channel_line;
7167
			}
7168
		}
7169
	}
7170
	return($wireless_channels);
7171
}
7172

    
7173
function set_interface_mtu($interface, $mtu) {
7174

    
7175
	/* LAGG interface must be destroyed and re-created to change MTU */
7176
	if ((substr($interface, 0, 4) == 'lagg') &&
7177
	    (!strstr($interface, "."))) {
7178
		if (isset($config['laggs']['lagg']) &&
7179
		    is_array($config['laggs']['lagg'])) {
7180
			foreach ($config['laggs']['lagg'] as $lagg) {
7181
				if ($lagg['laggif'] == $interface) {
7182
					interface_lagg_configure($lagg);
7183
					break;
7184
				}
7185
			}
7186
		}
7187
	} else {
7188
		pfSense_interface_mtu($interface, $mtu);
7189
		set_ipv6routes_mtu($interface, $mtu);
7190
	}
7191
}
7192

    
7193
/****f* interfaces/get_interface_mtu
7194
 * NAME
7195
 *   get_interface_mtu - Return the mtu of an interface
7196
 * RESULT
7197
 *   $tmp       - Returns the mtu of an interface
7198
 ******/
7199
function get_interface_mtu($interface) {
7200
	$mtu = pfSense_interface_getmtu($interface);
7201
	return $mtu['mtu'];
7202
}
7203

    
7204
function get_interface_mac($interface) {
7205
	$macinfo = pfSense_get_interface_addresses($interface);
7206
	return $macinfo["macaddr"];
7207
}
7208

    
7209
function get_interface_vendor_mac($interface) {
7210
	global $config, $g;
7211

    
7212
	$macinfo = pfSense_get_interface_addresses($interface);
7213
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7214
	    "00:00:00:00:00:00") {
7215
		return ($macinfo["hwaddr"]);
7216
	}
7217

    
7218
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7219
	if (file_exists($hwaddr_file)) {
7220
		$macaddr = trim(file_get_contents($hwaddr_file));
7221
		if (is_macaddr($macaddr)) {
7222
			return ($macaddr);
7223
		}
7224
	} elseif (is_macaddr($macinfo['macaddr'])) {
7225
		/* Save original macaddress to be restored when necessary */
7226
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7227
	}
7228

    
7229
	return (NULL);
7230
}
7231

    
7232
/****f* pfsense-utils/generate_random_mac_address
7233
 * NAME
7234
 *   generate_random_mac - generates a random mac address
7235
 * INPUTS
7236
 *   none
7237
 * RESULT
7238
 *   $mac - a random mac address
7239
 ******/
7240
function generate_random_mac_address() {
7241
	$mac = "02";
7242
	for ($x = 0; $x < 5; $x++) {
7243
		$mac .= ":" . dechex(rand(16, 255));
7244
	}
7245
	return $mac;
7246
}
7247

    
7248
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7249
	global $g;
7250

    
7251
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7252

    
7253
	if (!empty($iface) && !empty($pppif)) {
7254
		$cron_cmd = <<<EOD
7255
#!/bin/sh
7256
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7257
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7258

    
7259
EOD;
7260

    
7261
		@file_put_contents($cron_file, $cron_cmd);
7262
		chmod($cron_file, 0755);
7263
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7264
	} else {
7265
		unlink_if_exists($cron_file);
7266
	}
7267
}
7268

    
7269
function get_interface_default_mtu($type = "ethernet") {
7270
	switch ($type) {
7271
		case "gre":
7272
			return 1476;
7273
			break;
7274
		case "gif":
7275
			return 1280;
7276
			break;
7277
		case "tun":
7278
		case "vlan":
7279
		case "tap":
7280
		case "ethernet":
7281
		default:
7282
			return 1500;
7283
			break;
7284
	}
7285

    
7286
	/* Never reached */
7287
	return 1500;
7288
}
7289

    
7290
function get_vip_descr($ipaddress) {
7291
	global $config;
7292

    
7293
	foreach ($config['virtualip']['vip'] as $vip) {
7294
		if ($vip['subnet'] == $ipaddress) {
7295
			return ($vip['descr']);
7296
		}
7297
	}
7298
	return "";
7299
}
7300

    
7301
function interfaces_staticarp_configure($if) {
7302
	global $config, $g;
7303
	if (isset($config['system']['developerspew'])) {
7304
		$mt = microtime();
7305
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7306
	}
7307

    
7308
	$ifcfg = $config['interfaces'][$if];
7309

    
7310
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
7311
		return 0;
7312
	}
7313

    
7314
	/* Enable staticarp, if enabled */
7315
	if (isset($config['dhcpd'][$if]['staticarp'])) {
7316
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7317
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7318
	} else {
7319
		/*
7320
		 * Interfaces do not have staticarp enabled by default
7321
		 * Let's not disable staticarp on freshly created interfaces
7322
		 */
7323
		if (!platform_booting()) {
7324
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7325
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7326
		}
7327
	}
7328

    
7329
	/* Enable static arp entries */
7330
	if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
7331
		foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
7332
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7333
				continue;
7334
			}
7335
			if (isset($config['dhcpd'][$if]['staticarp']) || isset($arpent['arp_table_static_entry'])) {
7336
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7337
			}
7338
		}
7339
	}
7340

    
7341
	return 0;
7342
}
7343

    
7344
function get_failover_interface($interface, $family = "all") {
7345
	global $config;
7346

    
7347
	/* shortcut to get_real_interface if we find it in the config */
7348
	if (is_array($config['interfaces'][$interface])) {
7349
		return get_real_interface($interface, $family);
7350
	}
7351

    
7352
	/* compare against gateway groups */
7353
	$a_groups = return_gateway_groups_array(true);
7354
	if (is_array($a_groups[$interface])) {
7355
		/* we found a gateway group, fetch the interface or vip */
7356
		if (!empty($a_groups[$interface][0]['vip'])) {
7357
			return $a_groups[$interface][0]['vip'];
7358
		} else {
7359
			return $a_groups[$interface][0]['int'];
7360
		}
7361
	}
7362
	/* fall through to get_real_interface */
7363
	/* XXX: Really needed? */
7364
	return get_real_interface($interface, $family);
7365
}
7366

    
7367
/****f* interfaces/interface_has_dhcp
7368
 * NAME
7369
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7370
 * INPUTS
7371
 *   interface or gateway group name
7372
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7373
 * RESULT
7374
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7375
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7376
 ******/
7377
function interface_has_dhcp($interface, $family = 4) {
7378
	global $config;
7379

    
7380
	if ($config['interfaces'][$interface]) {
7381
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
7382
			return true;
7383
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
7384
			return true;
7385
		} else {
7386
			return false;
7387
		}
7388
	}
7389

    
7390
	if (!is_array($config['gateways']['gateway_group'])) {
7391
		return false;
7392
	}
7393

    
7394
	if ($family == 6) {
7395
		$dhcp_string = "_DHCP6";
7396
	} else {
7397
		$dhcp_string = "_DHCP";
7398
	}
7399

    
7400
	foreach ($config['gateways']['gateway_group'] as $group) {
7401
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7402
			continue;
7403
		}
7404
		foreach ($group['item'] as $item) {
7405
			$item_data = explode("|", $item);
7406
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7407
				return true;
7408
			}
7409
		}
7410
	}
7411

    
7412
	return false;
7413
}
7414

    
7415
function remove_ifindex($ifname) {
7416
	return preg_replace("/[0-9]+$/", "", $ifname);
7417
}
7418

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

    
7422
	$viplist = get_configured_vip_list($family, $type);
7423
	foreach ($viplist as $vip => $address) {
7424
		$interfaces[$vip] = $address;
7425
		if ($type = VIP_CARP) {
7426
			$vip = get_configured_vip($vipid);
7427
			if (isset($vip) && is_array($vip) ) {
7428
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7429
			}
7430
		}
7431
		if (get_vip_descr($address)) {
7432
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
7433
		}
7434
	}
7435
	return $interfaces;
7436
}
7437

    
7438
function return_gateway_groups_array_with_descr() {
7439
	$interfaces = array();
7440
	$grouplist = return_gateway_groups_array();
7441
	foreach ($grouplist as $name => $group) {
7442
		if ($group[0]['vip'] != "") {
7443
			$vipif = $group[0]['vip'];
7444
		} else {
7445
			$vipif = $group[0]['int'];
7446
		}
7447

    
7448
		$interfaces[$name] = "GW Group {$name}";
7449
	}
7450
	return $interfaces;
7451
}
7452

    
7453
function get_serial_ports() {
7454
	$linklist = array();
7455
	if (!is_dir("/var/spool/lock")) {
7456
		mwexec("/bin/mkdir -p /var/spool/lock");
7457
	}
7458
	$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);
7459
	foreach ($serialports as $port) {
7460
		$linklist[$port] = trim($port);
7461
	}
7462
	return $linklist;
7463
}
7464

    
7465
function get_interface_ports() {
7466
	global $config;
7467
	$linklist = array();
7468
	$portlist = get_interface_list();
7469
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7470
		foreach ($config['vlans']['vlan'] as $vlan) {
7471
			$portlist[$vlan['vlanif']] = $vlan;
7472
		}
7473
	}
7474

    
7475
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7476
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7477
			$members = explode(" ", $qinq['members']);
7478
			foreach ($members as $mem) {
7479
				$qentry = $qinq['vlanif'] . "." . $mem;
7480
				$portlist[$qentry] = $qentry;
7481
			}
7482
		}
7483
	}
7484

    
7485
	foreach ($portlist as $ifn => $ifinfo) {
7486
		$string = "";
7487
		if (is_array($ifinfo)) {
7488
			$string .= $ifn;
7489
			if ($ifinfo['mac']) {
7490
				$string .= " ({$ifinfo['mac']})";
7491
			}
7492
			if ($ifinfo['friendly']) {
7493
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7494
			} elseif ($ifinfo['descr']) {
7495
				$string .= " - {$ifinfo['descr']}";
7496
			}
7497
		} else {
7498
			$string .= $ifinfo;
7499
		}
7500

    
7501
		$linklist[$ifn] = $string;
7502
	}
7503
	return $linklist;
7504
}
7505

    
7506
function build_ppps_link_list() {
7507
	global $pconfig;
7508

    
7509
	$linklist = array('list' => array(), 'selected' => array());
7510

    
7511
	if ($pconfig['type'] == 'ppp') {
7512
		$linklist['list'] = get_serial_ports();
7513
	} else {
7514
		$iflist = get_interface_ports();
7515

    
7516
		$viplist = array();
7517
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7518
		foreach ($carplist as $vid => $vaddr) {
7519
			$vip = get_configured_vip($vid);
7520
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7521
		}
7522

    
7523
		$linklist['list'] = array_merge($iflist, $viplist);
7524

    
7525
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7526
		$lagglist = get_lagg_interface_list();
7527
		foreach ($lagglist as $laggif => $lagg) {
7528
			/* LAGG members cannot be assigned */
7529
			$laggmembers = explode(',', $lagg['members']);
7530
			foreach ($laggmembers as $lagm) {
7531
				if (isset($linklist['list'][$lagm])) {
7532
					unset($linklist['list'][$lagm]);
7533
				}
7534
			}
7535
		}
7536
	}
7537

    
7538
	$selected_ports = array();
7539
	if (is_array($pconfig['interfaces'])) {
7540
		$selected_ports = $pconfig['interfaces'];
7541
	} elseif (!empty($pconfig['interfaces'])) {
7542
		$selected_ports = explode(',', $pconfig['interfaces']);
7543
	}
7544
	foreach ($selected_ports as $port) {
7545
		if (isset($linklist['list'][$port])) {
7546
			array_push($linklist['selected'], $port);
7547
		}
7548
	}
7549
	return($linklist);
7550
}
7551

    
7552
function create_interface_list() {
7553
	global $config;
7554

    
7555
	$iflist = array();
7556

    
7557
	// add group interfaces
7558
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7559
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7560
			if (have_ruleint_access($ifgen['ifname'])) {
7561
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7562
			}
7563
		}
7564
	}
7565

    
7566
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7567
		if (have_ruleint_access($ifent)) {
7568
			$iflist[$ifent] = $ifdesc;
7569
		}
7570
	}
7571

    
7572
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
7573
		$iflist['l2tp'] = gettext('L2TP VPN');
7574
	}
7575

    
7576
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
7577
		$iflist['pppoe'] = gettext("PPPoE Server");
7578
	}
7579

    
7580
	// add ipsec interfaces
7581
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
7582
		$iflist["enc0"] = gettext("IPsec");
7583
	}
7584

    
7585
	// add openvpn/tun interfaces
7586
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7587
		$iflist["openvpn"] = gettext("OpenVPN");
7588
	}
7589

    
7590
	return($iflist);
7591
}
7592

    
7593
function is_pseudo_interface($inf, $tap=true) {
7594
	global $config;
7595
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7596
	foreach ($psifs as $pif) {
7597
		if (substr($inf, 0, strlen($pif)) == $pif) {
7598
			if (($pif == 'ovpn') && $tap) {
7599
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7600
				$type = ($m[1] == 'c') ? 'client' : 'server';
7601
				foreach ($config['openvpn']['openvpn-'.$type] as $ovpn) {
7602
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7603
						return false; 	
7604
					} elseif ($ovpn['vpnid'] == $m[2]) {
7605
						return true;
7606
					}
7607
				}
7608
			} else {
7609
				return true;
7610
			}
7611
		}
7612
	}
7613
	return false;
7614
}
7615

    
7616
function is_stf_interface($inf) {
7617
	global $config;
7618

    
7619
	if (is_array($config['interfaces'][$inf]) &&
7620
	    (($config['interfaces'][$inf]['ipaddrv6'] == '6rd') ||
7621
	    ($config['interfaces'][$inf]['ipaddrv6'] == '6to4'))) {
7622
	    return true;
7623
	}
7624

    
7625
	return false;
7626
}
7627

    
7628
?>
(22-22/61)