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", false);
1714
		}
1715
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
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", false);
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'], false);
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
				$ip6 = find_interface_ipv6($realifv6);
2080
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
2081
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
2082
				}
2083
				interface_vip_cleanup($interface, "inet6");
2084
				if ($destroy == true) {
2085
					pfSense_interface_flags($realif, -IFF_UP);
2086
				}
2087
			}
2088
			$track6 = link_interface_to_track6($interface);
2089
			break;
2090
		case "6rd":
2091
		case "6to4":
2092
			$realif = "{$interface}_stf";
2093
			if (does_interface_exist("$realif")) {
2094
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
2095
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
2096
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
2097
					$destroy = true;
2098
				} else {
2099
					/* get_interface_ipv6() returns empty value if interface is being disabled */
2100
					$ip6 = get_interface_ipv6($interface);
2101
					if (is_ipaddrv6($ip6)) {
2102
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2103
					}
2104
				}
2105
				interface_vip_cleanup($interface, "inet6");
2106
				if ($destroy == true) {
2107
					pfSense_interface_flags($realif, -IFF_UP);
2108
				}
2109
			}
2110
			$track6 = link_interface_to_track6($interface);
2111
			break;
2112
		default:
2113
			if (does_interface_exist("$realif")) {
2114
				$ip6 = get_interface_ipv6($interface);
2115
				if (is_ipaddrv6($ip6)) {
2116
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2117
				}
2118
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
2119
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
2120
				}
2121
				interface_vip_cleanup($interface, "inet6");
2122
				if ($destroy == true) {
2123
					pfSense_interface_flags($realif, -IFF_UP);
2124
				}
2125
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2126
			}
2127
			$track6 = link_interface_to_track6($interface);
2128
			break;
2129
	}
2130

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

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

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

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

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

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

    
2169
	return;
2170
}
2171

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

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

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

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

    
2208
	return false;
2209
}
2210

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

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

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

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

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

    
2242
	return false;
2243
}
2244

    
2245
function interfaces_ptpid_next() {
2246

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

    
2252
	return $ptpid;
2253
}
2254

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

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

    
2267
	return NULL;
2268
}
2269

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

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

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

    
2280
	$itemhash = getMPDCRONSettings($pppif);
2281

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2584
EOD;
2585
	}
2586

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

    
2591
EOD;
2592

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

    
2597
EOD;
2598
	}
2599

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

    
2620
EOD;
2621
	}
2622

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

    
2631
EOD;
2632

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

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

    
2643
EOD;
2644
	}
2645

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

    
2651
EOD;
2652
	}
2653

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

    
2658
EOD;
2659
	}
2660

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

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

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

    
2676
EOD;
2677
		}
2678

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

    
2683
EOD;
2684
		}
2685

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

    
2690
EOD;
2691
		}
2692

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

    
2698
EOD;
2699

    
2700

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

    
2705
EOD;
2706
		}
2707

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

    
2723
EOD;
2724
		}
2725

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

    
2732
EOD;
2733
		}
2734

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

    
2739
EOD;
2740
		}
2741

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

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

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

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

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

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

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

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

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

    
2814
EOD;
2815
		}
2816

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

    
2822
EOD;
2823
		}
2824

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

    
2830
EOD;
2831
		}
2832

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

    
2836

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

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

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

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

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

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

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

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

    
2943
	return 1;
2944
}
2945

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

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

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

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

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

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

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

    
2988
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2989
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2990

    
2991
		sleep(1);
2992

    
2993
		/* XXX: Handle an issue with pfsync(4) and carp(4). In a cluster carp will come up before pfsync(4) has updated and so will cause issues
2994
		 * for existing sessions.
2995
		 */
2996
		log_error(gettext("waiting for pfsync..."));
2997
		$i = 0;
2998
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2999
			$i++;
3000
			sleep(1);
3001
		}
3002
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
3003
		log_error(gettext("Configuring CARP settings finalize..."));
3004
	} else {
3005
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
3006
	}
3007

    
3008
	$carplist = get_configured_vip_list('all', VIP_CARP);
3009
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
3010
		set_single_sysctl("net.inet.carp.allow", "1");
3011
	} else {
3012
		set_single_sysctl("net.inet.carp.allow", "0");
3013
	}
3014

    
3015
	if (platform_booting()) {
3016
		unmute_kernel_msgs();
3017
		echo gettext("done.") . "\n";
3018
	}
3019
}
3020

    
3021
function interface_proxyarp_configure($interface = "") {
3022
	global $config, $g;
3023
	if (isset($config['system']['developerspew'])) {
3024
		$mt = microtime();
3025
		echo "interface_proxyarp_configure() being called $mt\n";
3026
	}
3027

    
3028
	/* kill any running choparp */
3029
	if (empty($interface)) {
3030
		killbyname("choparp");
3031
	} else {
3032
		$vipif = get_real_interface($interface);
3033
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
3034
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
3035
		}
3036
	}
3037

    
3038
	$paa = array();
3039
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
3040

    
3041
		/* group by interface */
3042
		foreach ($config['virtualip']['vip'] as $vipent) {
3043
			if ($vipent['mode'] === "proxyarp") {
3044
				if ($vipent['interface']) {
3045
					$proxyif = $vipent['interface'];
3046
				} else {
3047
					$proxyif = "wan";
3048
				}
3049

    
3050
				if (!empty($interface) && $interface != $proxyif) {
3051
					continue;
3052
				}
3053

    
3054
				if (!is_array($paa[$proxyif])) {
3055
					$paa[$proxyif] = array();
3056
				}
3057

    
3058
				$paa[$proxyif][] = $vipent;
3059
			}
3060
		}
3061
	}
3062

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

    
3102
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
3103
	global $g, $config;
3104

    
3105
	if (is_array($config['virtualip']['vip'])) {
3106
		foreach ($config['virtualip']['vip'] as $vip) {
3107

    
3108
			$iface = $vip['interface'];
3109
			if (substr($iface, 0, 4) == "_vip")
3110
				$iface = get_configured_vip_interface($vip['interface']);
3111
			if ($iface != $interface)
3112
				continue;
3113
			if ($type == VIP_CARP) {
3114
				if ($vip['mode'] != "carp")
3115
					continue;
3116
			} elseif ($type == VIP_IPALIAS) {
3117
				if ($vip['mode'] != "ipalias")
3118
					continue;
3119
			} else {
3120
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
3121
					continue;
3122
			}
3123

    
3124
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
3125
				interface_vip_bring_down($vip);
3126
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
3127
				interface_vip_bring_down($vip);
3128
			else if ($inet == "all")
3129
				interface_vip_bring_down($vip);
3130
		}
3131
	}
3132
}
3133

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

    
3173
function interface_ipalias_configure(&$vip) {
3174
	global $config;
3175

    
3176
	$gateway = '';
3177
	if ($vip['mode'] != 'ipalias') {
3178
		return;
3179
	}
3180

    
3181
	$realif = get_real_interface("_vip{$vip['uniqid']}");
3182
	if ($realif != "lo0") {
3183
		$if = convert_real_interface_to_friendly_interface_name($realif);
3184
		if (!isset($config['interfaces'][$if]) ||
3185
		    !isset($config['interfaces'][$if]['enable'])) {
3186
			return;
3187
		}
3188
		if (is_pseudo_interface($realif)) {
3189
			if (is_ipaddrv4($vip['subnet'])) {
3190
				$gateway = get_interface_gateway($if);
3191
			} else {
3192
				$gateway = get_interface_gateway_v6($if);
3193
			}
3194
		}
3195
	}
3196

    
3197
	$af = 'inet';
3198
	if (is_ipaddrv6($vip['subnet'])) {
3199
		$af = 'inet6';
3200
	}
3201
	$iface = $vip['interface'];
3202
	$vhid = '';
3203
	if (substr($vip['interface'], 0, 4) == "_vip") {
3204
		$carpvip = get_configured_vip($vip['interface']);
3205
		$iface = $carpvip['interface'];
3206
		$vhid = "vhid {$carpvip['vhid']}";
3207
	}
3208
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$gateway} {$vhid}");
3209
	unset($iface, $af, $realif, $carpvip, $vhid, $gateway);
3210
}
3211

    
3212
function interface_carp_configure(&$vip, $maintenancemode_only = false) {
3213
	global $config, $g;
3214
	if (isset($config['system']['developerspew'])) {
3215
		$mt = microtime();
3216
		echo "interface_carp_configure() being called $mt\n";
3217
	}
3218

    
3219
	if ($vip['mode'] != "carp") {
3220
		return;
3221
	}
3222

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

    
3237
	$vip_password = $vip['password'];
3238
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3239
	    $vip_password)));
3240
	if ($vip['password'] != "") {
3241
		$password = " pass {$vip_password}";
3242
	}
3243

    
3244
	$advbase = "";
3245
	if (!empty($vip['advbase'])) {
3246
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3247
	}
3248

    
3249
	$carp_maintenancemode = isset(
3250
	    $config["virtualip_carp_maintenancemode"]);
3251
	if ($carp_maintenancemode) {
3252
		$advskew = "advskew 254";
3253
	} else {
3254
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3255
	}
3256

    
3257
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) .
3258
	    " {$advskew} {$advbase} {$password}");
3259

    
3260
	if (!$maintenancemode_only) {
3261
		if (is_ipaddrv4($vip['subnet'])) {
3262
			mwexec("/sbin/ifconfig {$realif} " .
3263
			    escapeshellarg($vip['subnet']) . "/" .
3264
			    escapeshellarg($vip['subnet_bits']) .
3265
			    " alias vhid " . escapeshellarg($vip['vhid']));
3266
		} else if (is_ipaddrv6($vip['subnet'])) {
3267
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3268
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3269
			    escapeshellarg($vip['subnet_bits']) .
3270
			    " alias vhid " . escapeshellarg($vip['vhid']));
3271
		}
3272
	}
3273

    
3274
	return $realif;
3275
}
3276

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

    
3319
	if ($needs_clone == true) {
3320
		/* remove previous instance if it exists */
3321
		if (does_interface_exist($realif)) {
3322
			pfSense_interface_destroy($realif);
3323

    
3324
			/* Invalidate cache */
3325
			get_interface_arr(true);
3326
		}
3327

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

    
3344
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3345
	global $config, $g;
3346

    
3347
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3348
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3349
				 'regdomain', 'regcountry', 'reglocation');
3350

    
3351
	if (!is_interface_wireless($ifcfg['if'])) {
3352
		return;
3353
	}
3354

    
3355
	$baseif = interface_get_wireless_base($ifcfg['if']);
3356

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

    
3384
	// Read or write settings at shared area
3385
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3386
		foreach ($shared_settings as $setting) {
3387
			if ($sync_changes) {
3388
				if (isset($ifcfg['wireless'][$setting])) {
3389
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3390
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3391
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3392
				}
3393
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3394
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3395
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3396
				} else if (isset($ifcfg['wireless'][$setting])) {
3397
					unset($ifcfg['wireless'][$setting]);
3398
				}
3399
			}
3400
		}
3401
	}
3402

    
3403
	// Sync the mode on the clone creation page with the configured mode on the interface
3404
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3405
		foreach ($config['wireless']['clone'] as &$clone) {
3406
			if ($clone['cloneif'] == $ifcfg['if']) {
3407
				if ($sync_changes) {
3408
					$clone['mode'] = $ifcfg['wireless']['mode'];
3409
				} else {
3410
					$ifcfg['wireless']['mode'] = $clone['mode'];
3411
				}
3412
				break;
3413
			}
3414
		}
3415
		unset($clone);
3416
	}
3417
}
3418

    
3419
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3420
	global $config, $g;
3421

    
3422
	/*    open up a shell script that will be used to output the commands.
3423
	 *    since wireless is changing a lot, these series of commands are fragile
3424
	 *    and will sometimes need to be verified by a operator by executing the command
3425
	 *    and returning the output of the command to the developers for inspection.  please
3426
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3427
	 */
3428

    
3429
	// Remove script file
3430
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3431

    
3432
	// Clone wireless nic if needed.
3433
	interface_wireless_clone($if, $wl);
3434

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

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

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

    
3444
	/* set values for /path/program */
3445
	if (file_exists("/usr/local/sbin/hostapd")) {
3446
		$hostapd = "/usr/local/sbin/hostapd";
3447
	} else {
3448
		$hostapd = "/usr/sbin/hostapd";
3449
	}
3450
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3451
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3452
	} else {
3453
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3454
	}
3455
	$ifconfig = "/sbin/ifconfig";
3456
	$sysctl = "/sbin/sysctl";
3457
	$sysctl_args = "-q";
3458
	$killall = "/usr/bin/killall";
3459

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

    
3462
	$wlcmd = array();
3463
	$wl_sysctl = array();
3464
	/* Set a/b/g standard */
3465
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3466
	/* skip mode entirely for "auto" */
3467
	if ($wlcfg['standard'] != "auto") {
3468
		$wlcmd[] = "mode " . escapeshellarg($standard);
3469
	}
3470

    
3471
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3472
	 * to prevent massive packet loss under certain conditions. */
3473
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3474
		$wlcmd[] = "-ampdu";
3475
	}
3476

    
3477
	/* Set ssid */
3478
	if ($wlcfg['ssid']) {
3479
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3480
	}
3481

    
3482
	/* Set 802.11g protection mode */
3483
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3484

    
3485
	/* set wireless channel value */
3486
	if (isset($wlcfg['channel'])) {
3487
		if ($wlcfg['channel'] == "0") {
3488
			$wlcmd[] = "channel any";
3489
		} else {
3490
			if ($wlcfg['channel_width'] != "0") {
3491
				$channel_width = ":" . $wlcfg['channel_width'];
3492
			} else {
3493
				$channel_width = '';
3494
			}
3495
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3496
		}
3497
	}
3498

    
3499
	/* Set antenna diversity value */
3500
	if (isset($wlcfg['diversity'])) {
3501
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3502
	}
3503

    
3504
	/* Set txantenna value */
3505
	if (isset($wlcfg['txantenna'])) {
3506
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3507
	}
3508

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

    
3514
	/* set Distance value */
3515
	if ($wlcfg['distance']) {
3516
		$distance = escapeshellarg($wlcfg['distance']);
3517
	}
3518

    
3519
	/* Set wireless hostap mode */
3520
	if ($wlcfg['mode'] == "hostap") {
3521
		$wlcmd[] = "mediaopt hostap";
3522
	} else {
3523
		$wlcmd[] = "-mediaopt hostap";
3524
	}
3525

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

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

    
3535
	/* handle hide ssid option */
3536
	if (isset($wlcfg['hidessid']['enable'])) {
3537
		$wlcmd[] = "hidessid";
3538
	} else {
3539
		$wlcmd[] = "-hidessid";
3540
	}
3541

    
3542
	/* handle pureg (802.11g) only option */
3543
	if (isset($wlcfg['pureg']['enable'])) {
3544
		$wlcmd[] = "mode 11g pureg";
3545
	} else {
3546
		$wlcmd[] = "-pureg";
3547
	}
3548

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

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

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

    
3570
	/* handle txpower setting */
3571
	// or don't. this has issues at the moment.
3572
	/*
3573
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3574
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3575
	}*/
3576

    
3577
	/* handle wme option */
3578
	if (isset($wlcfg['wme']['enable'])) {
3579
		$wlcmd[] = "wme";
3580
	} else {
3581
		$wlcmd[] = "-wme";
3582
	}
3583

    
3584
	/* Enable wpa if it's configured. No WEP support anymore. */
3585
	if (isset($wlcfg['wpa']['enable'])) {
3586
		$wlcmd[] = "authmode wpa wepmode off ";
3587
	} else {
3588
		$wlcmd[] = "authmode open wepmode off ";
3589
	}
3590

    
3591
	kill_hostapd($if);
3592
	mwexec(kill_wpasupplicant("{$if}"));
3593

    
3594
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3595

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

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

    
3649
EOD;
3650

    
3651
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3652
					$wpa .= <<<EOD
3653
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3654
rsn_preauth=1
3655
rsn_preauth_interfaces={$if}
3656

    
3657
EOD;
3658
				}
3659
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3660
					$wpa .= "ieee8021x=1\n";
3661

    
3662
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3663
						$auth_server_port = "1812";
3664
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3665
							$auth_server_port = intval($wlcfg['auth_server_port']);
3666
						}
3667
						$wpa .= <<<EOD
3668

    
3669
auth_server_addr={$wlcfg['auth_server_addr']}
3670
auth_server_port={$auth_server_port}
3671
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3672

    
3673
EOD;
3674
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3675
							$auth_server_port2 = "1812";
3676
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3677
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3678
							}
3679

    
3680
							$wpa .= <<<EOD
3681
auth_server_addr={$wlcfg['auth_server_addr2']}
3682
auth_server_port={$auth_server_port2}
3683
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3684

    
3685
EOD;
3686
						}
3687
					}
3688
				}
3689

    
3690
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3691
				unset($wpa);
3692
			}
3693
			break;
3694
	}
3695

    
3696
	/*
3697
	 *    all variables are set, lets start up everything
3698
	 */
3699

    
3700
	$baseif = interface_get_wireless_base($if);
3701
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3702
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3703

    
3704
	/* set sysctls for the wireless interface */
3705
	if (!empty($wl_sysctl)) {
3706
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3707
		foreach ($wl_sysctl as $wl_sysctl_line) {
3708
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3709
		}
3710
	}
3711

    
3712
	/* set ack timers according to users preference (if he/she has any) */
3713
	if ($distance) {
3714
		fwrite($fd_set, "# Enable ATH distance settings\n");
3715
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3716
	}
3717

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

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

    
3735
			/* add line to script to restore spoofed mac after running hostapd */
3736
			if ($wl['spoofmac']) {
3737
				$if_curmac = get_interface_mac($if);
3738
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3739
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3740
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3741
				}
3742
			}
3743
		}
3744
	}
3745

    
3746
	fclose($fd_set);
3747

    
3748
	/* Making sure regulatory settings have actually changed
3749
	 * before applying, because changing them requires bringing
3750
	 * down all wireless networks on the interface. */
3751
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3752
	$ifconfig_str = implode($output);
3753
	unset($output);
3754
	$reg_changing = false;
3755

    
3756
	/* special case for the debug country code */
3757
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3758
		$reg_changing = true;
3759
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3760
		$reg_changing = true;
3761
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3762
		$reg_changing = true;
3763
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3764
		$reg_changing = true;
3765
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3766
		$reg_changing = true;
3767
	}
3768

    
3769
	if ($reg_changing) {
3770
		/* set regulatory domain */
3771
		if ($wlcfg['regdomain']) {
3772
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3773
		}
3774

    
3775
		/* set country */
3776
		if ($wlcfg['regcountry']) {
3777
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3778
		}
3779

    
3780
		/* set location */
3781
		if ($wlcfg['reglocation']) {
3782
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3783
		}
3784

    
3785
		$wlregcmd_args = implode(" ", $wlregcmd);
3786

    
3787
		/* build a complete list of the wireless clones for this interface */
3788
		$clone_list = array();
3789
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3790
			$clone_list[] = interface_get_wireless_clone($baseif);
3791
		}
3792
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3793
			foreach ($config['wireless']['clone'] as $clone) {
3794
				if ($clone['if'] == $baseif) {
3795
					$clone_list[] = $clone['cloneif'];
3796
				}
3797
			}
3798
		}
3799

    
3800
		/* find which clones are up and bring them down */
3801
		$clones_up = array();
3802
		foreach ($clone_list as $clone_if) {
3803
			$clone_status = pfSense_get_interface_addresses($clone_if);
3804
			if ($clone_status['status'] == 'up') {
3805
				$clones_up[] = $clone_if;
3806
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3807
			}
3808
		}
3809

    
3810
		/* apply the regulatory settings */
3811
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3812
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3813

    
3814
		/* bring the clones back up that were previously up */
3815
		foreach ($clones_up as $clone_if) {
3816
			interfaces_bring_up($clone_if);
3817

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

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

    
3843
	/* configure wireless */
3844
	$wlcmd_args = implode(" ", $wlcmd);
3845
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3846
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3847
	/* Bring the interface up only after setting up all the other parameters. */
3848
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3849
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3850
	fclose($wlan_setup_log);
3851

    
3852
	unset($wlcmd_args, $wlcmd);
3853

    
3854

    
3855
	sleep(1);
3856
	/* execute hostapd and wpa_supplicant if required in shell */
3857
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3858

    
3859
	return 0;
3860

    
3861
}
3862

    
3863
function kill_hostapd($interface) {
3864
	global $g;
3865

    
3866
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3867
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3868
	}
3869
}
3870

    
3871
function kill_wpasupplicant($interface) {
3872
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3873
}
3874

    
3875
function find_dhclient_process($interface) {
3876
	if ($interface) {
3877
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3878
	} else {
3879
		$pid = 0;
3880
	}
3881

    
3882
	return intval($pid);
3883
}
3884

    
3885
function kill_dhclient_process($interface) {
3886
	if (empty($interface) || !does_interface_exist($interface)) {
3887
		return;
3888
	}
3889

    
3890
	$i = 0;
3891
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3892
		/* 3rd time make it die for sure */
3893
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3894
		posix_kill($pid, $sig);
3895
		sleep(1);
3896
		$i++;
3897
	}
3898
	unset($i);
3899
}
3900

    
3901
function find_dhcp6c_process($interface) {
3902
	global $g;
3903

    
3904
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3905
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3906
	} else {
3907
		return(false);
3908
	}
3909

    
3910
	return intval($pid);
3911
}
3912

    
3913
function kill_dhcp6client_process($interface, $force, $release = false) {
3914
	global $g;
3915

    
3916
	$i = 0;
3917

    
3918
	/*
3919
	Beware of the following: Reason, the interface may be down, but
3920
	dhcp6c may still be running, it just complains it cannot send
3921
	and carries on. Commented out as will stop the call to kill.
3922

    
3923
	if (empty($interface) || !does_interface_exist($interface)) {
3924
		return;
3925
	}
3926
	*/
3927

    
3928
	/*********** Notes on signals for dhcp6c and this function *************
3929

    
3930
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3931
	a release and waiting for the response that never comes.
3932
	So we need to tell it that the interface is down and to just die quickly
3933
	otherwise a new client may launch and we have duplicate proceses.
3934
	In this case use SIGUSR1.
3935

    
3936
	If we want to exit normally obeying the no release flag then use SIGTERM.
3937
	If we want to exit with a release overiding the no release flag then
3938
	use SIGUSR2.
3939

    
3940
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3941
	exit quickly without sending release signals.
3942

    
3943
	If $Force is set to false and $release is also set to false dhcp6c will
3944
	follow the no-release flag.
3945

    
3946
	If $Force is set to false and $release is true then dhcp6c will send a
3947
	release regardless of the no-release flag.
3948
	***********************************************************************/
3949

    
3950
	if ($force == true) {
3951
		$psig=SIGUSR1;
3952
	} else if ($release == false) {
3953
		$psig=SIGTERM;
3954
	} else {
3955
		$psig=SIGUSR2;
3956
	}
3957

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

    
3971
	$pid = find_dhcp6c_process($interface);
3972

    
3973
	if($pid != 0) {
3974
		posix_kill($pid, SIGHUP);
3975
	}
3976
}
3977

    
3978
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3979
	global $g;
3980

    
3981
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3982
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3983

    
3984
	/*
3985
	 * Only run this if the lock does not exist. In theory the lock being
3986
	 * there in this mode means the user has selected dhcp6withoutRA while
3987
	 * a session is active in the other mode.
3988
	 *
3989
	 * It should not happen as the process should have been killed and the
3990
	 * lock deleted.
3991
	 */
3992

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

    
4008
function interface_virtual_create($interface) {
4009
	global $config;
4010

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

    
4061
function interface_vlan_mtu_configured($iface) {
4062
	global $config;
4063

    
4064
	$mtu = 0;
4065
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
4066
		foreach ($config['vlans']['vlan'] as $vlan) {
4067

    
4068
			if ($vlan['vlanif'] != $iface)
4069
				continue;
4070

    
4071
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4072
			$parentinf = convert_real_interface_to_friendly_interface_name($vlan['if']);
4073
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
4074
				/* VLAN MTU */
4075
				$mtu = $config['interfaces'][$assignedport]['mtu'];
4076
			} elseif (!empty($config['interfaces'][$parentinf]['mtu'])) {
4077
				/* Parent MTU */
4078
				$mtu = $config['interfaces'][$parentinf]['mtu'];
4079
			}
4080
		}
4081
	}
4082

    
4083
	return $mtu;
4084
}
4085

    
4086
function interface_mtu_wanted_for_pppoe($realif) {
4087
	global $config;
4088

    
4089
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
4090
		return 0;
4091

    
4092
	$mtu = 0;
4093
	foreach ($config['ppps']['ppp'] as $ppp) {
4094
		if ($ppp['type'] != "pppoe") {
4095
			continue;
4096
		}
4097

    
4098
		$mtus = array();
4099
		if (!empty($ppp['mtu'])) {
4100
			$mtus = explode(',', $ppp['mtu']);
4101
		}
4102
		$ports = explode(',', $ppp['ports']);
4103

    
4104
		foreach ($ports as $pid => $port) {
4105
			$parentifa = get_parent_interface($port);
4106
			$parentif = $parentifa[0];
4107
			if ($parentif != $realif)
4108
				continue;
4109

    
4110
			// there is an MTU configured on the port in question
4111
			if (!empty($mtus[$pid])) {
4112
				$mtu = intval($mtus[$pid]) + 8;
4113
			// or use the MTU configured on the interface ...
4114
			} elseif (is_array($config['interfaces'])) {
4115
				foreach ($config['interfaces'] as $interface) {
4116
					if ($interface['if'] == $ppp['if'] &&
4117
					    !empty($interface['mtu'])) {
4118
						$mtu = intval($interface['mtu']) + 8;
4119
						break;
4120
					}
4121
				}
4122
			}
4123
		}
4124
	}
4125

    
4126
	return $mtu;
4127
}
4128

    
4129
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
4130
	global $config, $g;
4131
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
4132
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
4133

    
4134
	$wancfg = $config['interfaces'][$interface];
4135

    
4136
	if (!isset($wancfg['enable'])) {
4137
		return;
4138
	}
4139

    
4140
	$realif = get_real_interface($interface);
4141
	$realhwif_array = get_parent_interface($interface);
4142
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
4143
	$realhwif = $realhwif_array[0];
4144

    
4145
	$mac_if_cfg = $wancfg;
4146
	if (interface_is_vlan($realif)) {
4147
		$mac_if = convert_real_interface_to_friendly_interface_name(
4148
		    $realhwif);
4149
		if (is_array($config['interfaces'][$mac_if])) {
4150
			$mac_if_cfg = $config['interfaces'][$mac_if];
4151
		} else {
4152
			$mac_if = $interface;
4153
		}
4154
	}
4155

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

    
4179
		/* only bring down the interface when both v4 and v6 are set to NONE */
4180
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4181
			interface_bring_down($interface);
4182
		}
4183
	}
4184

    
4185
	$interface_to_check = $realif;
4186
	if (interface_isppp_type($interface)) {
4187
		$interface_to_check = $realhwif;
4188
	}
4189

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

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

    
4208
	$current_mac = get_interface_mac($realhwif);
4209
	$vendor_mac = get_interface_vendor_mac($realhwif);
4210

    
4211
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4212
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4213

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

    
4233
	/* media */
4234
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4235
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4236
		if ($wancfg['media']) {
4237
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4238
		}
4239
		if ($wancfg['mediaopt']) {
4240
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4241
		}
4242
		mwexec($cmd);
4243
	}
4244

    
4245
	/* Apply hw offloading policies as configured */
4246
	enable_hardware_offloading($interface);
4247

    
4248
	/* invalidate interface/ip/sn cache */
4249
	get_interface_arr(true);
4250
	unset($interface_ip_arr_cache[$realif]);
4251
	unset($interface_sn_arr_cache[$realif]);
4252
	unset($interface_ipv6_arr_cache[$realif]);
4253
	unset($interface_snv6_arr_cache[$realif]);
4254

    
4255
	$tunnelif = substr($realif, 0, 3);
4256

    
4257
	$mtuif = $realif;
4258
	$mtuhwif = $realhwif;
4259

    
4260
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4261
	if (interface_isppp_type($interface)) {
4262
		$mtuif = $realhwif;
4263
		$mtuhwif_array = get_parent_interface($mtuif);
4264
		$mtuhwif = $mtuhwif_array[0];
4265
	}
4266

    
4267
	$wantedmtu = 0;
4268
	if (is_array($config['interfaces'])) {
4269
		foreach ($config['interfaces'] as $tmpinterface) {
4270
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4271
				$wantedmtu = $tmpinterface['mtu'];
4272
				break;
4273
			}
4274
		}
4275
	}
4276

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

    
4299
	/* Set the MTU to 1500 if no explicit MTU configured. */
4300
	if ($wantedmtu == 0) {
4301
		$wantedmtu = 1500; /* Default */
4302
	}
4303

    
4304
	if (interface_is_vlan($mtuif) != NULL) {
4305
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4306
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
4307
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
4308
			if ($wancfg['mtu'] > $parentmtu) {
4309
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4310
			}
4311
		}
4312

    
4313
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4314

    
4315
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4316
			$configuredmtu = $parentmtu;
4317
		if ($configuredmtu != 0)
4318
			$mtu = $configuredmtu;
4319
		else
4320
			$mtu = $wantedmtu;
4321

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

    
4348
	if (does_interface_exist($wancfg['if'])) {
4349
		interfaces_bring_up($wancfg['if']);
4350
	}
4351

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

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

    
4406
	interface_netgraph_needed($interface);
4407

    
4408
	if (!platform_booting()) {
4409
		link_interface_to_vips($interface, "update");
4410

    
4411
		if ($tunnelif != 'gre') {
4412
			unset($gre);
4413
			$gre = link_interface_to_tunnelif($interface, 'gre');
4414
			if (!empty($gre)) {
4415
				array_walk($gre, 'interface_gre_configure');
4416
			}
4417
		}
4418

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

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

    
4435
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4436
			unset($bridgetmp);
4437
			$bridgetmp = link_interface_to_bridge($interface);
4438
			if (!empty($bridgetmp)) {
4439
				interface_bridge_add_member($bridgetmp, $realif);
4440
			}
4441
		}
4442

    
4443
		$grouptmp = link_interface_to_group($interface);
4444
		if (!empty($grouptmp)) {
4445
			array_walk($grouptmp, 'interface_group_add_member');
4446
		}
4447

    
4448
		if ($interface == "lan") {
4449
			/* make new hosts file */
4450
			system_hosts_generate();
4451
		}
4452

    
4453
		if ($reloadall == true) {
4454

    
4455
			/* reconfigure static routes (kernel may have deleted them) */
4456
			system_routing_configure($interface);
4457

    
4458
			/* reload ipsec tunnels */
4459
			send_event("service reload ipsecdns");
4460

    
4461
			if (isset($config['dnsmasq']['enable'])) {
4462
				services_dnsmasq_configure();
4463
			}
4464

    
4465
			if (isset($config['unbound']['enable'])) {
4466
				services_unbound_configure();
4467
			}
4468

    
4469
			/* update dyndns */
4470
			send_event("service reload dyndns {$interface}");
4471

    
4472
			/* reload captive portal */
4473
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4474
				require_once('captiveportal.inc');
4475
			}
4476
			captiveportal_init_rules_byinterface($interface);
4477
		}
4478
	}
4479

    
4480
	if (!empty($wancfg['descr'])) {
4481
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4482
	};
4483

    
4484
	interfaces_staticarp_configure($interface);
4485
	return 0;
4486
}
4487

    
4488
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4489
	global $config, $g;
4490

    
4491
	if (!is_array($wancfg)) {
4492
		return;
4493
	}
4494

    
4495
	if (!isset($wancfg['enable'])) {
4496
		return;
4497
	}
4498

    
4499
	/* If the interface is not configured via another, exit */
4500
	if (empty($wancfg['track6-interface'])) {
4501
		return;
4502
	}
4503

    
4504
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4505
	$realif = get_real_interface($interface);
4506
	$linklocal = find_interface_ipv6_ll($realif, true);
4507
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4508
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4509
	}
4510

    
4511
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4512
	if (!isset($trackcfg['enable'])) {
4513
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4514
		return;
4515
	}
4516

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

    
4547
	if ($linkupevent == false && !platform_booting()) {
4548
		if (!function_exists('services_dhcpd_configure')) {
4549
			require_once("services.inc");
4550
		}
4551

    
4552
		/* restart dns servers (defering dhcpd reload) */
4553
		if (isset($config['unbound']['enable'])) {
4554
			services_unbound_configure(false);
4555
		}
4556
		if (isset($config['dnsmasq']['enable'])) {
4557
			services_dnsmasq_configure(false);
4558
		}
4559

    
4560
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4561
		services_dhcpd_configure("inet6");
4562
	}
4563

    
4564
	return 0;
4565
}
4566

    
4567
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4568
	global $config, $g;
4569
	global $interface_ipv6_arr_cache;
4570
	global $interface_snv6_arr_cache;
4571

    
4572
	if (!is_array($lancfg)) {
4573
		return;
4574
	}
4575

    
4576
	/* If the interface is not configured via another, exit */
4577
	if (empty($lancfg['track6-interface'])) {
4578
		return;
4579
	}
4580

    
4581
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4582
	if (empty($wancfg)) {
4583
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4584
		return;
4585
	}
4586

    
4587
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4588
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4589
		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']));
4590
		return;
4591
	}
4592
	$hexwanv4 = return_hex_ipv4($ip4address);
4593

    
4594
	/* create the long prefix notation for math, save the prefix length */
4595
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4596
	$rd6prefixlen = $rd6prefix[1];
4597
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4598

    
4599
	/* binary presentation of the prefix for all 128 bits. */
4600
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4601

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

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

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

    
4618
	$lanif = get_real_interface($interface);
4619
	$oip = find_interface_ipv6($lanif);
4620
	if (is_ipaddrv6($oip)) {
4621
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4622
	}
4623
	unset($interface_ipv6_arr_cache[$lanif]);
4624
	unset($interface_snv6_arr_cache[$lanif]);
4625
	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));
4626
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4627

    
4628
	return 0;
4629
}
4630

    
4631
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4632
	global $config, $g;
4633
	global $interface_ipv6_arr_cache;
4634
	global $interface_snv6_arr_cache;
4635

    
4636
	if (!is_array($lancfg)) {
4637
		return;
4638
	}
4639

    
4640
	/* If the interface is not configured via another, exit */
4641
	if (empty($lancfg['track6-interface'])) {
4642
		return;
4643
	}
4644

    
4645
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4646
	if (empty($wancfg)) {
4647
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4648
		return;
4649
	}
4650

    
4651
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4652
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4653
		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']));
4654
		return;
4655
	}
4656
	$hexwanv4 = return_hex_ipv4($ip4address);
4657

    
4658
	/* create the long prefix notation for math, save the prefix length */
4659
	$sixto4prefix = "2002::";
4660
	$sixto4prefixlen = 16;
4661
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4662

    
4663
	/* binary presentation of the prefix for all 128 bits. */
4664
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4665

    
4666
	/* just save the left prefix length bits */
4667
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4668
	/* add the v4 address */
4669
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4670
	/* add the custom prefix id */
4671
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4672
	/* fill the rest out with zeros */
4673
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4674

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

    
4678
	$lanif = get_real_interface($interface);
4679
	$oip = find_interface_ipv6($lanif);
4680
	if (is_ipaddrv6($oip)) {
4681
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4682
	}
4683
	unset($interface_ipv6_arr_cache[$lanif]);
4684
	unset($interface_snv6_arr_cache[$lanif]);
4685
	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));
4686
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4687

    
4688
	return 0;
4689
}
4690

    
4691
function interface_6rd_configure($interface = "wan", $wancfg) {
4692
	global $config, $g;
4693

    
4694
	/* because this is a tunnel interface we can only function
4695
	 *	with a public IPv4 address on the interface */
4696

    
4697
	if (!is_array($wancfg)) {
4698
		return;
4699
	}
4700

    
4701
	if (!is_module_loaded('if_stf.ko')) {
4702
		mwexec('/sbin/kldload if_stf.ko');
4703
	}
4704

    
4705
	$wanif = get_real_interface($interface);
4706
	$ip4address = find_interface_ip($wanif);
4707
	if (!is_ipaddrv4($ip4address)) {
4708
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4709
		return false;
4710
	}
4711
	$hexwanv4 = return_hex_ipv4($ip4address);
4712

    
4713
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4714
		$wancfg['prefix-6rd-v4plen'] = 0;
4715
	}
4716

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

    
4730
	/* binary presentation of the prefix for all 128 bits. */
4731
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4732

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

    
4740
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4741
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4742

    
4743

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

    
4767
	/* write out a default router file */
4768
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4769
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4770

    
4771
	$ip4gateway = get_interface_gateway($interface);
4772
	if (is_ipaddrv4($ip4gateway)) {
4773
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4774
	}
4775

    
4776
	/* configure dependent interfaces */
4777
	if (!platform_booting()) {
4778
		link_interface_to_track6($interface, "update");
4779
	}
4780

    
4781
	return 0;
4782
}
4783

    
4784
function interface_6to4_configure($interface = "wan", $wancfg) {
4785
	global $config, $g;
4786

    
4787
	/* because this is a tunnel interface we can only function
4788
	 *	with a public IPv4 address on the interface */
4789

    
4790
	if (!is_array($wancfg)) {
4791
		return;
4792
	}
4793

    
4794
	$wanif = get_real_interface($interface);
4795
	$ip4address = find_interface_ip($wanif);
4796
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4797
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4798
		return false;
4799
	}
4800

    
4801
	/* create the long prefix notation for math, save the prefix length */
4802
	$stfprefixlen = 16;
4803
	$stfprefix = Net_IPv6::uncompress("2002::");
4804
	$stfarr = explode(":", $stfprefix);
4805
	$v4prefixlen = "0";
4806

    
4807
	/* we need the hex form of the interface IPv4 address */
4808
	$ip4arr = explode(".", $ip4address);
4809
	$hexwanv4 = "";
4810
	foreach ($ip4arr as $octet) {
4811
		$hexwanv4 .= sprintf("%02x", $octet);
4812
	}
4813

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

    
4821
	/* binary presentation of the prefix for all 128 bits. */
4822
	$stfprefixbin = "";
4823
	foreach ($stfarr as $element) {
4824
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4825
	}
4826
	/* just save the left prefix length bits */
4827
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4828

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

    
4833
	/* for the local subnet too. */
4834
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4835
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4836

    
4837
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4838
	$stfbrarr = array();
4839
	$stfbrbinarr = array();
4840
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4841
	foreach ($stfbrbinarr as $bin) {
4842
		$stfbrarr[] = dechex(bindec($bin));
4843
	}
4844
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4845

    
4846
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4847
	$stflanarr = array();
4848
	$stflanbinarr = array();
4849
	$stflanbinarr = str_split($stflanbin, 16);
4850
	foreach ($stflanbinarr as $bin) {
4851
		$stflanarr[] = dechex(bindec($bin));
4852
	}
4853
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4854
	$stflanarr[7] = 1;
4855
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4856

    
4857
	/* setup the stf interface */
4858
	if (!is_module_loaded("if_stf")) {
4859
		mwexec("/sbin/kldload if_stf.ko");
4860
	}
4861
	$stfiface = "{$interface}_stf";
4862
	if (does_interface_exist($stfiface)) {
4863
		pfSense_interface_destroy($stfiface);
4864
	}
4865
	$tmpstfiface = pfSense_interface_create("stf");
4866
	pfSense_interface_rename($tmpstfiface, $stfiface);
4867
	pfSense_interface_flags($stfiface, IFF_LINK2);
4868
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4869

    
4870
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4871
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4872
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4873
	} elseif ($parentmtu > 1300) {
4874
		set_interface_mtu($stfiface, $parentmtu - 20);
4875
	}
4876
	if ($g['debug']) {
4877
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4878
	}
4879

    
4880
	/* write out a default router file */
4881
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4882
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4883

    
4884
	$ip4gateway = get_interface_gateway($interface);
4885
	if (is_ipaddrv4($ip4gateway)) {
4886
		route_add_or_change("192.88.99.1", $ip4gateway);
4887
	}
4888

    
4889
	if (!platform_booting()) {
4890
		link_interface_to_track6($interface, "update");
4891
	}
4892

    
4893
	return 0;
4894
}
4895

    
4896
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4897
	global $config, $g;
4898

    
4899
	if (!is_array($wancfg)) {
4900
		return;
4901
	}
4902

    
4903
	$wanif = get_real_interface($interface, "inet6");
4904
	$dhcp6cconf = "";
4905

    
4906
	if (!empty($config['system']['global-v6duid'])) {
4907
		// Write the DUID file
4908
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4909
		    log_error(gettext("Failed to write user DUID file!"));
4910
		}
4911
	}
4912

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

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

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

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

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

    
4954
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4955
			$dhcp6cconf .= "\trequest domain-name;\n";
4956

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

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

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

    
4996
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4997
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4998

    
4999
	/* wide-dhcp6c works for now. */
5000
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
5001
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
5002
		unset($dhcp6cconf);
5003
		return 1;
5004
	}
5005
	unset($dhcp6cconf);
5006

    
5007
	/*************** Script Debug Logging ***************************
5008
	Both dhcp6 scripts now have a logging message built in.
5009
	These logging messages ONLY appear if dhcp6c debug logging is set.
5010
	The logging messages appear in the dhcp section of the logs,
5011
	not in system.
5012

    
5013
	These scripts now also take advantage of the REASON= env vars
5014
	supplied by dhcp6c.
5015
	****************************************************************/
5016

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

    
5066
	unset($dhcp6cscriptwithoutra);
5067
	@chmod(
5068
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
5069
	    0755);
5070

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

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

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

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

    
5172
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
5173
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
5174
		log_error("Killing running rtsold process");
5175
		sleep(2);
5176
	}
5177

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

    
5220
	return 0;
5221
}
5222

    
5223
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5224
	global $g;
5225

    
5226
	$send_options = "";
5227
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5228
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5229
		foreach ($options as $option) {
5230
			$send_options .= "\tsend " . trim($option) . ";\n";
5231
		}
5232
	}
5233

    
5234
	$request_options = "";
5235
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5236
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5237
		foreach ($options as $option) {
5238
			$request_options .= "\trequest " . trim($option) . ";\n";
5239
		}
5240
	}
5241

    
5242
	$information_only = "";
5243
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5244
		$information_only = "\tinformation-only;\n";
5245
	}
5246

    
5247
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5248
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5249
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5250
	}
5251

    
5252
	$interface_statement  = "interface";
5253
	$interface_statement .= " {$wanif}";
5254
	$interface_statement .= " {\n";
5255
	$interface_statement .= "$send_options";
5256
	$interface_statement .= "$request_options";
5257
	$interface_statement .= "$information_only";
5258
	$interface_statement .= "$script";
5259
	$interface_statement .= "};\n";
5260

    
5261
	$id_assoc_statement_address = "";
5262
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5263
		$id_assoc_statement_address .= "id-assoc";
5264
		$id_assoc_statement_address .= " na";
5265
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5266
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5267
		}
5268
		$id_assoc_statement_address .= " { ";
5269

    
5270
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5271
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5272
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5273
			$id_assoc_statement_address .= "\n\taddress";
5274
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5275
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5276
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5277
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5278
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5279
			}
5280
			$id_assoc_statement_address .= ";\n";
5281
		}
5282

    
5283
		$id_assoc_statement_address .= "};\n";
5284
	}
5285

    
5286
	$id_assoc_statement_prefix = "";
5287
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5288
		$id_assoc_statement_prefix .= "id-assoc";
5289
		$id_assoc_statement_prefix .= " pd";
5290
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5291
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5292
		}
5293
		$id_assoc_statement_prefix .= " { ";
5294

    
5295
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5296
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5297
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5298
			$id_assoc_statement_prefix .= "\n\tprefix";
5299
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5300
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5301
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5302
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5303
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5304
			}
5305
			$id_assoc_statement_prefix .= ";";
5306
		}
5307

    
5308
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5309
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5310
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5311
			$id_assoc_statement_prefix .= " {$realif}";
5312
			$id_assoc_statement_prefix .= " {\n";
5313
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5314
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5315
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5316
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5317
			}
5318
			$id_assoc_statement_prefix .= "\t};";
5319
		}
5320

    
5321
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5322
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5323
			$id_assoc_statement_prefix .= "\n";
5324
		}
5325

    
5326
		$id_assoc_statement_prefix .= "};\n";
5327
	}
5328

    
5329
	$authentication_statement = "";
5330
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5331
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5332
		$authentication_statement .= "authentication";
5333
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5334
		$authentication_statement .= " {\n";
5335
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5336
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5337
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5338
		}
5339
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5340
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5341
		}
5342
		$authentication_statement .= "};\n";
5343
	}
5344

    
5345
	$key_info_statement = "";
5346
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5347
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5348
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5349
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5350
		$key_info_statement .= "keyinfo";
5351
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5352
		$key_info_statement .= " {\n";
5353
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5354
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5355
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5356
		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'])) {
5357
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5358
		}
5359
		$key_info_statement .= "};\n";
5360
	}
5361

    
5362
	$dhcp6cconf  = $interface_statement;
5363
	$dhcp6cconf .= $id_assoc_statement_address;
5364
	$dhcp6cconf .= $id_assoc_statement_prefix;
5365
	$dhcp6cconf .= $authentication_statement;
5366
	$dhcp6cconf .= $key_info_statement;
5367

    
5368
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5369

    
5370
	return $dhcp6cconf;
5371
}
5372

    
5373

    
5374
function DHCP6_Config_File_Override($wancfg, $wanif) {
5375

    
5376
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5377

    
5378
	if ($dhcp6cconf === false) {
5379
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5380
		return '';
5381
	} else {
5382
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5383
	}
5384
}
5385

    
5386

    
5387
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5388

    
5389
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5390

    
5391
	return $dhcp6cconf;
5392
}
5393

    
5394

    
5395
function interface_dhcp_configure($interface = "wan") {
5396
	global $config, $g, $vlanprio_values;
5397

    
5398
	$ifcfg = $config['interfaces'][$interface];
5399
	if (empty($ifcfg)) {
5400
		$ifcfg = array();
5401
	}
5402

    
5403
	$dhclientconf_vlantag = "";
5404
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5405
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5406
	}
5407

    
5408
	/* generate dhclient_wan.conf */
5409
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5410
	if (!$fd) {
5411
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5412
		return 1;
5413
	}
5414

    
5415
	if ($ifcfg['dhcphostname']) {
5416
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5417
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5418
	} else {
5419
		$dhclientconf_hostname = "";
5420
	}
5421

    
5422
	$realif = get_real_interface($interface);
5423
	if (empty($realif)) {
5424
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5425
		return 0;
5426
	}
5427
	$dhclientconf = "";
5428

    
5429
	$dhclientconf .= <<<EOD
5430
interface "{$realif}" {
5431
	supersede interface-mtu 0;
5432
	timeout 60;
5433
	retry 15;
5434
	select-timeout 0;
5435
	initial-interval 1;
5436
	{$dhclientconf_vlantag}
5437
	{$dhclientconf_hostname}
5438
	script "/usr/local/sbin/pfSense-dhclient-script";
5439
EOD;
5440

    
5441
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5442
		$dhclientconf .= <<<EOD
5443

    
5444
	reject {$ifcfg['dhcprejectfrom']};
5445
EOD;
5446
	}
5447
	$dhclientconf .= <<<EOD
5448

    
5449
}
5450

    
5451
EOD;
5452

    
5453
	// DHCP Config File Advanced
5454
	if ($ifcfg['adv_dhcp_config_advanced']) {
5455
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5456
	}
5457

    
5458
	if (is_ipaddr($ifcfg['alias-address'])) {
5459
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5460
		$dhclientconf .= <<<EOD
5461
alias {
5462
	interface "{$realif}";
5463
	fixed-address {$ifcfg['alias-address']};
5464
	option subnet-mask {$subnetmask};
5465
}
5466

    
5467
EOD;
5468
	}
5469

    
5470
	// DHCP Config File Override
5471
	if ($ifcfg['adv_dhcp_config_file_override']) {
5472
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5473
	}
5474

    
5475
	fwrite($fd, $dhclientconf);
5476
	fclose($fd);
5477

    
5478
	/* bring wan interface up before starting dhclient */
5479
	if ($realif) {
5480
		interfaces_bring_up($realif);
5481
	}
5482

    
5483
	/* Make sure dhclient is not running */
5484
	kill_dhclient_process($realif);
5485

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

    
5489
	return 0;
5490
}
5491

    
5492
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5493

    
5494
	$hostname = "";
5495
	if ($ifcfg['dhcphostname'] != '') {
5496
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5497
	}
5498

    
5499
	/* DHCP Protocol Timings */
5500
	$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");
5501
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5502
		$pt_variable = "{$Protocol_Timing}";
5503
		${$pt_variable} = "";
5504
		if ($ifcfg[$Protocol_Timing] != "") {
5505
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5506
		}
5507
	}
5508

    
5509
	$send_options = "";
5510
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5511
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5512
		foreach ($options as $option) {
5513
			$send_options .= "\tsend " . trim($option) . ";\n";
5514
		}
5515
	}
5516

    
5517
	$request_options = "";
5518
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5519
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5520
	}
5521

    
5522
	$required_options = "";
5523
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5524
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5525
	}
5526

    
5527
	$option_modifiers = "";
5528
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5529
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5530
		foreach ($modifiers as $modifier) {
5531
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5532
		}
5533
	}
5534

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

    
5559
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5560

    
5561
	return $dhclientconf;
5562
}
5563

    
5564
function DHCP_Config_Option_Split($option_string) {
5565
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5566
	return $matches ? $matches[0] : [];
5567
}
5568

    
5569
function DHCP_Config_File_Override($ifcfg, $realif) {
5570

    
5571
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5572

    
5573
	if ($dhclientconf === false) {
5574
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5575
		return '';
5576
	} else {
5577
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5578
	}
5579
}
5580

    
5581

    
5582
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5583

    
5584
	/* Apply Interface Substitutions */
5585
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5586

    
5587
	/* Apply Hostname Substitutions */
5588
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5589

    
5590
	/* Arrays of MAC Address Types, Cases, Delimiters */
5591
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5592
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5593
	$various_mac_cases      = array("U", "L");
5594
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5595

    
5596
	/* Apply MAC Address Substitutions */
5597
	foreach ($various_mac_types as $various_mac_type) {
5598
		foreach ($various_mac_cases as $various_mac_case) {
5599
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5600

    
5601
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5602
				if ($res !== false) {
5603

    
5604
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5605
					if ("$various_mac_case" == "U") {
5606
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5607
					}
5608
					if ("$various_mac_case" == "L") {
5609
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5610
					}
5611

    
5612
					if ("$various_mac_type" == "mac_addr_hex") {
5613
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5614
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5615
						$dhcpclientconf_mac_hex = "";
5616
						$delimiter = "";
5617
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5618
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5619
							$delimiter = ":";
5620
						}
5621
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5622
					}
5623

    
5624
					/* MAC Address Delimiter Substitutions */
5625
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5626

    
5627
					/* Apply MAC Address Substitutions */
5628
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5629
				}
5630
			}
5631
		}
5632
	}
5633

    
5634
	return $dhclientconf;
5635
}
5636

    
5637
function interfaces_group_setup() {
5638
	global $config;
5639

    
5640
	if (!isset($config['ifgroups']['ifgroupentry']) || !is_array($config['ifgroups']['ifgroupentry'])) {
5641
		return;
5642
	}
5643

    
5644
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5645
		interface_group_setup($groupar);
5646
	}
5647

    
5648
	return;
5649
}
5650

    
5651
function interface_group_setup(&$groupname /* The parameter is an array */) {
5652
	global $config;
5653

    
5654
	if (!is_array($groupname)) {
5655
		return;
5656
	}
5657
	$members = explode(" ", $groupname['members']);
5658
	foreach ($members as $ifs) {
5659
		$realif = get_real_interface($ifs);
5660
		if ($realif && does_interface_exist($realif)) {
5661
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5662
		}
5663
	}
5664

    
5665
	return;
5666
}
5667

    
5668
function is_interface_group($if) {
5669
	global $config;
5670

    
5671
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5672
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5673
			if ($groupentry['ifname'] === $if) {
5674
				return true;
5675
			}
5676
		}
5677
	}
5678

    
5679
	return false;
5680
}
5681

    
5682
function interface_group_add_member($interface, $groupname) {
5683
	$interface = get_real_interface($interface);
5684
	if (does_interface_exist($interface)) {
5685
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5686
	}
5687
}
5688

    
5689
/* COMPAT Function */
5690
function convert_friendly_interface_to_real_interface_name($interface) {
5691
	return get_real_interface($interface);
5692
}
5693

    
5694
/* COMPAT Function */
5695
function get_real_wan_interface($interface = "wan") {
5696
	return get_real_interface($interface);
5697
}
5698

    
5699
/* COMPAT Function */
5700
function get_current_wan_address($interface = "wan") {
5701
	return get_interface_ip($interface);
5702
}
5703

    
5704
/*
5705
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5706
 */
5707
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5708
	global $config;
5709

    
5710
	/* XXX: For speed reasons reference directly the interface array */
5711
	init_config_arr(array('interfaces'));
5712
	$ifdescrs = &$config['interfaces'];
5713
	//$ifdescrs = get_configured_interface_list(true);
5714

    
5715
	foreach ($ifdescrs as $if => $ifname) {
5716
		if ($if == $interface || $ifname['if'] == $interface) {
5717
			return $if;
5718
		}
5719

    
5720
		if (get_real_interface($if) == $interface) {
5721
			return $if;
5722
		}
5723

    
5724
		if ($checkparent == false) {
5725
			continue;
5726
		}
5727

    
5728
		$int = get_parent_interface($if, true);
5729
		if (is_array($int)) {
5730
			foreach ($int as $iface) {
5731
				if ($iface == $interface) {
5732
					return $if;
5733
				}
5734
			}
5735
		}
5736
	}
5737

    
5738
	if ($interface == "enc0") {
5739
		return 'IPsec';
5740
	}
5741
}
5742

    
5743
/* attempt to resolve interface to friendly descr */
5744
function convert_friendly_interface_to_friendly_descr($interface) {
5745
	global $config;
5746

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

    
5802
				/* if list */
5803
				$ifdescrs = get_configured_interface_with_descr(true);
5804
				foreach ($ifdescrs as $if => $ifname) {
5805
					if ($if == $interface || $ifname == $interface) {
5806
						return $ifname;
5807
					}
5808
				}
5809
			}
5810
			break;
5811
	}
5812

    
5813
	return $ifdesc;
5814
}
5815

    
5816
function convert_real_interface_to_friendly_descr($interface) {
5817

    
5818
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5819

    
5820
	if (!empty($ifdesc)) {
5821
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5822
	}
5823

    
5824
	return $interface;
5825
}
5826

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

    
5839
	$parents = array();
5840
	//Check that we got a valid interface passed
5841
	$realif = get_real_interface($interface);
5842
	if ($realif == NULL) {
5843
		return $parents;
5844
	}
5845

    
5846
	// If we got a real interface, find it's friendly assigned name
5847
	if ($interface == $realif && $avoidrecurse == false) {
5848
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5849
	}
5850

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

    
5884
	if (empty($parents)) {
5885
		// Handle _vlans not assigned to an interface
5886
		$vlan = interface_is_vlan($realif);
5887
		if ($vlan != NULL) {
5888
			$parents[0] = $vlan['if'];
5889
		}
5890
	}
5891

    
5892
	if (empty($parents)) {
5893
		/* Handle LAGGs. */
5894
		$lagg = interface_is_type($realif, 'lagg');
5895
		if ($lagg != NULL && isset($lagg['members'])) {
5896
			$parents = explode(",", $lagg['members']);
5897
		}
5898
	}
5899

    
5900
	if (empty($parents)) {
5901
		$parents[0] = $realif;
5902
	}
5903

    
5904
	return $parents;
5905
}
5906

    
5907
/*
5908
 *  get_parent_physical_interface($interface):
5909
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5910
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5911
 */
5912
function get_parent_physical_interface($interface) {
5913
	global $config;
5914

    
5915
	$realif = get_parent_interface($interface);
5916

    
5917
	if (substr($realif[0], 0, 4) == "lagg") {
5918
		foreach ($config['laggs']['lagg'] as $lagg) {
5919
			if ($realif[0] == $lagg['laggif']) {
5920
				return explode(",", $lagg['members']);
5921
			}
5922
		}
5923
	} else {
5924
		return $realif;
5925
	}
5926
}
5927

    
5928
function interface_is_wireless_clone($wlif) {
5929
	if (!stristr($wlif, "_wlan")) {
5930
		return false;
5931
	} else {
5932
		return true;
5933
	}
5934
}
5935

    
5936
function interface_get_wireless_base($wlif) {
5937
	if (!stristr($wlif, "_wlan")) {
5938
		return $wlif;
5939
	} else {
5940
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5941
	}
5942
}
5943

    
5944
function interface_get_wireless_clone($wlif) {
5945
	if (!stristr($wlif, "_wlan")) {
5946
		return $wlif . "_wlan0";
5947
	} else {
5948
		return $wlif;
5949
	}
5950
}
5951

    
5952
function interface_list_wireless() {
5953
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5954

    
5955
	$result = array();
5956
	foreach ($portlist as $port) {
5957
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5958
			continue;
5959
		}
5960

    
5961
		$desc = $port . " ( " . get_single_sysctl(
5962
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5963

    
5964
		$result[] = array(
5965
		    "if" => $port,
5966
		    "descr" => $desc
5967
		);
5968
	}
5969

    
5970
	return $result;
5971
}
5972

    
5973
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
5974
	global $config, $g;
5975

    
5976
	$wanif = NULL;
5977

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

    
6020
			if (empty($config['interfaces'][$interface])) {
6021
				break;
6022
			}
6023

    
6024
			$cfg = &$config['interfaces'][$interface];
6025

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

    
6084
	return $wanif;
6085
}
6086

    
6087
/* Guess the physical interface by providing a IP address */
6088
function guess_interface_from_ip($ipaddress) {
6089

    
6090
	if (!is_ipaddr($ipaddress)) {
6091
		return false;
6092
	}
6093

    
6094
	$route = route_get($ipaddress);
6095
	if (empty($route)) {
6096
		return false;
6097
	}
6098

    
6099
	if (!empty($route[0]['interface-name'])) {
6100
		return $route[0]['interface-name'];
6101
	}
6102

    
6103
	return false;
6104
}
6105

    
6106
/*
6107
 * find_ip_interface($ip): return the interface where an ip is defined
6108
 *   (or if $bits is specified, where an IP within the subnet is defined)
6109
 */
6110
function find_ip_interface($ip, $bits = null) {
6111
	if (!is_ipaddr($ip)) {
6112
		return false;
6113
	}
6114

    
6115
	$isv6ip = is_ipaddrv6($ip);
6116

    
6117
	/* if list */
6118
	$ifdescrs = get_configured_interface_list();
6119

    
6120
	foreach ($ifdescrs as $ifdescr => $ifname) {
6121
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
6122
		if (is_null($ifip)) {
6123
			continue;
6124
		}
6125
		if (is_null($bits)) {
6126
			if ($ip == $ifip) {
6127
				$int = get_real_interface($ifname);
6128
				return $int;
6129
			}
6130
		} else {
6131
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
6132
				$int = get_real_interface($ifname);
6133
				return $int;
6134
			}
6135
		}
6136
	}
6137

    
6138
	return false;
6139
}
6140

    
6141
/*
6142
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6143
 *   (or if $bits is specified, where an IP within the subnet is found)
6144
 */
6145
function find_virtual_ip_alias($ip, $bits = null) {
6146
	global $config;
6147

    
6148
	if (!is_array($config['virtualip']['vip'])) {
6149
		return false;
6150
	}
6151
	if (!is_ipaddr($ip)) {
6152
		return false;
6153
	}
6154

    
6155
	$isv6ip = is_ipaddrv6($ip);
6156

    
6157
	foreach ($config['virtualip']['vip'] as $vip) {
6158
		if ($vip['mode'] === "ipalias") {
6159
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
6160
				continue;
6161
			}
6162
			if (is_null($bits)) {
6163
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
6164
					return $vip;
6165
				}
6166
			} else {
6167
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
6168
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
6169
					return $vip;
6170
				}
6171
			}
6172
		}
6173
	}
6174
	return false;
6175
}
6176

    
6177
function link_interface_to_track6($int, $action = "") {
6178
	global $config;
6179

    
6180
	if (empty($int)) {
6181
		return;
6182
	}
6183

    
6184
	if (is_array($config['interfaces'])) {
6185
		$list = array();
6186
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
6187
			if (!isset($ifcfg['enable'])) {
6188
				continue;
6189
			}
6190
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
6191
				if ($action == "update") {
6192
					interface_track6_configure($ifname, $ifcfg);
6193
				} else if ($action == "") {
6194
					$list[$ifname] = $ifcfg;
6195
				}
6196
			}
6197
		}
6198
		return $list;
6199
	}
6200
}
6201

    
6202
function interface_find_child_cfgmtu($realiface) {
6203
	global $config;
6204

    
6205
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6206
	$vlans = link_interface_to_vlans($realiface);
6207
	$qinqs = link_interface_to_qinqs($realiface);
6208
	$bridge = link_interface_to_bridge($realiface);
6209
	if (!empty($interface)) {
6210
		$gifs = link_interface_to_tunnelif($interface, 'gif');
6211
		$gres = link_interface_to_tunnelif($interface, 'gre');
6212
		$vxlans = link_interface_to_tunnelif($interface, 'vxlan');
6213
	} else {
6214
		$gifs = array();
6215
		$gres = array();
6216
		$vxlans = array();
6217
	}
6218

    
6219
	$mtu = 0;
6220
	if (is_array($vlans)) {
6221
		foreach ($vlans as $vlan) {
6222
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
6223
			if (empty($ifass)) {
6224
				continue;
6225
			}
6226
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6227
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6228
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6229
				}
6230
			}
6231
		}
6232
	}
6233
	if (is_array($qinqs)) {
6234
		foreach ($qinqs as $qinq) {
6235
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
6236
			if (empty($ifass)) {
6237
				continue;
6238
			}
6239
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6240
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6241
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6242
				}
6243
			}
6244
		}
6245
	}
6246
	if (is_array($gifs)) {
6247
		foreach ($gifs as $gif) {
6248
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
6249
			if (empty($ifass)) {
6250
				continue;
6251
			}
6252
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6253
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6254
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6255
				}
6256
			}
6257
		}
6258
	}
6259
	if (is_array($gres)) {
6260
		foreach ($gres as $gre) {
6261
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
6262
			if (empty($ifass)) {
6263
				continue;
6264
			}
6265
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6266
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6267
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6268
				}
6269
			}
6270
		}
6271
	}
6272
	if (is_array($vxlans)) {
6273
		foreach ($vxlans as $vxlan) {
6274
			$ifass = convert_real_interface_to_friendly_interface_name($vxlan['vxlanif']);
6275
			if (empty($ifass)) {
6276
				continue;
6277
			}
6278
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6279
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6280
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6281
				}
6282
			}
6283
		}
6284
	}
6285
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
6286
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
6287
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6288
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
6289
		}
6290
	}
6291
	unset($vlans, $bridge, $gifs, $gres, $vxlans, $ifass, $vlan);
6292

    
6293
	return $mtu;
6294
}
6295

    
6296
function link_interface_to_vlans($int, $action = "") {
6297
	global $config;
6298

    
6299
	if (empty($int)) {
6300
		return;
6301
	}
6302

    
6303
	if (is_array($config['vlans']['vlan'])) {
6304
		$ifaces = array();
6305
		foreach ($config['vlans']['vlan'] as $vlan) {
6306
			if ($int == $vlan['if']) {
6307
				if ($action == "update") {
6308
					interfaces_bring_up($int);
6309
				} else {
6310
					$ifaces[$vlan['tag']] = $vlan;
6311
				}
6312
			}
6313
		}
6314
		if (!empty($ifaces)) {
6315
			return $ifaces;
6316
		}
6317
	}
6318
}
6319

    
6320
function link_interface_to_qinqs($int, $action = "") {
6321
	global $config;
6322

    
6323
	if (empty($int)) {
6324
		return;
6325
	}
6326

    
6327
	if (is_array($config['qinqs']['qinqentry'])) {
6328
		$ifaces = array();
6329
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
6330
			if ($int == $qinq['if']) {
6331
				if ($action == "update") {
6332
					interfaces_bring_up($int);
6333
				} else {
6334
					$ifaces[$qinq['tag']] = $qinq;
6335
				}
6336
			}
6337
		}
6338
		if (!empty($ifaces)) {
6339
			return $ifaces;
6340
		}
6341
	}
6342
}
6343

    
6344
function link_interface_to_vips($int, $action = "", $vhid = '') {
6345
	global $config;
6346

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

    
6374
	return NULL;
6375
}
6376

    
6377
/****f* interfaces/link_interface_to_bridge
6378
 * NAME
6379
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6380
 * INPUTS
6381
 *   $ip
6382
 * RESULT
6383
 *   bridge[0-99]
6384
 ******/
6385
function link_interface_to_bridge($int) {
6386
	global $config;
6387

    
6388
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6389
		foreach ($config['bridges']['bridged'] as $bridge) {
6390
			if (in_array($int, explode(',', $bridge['members']))) {
6391
				return "{$bridge['bridgeif']}";
6392
			}
6393
		}
6394
	}
6395
}
6396

    
6397
function link_interface_to_lagg($int) {
6398
	global $config;
6399

    
6400
	if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
6401
		foreach ($config['laggs']['lagg'] as $lagg) {
6402
			if (in_array($int, explode(',', $lagg['members']))) {
6403
				return "{$lagg['laggif']}";
6404
			}
6405
		}
6406
	}
6407
}
6408

    
6409
function link_interface_to_group($int) {
6410
	global $config;
6411

    
6412
	$result = array();
6413

    
6414
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6415
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6416
			if (in_array($int, explode(" ", $group['members']))) {
6417
				$result[$group['ifname']] = $int;
6418
			}
6419
		}
6420
	}
6421

    
6422
	return $result;
6423
}
6424

    
6425
function link_interface_to_tunnelif($interface, $type) {
6426
	global $config;
6427

    
6428
	if (!in_array($type, array('gre', 'gif', 'vxlan'))) {
6429
		return;
6430
	}
6431

    
6432
	$result = array();
6433

    
6434
	if (is_array($config["{$type}s"][$type])) {
6435
		foreach ($config["{$type}s"][$type] as $tunnel) {
6436
			if ($tunnel['if'] == $interface) {
6437
				$result[] = $tunnel;
6438
			}
6439
		}
6440
	}
6441

    
6442
	return $result;
6443
}
6444

    
6445
/*
6446
 * find_interface_ip($interface): return the interface ip (first found)
6447
 */
6448
function find_interface_ip($interface, $flush = false) {
6449
	global $interface_ip_arr_cache;
6450
	global $interface_sn_arr_cache;
6451

    
6452
	$interface = str_replace("\n", "", $interface);
6453

    
6454
	if (!does_interface_exist($interface)) {
6455
		return;
6456
	}
6457

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

    
6479
	return $interface_ip_arr_cache[$interface];
6480
}
6481

    
6482
/*
6483
 * find_interface_ipv6($interface): return the interface ip (first found)
6484
 */
6485
function find_interface_ipv6($interface, $flush = false) {
6486
	global $interface_ipv6_arr_cache;
6487
	global $interface_snv6_arr_cache;
6488
	global $config;
6489

    
6490
	$interface = trim($interface);
6491
	$interface = get_real_interface($interface);
6492

    
6493
	if (!does_interface_exist($interface)) {
6494
		return;
6495
	}
6496

    
6497
	/* Setup IP cache */
6498
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6499
		$ifinfo = pfSense_get_interface_addresses($interface);
6500
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6501
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6502
	}
6503

    
6504
	return $interface_ipv6_arr_cache[$interface];
6505
}
6506

    
6507
/*
6508
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6509
 */
6510
function find_interface_ipv6_ll($interface, $flush = false) {
6511
	global $interface_llv6_arr_cache;
6512
	global $config;
6513

    
6514
	$interface = str_replace("\n", "", $interface);
6515

    
6516
	if (!does_interface_exist($interface)) {
6517
		return;
6518
	}
6519

    
6520
	/* Setup IP cache */
6521
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6522
		$ifinfo = pfSense_getall_interface_addresses($interface);
6523
		foreach ($ifinfo as $line) {
6524
			if (strstr($line, ":")) {
6525
				$parts = explode("/", $line);
6526
				if (is_linklocal($parts[0])) {
6527
					$ifinfo['linklocal'] = $parts[0];
6528
				}
6529
			}
6530
		}
6531
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6532
	}
6533
	return $interface_llv6_arr_cache[$interface];
6534
}
6535

    
6536
function find_interface_subnet($interface, $flush = false) {
6537
	global $interface_sn_arr_cache;
6538
	global $interface_ip_arr_cache;
6539

    
6540
	$interface = str_replace("\n", "", $interface);
6541
	if (does_interface_exist($interface) == false) {
6542
		return;
6543
	}
6544

    
6545
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6546
		$ifinfo = pfSense_get_interface_addresses($interface);
6547
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6548
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6549
	}
6550

    
6551
	return $interface_sn_arr_cache[$interface];
6552
}
6553

    
6554
function find_interface_subnetv6($interface, $flush = false) {
6555
	global $interface_snv6_arr_cache;
6556
	global $interface_ipv6_arr_cache;
6557

    
6558
	$interface = str_replace("\n", "", $interface);
6559
	if (does_interface_exist($interface) == false) {
6560
		return;
6561
	}
6562

    
6563
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6564
		$ifinfo = pfSense_get_interface_addresses($interface);
6565
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6566
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6567
	}
6568

    
6569
	return $interface_snv6_arr_cache[$interface];
6570
}
6571

    
6572
function ip_in_interface_alias_subnet($interface, $ipalias) {
6573
	global $config;
6574

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

    
6594
	return false;
6595
}
6596

    
6597
function get_possible_listen_ips($include_ipv6_link_local=false) {
6598

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

    
6620
	$interfaces['lo0'] = 'Localhost';
6621

    
6622
	return $interfaces;
6623
}
6624

    
6625
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6626
	global $config;
6627

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

    
6653
function get_interface_ip($interface = "wan") {
6654
	global $config;
6655

    
6656
	if (substr($interface, 0, 4) == '_vip') {
6657
		return get_configured_vip_ipv4($interface);
6658
	} else if (substr($interface, 0, 5) == '_lloc') {
6659
		/* No link-local address for v4. */
6660
		return null;
6661
	}
6662

    
6663
	$realif = get_failover_interface($interface, 'inet');
6664
	if (!$realif) {
6665
		return null;
6666
	}
6667

    
6668
	if (substr($realif, 0, 4) == '_vip') {
6669
		return get_configured_vip_ipv4($realif);
6670
	} else if (substr($realif, 0, 5) == '_lloc') {
6671
		/* No link-local address for v4. */
6672
		return null;
6673
	}
6674

    
6675
	if (is_array($config['interfaces'][$interface]) &&
6676
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6677
		return ($config['interfaces'][$interface]['ipaddr']);
6678
	}
6679

    
6680
	/*
6681
	 * Beaware that find_interface_ip() is our last option, it will
6682
	 * return the first IP it find on interface, not necessarily the
6683
	 * main IP address.
6684
	 */
6685
	$curip = find_interface_ip($realif);
6686
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6687
		return $curip;
6688
	} else {
6689
		return null;
6690
	}
6691
}
6692

    
6693
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6694
	global $config;
6695

    
6696
	if (substr($interface, 0, 4) == '_vip') {
6697
		return get_configured_vip_ipv6($interface);
6698
	} else if (substr($interface, 0, 5) == '_lloc') {
6699
		return get_interface_linklocal($interface);
6700
	}
6701

    
6702
	$realif = get_failover_interface($interface, 'inet6');
6703
	if (!$realif) {
6704
		return null;
6705
	}
6706

    
6707
	if (substr($realif, 0, 4) == '_vip') {
6708
		return get_configured_vip_ipv6($realif);
6709
	} else if (substr($realif, 0, 5) == '_lloc') {
6710
		return get_interface_linklocal($realif);
6711
	}
6712

    
6713
	if (is_array($config['interfaces'][$interface])) {
6714
		switch ($config['interfaces'][$interface]['ipaddr']) {
6715
			case 'pppoe':
6716
			case 'l2tp':
6717
			case 'pptp':
6718
			case 'ppp':
6719
				if (($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') ||
6720
				    ($config['interfaces'][$interface]['ipaddrv6'] == 'slaac')) {
6721
					$realif = get_real_interface($interface, 'inet6', false);
6722
				}
6723
				break;
6724
		}
6725
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6726
			return ($config['interfaces'][$interface]['ipaddrv6']);
6727
		}
6728
	}
6729

    
6730
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6731
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6732
		$curip = get_interface_track6ip($interface);
6733
		if ($curip) {
6734
			return $curip[0];
6735
		}
6736
	}
6737

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

    
6761
function get_interface_linklocal($interface = "wan") {
6762

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

    
6768
	if (substr($interface, 0, 4) == '_vip') {
6769
		$realif = get_real_interface($interface);
6770
	} else if (substr($interface, 0, 5) == '_lloc') {
6771
		$realif = get_real_interface(substr($interface, 5));
6772
	}
6773

    
6774
	$curip = find_interface_ipv6_ll($realif);
6775
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6776
		return $curip;
6777
	} else {
6778
		return null;
6779
	}
6780
}
6781

    
6782
function get_interface_track6ip($interface = "wan") {
6783
	$realif = get_real_interface($interface);
6784
	$vips = get_configured_vip_list('inet6');
6785

    
6786
	foreach (pfSense_getall_interface_addresses($realif) as $ifaddr) {
6787
		list($ip, $bits) = explode("/", $ifaddr);
6788
		$ip = text_to_compressed_ip6($ip);
6789
		if (is_ipaddrv6($ip) && !is_linklocal($ip)) {
6790
			foreach ($vips as $vip) {
6791
				if ($ip != text_to_compressed_ip6($vip)) {
6792
					return array($ip, $bits);
6793
				}
6794
			}
6795
		}
6796
	}
6797
	return false;
6798
}
6799

    
6800
function get_interface_subnet($interface = "wan") {
6801
	global $config;
6802

    
6803
	if (substr($interface, 0, 4) == '_vip') {
6804
		return (get_configured_vip_subnetv4($interface));
6805
	}
6806

    
6807
	if (is_array($config['interfaces'][$interface]) &&
6808
	    !empty($config['interfaces'][$interface]['subnet']) &&
6809
	    is_ipaddrv4($config['interfaces'][$interface]['ipaddr'])) {
6810
		return ($config['interfaces'][$interface]['subnet']);
6811
	}
6812

    
6813
	$realif = get_real_interface($interface);
6814
	if (!$realif) {
6815
		return (NULL);
6816
	}
6817

    
6818
	$cursn = find_interface_subnet($realif);
6819
	if (!empty($cursn)) {
6820
		return ($cursn);
6821
	}
6822

    
6823
	return (NULL);
6824
}
6825

    
6826
function get_interface_subnetv6($interface = "wan") {
6827
	global $config;
6828

    
6829
	if (substr($interface, 0, 4) == '_vip') {
6830
		return (get_configured_vip_subnetv6($interface));
6831
	} else if (substr($interface, 0, 5) == '_lloc') {
6832
		$interface = substr($interface, 5);
6833
	}
6834

    
6835
	if (is_array($config['interfaces'][$interface]) &&
6836
	    !empty($config['interfaces'][$interface]['subnetv6']) &&
6837
	    is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6838
		return ($config['interfaces'][$interface]['subnetv6']);
6839
	}
6840

    
6841
	$realif = get_real_interface($interface, 'inet6');
6842
	if (!$realif) {
6843
		return (NULL);
6844
	}
6845

    
6846
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6847
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6848
		$curip = get_interface_track6ip($interface);
6849
		if ($curip) {
6850
			return $curip[1];
6851
		}
6852
	}
6853

    
6854
	$cursn = find_interface_subnetv6($realif);
6855
	if (!empty($cursn)) {
6856
		return ($cursn);
6857
	}
6858

    
6859
	return (NULL);
6860
}
6861

    
6862
/* return outside interfaces with a gateway */
6863
function get_interfaces_with_gateway() {
6864
	global $config;
6865

    
6866
	$ints = array();
6867

    
6868
	/* loop interfaces, check config for outbound */
6869
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6870
		switch ($ifname['ipaddr']) {
6871
			case "dhcp":
6872
			case "pppoe":
6873
			case "pptp":
6874
			case "l2tp":
6875
			case "ppp":
6876
				$ints[$ifdescr] = $ifdescr;
6877
				break;
6878
			default:
6879
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6880
				    !empty($ifname['gateway'])) {
6881
					$ints[$ifdescr] = $ifdescr;
6882
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6883
				    !empty($ifname['gateway'])) {
6884
					$ints[$ifdescr] = $ifdescr;
6885
				}
6886

    
6887
				break;
6888
		}
6889
	}
6890
	return $ints;
6891
}
6892

    
6893
/* return true if interface has a gateway */
6894
function interface_has_gateway($friendly) {
6895
	global $config;
6896

    
6897
	if (!empty($config['interfaces'][$friendly])) {
6898
		$ifname = &$config['interfaces'][$friendly];
6899
		switch ($ifname['ipaddr']) {
6900
			case "dhcp":
6901
			case "pppoe":
6902
			case "pptp":
6903
			case "l2tp":
6904
			case "ppp":
6905
				return true;
6906
			break;
6907
			default:
6908
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6909
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6910
					return true;
6911
				}
6912
				$tunnelif = substr($ifname['if'], 0, 3);
6913
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6914
					if (find_interface_ip($ifname['if'])) {
6915
						return true;
6916
					}
6917
				}
6918
				if (!empty($ifname['gateway'])) {
6919
					return true;
6920
				}
6921
			break;
6922
		}
6923
	}
6924

    
6925
	return false;
6926
}
6927

    
6928
/* return true if interface has a gateway */
6929
function interface_has_gatewayv6($friendly) {
6930
	global $config;
6931

    
6932
	if (!empty($config['interfaces'][$friendly])) {
6933
		$ifname = &$config['interfaces'][$friendly];
6934
		switch ($ifname['ipaddrv6']) {
6935
			case "slaac":
6936
			case "dhcp6":
6937
			case "6to4":
6938
			case "6rd":
6939
				return true;
6940
				break;
6941
			default:
6942
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6943
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6944
					return true;
6945
				}
6946
				$tunnelif = substr($ifname['if'], 0, 3);
6947
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6948
					if (find_interface_ipv6($ifname['if'])) {
6949
						return true;
6950
					}
6951
				}
6952
				if (!empty($ifname['gatewayv6'])) {
6953
					return true;
6954
				}
6955
				break;
6956
		}
6957
	}
6958

    
6959
	return false;
6960
}
6961

    
6962
/****f* interfaces/is_altq_capable
6963
 * NAME
6964
 *   is_altq_capable - Test if interface is capable of using ALTQ
6965
 * INPUTS
6966
 *   $int            - string containing interface name
6967
 * RESULT
6968
 *   boolean         - true or false
6969
 ******/
6970

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

    
6986
	$int_family = remove_ifindex($int);
6987

    
6988
	if (in_array($int_family, $capable)) {
6989
		return true;
6990
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6991
		return true;
6992
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6993
		return true;
6994
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6995
		return true;
6996
	} else {
6997
		return false;
6998
	}
6999
}
7000

    
7001
/****f* interfaces/is_interface_wireless
7002
 * NAME
7003
 *   is_interface_wireless - Returns if an interface is wireless
7004
 * RESULT
7005
 *   $tmp       - Returns if an interface is wireless
7006
 ******/
7007
function is_interface_wireless($interface) {
7008
	global $config, $g;
7009

    
7010
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
7011
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
7012
		if (preg_match($g['wireless_regex'], $interface)) {
7013
			if (isset($config['interfaces'][$friendly])) {
7014
				$config['interfaces'][$friendly]['wireless'] = array();
7015
			}
7016
			return true;
7017
		}
7018
		return false;
7019
	} else {
7020
		return true;
7021
	}
7022
}
7023

    
7024
function get_wireless_modes($interface) {
7025
	/* return wireless modes and channels */
7026
	$wireless_modes = array();
7027

    
7028
	$cloned_interface = get_real_interface($interface);
7029

    
7030
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7031
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
7032
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
7033
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
7034

    
7035
		$interface_channels = "";
7036
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
7037
		$interface_channel_count = count($interface_channels);
7038

    
7039
		$c = 0;
7040
		while ($c < $interface_channel_count) {
7041
			$channel_line = explode(",", $interface_channels["$c"]);
7042
			$wireless_mode = trim($channel_line[0]);
7043
			$wireless_channel = trim($channel_line[1]);
7044
			if (trim($wireless_mode) != "") {
7045
				/* if we only have 11g also set 11b channels */
7046
				if ($wireless_mode == "11g") {
7047
					if (!isset($wireless_modes["11b"])) {
7048
						$wireless_modes["11b"] = array();
7049
					}
7050
				} else if ($wireless_mode == "11g ht") {
7051
					if (!isset($wireless_modes["11b"])) {
7052
						$wireless_modes["11b"] = array();
7053
					}
7054
					if (!isset($wireless_modes["11g"])) {
7055
						$wireless_modes["11g"] = array();
7056
					}
7057
					$wireless_mode = "11ng";
7058
				} else if ($wireless_mode == "11a ht") {
7059
					if (!isset($wireless_modes["11a"])) {
7060
						$wireless_modes["11a"] = array();
7061
					}
7062
					$wireless_mode = "11na";
7063
				}
7064
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
7065
			}
7066
			$c++;
7067
		}
7068
	}
7069
	return($wireless_modes);
7070
}
7071

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

    
7077
		$interface_channels = "";
7078
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7079
		return $interface_channels;
7080
}
7081

    
7082
/* return wireless HT modes */
7083
function get_wireless_ht_modes($interface) {
7084
	$wireless_hts_supported = array(0 => gettext('Auto'));
7085

    
7086
	$cloned_interface = get_real_interface($interface);
7087

    
7088
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7089
		$interface_channels = get_wireless_channels($cloned_interface);
7090

    
7091
		foreach ($interface_channels as $channel) {
7092
			$channel_line = explode(",", $channel);
7093
			$wireless_ht = trim($channel_line[1]);
7094
			if (!empty($wireless_ht)) {
7095
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
7096
			}
7097
		}
7098
	}
7099
	return($wireless_hts_supported);
7100
}
7101

    
7102
/* return wireless HT by channel/standard */
7103
function get_wireless_ht_list($interface) {
7104
	$wireless_hts = array();
7105

    
7106
	$cloned_interface = get_real_interface($interface);
7107

    
7108
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7109
		$interface_channels = get_wireless_channels($cloned_interface);
7110
		$interface_channel_count = count($interface_channels);
7111

    
7112
		$c = 0;
7113
		while ($c < $interface_channel_count) {
7114
			$channel_line = explode(",", $interface_channels["$c"]);
7115
			$wireless_mode = trim($channel_line[0]);
7116
			$wireless_ht = trim($channel_line[1]);
7117
			$wireless_channel = trim($channel_line[2]);
7118
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
7119
				if ($wireless_mode == "11g") {
7120
					if (!isset($wireless_modes["11g"])) {
7121
						$wireless_hts["11g"] = array();
7122
					}
7123
					$wireless_mode = "11ng";
7124
				} elseif ($wireless_mode == "11a") {
7125
					if (!isset($wireless_modes["11a"])) {
7126
						$wireless_hts["11a"] = array();
7127
					}
7128
					$wireless_mode = "11na";
7129
				}
7130
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
7131
			}
7132
			$c++;
7133
		}
7134
	}
7135
	return($wireless_hts);
7136
}
7137

    
7138
/* return channel numbers, frequency, max txpower, and max regulation txpower */
7139
function get_wireless_channel_info($interface) {
7140
	$wireless_channels = array();
7141

    
7142
	$cloned_interface = get_real_interface($interface);
7143

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

    
7149
		$interface_channels = "";
7150
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7151

    
7152
		foreach ($interface_channels as $channel_line) {
7153
			$channel_line = explode(",", $channel_line);
7154
			if (!isset($wireless_channels[$channel_line[0]])) {
7155
				$wireless_channels[$channel_line[0]] = $channel_line;
7156
			}
7157
		}
7158
	}
7159
	return($wireless_channels);
7160
}
7161

    
7162
function set_interface_mtu($interface, $mtu) {
7163

    
7164
	/* LAGG interface must be destroyed and re-created to change MTU */
7165
	if ((substr($interface, 0, 4) == 'lagg') &&
7166
	    (!strstr($interface, "."))) {
7167
		if (isset($config['laggs']['lagg']) &&
7168
		    is_array($config['laggs']['lagg'])) {
7169
			foreach ($config['laggs']['lagg'] as $lagg) {
7170
				if ($lagg['laggif'] == $interface) {
7171
					interface_lagg_configure($lagg);
7172
					break;
7173
				}
7174
			}
7175
		}
7176
	} else {
7177
		pfSense_interface_mtu($interface, $mtu);
7178
		set_ipv6routes_mtu($interface, $mtu);
7179
	}
7180
}
7181

    
7182
/****f* interfaces/get_interface_mtu
7183
 * NAME
7184
 *   get_interface_mtu - Return the mtu of an interface
7185
 * RESULT
7186
 *   $tmp       - Returns the mtu of an interface
7187
 ******/
7188
function get_interface_mtu($interface) {
7189
	$mtu = pfSense_interface_getmtu($interface);
7190
	return $mtu['mtu'];
7191
}
7192

    
7193
function get_interface_mac($interface) {
7194
	$macinfo = pfSense_get_interface_addresses($interface);
7195
	return $macinfo["macaddr"];
7196
}
7197

    
7198
function get_interface_vendor_mac($interface) {
7199
	global $config, $g;
7200

    
7201
	$macinfo = pfSense_get_interface_addresses($interface);
7202
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7203
	    "00:00:00:00:00:00") {
7204
		return ($macinfo["hwaddr"]);
7205
	}
7206

    
7207
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7208
	if (file_exists($hwaddr_file)) {
7209
		$macaddr = trim(file_get_contents($hwaddr_file));
7210
		if (is_macaddr($macaddr)) {
7211
			return ($macaddr);
7212
		}
7213
	} elseif (is_macaddr($macinfo['macaddr'])) {
7214
		/* Save original macaddress to be restored when necessary */
7215
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7216
	}
7217

    
7218
	return (NULL);
7219
}
7220

    
7221
/****f* pfsense-utils/generate_random_mac_address
7222
 * NAME
7223
 *   generate_random_mac - generates a random mac address
7224
 * INPUTS
7225
 *   none
7226
 * RESULT
7227
 *   $mac - a random mac address
7228
 ******/
7229
function generate_random_mac_address() {
7230
	$mac = "02";
7231
	for ($x = 0; $x < 5; $x++) {
7232
		$mac .= ":" . dechex(rand(16, 255));
7233
	}
7234
	return $mac;
7235
}
7236

    
7237
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7238
	global $g;
7239

    
7240
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7241

    
7242
	if (!empty($iface) && !empty($pppif)) {
7243
		$cron_cmd = <<<EOD
7244
#!/bin/sh
7245
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7246
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7247

    
7248
EOD;
7249

    
7250
		@file_put_contents($cron_file, $cron_cmd);
7251
		chmod($cron_file, 0755);
7252
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7253
	} else {
7254
		unlink_if_exists($cron_file);
7255
	}
7256
}
7257

    
7258
function get_interface_default_mtu($type = "ethernet") {
7259
	switch ($type) {
7260
		case "gre":
7261
			return 1476;
7262
			break;
7263
		case "gif":
7264
			return 1280;
7265
			break;
7266
		case "tun":
7267
		case "vlan":
7268
		case "tap":
7269
		case "ethernet":
7270
		default:
7271
			return 1500;
7272
			break;
7273
	}
7274

    
7275
	/* Never reached */
7276
	return 1500;
7277
}
7278

    
7279
function get_vip_descr($ipaddress) {
7280
	global $config;
7281

    
7282
	foreach ($config['virtualip']['vip'] as $vip) {
7283
		if ($vip['subnet'] == $ipaddress) {
7284
			return ($vip['descr']);
7285
		}
7286
	}
7287
	return "";
7288
}
7289

    
7290
function interfaces_staticarp_configure($if) {
7291
	global $config, $g;
7292
	if (isset($config['system']['developerspew'])) {
7293
		$mt = microtime();
7294
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7295
	}
7296

    
7297
	$ifcfg = $config['interfaces'][$if];
7298

    
7299
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
7300
		return 0;
7301
	}
7302

    
7303
	/* Enable staticarp, if enabled */
7304
	if (isset($config['dhcpd'][$if]['staticarp'])) {
7305
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7306
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7307
	} else {
7308
		/*
7309
		 * Interfaces do not have staticarp enabled by default
7310
		 * Let's not disable staticarp on freshly created interfaces
7311
		 */
7312
		if (!platform_booting()) {
7313
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7314
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7315
		}
7316
	}
7317

    
7318
	/* Enable static arp entries */
7319
	if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
7320
		foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
7321
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7322
				continue;
7323
			}
7324
			if (isset($config['dhcpd'][$if]['staticarp']) || isset($arpent['arp_table_static_entry'])) {
7325
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7326
			}
7327
		}
7328
	}
7329

    
7330
	return 0;
7331
}
7332

    
7333
function get_failover_interface($interface, $family = "all") {
7334
	global $config;
7335

    
7336
	/* shortcut to get_real_interface if we find it in the config */
7337
	if (is_array($config['interfaces'][$interface])) {
7338
		return get_real_interface($interface, $family);
7339
	}
7340

    
7341
	/* compare against gateway groups */
7342
	$a_groups = return_gateway_groups_array(true);
7343
	if (is_array($a_groups[$interface])) {
7344
		/* we found a gateway group, fetch the interface or vip */
7345
		if (!empty($a_groups[$interface][0]['vip'])) {
7346
			return $a_groups[$interface][0]['vip'];
7347
		} else {
7348
			return $a_groups[$interface][0]['int'];
7349
		}
7350
	}
7351
	/* fall through to get_real_interface */
7352
	/* XXX: Really needed? */
7353
	return get_real_interface($interface, $family);
7354
}
7355

    
7356
/****f* interfaces/interface_has_dhcp
7357
 * NAME
7358
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7359
 * INPUTS
7360
 *   interface or gateway group name
7361
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7362
 * RESULT
7363
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7364
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7365
 ******/
7366
function interface_has_dhcp($interface, $family = 4) {
7367
	global $config;
7368

    
7369
	if ($config['interfaces'][$interface]) {
7370
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
7371
			return true;
7372
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
7373
			return true;
7374
		} else {
7375
			return false;
7376
		}
7377
	}
7378

    
7379
	if (!is_array($config['gateways']['gateway_group'])) {
7380
		return false;
7381
	}
7382

    
7383
	if ($family == 6) {
7384
		$dhcp_string = "_DHCP6";
7385
	} else {
7386
		$dhcp_string = "_DHCP";
7387
	}
7388

    
7389
	foreach ($config['gateways']['gateway_group'] as $group) {
7390
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7391
			continue;
7392
		}
7393
		foreach ($group['item'] as $item) {
7394
			$item_data = explode("|", $item);
7395
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7396
				return true;
7397
			}
7398
		}
7399
	}
7400

    
7401
	return false;
7402
}
7403

    
7404
function remove_ifindex($ifname) {
7405
	return preg_replace("/[0-9]+$/", "", $ifname);
7406
}
7407

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

    
7411
	$viplist = get_configured_vip_list($family, $type);
7412
	foreach ($viplist as $vip => $address) {
7413
		$interfaces[$vip] = $address;
7414
		if ($type = VIP_CARP) {
7415
			$vip = get_configured_vip($vipid);
7416
			if (isset($vip) && is_array($vip) ) {
7417
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7418
			}
7419
		}
7420
		if (get_vip_descr($address)) {
7421
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
7422
		}
7423
	}
7424
	return $interfaces;
7425
}
7426

    
7427
function return_gateway_groups_array_with_descr() {
7428
	$interfaces = array();
7429
	$grouplist = return_gateway_groups_array();
7430
	foreach ($grouplist as $name => $group) {
7431
		if ($group[0]['vip'] != "") {
7432
			$vipif = $group[0]['vip'];
7433
		} else {
7434
			$vipif = $group[0]['int'];
7435
		}
7436

    
7437
		$interfaces[$name] = "GW Group {$name}";
7438
	}
7439
	return $interfaces;
7440
}
7441

    
7442
function get_serial_ports() {
7443
	$linklist = array();
7444
	if (!is_dir("/var/spool/lock")) {
7445
		mwexec("/bin/mkdir -p /var/spool/lock");
7446
	}
7447
	$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);
7448
	foreach ($serialports as $port) {
7449
		$linklist[$port] = trim($port);
7450
	}
7451
	return $linklist;
7452
}
7453

    
7454
function get_interface_ports() {
7455
	global $config;
7456
	$linklist = array();
7457
	$portlist = get_interface_list();
7458
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7459
		foreach ($config['vlans']['vlan'] as $vlan) {
7460
			$portlist[$vlan['vlanif']] = $vlan;
7461
		}
7462
	}
7463

    
7464
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7465
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7466
			$members = explode(" ", $qinq['members']);
7467
			foreach ($members as $mem) {
7468
				$qentry = $qinq['vlanif'] . "." . $mem;
7469
				$portlist[$qentry] = $qentry;
7470
			}
7471
		}
7472
	}
7473

    
7474
	foreach ($portlist as $ifn => $ifinfo) {
7475
		$string = "";
7476
		if (is_array($ifinfo)) {
7477
			$string .= $ifn;
7478
			if ($ifinfo['mac']) {
7479
				$string .= " ({$ifinfo['mac']})";
7480
			}
7481
			if ($ifinfo['friendly']) {
7482
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7483
			} elseif ($ifinfo['descr']) {
7484
				$string .= " - {$ifinfo['descr']}";
7485
			}
7486
		} else {
7487
			$string .= $ifinfo;
7488
		}
7489

    
7490
		$linklist[$ifn] = $string;
7491
	}
7492
	return $linklist;
7493
}
7494

    
7495
function build_ppps_link_list() {
7496
	global $pconfig;
7497

    
7498
	$linklist = array('list' => array(), 'selected' => array());
7499

    
7500
	if ($pconfig['type'] == 'ppp') {
7501
		$linklist['list'] = get_serial_ports();
7502
	} else {
7503
		$iflist = get_interface_ports();
7504

    
7505
		$viplist = array();
7506
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7507
		foreach ($carplist as $vid => $vaddr) {
7508
			$vip = get_configured_vip($vid);
7509
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7510
		}
7511

    
7512
		$linklist['list'] = array_merge($iflist, $viplist);
7513

    
7514
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7515
		$lagglist = get_lagg_interface_list();
7516
		foreach ($lagglist as $laggif => $lagg) {
7517
			/* LAGG members cannot be assigned */
7518
			$laggmembers = explode(',', $lagg['members']);
7519
			foreach ($laggmembers as $lagm) {
7520
				if (isset($linklist['list'][$lagm])) {
7521
					unset($linklist['list'][$lagm]);
7522
				}
7523
			}
7524
		}
7525
	}
7526

    
7527
	$selected_ports = array();
7528
	if (is_array($pconfig['interfaces'])) {
7529
		$selected_ports = $pconfig['interfaces'];
7530
	} elseif (!empty($pconfig['interfaces'])) {
7531
		$selected_ports = explode(',', $pconfig['interfaces']);
7532
	}
7533
	foreach ($selected_ports as $port) {
7534
		if (isset($linklist['list'][$port])) {
7535
			array_push($linklist['selected'], $port);
7536
		}
7537
	}
7538
	return($linklist);
7539
}
7540

    
7541
function create_interface_list() {
7542
	global $config;
7543

    
7544
	$iflist = array();
7545

    
7546
	// add group interfaces
7547
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7548
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7549
			if (have_ruleint_access($ifgen['ifname'])) {
7550
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7551
			}
7552
		}
7553
	}
7554

    
7555
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7556
		if (have_ruleint_access($ifent)) {
7557
			$iflist[$ifent] = $ifdesc;
7558
		}
7559
	}
7560

    
7561
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
7562
		$iflist['l2tp'] = gettext('L2TP VPN');
7563
	}
7564

    
7565
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
7566
		$iflist['pppoe'] = gettext("PPPoE Server");
7567
	}
7568

    
7569
	// add ipsec interfaces
7570
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
7571
		$iflist["enc0"] = gettext("IPsec");
7572
	}
7573

    
7574
	// add openvpn/tun interfaces
7575
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7576
		$iflist["openvpn"] = gettext("OpenVPN");
7577
	}
7578

    
7579
	return($iflist);
7580
}
7581

    
7582
function is_pseudo_interface($inf, $tap=true) {
7583
	global $config;
7584
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7585
	foreach ($psifs as $pif) {
7586
		if (substr($inf, 0, strlen($pif)) == $pif) {
7587
			if (($pif == 'ovpn') && $tap) {
7588
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7589
				$type = ($m[1] == 'c') ? 'client' : 'server';
7590
				foreach ($config['openvpn']['openvpn-'.$type] as $ovpn) {
7591
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7592
						return false; 	
7593
					} elseif ($ovpn['vpnid'] == $m[2]) {
7594
						return true;
7595
					}
7596
				}
7597
			} else {
7598
				return true;
7599
			}
7600
		}
7601
	}
7602
	return false;
7603
}
7604

    
7605
function is_stf_interface($inf) {
7606
	global $config;
7607

    
7608
	if (is_array($config['interfaces'][$inf]) &&
7609
	    (($config['interfaces'][$inf]['ipaddrv6'] == '6rd') ||
7610
	    ($config['interfaces'][$inf]['ipaddrv6'] == '6to4'))) {
7611
	    return true;
7612
	}
7613

    
7614
	return false;
7615
}
7616

    
7617
?>
(22-22/61)