Project

General

Profile

Download (218 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($realif = "") {
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($realif) && $realif != $vlan['vlanif']) {
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
	return $vlanif;
500
}
501

    
502
function interface_qinq_configure(&$qinq, $fd = NULL, $flush = true) {
503
	global $config, $g;
504

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

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

    
517
	if (!does_interface_exist($qinqif)) {
518
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
519
		return;
520
	}
521

    
522
	$vlanif = interface_vlan_configure($qinq);
523
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
524
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
525
		return;
526
	}
527

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

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

    
553
	/* invalidate interface cache */
554
	if ($flush) {
555
		get_interface_arr(true);
556
	}
557

    
558
	if (interface_is_vlan($qinqif) == NULL) {
559
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
560
	}
561

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

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

    
591
	return $vlanif;
592
}
593

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

    
606
	/* Invalidate cache */
607
	get_interface_arr(true);
608

    
609
	if (platform_booting()) {
610
		echo gettext("done.") . "\n";
611
	}
612
}
613

    
614
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr, $flush = true) {
615
	global $config, $g;
616

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

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

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

    
643
	/* invalidate interface cache */
644
	if ($flush) {
645
		get_interface_arr(true);
646
	}
647

    
648
	return $vlanif;
649
}
650

    
651
function interfaces_create_wireless_clones() {
652
	global $config, $g;
653

    
654
	if (platform_booting()) {
655
		echo gettext("Creating wireless clone interfaces...");
656
	}
657

    
658
	$iflist = get_configured_interface_list();
659

    
660
	foreach ($iflist as $if) {
661
		$realif = $config['interfaces'][$if]['if'];
662
		if (is_interface_wireless($realif)) {
663
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
664
		}
665
	}
666

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

    
683
}
684

    
685
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
686
	global $config;
687

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

    
705
			if (($checkmember == 1) && $ifname &&
706
			    ($config['interfaces'][$ifname]['ipaddrv6'] == "track6")) {
707
				continue;
708
			} elseif (($checkmember == 2) && !$ifname) {
709
				continue;
710
			}
711

    
712
			/* XXX: Maybe we should report any errors?! */
713
			interface_bridge_configure($bridge, $checkmember,
714
			    false);
715
			$i++;
716
		}
717

    
718
		/* Invalidate cache */
719
		get_interface_arr(true);
720
	}
721
}
722

    
723
function interface_bridge_configure(&$bridge, $checkmember = 0, $flush = true) {
724
	global $config, $g;
725

    
726
	if (!is_array($bridge)) {
727
		return;
728
	}
729

    
730
	if (empty($bridge['members'])) {
731
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
732
		return;
733
	}
734

    
735
	$members = explode(',', $bridge['members']);
736
	if (!count($members)) {
737
		return;
738
	}
739

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

    
765
	/* Just in case anything is not working well */
766
	if ($smallermtu == 0) {
767
		$smallermtu = 1500;
768
	}
769

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

    
781
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
782
	if ($bridgemtu > $smallermtu) {
783
		$smallermtu = $bridgemtu;
784
	}
785

    
786
	$checklist = get_configured_interface_list();
787

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

    
805
	if (isset($bridge['enablestp'])) {
806
		interface_bridge_configure_stp($bridge);
807
	}
808

    
809
	interface_bridge_configure_advanced($bridge);
810

    
811
	interface_bridge_configure_ip6linklocal($bridge);
812

    
813
	if ($flush) {
814
		get_interface_arr(true);
815
	}
816

    
817
	if ($bridge['bridgeif']) {
818
		interfaces_bring_up($bridge['bridgeif']);
819
	} else {
820
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
821
	}
822
}
823

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

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

    
883
function interface_bridge_configure_advanced($bridge) {
884
	$bridgeif = trim($bridge['bridgeif']);
885

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

    
943
function interface_bridge_configure_ip6linklocal($bridge) {
944
	$bridgeif = trim($bridge['bridgeif']);
945

    
946
	$members = explode(',', $bridge['members']);
947
	if (!count($members)) {
948
		return;
949
	}
950

    
951
	$auto_linklocal = isset($bridge['ip6linklocal']);
952
	$bridgeop = $auto_linklocal ? '' : '-';
953
	$memberop = $auto_linklocal ? '-' : '';
954

    
955
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
956
	foreach ($members as $member) {
957
		$realif = get_real_interface($member);
958
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
959
	}
960
}
961

    
962
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
963
	global $config;
964

    
965
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
966
		return;
967
	}
968

    
969
	if ($flagsapplied == false) {
970
		$mtu = get_interface_mtu($bridgeif);
971
		$mtum = get_interface_mtu($interface);
972
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
973
			pfSense_interface_mtu($interface, $mtu);
974
		}
975

    
976
		hardware_offloading_applyflags($interface);
977
		interfaces_bring_up($interface);
978
	}
979

    
980
	pfSense_bridge_add_member($bridgeif, $interface);
981
	if (is_array($config['bridges']['bridged'])) {
982
		foreach ($config['bridges']['bridged'] as $bridge) {
983
			if ($bridgeif == $bridge['bridgeif']) {
984
				interface_bridge_configure_stp($bridge);
985
				interface_bridge_configure_advanced($bridge);
986
			}
987
		}
988
	}
989
}
990

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

    
1010
		/* Invalidate cache */
1011
		get_interface_arr(true);
1012
	}
1013
	if (platform_booting()) {
1014
		echo gettext("done.") . "\n";
1015
	}
1016
}
1017

    
1018
function interface_lagg_configure($lagg, $flush = true) {
1019
	global $config, $g;
1020

    
1021
	if (!is_array($lagg)) {
1022
		return -1;
1023
	}
1024

    
1025
	$members = explode(',', $lagg['members']);
1026
	if (!count($members)) {
1027
		return -1;
1028
	}
1029

    
1030
	if (platform_booting() || !(empty($lagg['laggif']))) {
1031
		pfSense_interface_destroy($lagg['laggif']);
1032
		pfSense_interface_create($lagg['laggif']);
1033
		$laggif = $lagg['laggif'];
1034
	} else {
1035
		$laggif = pfSense_interface_create("lagg");
1036
	}
1037

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

    
1051
	/* Just in case anything is not working well */
1052
	if ($lagg_mtu == 0) {
1053
		$lagg_mtu = 1500;
1054
	}
1055

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

    
1063
	if (($lagg['proto'] == 'lacp') && isset($lagg['lacptimeout']) &&
1064
	    ($lagg['lacptimeout'] != 'slow')) {
1065
		$lacptimeout = 'lacp_fast_timeout';
1066
	} else {
1067
		$lacptimeout = '';
1068
	}
1069

    
1070
	foreach ($members as $member) {
1071
		if (!does_interface_exist($member)) {
1072
			continue;
1073
		}
1074

    
1075
		/* make sure the parent interface is up */
1076
		pfSense_interface_mtu($member, $lagg_mtu);
1077
		interfaces_bring_up($member);
1078
		hardware_offloading_applyflags($member);
1079

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

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

    
1088
	if ($flush) {
1089
		get_interface_arr(true);
1090
	}
1091

    
1092
	interfaces_bring_up($laggif);
1093

    
1094
	return $laggif;
1095
}
1096

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

    
1101
	if (!is_array($gre)) {
1102
		return -1;
1103
	}
1104

    
1105
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1106
	if (!interface_is_vlan($realif)) {
1107
		$realif = get_real_interface($gre['if']);
1108
	}
1109
	$realifip = get_interface_ip($gre['if']);
1110
	$realifip6 = get_interface_ipv6($gre['if']);
1111

    
1112
	/* make sure the parent interface is up */
1113
	interfaces_bring_up($realif);
1114

    
1115
	if (platform_booting() || !(empty($gre['greif']))) {
1116
		pfSense_interface_destroy($gre['greif']);
1117
		pfSense_interface_create($gre['greif']);
1118
		$greif = $gre['greif'];
1119
	} else {
1120
		$greif = pfSense_interface_create("gre");
1121
	}
1122

    
1123
	$tunnel_type = '';
1124
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1125
		$tunnel_type = 'v4';
1126
	}
1127
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1128
		$tunnel_type .= 'v6';
1129
	}
1130

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

    
1145
	$parentif = get_real_interface($gre['if']);
1146
	if ($parentif) {
1147
		interfaces_bring_up($parentif);
1148
	} else {
1149
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1150
	}
1151

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

    
1167
	if ($flush) {
1168
		get_interface_arr(true);
1169
	}
1170

    
1171
	interfaces_bring_up($greif);
1172

    
1173
	return $greif;
1174
}
1175

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

    
1203
	if (!isset($config[$list][$entry]) || !is_array($config[$list][$entry])) {
1204
		return (NULL);
1205
	}
1206

    
1207
	foreach ($config[$list][$entry] as $ent) {
1208
		if ($ent[$entif] == $if) {
1209
			return ($ent);
1210
		}
1211
	}
1212
	return (NULL);
1213
}
1214

    
1215
function is_greipsec($if) {
1216
	global $config;
1217

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

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

    
1241
	if (!is_array($gif)) {
1242
		return -1;
1243
	}
1244

    
1245
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1246
	if (!interface_is_vlan($realif)) {
1247
		$realif = get_real_interface($gif['if']);
1248
	}
1249
	$ipaddr = get_interface_ip($gif['if']);
1250

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

    
1274
	if (platform_booting() || !(empty($gif['gifif']))) {
1275
		pfSense_interface_destroy($gif['gifif']);
1276
		pfSense_interface_create($gif['gifif']);
1277
		$gifif = $gif['gifif'];
1278
	} else {
1279
		$gifif = pfSense_interface_create("gif");
1280
	}
1281

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

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

    
1337

    
1338
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1339
		file_put_contents("{$g['tmp_path']}/{$gifif}_router",
1340
		    $gif['tunnel-remote-addr']);
1341
	} else if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1342
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6",
1343
		    $gif['tunnel-remote-addr']);
1344
	}
1345

    
1346
	route_add_or_change($gif['remote-addr'], $realifgw);
1347

    
1348
	if ($flush) {
1349
		get_interface_arr(true);
1350
	}
1351

    
1352
	interfaces_bring_up($gifif);
1353

    
1354
	return $gifif;
1355
}
1356

    
1357
/*
1358
 * $ipsecifnum = get_ipsecifnum($ikeid, $idx);
1359
 * locates and returns an ipsecifnum in the config.
1360
 */
1361
function get_ipsecifnum($ikeid, $idx) {
1362
	global $config;
1363

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

    
1372
	return false;
1373
}
1374
	
1375
function ipsec_create_vtimap($ikeid, $idx) {
1376
	global $config;
1377

    
1378
	if ((($ikeid < 33) && ($idx < 10)) || (($ikeid < 10) && ($idx < 100))) {
1379
		$oldformat = "{$ikeid}00{$idx}";
1380
		return array(
1381
			"reqid" => $ikeid,
1382
			"index" => $idx,
1383
			"ifnum" => $oldformat
1384
		);
1385
	}
1386

    
1387
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1388

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

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

    
1418
function ipsec_del_vtimap($phase2) {
1419
	global $config;
1420

    
1421
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1422

    
1423
	if (count($config['ipsec']['vtimaps']['item']) == 0) {
1424
		return;
1425
	}
1426

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

    
1439
	$vtisubnet_spec = ipsec_vti($phase1, true);
1440
	if (($phase1['iketype'] == 'ikev1') || isset($phase1['splitconn']) ||
1441
	    (count($vtisubnet_spec) == 1)) {
1442
		unset($a_vtimaps[$last]);
1443
		return true;
1444
	}
1445
}
1446

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

    
1451
	if (!is_array($vxlan)) {
1452
		return -1;
1453
	}
1454

    
1455
	$realif = convert_friendly_interface_to_real_interface_name($vxlan['if']);
1456
	if (!interface_is_vlan($realif)) {
1457
		$realif = get_real_interface($vxlan['if']);
1458
	}
1459
	$realifip = get_interface_ip($vxlan['if']);
1460
	$realifip6 = get_interface_ipv6($vxlan['if']);
1461

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

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

    
1489
	$ifconfigcmd = "/sbin/ifconfig " . escapeshellarg($vxlanif) .
1490
	    " vxlanid " .  escapeshellarg($vxlan['vxlanid']);
1491

    
1492
	if (is_mcast($vxlan['remote-addr'])) {
1493
		$ifconfigcmd .= " vxlangroup " .
1494
		    escapeshellarg($vxlan['remote-addr']) . " vxlandev " .
1495
		    escapeshellarg($realif);
1496
	} else {
1497
		$ifconfigcmd .= " vxlanremote " .
1498
		    escapeshellarg($vxlan['remote-addr']);
1499
	}
1500

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

    
1509
	if (!empty($vxlan['vxlanlocalport'])) {
1510
		$ifconfigcmd .= " vxlanlocalport " . escapeshellarg($vxlan['vxlanlocalport']);
1511
	}
1512

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

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

    
1521
	if (isset($vxlan['vxlanlearn'])) {
1522
		$ifconfigcmd .= " vxlanlearn ";
1523
	} else {
1524
		$ifconfigcmd .= " -vxlanlearn ";
1525
	}
1526

    
1527
	mwexec($ifconfigcmd);
1528

    
1529
	if ($flush) {
1530
		get_interface_arr(true);
1531
	}
1532

    
1533
	interfaces_bring_up($vxlanif);
1534

    
1535
	return $vxlanif;
1536
}
1537

    
1538
function interfaces_tunnel_configure($checkparent = 0, $realif = "", $type = "") {
1539
	global $config;
1540

    
1541
	if (!in_array($type, array('gre', 'gif', 'vxlan'))) {
1542
		return;
1543
	}
1544

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

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

    
1583
		/* Invalidate cache */
1584
		get_interface_arr(true);
1585
	}
1586
}
1587

    
1588
/* Build a list of IPsec interfaces */
1589
function interface_ipsec_vti_list_p1($ph1ent) {
1590
	global $config;
1591
	$iface_list = array();
1592

    
1593
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1594
		return $iface_list;
1595
	}
1596

    
1597
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1598
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1599
		return $iface_list;
1600
	}
1601

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

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

    
1651
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1652
		return false;
1653
	}
1654

    
1655
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1656
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1657
		return false;
1658
	}
1659

    
1660
	$left_spec = ipsec_get_phase1_src($ph1ent);
1661
	$right_spec = $ph1ent['remote-gateway'];
1662

    
1663
	$iface_addrs = array();
1664

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

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

    
1713
		/* Apply the outer tunnel addresses to the interface */
1714
		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
1715
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up", false);
1716

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

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

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

    
1773
function interfaces_configure() {
1774
	global $config, $g;
1775

    
1776
	/* Set up our loopback interface */
1777
	interfaces_loopback_configure();
1778

    
1779
	/* create the unconfigured wireless clones */
1780
	interfaces_create_wireless_clones();
1781

    
1782
	/* set up LAGG virtual interfaces */
1783
	interfaces_lagg_configure();
1784

    
1785
	/* set up VLAN virtual interfaces */
1786
	interfaces_vlan_configure();
1787

    
1788
	interfaces_qinq_configure();
1789

    
1790
	/* set up IPsec VTI interfaces */
1791
	interfaces_ipsec_vti_configure();
1792

    
1793
	$iflist = get_configured_interface_with_descr();
1794
	$delayed_list = array();
1795
	$bridge_list = array();
1796
	$track6_list = array();
1797

    
1798
	/* This is needed to speedup interfaces on bootup. */
1799
	$reload = false;
1800
	if (!platform_booting()) {
1801
		$reload = true;
1802
	}
1803

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

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

    
1836
	/*
1837
	 * NOTE: The following function parameter consists of
1838
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1839
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1840
	 */
1841

    
1842
	/* set up GRE virtual interfaces */
1843
	interfaces_tunnel_configure(1,'','gre');
1844

    
1845
	/* set up GIF virtual interfaces */
1846
	interfaces_tunnel_configure(1,'','gif');
1847

    
1848
	/* set up VXLAN virtual interfaces */
1849
	interfaces_tunnel_configure(1,'','vxlan');
1850

    
1851
	/* set up BRIDGe virtual interfaces */
1852
	interfaces_bridge_configure(1);
1853

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

    
1862
		interface_configure($if, $reload);
1863

    
1864
		if (platform_booting()) {
1865
			echo gettext("done.") . "\n";
1866
		}
1867
	}
1868

    
1869
	/* bring up vip interfaces */
1870
	interfaces_vips_configure();
1871

    
1872
	/* set up GRE virtual interfaces */
1873
	interfaces_tunnel_configure(2,'','gre');
1874

    
1875
	/* set up GIF virtual interfaces */
1876
	interfaces_tunnel_configure(2,'','gif');
1877

    
1878
	/* set up VXLAN virtual interfaces */
1879
	interfaces_tunnel_configure(2,'','vxlan');
1880

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

    
1889
		interface_configure($if, $reload);
1890

    
1891
		if (platform_booting()) {
1892
			echo gettext("done.") . "\n";
1893
		}
1894
	}
1895

    
1896
	/* set up BRIDGe virtual interfaces */
1897
	interfaces_bridge_configure(2);
1898

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

    
1907
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1908
		// redmine #3997
1909
		interface_reconfigure($if, $reload);
1910
		interfaces_vips_configure($if);
1911

    
1912
		if (platform_booting()) {
1913
			echo gettext("done.") . "\n";
1914
		}
1915
	}
1916

    
1917
	/* configure interface groups */
1918
	interfaces_group_setup();
1919

    
1920
	if (!platform_booting()) {
1921
		/* reconfigure static routes (kernel may have deleted them) */
1922
		system_routing_configure();
1923

    
1924
		/* reload IPsec tunnels */
1925
		ipsec_configure();
1926

    
1927
		/* restart dns servers (defering dhcpd reload) */
1928
		if (isset($config['dnsmasq']['enable'])) {
1929
			services_dnsmasq_configure(false);
1930
		}
1931
		if (isset($config['unbound']['enable'])) {
1932
			services_unbound_configure(false);
1933
		}
1934

    
1935
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1936
		services_dhcpd_configure();
1937
	}
1938

    
1939
	return 0;
1940
}
1941

    
1942
function interface_reconfigure($interface = "wan", $reloadall = false) {
1943
	interface_bring_down($interface);
1944
	interface_configure($interface, $reloadall);
1945
}
1946

    
1947
function interface_vip_bring_down($vip) {
1948
	global $g;
1949

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

    
1979
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1980
	global $config, $g;
1981

    
1982
	if (!isset($config['interfaces'][$interface])) {
1983
		return;
1984
	}
1985

    
1986
	if ($g['debug']) {
1987
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1988
	}
1989

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

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

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

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

    
2135
	$old_router = '';
2136
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
2137
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
2138
	}
2139

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

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

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

    
2160
			/* Invalidate cache */
2161
			get_interface_arr(true);
2162
		}
2163
	}
2164

    
2165
	return;
2166
}
2167

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

    
2180
	if (is_array($viparr)) {
2181
		foreach ($viparr as $vip) {
2182
			if ($vip['mode'] == "carp") {
2183
				interface_carp_configure($vip, true);
2184
			}
2185
		}
2186
	}
2187
}
2188

    
2189
function interface_wait_tentative($interface, $timeout = 10) {
2190
	if (!does_interface_exist($interface)) {
2191
		return false;
2192
	}
2193

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

    
2204
	return false;
2205
}
2206

    
2207
function interface_isppp_type($interface) {
2208
	global $config;
2209

    
2210
	if (!is_array($config['interfaces'][$interface])) {
2211
		return false;
2212
	}
2213

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

    
2227
function interfaces_ptpid_used($ptpid) {
2228
	global $config;
2229

    
2230
	if (is_array($config['ppps']['ppp'])) {
2231
		foreach ($config['ppps']['ppp'] as & $settings) {
2232
			if ($ptpid == $settings['ptpid']) {
2233
				return true;
2234
			}
2235
		}
2236
	}
2237

    
2238
	return false;
2239
}
2240

    
2241
function interfaces_ptpid_next() {
2242

    
2243
	$ptpid = 0;
2244
	while (interfaces_ptpid_used($ptpid)) {
2245
		$ptpid++;
2246
	}
2247

    
2248
	return $ptpid;
2249
}
2250

    
2251
function getMPDCRONSettings($pppif) {
2252
	global $config;
2253

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

    
2263
	return NULL;
2264
}
2265

    
2266
function handle_pppoe_reset($post_array) {
2267
	global $config, $g;
2268

    
2269
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2270
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2271

    
2272
	if (!is_array($config['cron']['item'])) {
2273
		$config['cron']['item'] = array();
2274
	}
2275

    
2276
	$itemhash = getMPDCRONSettings($pppif);
2277

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

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

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

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

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

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

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

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

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

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

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

    
2491
	if ($type == "modem") {
2492
		if (is_ipaddr($ppp['localip'])) {
2493
			$localip = $ppp['localip'];
2494
		} else {
2495
			$localip = '0.0.0.0';
2496
		}
2497

    
2498
		if (is_ipaddr($ppp['gateway'])) {
2499
			$gateway = $ppp['gateway'];
2500
		} else {
2501
			$gateway = "10.64.64.{$pppid}";
2502
		}
2503
		$ranges = "{$localip}/0 {$gateway}/0";
2504

    
2505
		if (empty($ppp['apnum'])) {
2506
			$ppp['apnum'] = 1;
2507
		}
2508
	} else {
2509
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2510
	}
2511

    
2512
	if (isset($ppp['ondemand'])) {
2513
		$ondemand = "enable";
2514
	} else {
2515
		$ondemand = "disable";
2516
	}
2517
	if (!isset($ppp['idletimeout'])) {
2518
		$ppp['idletimeout'] = 0;
2519
	}
2520

    
2521
	if (empty($ppp['username']) && $type == "modem") {
2522
		$ppp['username'] = "user";
2523
		$ppp['password'] = "none";
2524
	}
2525
	if (empty($ppp['password']) && $type == "modem") {
2526
		$passwd = "none";
2527
	} else {
2528
		$passwd = base64_decode($ppp['password']);
2529
	}
2530

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

    
2549
	// Construct the mpd.conf file
2550
	$mpdconf = <<<EOD
2551
startup:
2552
	# configure the console
2553
	set console close
2554
	# configure the web server
2555
	set web close
2556

    
2557
default:
2558
{$ppp['type']}client:
2559
	create bundle static {$interface}
2560
	{$ipv6cp}
2561
	set iface name {$pppif}
2562

    
2563
EOD;
2564
	$setdefaultgw = false;
2565
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2566
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2567
	if ($defgw4['interface'] == $interface) {
2568
		$setdefaultgw = true;
2569
	}
2570

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

    
2580
EOD;
2581
	}
2582

    
2583
	$mpdconf .= <<<EOD
2584
	set iface {$ondemand} on-demand
2585
	set iface idle {$ppp['idletimeout']}
2586

    
2587
EOD;
2588

    
2589
	if (isset($ppp['ondemand'])) {
2590
		$mpdconf .= <<<EOD
2591
	set iface addrs 10.10.1.1 10.10.1.2
2592

    
2593
EOD;
2594
	}
2595

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

    
2616
EOD;
2617
	}
2618

    
2619
	if (isset($ppp['tcpmssfix'])) {
2620
		$tcpmss = "disable";
2621
	} else {
2622
		$tcpmss = "enable";
2623
	}
2624
	$mpdconf .= <<<EOD
2625
	set iface {$tcpmss} tcpmssfix
2626

    
2627
EOD;
2628

    
2629
	$mpdconf .= <<<EOD
2630
	set iface up-script /usr/local/sbin/ppp-linkup
2631
	set iface down-script /usr/local/sbin/ppp-linkdown
2632
	set ipcp ranges {$ranges}
2633

    
2634
EOD;
2635
	if (isset($ppp['vjcomp'])) {
2636
		$mpdconf .= <<<EOD
2637
	set ipcp no vjcomp
2638

    
2639
EOD;
2640
	}
2641

    
2642
	if (isset($config['system']['dnsallowoverride'])) {
2643
		$mpdconf .= <<<EOD
2644
	set ipcp enable req-pri-dns
2645
	set ipcp enable req-sec-dns
2646

    
2647
EOD;
2648
	}
2649

    
2650
	if (!isset($ppp['verbose_log'])) {
2651
		$mpdconf .= <<<EOD
2652
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2653

    
2654
EOD;
2655
	}
2656

    
2657
	foreach ($ports as $pid => $port) {
2658
		$port = get_real_interface($port);
2659
		$mpdconf .= <<<EOD
2660

    
2661
	create link static {$interface}_link{$pid} {$type}
2662
	set link action bundle {$interface}
2663
	set link {$multilink} multilink
2664
	set link keep-alive 10 60
2665
	set link max-redial 0
2666

    
2667
EOD;
2668
		if (isset($ppp['shortseq'])) {
2669
			$mpdconf .= <<<EOD
2670
	set link no shortseq
2671

    
2672
EOD;
2673
		}
2674

    
2675
		if (isset($ppp['acfcomp'])) {
2676
			$mpdconf .= <<<EOD
2677
	set link no acfcomp
2678

    
2679
EOD;
2680
		}
2681

    
2682
		if (isset($ppp['protocomp'])) {
2683
			$mpdconf .= <<<EOD
2684
	set link no protocomp
2685

    
2686
EOD;
2687
		}
2688

    
2689
		$mpdconf .= <<<EOD
2690
	set link disable chap pap
2691
	set link accept chap pap eap
2692
	set link disable incoming
2693

    
2694
EOD;
2695

    
2696

    
2697
		if (!empty($bandwidths[$pid])) {
2698
			$mpdconf .= <<<EOD
2699
	set link bandwidth {$bandwidths[$pid]}
2700

    
2701
EOD;
2702
		}
2703

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

    
2719
EOD;
2720
		}
2721

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

    
2728
EOD;
2729
		}
2730

    
2731
		if (!empty($mrrus[$pid])) {
2732
			$mpdconf .= <<<EOD
2733
	set link mrru {$mrrus[$pid]}
2734

    
2735
EOD;
2736
		}
2737

    
2738
		$mpdconf .= <<<EOD
2739
	set auth authname "{$ppp['username']}"
2740
	set auth password {$passwd}
2741

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

    
2752
EOD;
2753
		}
2754
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2755
			$mpdconf .= <<<EOD
2756
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2757

    
2758
EOD;
2759
		}
2760
		if (isset($ppp['initstr']) && $type == "modem") {
2761
			$initstr = base64_decode($ppp['initstr']);
2762
			$mpdconf .= <<<EOD
2763
	set modem var \$InitString "{$initstr}"
2764

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

    
2775
EOD;
2776
		}
2777
		if (isset($ppp['apn']) && $type == "modem") {
2778
			$mpdconf .= <<<EOD
2779
	set modem var \$APN "{$ppp['apn']}"
2780
	set modem var \$APNum "{$ppp['apnum']}"
2781

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

    
2798
EOD;
2799
		}
2800
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2801
			$mpdconf .= <<<EOD
2802
	set pppoe max-payload {$mtus[$pid]}
2803

    
2804
EOD;
2805
		}
2806
		if ($type == "pppoe") {
2807
			$mpdconf .= <<<EOD
2808
	set pppoe iface {$port}
2809

    
2810
EOD;
2811
		}
2812

    
2813
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2814
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2815
			$mpdconf .= <<<EOD
2816
	set l2tp secret "{$secret}"
2817

    
2818
EOD;
2819
		}
2820

    
2821
		if (($type == "pptp") || ($type == "l2tp")) {
2822
			$mpdconf .= <<<EOD
2823
	set {$type} self {$localips[$pid]}
2824
	set {$type} peer {$gateways[$pid]}
2825

    
2826
EOD;
2827
		}
2828

    
2829
		$mpdconf .= "\topen\n";
2830
	} //end foreach ($port)
2831

    
2832

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

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

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

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

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

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

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

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

    
2939
	return 1;
2940
}
2941

    
2942
function interfaces_sync_setup() {
2943
	global $g, $config;
2944

    
2945
	if (isset($config['system']['developerspew'])) {
2946
		$mt = microtime();
2947
		echo "interfaces_sync_setup() being called $mt\n";
2948
	}
2949

    
2950
	if (platform_booting()) {
2951
		echo gettext("Configuring CARP settings...");
2952
		mute_kernel_msgs();
2953
	}
2954

    
2955
	/* suck in configuration items */
2956
	if ($config['hasync']) {
2957
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2958
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2959
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2960
	} else {
2961
		unset($pfsyncinterface);
2962
		unset($pfsyncenabled);
2963
	}
2964

    
2965
	set_sysctl(array(
2966
		"net.inet.carp.preempt" => "1",
2967
		"net.inet.carp.log" => "1")
2968
	);
2969

    
2970
	if (!empty($pfsyncinterface)) {
2971
		$carp_sync_int = get_real_interface($pfsyncinterface);
2972
	} else {
2973
		unset($carp_sync_int);
2974
	}
2975

    
2976
	/* setup pfsync interface */
2977
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2978
		if (is_ipaddr($pfsyncpeerip)) {
2979
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2980
		} else {
2981
			$syncpeer = "-syncpeer";
2982
		}
2983

    
2984
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2985
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2986

    
2987
		sleep(1);
2988

    
2989
		/* 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
2990
		 * for existing sessions.
2991
		 */
2992
		log_error(gettext("waiting for pfsync..."));
2993
		$i = 0;
2994
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2995
			$i++;
2996
			sleep(1);
2997
		}
2998
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2999
		log_error(gettext("Configuring CARP settings finalize..."));
3000
	} else {
3001
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
3002
	}
3003

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

    
3011
	if (platform_booting()) {
3012
		unmute_kernel_msgs();
3013
		echo gettext("done.") . "\n";
3014
	}
3015
}
3016

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

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

    
3034
	$paa = array();
3035
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
3036

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

    
3046
				if (!empty($interface) && $interface != $proxyif) {
3047
					continue;
3048
				}
3049

    
3050
				if (!is_array($paa[$proxyif])) {
3051
					$paa[$proxyif] = array();
3052
				}
3053

    
3054
				$paa[$proxyif][] = $vipent;
3055
			}
3056
		}
3057
	}
3058

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

    
3098
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
3099
	global $g, $config;
3100

    
3101
	if (is_array($config['virtualip']['vip'])) {
3102
		foreach ($config['virtualip']['vip'] as $vip) {
3103

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

    
3120
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
3121
				interface_vip_bring_down($vip);
3122
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
3123
				interface_vip_bring_down($vip);
3124
			else if ($inet == "all")
3125
				interface_vip_bring_down($vip);
3126
		}
3127
	}
3128
}
3129

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

    
3169
function interface_ipalias_configure(&$vip) {
3170
	global $config;
3171

    
3172
	$gateway = '';
3173
	if ($vip['mode'] != 'ipalias') {
3174
		return;
3175
	}
3176

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

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

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

    
3215
	if ($vip['mode'] != "carp") {
3216
		return;
3217
	}
3218

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

    
3233
	$vip_password = $vip['password'];
3234
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3235
	    $vip_password)));
3236
	if ($vip['password'] != "") {
3237
		$password = " pass {$vip_password}";
3238
	}
3239

    
3240
	$advbase = "";
3241
	if (!empty($vip['advbase'])) {
3242
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3243
	}
3244

    
3245
	$carp_maintenancemode = isset(
3246
	    $config["virtualip_carp_maintenancemode"]);
3247
	if ($carp_maintenancemode) {
3248
		$advskew = "advskew 254";
3249
	} else {
3250
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3251
	}
3252

    
3253
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) .
3254
	    " {$advskew} {$advbase} {$password}");
3255

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

    
3270
	return $realif;
3271
}
3272

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

    
3315
	if ($needs_clone == true) {
3316
		/* remove previous instance if it exists */
3317
		if (does_interface_exist($realif)) {
3318
			pfSense_interface_destroy($realif);
3319

    
3320
			/* Invalidate cache */
3321
			get_interface_arr(true);
3322
		}
3323

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

    
3340
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3341
	global $config, $g;
3342

    
3343
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3344
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3345
				 'regdomain', 'regcountry', 'reglocation');
3346

    
3347
	if (!is_interface_wireless($ifcfg['if'])) {
3348
		return;
3349
	}
3350

    
3351
	$baseif = interface_get_wireless_base($ifcfg['if']);
3352

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

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

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

    
3415
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3416
	global $config, $g;
3417

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

    
3425
	// Remove script file
3426
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3427

    
3428
	// Clone wireless nic if needed.
3429
	interface_wireless_clone($if, $wl);
3430

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

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

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

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

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

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

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

    
3473
	/* Set ssid */
3474
	if ($wlcfg['ssid']) {
3475
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3476
	}
3477

    
3478
	/* Set 802.11g protection mode */
3479
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3480

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

    
3495
	/* Set antenna diversity value */
3496
	if (isset($wlcfg['diversity'])) {
3497
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3498
	}
3499

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

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

    
3510
	/* set Distance value */
3511
	if ($wlcfg['distance']) {
3512
		$distance = escapeshellarg($wlcfg['distance']);
3513
	}
3514

    
3515
	/* Set wireless hostap mode */
3516
	if ($wlcfg['mode'] == "hostap") {
3517
		$wlcmd[] = "mediaopt hostap";
3518
	} else {
3519
		$wlcmd[] = "-mediaopt hostap";
3520
	}
3521

    
3522
	/* Set wireless adhoc mode */
3523
	if ($wlcfg['mode'] == "adhoc") {
3524
		$wlcmd[] = "mediaopt adhoc";
3525
	} else {
3526
		$wlcmd[] = "-mediaopt adhoc";
3527
	}
3528

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

    
3531
	/* handle hide ssid option */
3532
	if (isset($wlcfg['hidessid']['enable'])) {
3533
		$wlcmd[] = "hidessid";
3534
	} else {
3535
		$wlcmd[] = "-hidessid";
3536
	}
3537

    
3538
	/* handle pureg (802.11g) only option */
3539
	if (isset($wlcfg['pureg']['enable'])) {
3540
		$wlcmd[] = "mode 11g pureg";
3541
	} else {
3542
		$wlcmd[] = "-pureg";
3543
	}
3544

    
3545
	/* handle puren (802.11n) only option */
3546
	if (isset($wlcfg['puren']['enable'])) {
3547
		$wlcmd[] = "puren";
3548
	} else {
3549
		$wlcmd[] = "-puren";
3550
	}
3551

    
3552
	/* enable apbridge option */
3553
	if (isset($wlcfg['apbridge']['enable'])) {
3554
		$wlcmd[] = "apbridge";
3555
	} else {
3556
		$wlcmd[] = "-apbridge";
3557
	}
3558

    
3559
	/* handle turbo option */
3560
	if (isset($wlcfg['turbo']['enable'])) {
3561
		$wlcmd[] = "mediaopt turbo";
3562
	} else {
3563
		$wlcmd[] = "-mediaopt turbo";
3564
	}
3565

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

    
3573
	/* handle wme option */
3574
	if (isset($wlcfg['wme']['enable'])) {
3575
		$wlcmd[] = "wme";
3576
	} else {
3577
		$wlcmd[] = "-wme";
3578
	}
3579

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

    
3587
	kill_hostapd($if);
3588
	mwexec(kill_wpasupplicant("{$if}"));
3589

    
3590
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3591

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

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

    
3645
EOD;
3646

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

    
3653
EOD;
3654
				}
3655
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3656
					$wpa .= "ieee8021x=1\n";
3657

    
3658
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3659
						$auth_server_port = "1812";
3660
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3661
							$auth_server_port = intval($wlcfg['auth_server_port']);
3662
						}
3663
						$wpa .= <<<EOD
3664

    
3665
auth_server_addr={$wlcfg['auth_server_addr']}
3666
auth_server_port={$auth_server_port}
3667
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3668

    
3669
EOD;
3670
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3671
							$auth_server_port2 = "1812";
3672
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3673
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3674
							}
3675

    
3676
							$wpa .= <<<EOD
3677
auth_server_addr={$wlcfg['auth_server_addr2']}
3678
auth_server_port={$auth_server_port2}
3679
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3680

    
3681
EOD;
3682
						}
3683
					}
3684
				}
3685

    
3686
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3687
				unset($wpa);
3688
			}
3689
			break;
3690
	}
3691

    
3692
	/*
3693
	 *    all variables are set, lets start up everything
3694
	 */
3695

    
3696
	$baseif = interface_get_wireless_base($if);
3697
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3698
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3699

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

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

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

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

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

    
3742
	fclose($fd_set);
3743

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

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

    
3765
	if ($reg_changing) {
3766
		/* set regulatory domain */
3767
		if ($wlcfg['regdomain']) {
3768
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3769
		}
3770

    
3771
		/* set country */
3772
		if ($wlcfg['regcountry']) {
3773
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3774
		}
3775

    
3776
		/* set location */
3777
		if ($wlcfg['reglocation']) {
3778
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3779
		}
3780

    
3781
		$wlregcmd_args = implode(" ", $wlregcmd);
3782

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

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

    
3806
		/* apply the regulatory settings */
3807
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3808
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3809

    
3810
		/* bring the clones back up that were previously up */
3811
		foreach ($clones_up as $clone_if) {
3812
			interfaces_bring_up($clone_if);
3813

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

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

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

    
3848
	unset($wlcmd_args, $wlcmd);
3849

    
3850

    
3851
	sleep(1);
3852
	/* execute hostapd and wpa_supplicant if required in shell */
3853
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3854

    
3855
	return 0;
3856

    
3857
}
3858

    
3859
function kill_hostapd($interface) {
3860
	global $g;
3861

    
3862
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3863
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3864
	}
3865
}
3866

    
3867
function kill_wpasupplicant($interface) {
3868
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3869
}
3870

    
3871
function find_dhclient_process($interface) {
3872
	if ($interface) {
3873
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3874
	} else {
3875
		$pid = 0;
3876
	}
3877

    
3878
	return intval($pid);
3879
}
3880

    
3881
function kill_dhclient_process($interface) {
3882
	if (empty($interface) || !does_interface_exist($interface)) {
3883
		return;
3884
	}
3885

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

    
3897
function find_dhcp6c_process($interface) {
3898
	global $g;
3899

    
3900
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3901
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3902
	} else {
3903
		return(false);
3904
	}
3905

    
3906
	return intval($pid);
3907
}
3908

    
3909
function kill_dhcp6client_process($interface, $force, $release = false) {
3910
	global $g;
3911

    
3912
	$i = 0;
3913

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

    
3919
	if (empty($interface) || !does_interface_exist($interface)) {
3920
		return;
3921
	}
3922
	*/
3923

    
3924
	/*********** Notes on signals for dhcp6c and this function *************
3925

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

    
3932
	If we want to exit normally obeying the no release flag then use SIGTERM.
3933
	If we want to exit with a release overiding the no release flag then
3934
	use SIGUSR2.
3935

    
3936
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3937
	exit quickly without sending release signals.
3938

    
3939
	If $Force is set to false and $release is also set to false dhcp6c will
3940
	follow the no-release flag.
3941

    
3942
	If $Force is set to false and $release is true then dhcp6c will send a
3943
	release regardless of the no-release flag.
3944
	***********************************************************************/
3945

    
3946
	if ($force == true) {
3947
		$psig=SIGUSR1;
3948
	} else if ($release == false) {
3949
		$psig=SIGTERM;
3950
	} else {
3951
		$psig=SIGUSR2;
3952
	}
3953

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

    
3967
	$pid = find_dhcp6c_process($interface);
3968

    
3969
	if($pid != 0) {
3970
		posix_kill($pid, SIGHUP);
3971
	}
3972
}
3973

    
3974
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3975
	global $g;
3976

    
3977
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3978
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3979

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

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

    
4004
function interface_virtual_create($interface) {
4005
	global $config;
4006

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

    
4057
function interface_vlan_mtu_configured($iface) {
4058
	global $config;
4059

    
4060
	$mtu = 0;
4061
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
4062
		foreach ($config['vlans']['vlan'] as $vlan) {
4063

    
4064
			if ($vlan['vlanif'] != $iface)
4065
				continue;
4066

    
4067
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4068
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
4069
				/* VLAN MTU */
4070
				$mtu = $config['interfaces'][$assignedport]['mtu'];
4071
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
4072
				/* Parent MTU */
4073
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
4074
			}
4075
		}
4076
	}
4077

    
4078
	return $mtu;
4079
}
4080

    
4081
function interface_mtu_wanted_for_pppoe($realif) {
4082
	global $config;
4083

    
4084
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
4085
		return 0;
4086

    
4087
	$mtu = 0;
4088
	foreach ($config['ppps']['ppp'] as $ppp) {
4089
		if ($ppp['type'] != "pppoe") {
4090
			continue;
4091
		}
4092

    
4093
		$mtus = array();
4094
		if (!empty($ppp['mtu'])) {
4095
			$mtus = explode(',', $ppp['mtu']);
4096
		}
4097
		$ports = explode(',', $ppp['ports']);
4098

    
4099
		foreach ($ports as $pid => $port) {
4100
			$parentifa = get_parent_interface($port);
4101
			$parentif = $parentifa[0];
4102
			if ($parentif != $realif)
4103
				continue;
4104

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

    
4121
	return $mtu;
4122
}
4123

    
4124
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
4125
	global $config, $g;
4126
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
4127
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
4128

    
4129
	$wancfg = $config['interfaces'][$interface];
4130

    
4131
	if (!isset($wancfg['enable'])) {
4132
		return;
4133
	}
4134

    
4135
	$realif = get_real_interface($interface);
4136
	$realhwif_array = get_parent_interface($interface);
4137
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
4138
	$realhwif = $realhwif_array[0];
4139

    
4140
	$mac_if_cfg = $wancfg;
4141
	if (interface_is_vlan($realif)) {
4142
		$mac_if = convert_real_interface_to_friendly_interface_name(
4143
		    $realhwif);
4144
		if (is_array($config['interfaces'][$mac_if])) {
4145
			$mac_if_cfg = $config['interfaces'][$mac_if];
4146
		} else {
4147
			$mac_if = $interface;
4148
		}
4149
	}
4150

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

    
4174
		/* only bring down the interface when both v4 and v6 are set to NONE */
4175
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4176
			interface_bring_down($interface);
4177
		}
4178
	}
4179

    
4180
	$interface_to_check = $realif;
4181
	if (interface_isppp_type($interface)) {
4182
		$interface_to_check = $realhwif;
4183
	}
4184

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

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

    
4203
	$current_mac = get_interface_mac($realhwif);
4204
	$vendor_mac = get_interface_vendor_mac($realhwif);
4205

    
4206
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4207
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4208

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

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

    
4240
	/* Apply hw offloading policies as configured */
4241
	enable_hardware_offloading($interface);
4242

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

    
4250
	$tunnelif = substr($realif, 0, 3);
4251

    
4252
	$mtuif = $realif;
4253
	$mtuhwif = $realhwif;
4254

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

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

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

    
4294
	/* Set the MTU to 1500 if no explicit MTU configured. */
4295
	if ($wantedmtu == 0) {
4296
		$wantedmtu = 1500; /* Default */
4297
	}
4298

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

    
4308
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4309

    
4310
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4311
			$configuredmtu = $parentmtu;
4312
		if ($configuredmtu != 0)
4313
			$mtu = $configuredmtu;
4314
		else
4315
			$mtu = $wantedmtu;
4316

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

    
4343
	if (does_interface_exist($wancfg['if'])) {
4344
		interfaces_bring_up($wancfg['if']);
4345
	}
4346

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

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

    
4401
	interface_netgraph_needed($interface);
4402

    
4403
	if (!platform_booting()) {
4404
		link_interface_to_vips($interface, "update");
4405

    
4406
		if ($tunnelif != 'gre') {
4407
			unset($gre);
4408
			$gre = link_interface_to_tunnelif($interface, 'gre');
4409
			if (!empty($gre)) {
4410
				array_walk($gre, 'interface_gre_configure');
4411
			}
4412
		}
4413

    
4414
		if ($tunnelif != 'gif') {
4415
			unset($gif);
4416
			$gif = link_interface_to_tunnelif($interface, 'gif');
4417
			if (!empty($gif)) {
4418
				array_walk($gif, 'interface_gif_configure');
4419
			}
4420
		}
4421

    
4422
		if ($tunnelif != 'vxlan') {
4423
			unset($vxlan);
4424
			$vxlan = link_interface_to_tunnelif($interface, 'vxlan');
4425
			if (!empty($vxlan)) {
4426
				array_walk($vxlan, 'interface_vxlan_configure');
4427
			}
4428
		}
4429

    
4430
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4431
			unset($bridgetmp);
4432
			$bridgetmp = link_interface_to_bridge($interface);
4433
			if (!empty($bridgetmp)) {
4434
				interface_bridge_add_member($bridgetmp, $realif);
4435
			}
4436
		}
4437

    
4438
		$grouptmp = link_interface_to_group($interface);
4439
		if (!empty($grouptmp)) {
4440
			array_walk($grouptmp, 'interface_group_add_member');
4441
		}
4442

    
4443
		if ($interface == "lan") {
4444
			/* make new hosts file */
4445
			system_hosts_generate();
4446
		}
4447

    
4448
		if ($reloadall == true) {
4449

    
4450
			/* reconfigure static routes (kernel may have deleted them) */
4451
			system_routing_configure($interface);
4452

    
4453
			/* reload ipsec tunnels */
4454
			send_event("service reload ipsecdns");
4455

    
4456
			if (isset($config['dnsmasq']['enable'])) {
4457
				services_dnsmasq_configure();
4458
			}
4459

    
4460
			if (isset($config['unbound']['enable'])) {
4461
				services_unbound_configure();
4462
			}
4463

    
4464
			/* update dyndns */
4465
			send_event("service reload dyndns {$interface}");
4466

    
4467
			/* reload captive portal */
4468
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4469
				require_once('captiveportal.inc');
4470
			}
4471
			captiveportal_init_rules_byinterface($interface);
4472
		}
4473
	}
4474

    
4475
	if (!empty($wancfg['descr'])) {
4476
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4477
	};
4478

    
4479
	interfaces_staticarp_configure($interface);
4480
	return 0;
4481
}
4482

    
4483
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4484
	global $config, $g;
4485

    
4486
	if (!is_array($wancfg)) {
4487
		return;
4488
	}
4489

    
4490
	if (!isset($wancfg['enable'])) {
4491
		return;
4492
	}
4493

    
4494
	/* If the interface is not configured via another, exit */
4495
	if (empty($wancfg['track6-interface'])) {
4496
		return;
4497
	}
4498

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

    
4506
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4507
	if (!isset($trackcfg['enable'])) {
4508
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4509
		return;
4510
	}
4511

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

    
4542
	if ($linkupevent == false && !platform_booting()) {
4543
		if (!function_exists('services_dhcpd_configure')) {
4544
			require_once("services.inc");
4545
		}
4546

    
4547
		/* restart dns servers (defering dhcpd reload) */
4548
		if (isset($config['unbound']['enable'])) {
4549
			services_unbound_configure(false);
4550
		}
4551
		if (isset($config['dnsmasq']['enable'])) {
4552
			services_dnsmasq_configure(false);
4553
		}
4554

    
4555
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4556
		services_dhcpd_configure("inet6");
4557
	}
4558

    
4559
	return 0;
4560
}
4561

    
4562
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4563
	global $config, $g;
4564
	global $interface_ipv6_arr_cache;
4565
	global $interface_snv6_arr_cache;
4566

    
4567
	if (!is_array($lancfg)) {
4568
		return;
4569
	}
4570

    
4571
	/* If the interface is not configured via another, exit */
4572
	if (empty($lancfg['track6-interface'])) {
4573
		return;
4574
	}
4575

    
4576
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4577
	if (empty($wancfg)) {
4578
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4579
		return;
4580
	}
4581

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

    
4589
	/* create the long prefix notation for math, save the prefix length */
4590
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4591
	$rd6prefixlen = $rd6prefix[1];
4592
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4593

    
4594
	/* binary presentation of the prefix for all 128 bits. */
4595
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4596

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

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

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

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

    
4623
	return 0;
4624
}
4625

    
4626
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4627
	global $config, $g;
4628
	global $interface_ipv6_arr_cache;
4629
	global $interface_snv6_arr_cache;
4630

    
4631
	if (!is_array($lancfg)) {
4632
		return;
4633
	}
4634

    
4635
	/* If the interface is not configured via another, exit */
4636
	if (empty($lancfg['track6-interface'])) {
4637
		return;
4638
	}
4639

    
4640
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4641
	if (empty($wancfg)) {
4642
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4643
		return;
4644
	}
4645

    
4646
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4647
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4648
		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']));
4649
		return;
4650
	}
4651
	$hexwanv4 = return_hex_ipv4($ip4address);
4652

    
4653
	/* create the long prefix notation for math, save the prefix length */
4654
	$sixto4prefix = "2002::";
4655
	$sixto4prefixlen = 16;
4656
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4657

    
4658
	/* binary presentation of the prefix for all 128 bits. */
4659
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4660

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

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

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

    
4683
	return 0;
4684
}
4685

    
4686
function interface_6rd_configure($interface = "wan", $wancfg) {
4687
	global $config, $g;
4688

    
4689
	/* because this is a tunnel interface we can only function
4690
	 *	with a public IPv4 address on the interface */
4691

    
4692
	if (!is_array($wancfg)) {
4693
		return;
4694
	}
4695

    
4696
	if (!is_module_loaded('if_stf.ko')) {
4697
		mwexec('/sbin/kldload if_stf.ko');
4698
	}
4699

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

    
4708
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4709
		$wancfg['prefix-6rd-v4plen'] = 0;
4710
	}
4711

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

    
4725
	/* binary presentation of the prefix for all 128 bits. */
4726
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4727

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

    
4735
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4736
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4737

    
4738

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

    
4762
	/* write out a default router file */
4763
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4764
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4765

    
4766
	$ip4gateway = get_interface_gateway($interface);
4767
	if (is_ipaddrv4($ip4gateway)) {
4768
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4769
	}
4770

    
4771
	/* configure dependent interfaces */
4772
	if (!platform_booting()) {
4773
		link_interface_to_track6($interface, "update");
4774
	}
4775

    
4776
	return 0;
4777
}
4778

    
4779
function interface_6to4_configure($interface = "wan", $wancfg) {
4780
	global $config, $g;
4781

    
4782
	/* because this is a tunnel interface we can only function
4783
	 *	with a public IPv4 address on the interface */
4784

    
4785
	if (!is_array($wancfg)) {
4786
		return;
4787
	}
4788

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

    
4796
	/* create the long prefix notation for math, save the prefix length */
4797
	$stfprefixlen = 16;
4798
	$stfprefix = Net_IPv6::uncompress("2002::");
4799
	$stfarr = explode(":", $stfprefix);
4800
	$v4prefixlen = "0";
4801

    
4802
	/* we need the hex form of the interface IPv4 address */
4803
	$ip4arr = explode(".", $ip4address);
4804
	$hexwanv4 = "";
4805
	foreach ($ip4arr as $octet) {
4806
		$hexwanv4 .= sprintf("%02x", $octet);
4807
	}
4808

    
4809
	/* we need the hex form of the broker IPv4 address */
4810
	$ip4arr = explode(".", "192.88.99.1");
4811
	$hexbrv4 = "";
4812
	foreach ($ip4arr as $octet) {
4813
		$hexbrv4 .= sprintf("%02x", $octet);
4814
	}
4815

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

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

    
4828
	/* for the local subnet too. */
4829
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4830
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4831

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

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

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

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

    
4875
	/* write out a default router file */
4876
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4877
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4878

    
4879
	$ip4gateway = get_interface_gateway($interface);
4880
	if (is_ipaddrv4($ip4gateway)) {
4881
		route_add_or_change("192.88.99.1", $ip4gateway);
4882
	}
4883

    
4884
	if (!platform_booting()) {
4885
		link_interface_to_track6($interface, "update");
4886
	}
4887

    
4888
	return 0;
4889
}
4890

    
4891
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4892
	global $config, $g;
4893

    
4894
	if (!is_array($wancfg)) {
4895
		return;
4896
	}
4897

    
4898
	$wanif = get_real_interface($interface, "inet6");
4899
	$dhcp6cconf = "";
4900

    
4901
	if (!empty($config['system']['global-v6duid'])) {
4902
		// Write the DUID file
4903
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4904
		    log_error(gettext("Failed to write user DUID file!"));
4905
		}
4906
	}
4907

    
4908
	/* accept router advertisements for this interface                 */
4909
	/* Moved to early in the function as sometimes interface not ready */
4910
	/* RTSOLD fails as interface does not accept .....                 */
4911

    
4912
	log_error("Accept router advertisements on interface {$wanif} ");
4913
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4914

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

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

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

    
4949
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4950
			$dhcp6cconf .= "\trequest domain-name;\n";
4951

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

    
4963
			if (!isset($wancfg['dhcp6prefixonly'])) {
4964
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4965
			}
4966

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

    
4991
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4992
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4993

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

    
5002
	/*************** Script Debug Logging ***************************
5003
	Both dhcp6 scripts now have a logging message built in.
5004
	These logging messages ONLY appear if dhcp6c debug logging is set.
5005
	The logging messages appear in the dhcp section of the logs,
5006
	not in system.
5007

    
5008
	These scripts now also take advantage of the REASON= env vars
5009
	supplied by dhcp6c.
5010
	****************************************************************/
5011

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

    
5061
	unset($dhcp6cscriptwithoutra);
5062
	@chmod(
5063
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
5064
	    0755);
5065

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

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

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

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

    
5167
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
5168
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
5169
		log_error("Killing running rtsold process");
5170
		sleep(2);
5171
	}
5172

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

    
5215
	return 0;
5216
}
5217

    
5218
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5219
	global $g;
5220

    
5221
	$send_options = "";
5222
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5223
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5224
		foreach ($options as $option) {
5225
			$send_options .= "\tsend " . trim($option) . ";\n";
5226
		}
5227
	}
5228

    
5229
	$request_options = "";
5230
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5231
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5232
		foreach ($options as $option) {
5233
			$request_options .= "\trequest " . trim($option) . ";\n";
5234
		}
5235
	}
5236

    
5237
	$information_only = "";
5238
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5239
		$information_only = "\tinformation-only;\n";
5240
	}
5241

    
5242
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5243
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5244
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5245
	}
5246

    
5247
	$interface_statement  = "interface";
5248
	$interface_statement .= " {$wanif}";
5249
	$interface_statement .= " {\n";
5250
	$interface_statement .= "$send_options";
5251
	$interface_statement .= "$request_options";
5252
	$interface_statement .= "$information_only";
5253
	$interface_statement .= "$script";
5254
	$interface_statement .= "};\n";
5255

    
5256
	$id_assoc_statement_address = "";
5257
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5258
		$id_assoc_statement_address .= "id-assoc";
5259
		$id_assoc_statement_address .= " na";
5260
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5261
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5262
		}
5263
		$id_assoc_statement_address .= " { ";
5264

    
5265
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5266
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5267
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5268
			$id_assoc_statement_address .= "\n\taddress";
5269
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5270
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5271
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5272
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5273
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5274
			}
5275
			$id_assoc_statement_address .= ";\n";
5276
		}
5277

    
5278
		$id_assoc_statement_address .= "};\n";
5279
	}
5280

    
5281
	$id_assoc_statement_prefix = "";
5282
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5283
		$id_assoc_statement_prefix .= "id-assoc";
5284
		$id_assoc_statement_prefix .= " pd";
5285
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5286
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5287
		}
5288
		$id_assoc_statement_prefix .= " { ";
5289

    
5290
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5291
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5292
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5293
			$id_assoc_statement_prefix .= "\n\tprefix";
5294
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5295
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5296
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5297
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5298
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5299
			}
5300
			$id_assoc_statement_prefix .= ";";
5301
		}
5302

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

    
5316
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5317
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5318
			$id_assoc_statement_prefix .= "\n";
5319
		}
5320

    
5321
		$id_assoc_statement_prefix .= "};\n";
5322
	}
5323

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

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

    
5357
	$dhcp6cconf  = $interface_statement;
5358
	$dhcp6cconf .= $id_assoc_statement_address;
5359
	$dhcp6cconf .= $id_assoc_statement_prefix;
5360
	$dhcp6cconf .= $authentication_statement;
5361
	$dhcp6cconf .= $key_info_statement;
5362

    
5363
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5364

    
5365
	return $dhcp6cconf;
5366
}
5367

    
5368

    
5369
function DHCP6_Config_File_Override($wancfg, $wanif) {
5370

    
5371
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5372

    
5373
	if ($dhcp6cconf === false) {
5374
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5375
		return '';
5376
	} else {
5377
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5378
	}
5379
}
5380

    
5381

    
5382
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5383

    
5384
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5385

    
5386
	return $dhcp6cconf;
5387
}
5388

    
5389

    
5390
function interface_dhcp_configure($interface = "wan") {
5391
	global $config, $g, $vlanprio_values;
5392

    
5393
	$ifcfg = $config['interfaces'][$interface];
5394
	if (empty($ifcfg)) {
5395
		$ifcfg = array();
5396
	}
5397

    
5398
	$dhclientconf_vlantag = "";
5399
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5400
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5401
	}
5402

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

    
5410
	if ($ifcfg['dhcphostname']) {
5411
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5412
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5413
	} else {
5414
		$dhclientconf_hostname = "";
5415
	}
5416

    
5417
	$realif = get_real_interface($interface);
5418
	if (empty($realif)) {
5419
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5420
		return 0;
5421
	}
5422
	$dhclientconf = "";
5423

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

    
5436
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5437
		$dhclientconf .= <<<EOD
5438

    
5439
	reject {$ifcfg['dhcprejectfrom']};
5440
EOD;
5441
	}
5442
	$dhclientconf .= <<<EOD
5443

    
5444
}
5445

    
5446
EOD;
5447

    
5448
	// DHCP Config File Advanced
5449
	if ($ifcfg['adv_dhcp_config_advanced']) {
5450
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5451
	}
5452

    
5453
	if (is_ipaddr($ifcfg['alias-address'])) {
5454
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5455
		$dhclientconf .= <<<EOD
5456
alias {
5457
	interface "{$realif}";
5458
	fixed-address {$ifcfg['alias-address']};
5459
	option subnet-mask {$subnetmask};
5460
}
5461

    
5462
EOD;
5463
	}
5464

    
5465
	// DHCP Config File Override
5466
	if ($ifcfg['adv_dhcp_config_file_override']) {
5467
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5468
	}
5469

    
5470
	fwrite($fd, $dhclientconf);
5471
	fclose($fd);
5472

    
5473
	/* bring wan interface up before starting dhclient */
5474
	if ($realif) {
5475
		interfaces_bring_up($realif);
5476
	}
5477

    
5478
	/* Make sure dhclient is not running */
5479
	kill_dhclient_process($realif);
5480

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

    
5484
	return 0;
5485
}
5486

    
5487
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5488

    
5489
	$hostname = "";
5490
	if ($ifcfg['dhcphostname'] != '') {
5491
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5492
	}
5493

    
5494
	/* DHCP Protocol Timings */
5495
	$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");
5496
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5497
		$pt_variable = "{$Protocol_Timing}";
5498
		${$pt_variable} = "";
5499
		if ($ifcfg[$Protocol_Timing] != "") {
5500
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5501
		}
5502
	}
5503

    
5504
	$send_options = "";
5505
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5506
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5507
		foreach ($options as $option) {
5508
			$send_options .= "\tsend " . trim($option) . ";\n";
5509
		}
5510
	}
5511

    
5512
	$request_options = "";
5513
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5514
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5515
	}
5516

    
5517
	$required_options = "";
5518
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5519
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5520
	}
5521

    
5522
	$option_modifiers = "";
5523
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5524
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5525
		foreach ($modifiers as $modifier) {
5526
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5527
		}
5528
	}
5529

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

    
5554
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5555

    
5556
	return $dhclientconf;
5557
}
5558

    
5559
function DHCP_Config_Option_Split($option_string) {
5560
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5561
	return $matches ? $matches[0] : [];
5562
}
5563

    
5564
function DHCP_Config_File_Override($ifcfg, $realif) {
5565

    
5566
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5567

    
5568
	if ($dhclientconf === false) {
5569
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5570
		return '';
5571
	} else {
5572
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5573
	}
5574
}
5575

    
5576

    
5577
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5578

    
5579
	/* Apply Interface Substitutions */
5580
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5581

    
5582
	/* Apply Hostname Substitutions */
5583
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5584

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

    
5591
	/* Apply MAC Address Substitutions */
5592
	foreach ($various_mac_types as $various_mac_type) {
5593
		foreach ($various_mac_cases as $various_mac_case) {
5594
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5595

    
5596
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5597
				if ($res !== false) {
5598

    
5599
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5600
					if ("$various_mac_case" == "U") {
5601
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5602
					}
5603
					if ("$various_mac_case" == "L") {
5604
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5605
					}
5606

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

    
5619
					/* MAC Address Delimiter Substitutions */
5620
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5621

    
5622
					/* Apply MAC Address Substitutions */
5623
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5624
				}
5625
			}
5626
		}
5627
	}
5628

    
5629
	return $dhclientconf;
5630
}
5631

    
5632
function interfaces_group_setup() {
5633
	global $config;
5634

    
5635
	if (!isset($config['ifgroups']['ifgroupentry']) || !is_array($config['ifgroups']['ifgroupentry'])) {
5636
		return;
5637
	}
5638

    
5639
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5640
		interface_group_setup($groupar);
5641
	}
5642

    
5643
	return;
5644
}
5645

    
5646
function interface_group_setup(&$groupname /* The parameter is an array */) {
5647
	global $config;
5648

    
5649
	if (!is_array($groupname)) {
5650
		return;
5651
	}
5652
	$members = explode(" ", $groupname['members']);
5653
	foreach ($members as $ifs) {
5654
		$realif = get_real_interface($ifs);
5655
		if ($realif && does_interface_exist($realif)) {
5656
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5657
		}
5658
	}
5659

    
5660
	return;
5661
}
5662

    
5663
function is_interface_group($if) {
5664
	global $config;
5665

    
5666
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5667
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5668
			if ($groupentry['ifname'] === $if) {
5669
				return true;
5670
			}
5671
		}
5672
	}
5673

    
5674
	return false;
5675
}
5676

    
5677
function interface_group_add_member($interface, $groupname) {
5678
	$interface = get_real_interface($interface);
5679
	if (does_interface_exist($interface)) {
5680
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5681
	}
5682
}
5683

    
5684
/* COMPAT Function */
5685
function convert_friendly_interface_to_real_interface_name($interface) {
5686
	return get_real_interface($interface);
5687
}
5688

    
5689
/* COMPAT Function */
5690
function get_real_wan_interface($interface = "wan") {
5691
	return get_real_interface($interface);
5692
}
5693

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

    
5699
/*
5700
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5701
 */
5702
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5703
	global $config;
5704

    
5705
	/* XXX: For speed reasons reference directly the interface array */
5706
	init_config_arr(array('interfaces'));
5707
	$ifdescrs = &$config['interfaces'];
5708
	//$ifdescrs = get_configured_interface_list(true);
5709

    
5710
	foreach ($ifdescrs as $if => $ifname) {
5711
		if ($if == $interface || $ifname['if'] == $interface) {
5712
			return $if;
5713
		}
5714

    
5715
		if (get_real_interface($if) == $interface) {
5716
			return $if;
5717
		}
5718

    
5719
		if ($checkparent == false) {
5720
			continue;
5721
		}
5722

    
5723
		$int = get_parent_interface($if, true);
5724
		if (is_array($int)) {
5725
			foreach ($int as $iface) {
5726
				if ($iface == $interface) {
5727
					return $if;
5728
				}
5729
			}
5730
		}
5731
	}
5732

    
5733
	if ($interface == "enc0") {
5734
		return 'IPsec';
5735
	}
5736
}
5737

    
5738
/* attempt to resolve interface to friendly descr */
5739
function convert_friendly_interface_to_friendly_descr($interface) {
5740
	global $config;
5741

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

    
5797
				/* if list */
5798
				$ifdescrs = get_configured_interface_with_descr(true);
5799
				foreach ($ifdescrs as $if => $ifname) {
5800
					if ($if == $interface || $ifname == $interface) {
5801
						return $ifname;
5802
					}
5803
				}
5804
			}
5805
			break;
5806
	}
5807

    
5808
	return $ifdesc;
5809
}
5810

    
5811
function convert_real_interface_to_friendly_descr($interface) {
5812

    
5813
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5814

    
5815
	if (!empty($ifdesc)) {
5816
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5817
	}
5818

    
5819
	return $interface;
5820
}
5821

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

    
5834
	$parents = array();
5835
	//Check that we got a valid interface passed
5836
	$realif = get_real_interface($interface);
5837
	if ($realif == NULL) {
5838
		return $parents;
5839
	}
5840

    
5841
	// If we got a real interface, find it's friendly assigned name
5842
	if ($interface == $realif && $avoidrecurse == false) {
5843
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5844
	}
5845

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

    
5879
	if (empty($parents)) {
5880
		// Handle _vlans not assigned to an interface
5881
		$vlan = interface_is_vlan($realif);
5882
		if ($vlan != NULL) {
5883
			$parents[0] = $vlan['if'];
5884
		}
5885
	}
5886

    
5887
	if (empty($parents)) {
5888
		/* Handle LAGGs. */
5889
		$lagg = interface_is_type($realif, 'lagg');
5890
		if ($lagg != NULL && isset($lagg['members'])) {
5891
			$parents = explode(",", $lagg['members']);
5892
		}
5893
	}
5894

    
5895
	if (empty($parents)) {
5896
		$parents[0] = $realif;
5897
	}
5898

    
5899
	return $parents;
5900
}
5901

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

    
5910
	$realif = get_parent_interface($interface);
5911

    
5912
	if (substr($realif[0], 0, 4) == "lagg") {
5913
		foreach ($config['laggs']['lagg'] as $lagg) {
5914
			if ($realif[0] == $lagg['laggif']) {
5915
				return explode(",", $lagg['members']);
5916
			}
5917
		}
5918
	} else {
5919
		return $realif;
5920
	}
5921
}
5922

    
5923
function interface_is_wireless_clone($wlif) {
5924
	if (!stristr($wlif, "_wlan")) {
5925
		return false;
5926
	} else {
5927
		return true;
5928
	}
5929
}
5930

    
5931
function interface_get_wireless_base($wlif) {
5932
	if (!stristr($wlif, "_wlan")) {
5933
		return $wlif;
5934
	} else {
5935
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5936
	}
5937
}
5938

    
5939
function interface_get_wireless_clone($wlif) {
5940
	if (!stristr($wlif, "_wlan")) {
5941
		return $wlif . "_wlan0";
5942
	} else {
5943
		return $wlif;
5944
	}
5945
}
5946

    
5947
function interface_list_wireless() {
5948
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5949

    
5950
	$result = array();
5951
	foreach ($portlist as $port) {
5952
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5953
			continue;
5954
		}
5955

    
5956
		$desc = $port . " ( " . get_single_sysctl(
5957
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5958

    
5959
		$result[] = array(
5960
		    "if" => $port,
5961
		    "descr" => $desc
5962
		);
5963
	}
5964

    
5965
	return $result;
5966
}
5967

    
5968
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
5969
	global $config, $g;
5970

    
5971
	$wanif = NULL;
5972

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

    
6015
			if (empty($config['interfaces'][$interface])) {
6016
				break;
6017
			}
6018

    
6019
			$cfg = &$config['interfaces'][$interface];
6020

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

    
6079
	return $wanif;
6080
}
6081

    
6082
/* Guess the physical interface by providing a IP address */
6083
function guess_interface_from_ip($ipaddress) {
6084

    
6085
	if (!is_ipaddr($ipaddress)) {
6086
		return false;
6087
	}
6088

    
6089
	$route = route_get($ipaddress);
6090
	if (empty($route)) {
6091
		return false;
6092
	}
6093

    
6094
	if (!empty($route[0]['interface-name'])) {
6095
		return $route[0]['interface-name'];
6096
	}
6097

    
6098
	return false;
6099
}
6100

    
6101
/*
6102
 * find_ip_interface($ip): return the interface where an ip is defined
6103
 *   (or if $bits is specified, where an IP within the subnet is defined)
6104
 */
6105
function find_ip_interface($ip, $bits = null) {
6106
	if (!is_ipaddr($ip)) {
6107
		return false;
6108
	}
6109

    
6110
	$isv6ip = is_ipaddrv6($ip);
6111

    
6112
	/* if list */
6113
	$ifdescrs = get_configured_interface_list();
6114

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

    
6133
	return false;
6134
}
6135

    
6136
/*
6137
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6138
 *   (or if $bits is specified, where an IP within the subnet is found)
6139
 */
6140
function find_virtual_ip_alias($ip, $bits = null) {
6141
	global $config;
6142

    
6143
	if (!is_array($config['virtualip']['vip'])) {
6144
		return false;
6145
	}
6146
	if (!is_ipaddr($ip)) {
6147
		return false;
6148
	}
6149

    
6150
	$isv6ip = is_ipaddrv6($ip);
6151

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

    
6172
function link_interface_to_track6($int, $action = "") {
6173
	global $config;
6174

    
6175
	if (empty($int)) {
6176
		return;
6177
	}
6178

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

    
6197
function interface_find_child_cfgmtu($realiface) {
6198
	global $config;
6199

    
6200
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6201
	$vlans = link_interface_to_vlans($realiface);
6202
	$qinqs = link_interface_to_qinqs($realiface);
6203
	$bridge = link_interface_to_bridge($realiface);
6204
	if (!empty($interface)) {
6205
		$gifs = link_interface_to_tunnelif($interface, 'gif');
6206
		$gres = link_interface_to_tunnelif($interface, 'gre');
6207
		$vxlans = link_interface_to_tunnelif($interface, 'vxlan');
6208
	} else {
6209
		$gifs = array();
6210
		$gres = array();
6211
		$vxlans = array();
6212
	}
6213

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

    
6288
	return $mtu;
6289
}
6290

    
6291
function link_interface_to_vlans($int, $action = "") {
6292
	global $config;
6293

    
6294
	if (empty($int)) {
6295
		return;
6296
	}
6297

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

    
6315
function link_interface_to_qinqs($int, $action = "") {
6316
	global $config;
6317

    
6318
	if (empty($int)) {
6319
		return;
6320
	}
6321

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

    
6339
function link_interface_to_vips($int, $action = "", $vhid = '') {
6340
	global $config;
6341

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

    
6369
	return NULL;
6370
}
6371

    
6372
/****f* interfaces/link_interface_to_bridge
6373
 * NAME
6374
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6375
 * INPUTS
6376
 *   $ip
6377
 * RESULT
6378
 *   bridge[0-99]
6379
 ******/
6380
function link_interface_to_bridge($int) {
6381
	global $config;
6382

    
6383
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6384
		foreach ($config['bridges']['bridged'] as $bridge) {
6385
			if (in_array($int, explode(',', $bridge['members']))) {
6386
				return "{$bridge['bridgeif']}";
6387
			}
6388
		}
6389
	}
6390
}
6391

    
6392
function link_interface_to_lagg($int) {
6393
	global $config;
6394

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

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

    
6407
	$result = array();
6408

    
6409
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6410
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6411
			if (in_array($int, explode(" ", $group['members']))) {
6412
				$result[$group['ifname']] = $int;
6413
			}
6414
		}
6415
	}
6416

    
6417
	return $result;
6418
}
6419

    
6420
function link_interface_to_tunnelif($interface, $type) {
6421
	global $config;
6422

    
6423
	if (!in_array($type, array('gre', 'gif', 'vxlan'))) {
6424
		return;
6425
	}
6426

    
6427
	$result = array();
6428

    
6429
	if (is_array($config["{$type}s"][$type])) {
6430
		foreach ($config["{$type}s"][$type] as $tunnel) {
6431
			if ($tunnel['if'] == $interface) {
6432
				$result[] = $tunnel;
6433
			}
6434
		}
6435
	}
6436

    
6437
	return $result;
6438
}
6439

    
6440
/*
6441
 * find_interface_ip($interface): return the interface ip (first found)
6442
 */
6443
function find_interface_ip($interface, $flush = false) {
6444
	global $interface_ip_arr_cache;
6445
	global $interface_sn_arr_cache;
6446

    
6447
	$interface = str_replace("\n", "", $interface);
6448

    
6449
	if (!does_interface_exist($interface)) {
6450
		return;
6451
	}
6452

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

    
6474
	return $interface_ip_arr_cache[$interface];
6475
}
6476

    
6477
/*
6478
 * find_interface_ipv6($interface): return the interface ip (first found)
6479
 */
6480
function find_interface_ipv6($interface, $flush = false) {
6481
	global $interface_ipv6_arr_cache;
6482
	global $interface_snv6_arr_cache;
6483
	global $config;
6484

    
6485
	$interface = trim($interface);
6486
	$interface = get_real_interface($interface);
6487

    
6488
	if (!does_interface_exist($interface)) {
6489
		return;
6490
	}
6491

    
6492
	/* Setup IP cache */
6493
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6494
		$ifinfo = pfSense_get_interface_addresses($interface);
6495
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6496
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6497
	}
6498

    
6499
	return $interface_ipv6_arr_cache[$interface];
6500
}
6501

    
6502
/*
6503
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6504
 */
6505
function find_interface_ipv6_ll($interface, $flush = false) {
6506
	global $interface_llv6_arr_cache;
6507
	global $config;
6508

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

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

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

    
6531
function find_interface_subnet($interface, $flush = false) {
6532
	global $interface_sn_arr_cache;
6533
	global $interface_ip_arr_cache;
6534

    
6535
	$interface = str_replace("\n", "", $interface);
6536
	if (does_interface_exist($interface) == false) {
6537
		return;
6538
	}
6539

    
6540
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6541
		$ifinfo = pfSense_get_interface_addresses($interface);
6542
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6543
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6544
	}
6545

    
6546
	return $interface_sn_arr_cache[$interface];
6547
}
6548

    
6549
function find_interface_subnetv6($interface, $flush = false) {
6550
	global $interface_snv6_arr_cache;
6551
	global $interface_ipv6_arr_cache;
6552

    
6553
	$interface = str_replace("\n", "", $interface);
6554
	if (does_interface_exist($interface) == false) {
6555
		return;
6556
	}
6557

    
6558
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6559
		$ifinfo = pfSense_get_interface_addresses($interface);
6560
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6561
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6562
	}
6563

    
6564
	return $interface_snv6_arr_cache[$interface];
6565
}
6566

    
6567
function ip_in_interface_alias_subnet($interface, $ipalias) {
6568
	global $config;
6569

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

    
6589
	return false;
6590
}
6591

    
6592
function get_possible_listen_ips($include_ipv6_link_local=false) {
6593

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

    
6615
	$interfaces['lo0'] = 'Localhost';
6616

    
6617
	return $interfaces;
6618
}
6619

    
6620
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6621
	global $config;
6622

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

    
6648
function get_interface_ip($interface = "wan") {
6649
	global $config;
6650

    
6651
	if (substr($interface, 0, 4) == '_vip') {
6652
		return get_configured_vip_ipv4($interface);
6653
	} else if (substr($interface, 0, 5) == '_lloc') {
6654
		/* No link-local address for v4. */
6655
		return null;
6656
	}
6657

    
6658
	$realif = get_failover_interface($interface, 'inet');
6659
	if (!$realif) {
6660
		return null;
6661
	}
6662

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

    
6670
	if (is_array($config['interfaces'][$interface]) &&
6671
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6672
		return ($config['interfaces'][$interface]['ipaddr']);
6673
	}
6674

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

    
6688
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6689
	global $config;
6690

    
6691
	if (substr($interface, 0, 4) == '_vip') {
6692
		return get_configured_vip_ipv6($interface);
6693
	} else if (substr($interface, 0, 5) == '_lloc') {
6694
		return get_interface_linklocal($interface);
6695
	}
6696

    
6697
	$realif = get_failover_interface($interface, 'inet6');
6698
	if (!$realif) {
6699
		return null;
6700
	}
6701

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

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

    
6725
	/*
6726
	 * Beaware that find_interface_ip() is our last option, it will
6727
	 * return the first IP it find on interface, not necessarily the
6728
	 * main IP address.
6729
	 */
6730
	$curip = find_interface_ipv6($realif, $flush);
6731
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6732
		return $curip;
6733
	} else {
6734
		/*
6735
		 * NOTE: On the case when only the prefix is requested,
6736
		 * the communication on WAN will be done over link-local.
6737
		 */
6738
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6739
			$curip = find_interface_ipv6_ll($realif, $flush);
6740
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6741
				return $curip;
6742
			}
6743
		}
6744
	}
6745
	return null;
6746
}
6747

    
6748
function get_interface_linklocal($interface = "wan") {
6749

    
6750
	$realif = get_failover_interface($interface, 'inet6');
6751
	if (!$realif) {
6752
		return null;
6753
	}
6754

    
6755
	if (substr($interface, 0, 4) == '_vip') {
6756
		$realif = get_real_interface($interface);
6757
	} else if (substr($interface, 0, 5) == '_lloc') {
6758
		$realif = get_real_interface(substr($interface, 5));
6759
	}
6760

    
6761
	$curip = find_interface_ipv6_ll($realif);
6762
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6763
		return $curip;
6764
	} else {
6765
		return null;
6766
	}
6767
}
6768

    
6769
function get_interface_subnet($interface = "wan") {
6770
	global $config;
6771

    
6772
	if (substr($interface, 0, 4) == '_vip') {
6773
		return (get_configured_vip_subnetv4($interface));
6774
	}
6775

    
6776
	if (is_array($config['interfaces'][$interface]) &&
6777
	    !empty($config['interfaces'][$interface]['subnet']) &&
6778
	    is_ipaddrv4($config['interfaces'][$interface]['ipaddr'])) {
6779
		return ($config['interfaces'][$interface]['subnet']);
6780
	}
6781

    
6782
	$realif = get_real_interface($interface);
6783
	if (!$realif) {
6784
		return (NULL);
6785
	}
6786

    
6787
	$cursn = find_interface_subnet($realif);
6788
	if (!empty($cursn)) {
6789
		return ($cursn);
6790
	}
6791

    
6792
	return (NULL);
6793
}
6794

    
6795
function get_interface_subnetv6($interface = "wan") {
6796
	global $config;
6797

    
6798
	if (substr($interface, 0, 4) == '_vip') {
6799
		return (get_configured_vip_subnetv6($interface));
6800
	} else if (substr($interface, 0, 5) == '_lloc') {
6801
		$interface = substr($interface, 5);
6802
	}
6803

    
6804
	if (is_array($config['interfaces'][$interface]) &&
6805
	    !empty($config['interfaces'][$interface]['subnetv6']) &&
6806
	    is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6807
		return ($config['interfaces'][$interface]['subnetv6']);
6808
	}
6809

    
6810
	$realif = get_real_interface($interface, 'inet6');
6811
	if (!$realif) {
6812
		return (NULL);
6813
	}
6814

    
6815
	$cursn = find_interface_subnetv6($realif);
6816
	if (!empty($cursn)) {
6817
		return ($cursn);
6818
	}
6819

    
6820
	return (NULL);
6821
}
6822

    
6823
/* return outside interfaces with a gateway */
6824
function get_interfaces_with_gateway() {
6825
	global $config;
6826

    
6827
	$ints = array();
6828

    
6829
	/* loop interfaces, check config for outbound */
6830
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6831
		switch ($ifname['ipaddr']) {
6832
			case "dhcp":
6833
			case "pppoe":
6834
			case "pptp":
6835
			case "l2tp":
6836
			case "ppp":
6837
				$ints[$ifdescr] = $ifdescr;
6838
				break;
6839
			default:
6840
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6841
				    !empty($ifname['gateway'])) {
6842
					$ints[$ifdescr] = $ifdescr;
6843
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6844
				    !empty($ifname['gateway'])) {
6845
					$ints[$ifdescr] = $ifdescr;
6846
				}
6847

    
6848
				break;
6849
		}
6850
	}
6851
	return $ints;
6852
}
6853

    
6854
/* return true if interface has a gateway */
6855
function interface_has_gateway($friendly) {
6856
	global $config;
6857

    
6858
	if (!empty($config['interfaces'][$friendly])) {
6859
		$ifname = &$config['interfaces'][$friendly];
6860
		switch ($ifname['ipaddr']) {
6861
			case "dhcp":
6862
			case "pppoe":
6863
			case "pptp":
6864
			case "l2tp":
6865
			case "ppp":
6866
				return true;
6867
			break;
6868
			default:
6869
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6870
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6871
					return true;
6872
				}
6873
				$tunnelif = substr($ifname['if'], 0, 3);
6874
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6875
					if (find_interface_ip($ifname['if'])) {
6876
						return true;
6877
					}
6878
				}
6879
				if (!empty($ifname['gateway'])) {
6880
					return true;
6881
				}
6882
			break;
6883
		}
6884
	}
6885

    
6886
	return false;
6887
}
6888

    
6889
/* return true if interface has a gateway */
6890
function interface_has_gatewayv6($friendly) {
6891
	global $config;
6892

    
6893
	if (!empty($config['interfaces'][$friendly])) {
6894
		$ifname = &$config['interfaces'][$friendly];
6895
		switch ($ifname['ipaddrv6']) {
6896
			case "slaac":
6897
			case "dhcp6":
6898
			case "6to4":
6899
			case "6rd":
6900
				return true;
6901
				break;
6902
			default:
6903
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6904
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6905
					return true;
6906
				}
6907
				$tunnelif = substr($ifname['if'], 0, 3);
6908
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6909
					if (find_interface_ipv6($ifname['if'])) {
6910
						return true;
6911
					}
6912
				}
6913
				if (!empty($ifname['gatewayv6'])) {
6914
					return true;
6915
				}
6916
				break;
6917
		}
6918
	}
6919

    
6920
	return false;
6921
}
6922

    
6923
/****f* interfaces/is_altq_capable
6924
 * NAME
6925
 *   is_altq_capable - Test if interface is capable of using ALTQ
6926
 * INPUTS
6927
 *   $int            - string containing interface name
6928
 * RESULT
6929
 *   boolean         - true or false
6930
 ******/
6931

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

    
6947
	$int_family = remove_ifindex($int);
6948

    
6949
	if (in_array($int_family, $capable)) {
6950
		return true;
6951
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6952
		return true;
6953
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6954
		return true;
6955
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6956
		return true;
6957
	} else {
6958
		return false;
6959
	}
6960
}
6961

    
6962
/****f* interfaces/is_interface_wireless
6963
 * NAME
6964
 *   is_interface_wireless - Returns if an interface is wireless
6965
 * RESULT
6966
 *   $tmp       - Returns if an interface is wireless
6967
 ******/
6968
function is_interface_wireless($interface) {
6969
	global $config, $g;
6970

    
6971
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6972
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6973
		if (preg_match($g['wireless_regex'], $interface)) {
6974
			if (isset($config['interfaces'][$friendly])) {
6975
				$config['interfaces'][$friendly]['wireless'] = array();
6976
			}
6977
			return true;
6978
		}
6979
		return false;
6980
	} else {
6981
		return true;
6982
	}
6983
}
6984

    
6985
function get_wireless_modes($interface) {
6986
	/* return wireless modes and channels */
6987
	$wireless_modes = array();
6988

    
6989
	$cloned_interface = get_real_interface($interface);
6990

    
6991
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6992
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6993
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6994
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6995

    
6996
		$interface_channels = "";
6997
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6998
		$interface_channel_count = count($interface_channels);
6999

    
7000
		$c = 0;
7001
		while ($c < $interface_channel_count) {
7002
			$channel_line = explode(",", $interface_channels["$c"]);
7003
			$wireless_mode = trim($channel_line[0]);
7004
			$wireless_channel = trim($channel_line[1]);
7005
			if (trim($wireless_mode) != "") {
7006
				/* if we only have 11g also set 11b channels */
7007
				if ($wireless_mode == "11g") {
7008
					if (!isset($wireless_modes["11b"])) {
7009
						$wireless_modes["11b"] = array();
7010
					}
7011
				} else if ($wireless_mode == "11g ht") {
7012
					if (!isset($wireless_modes["11b"])) {
7013
						$wireless_modes["11b"] = array();
7014
					}
7015
					if (!isset($wireless_modes["11g"])) {
7016
						$wireless_modes["11g"] = array();
7017
					}
7018
					$wireless_mode = "11ng";
7019
				} else if ($wireless_mode == "11a ht") {
7020
					if (!isset($wireless_modes["11a"])) {
7021
						$wireless_modes["11a"] = array();
7022
					}
7023
					$wireless_mode = "11na";
7024
				}
7025
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
7026
			}
7027
			$c++;
7028
		}
7029
	}
7030
	return($wireless_modes);
7031
}
7032

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

    
7038
		$interface_channels = "";
7039
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7040
		return $interface_channels;
7041
}
7042

    
7043
/* return wireless HT modes */
7044
function get_wireless_ht_modes($interface) {
7045
	$wireless_hts_supported = array(0 => gettext('Auto'));
7046

    
7047
	$cloned_interface = get_real_interface($interface);
7048

    
7049
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7050
		$interface_channels = get_wireless_channels($cloned_interface);
7051

    
7052
		foreach ($interface_channels as $channel) {
7053
			$channel_line = explode(",", $channel);
7054
			$wireless_ht = trim($channel_line[1]);
7055
			if (!empty($wireless_ht)) {
7056
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
7057
			}
7058
		}
7059
	}
7060
	return($wireless_hts_supported);
7061
}
7062

    
7063
/* return wireless HT by channel/standard */
7064
function get_wireless_ht_list($interface) {
7065
	$wireless_hts = array();
7066

    
7067
	$cloned_interface = get_real_interface($interface);
7068

    
7069
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7070
		$interface_channels = get_wireless_channels($cloned_interface);
7071
		$interface_channel_count = count($interface_channels);
7072

    
7073
		$c = 0;
7074
		while ($c < $interface_channel_count) {
7075
			$channel_line = explode(",", $interface_channels["$c"]);
7076
			$wireless_mode = trim($channel_line[0]);
7077
			$wireless_ht = trim($channel_line[1]);
7078
			$wireless_channel = trim($channel_line[2]);
7079
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
7080
				if ($wireless_mode == "11g") {
7081
					if (!isset($wireless_modes["11g"])) {
7082
						$wireless_hts["11g"] = array();
7083
					}
7084
					$wireless_mode = "11ng";
7085
				} elseif ($wireless_mode == "11a") {
7086
					if (!isset($wireless_modes["11a"])) {
7087
						$wireless_hts["11a"] = array();
7088
					}
7089
					$wireless_mode = "11na";
7090
				}
7091
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
7092
			}
7093
			$c++;
7094
		}
7095
	}
7096
	return($wireless_hts);
7097
}
7098

    
7099
/* return channel numbers, frequency, max txpower, and max regulation txpower */
7100
function get_wireless_channel_info($interface) {
7101
	$wireless_channels = array();
7102

    
7103
	$cloned_interface = get_real_interface($interface);
7104

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

    
7110
		$interface_channels = "";
7111
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7112

    
7113
		foreach ($interface_channels as $channel_line) {
7114
			$channel_line = explode(",", $channel_line);
7115
			if (!isset($wireless_channels[$channel_line[0]])) {
7116
				$wireless_channels[$channel_line[0]] = $channel_line;
7117
			}
7118
		}
7119
	}
7120
	return($wireless_channels);
7121
}
7122

    
7123
function set_interface_mtu($interface, $mtu) {
7124

    
7125
	/* LAGG interface must be destroyed and re-created to change MTU */
7126
	if ((substr($interface, 0, 4) == 'lagg') &&
7127
	    (!strstr($interface, "."))) {
7128
		if (isset($config['laggs']['lagg']) &&
7129
		    is_array($config['laggs']['lagg'])) {
7130
			foreach ($config['laggs']['lagg'] as $lagg) {
7131
				if ($lagg['laggif'] == $interface) {
7132
					interface_lagg_configure($lagg);
7133
					break;
7134
				}
7135
			}
7136
		}
7137
	} else {
7138
		pfSense_interface_mtu($interface, $mtu);
7139
		set_ipv6routes_mtu($interface, $mtu);
7140
	}
7141
}
7142

    
7143
/****f* interfaces/get_interface_mtu
7144
 * NAME
7145
 *   get_interface_mtu - Return the mtu of an interface
7146
 * RESULT
7147
 *   $tmp       - Returns the mtu of an interface
7148
 ******/
7149
function get_interface_mtu($interface) {
7150
	$mtu = pfSense_interface_getmtu($interface);
7151
	return $mtu['mtu'];
7152
}
7153

    
7154
function get_interface_mac($interface) {
7155
	$macinfo = pfSense_get_interface_addresses($interface);
7156
	return $macinfo["macaddr"];
7157
}
7158

    
7159
function get_interface_vendor_mac($interface) {
7160
	global $config, $g;
7161

    
7162
	$macinfo = pfSense_get_interface_addresses($interface);
7163
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7164
	    "00:00:00:00:00:00") {
7165
		return ($macinfo["hwaddr"]);
7166
	}
7167

    
7168
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7169
	if (file_exists($hwaddr_file)) {
7170
		$macaddr = trim(file_get_contents($hwaddr_file));
7171
		if (is_macaddr($macaddr)) {
7172
			return ($macaddr);
7173
		}
7174
	} elseif (is_macaddr($macinfo['macaddr'])) {
7175
		/* Save original macaddress to be restored when necessary */
7176
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7177
	}
7178

    
7179
	return (NULL);
7180
}
7181

    
7182
/****f* pfsense-utils/generate_random_mac_address
7183
 * NAME
7184
 *   generate_random_mac - generates a random mac address
7185
 * INPUTS
7186
 *   none
7187
 * RESULT
7188
 *   $mac - a random mac address
7189
 ******/
7190
function generate_random_mac_address() {
7191
	$mac = "02";
7192
	for ($x = 0; $x < 5; $x++) {
7193
		$mac .= ":" . dechex(rand(16, 255));
7194
	}
7195
	return $mac;
7196
}
7197

    
7198
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7199
	global $g;
7200

    
7201
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7202

    
7203
	if (!empty($iface) && !empty($pppif)) {
7204
		$cron_cmd = <<<EOD
7205
#!/bin/sh
7206
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7207
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7208

    
7209
EOD;
7210

    
7211
		@file_put_contents($cron_file, $cron_cmd);
7212
		chmod($cron_file, 0755);
7213
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7214
	} else {
7215
		unlink_if_exists($cron_file);
7216
	}
7217
}
7218

    
7219
function get_interface_default_mtu($type = "ethernet") {
7220
	switch ($type) {
7221
		case "gre":
7222
			return 1476;
7223
			break;
7224
		case "gif":
7225
			return 1280;
7226
			break;
7227
		case "tun":
7228
		case "vlan":
7229
		case "tap":
7230
		case "ethernet":
7231
		default:
7232
			return 1500;
7233
			break;
7234
	}
7235

    
7236
	/* Never reached */
7237
	return 1500;
7238
}
7239

    
7240
function get_vip_descr($ipaddress) {
7241
	global $config;
7242

    
7243
	foreach ($config['virtualip']['vip'] as $vip) {
7244
		if ($vip['subnet'] == $ipaddress) {
7245
			return ($vip['descr']);
7246
		}
7247
	}
7248
	return "";
7249
}
7250

    
7251
function interfaces_staticarp_configure($if) {
7252
	global $config, $g;
7253
	if (isset($config['system']['developerspew'])) {
7254
		$mt = microtime();
7255
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7256
	}
7257

    
7258
	$ifcfg = $config['interfaces'][$if];
7259

    
7260
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
7261
		return 0;
7262
	}
7263

    
7264
	/* Enable staticarp, if enabled */
7265
	if (isset($config['dhcpd'][$if]['staticarp'])) {
7266
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7267
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7268
	} else {
7269
		/*
7270
		 * Interfaces do not have staticarp enabled by default
7271
		 * Let's not disable staticarp on freshly created interfaces
7272
		 */
7273
		if (!platform_booting()) {
7274
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7275
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7276
		}
7277
	}
7278

    
7279
	/* Enable static arp entries */
7280
	if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
7281
		foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
7282
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7283
				continue;
7284
			}
7285
			if (isset($config['dhcpd'][$if]['staticarp']) || isset($arpent['arp_table_static_entry'])) {
7286
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7287
			}
7288
		}
7289
	}
7290

    
7291
	return 0;
7292
}
7293

    
7294
function get_failover_interface($interface, $family = "all") {
7295
	global $config;
7296

    
7297
	/* shortcut to get_real_interface if we find it in the config */
7298
	if (is_array($config['interfaces'][$interface])) {
7299
		return get_real_interface($interface, $family);
7300
	}
7301

    
7302
	/* compare against gateway groups */
7303
	$a_groups = return_gateway_groups_array(true);
7304
	if (is_array($a_groups[$interface])) {
7305
		/* we found a gateway group, fetch the interface or vip */
7306
		if (!empty($a_groups[$interface][0]['vip'])) {
7307
			return $a_groups[$interface][0]['vip'];
7308
		} else {
7309
			return $a_groups[$interface][0]['int'];
7310
		}
7311
	}
7312
	/* fall through to get_real_interface */
7313
	/* XXX: Really needed? */
7314
	return get_real_interface($interface, $family);
7315
}
7316

    
7317
/****f* interfaces/interface_has_dhcp
7318
 * NAME
7319
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7320
 * INPUTS
7321
 *   interface or gateway group name
7322
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7323
 * RESULT
7324
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7325
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7326
 ******/
7327
function interface_has_dhcp($interface, $family = 4) {
7328
	global $config;
7329

    
7330
	if ($config['interfaces'][$interface]) {
7331
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
7332
			return true;
7333
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
7334
			return true;
7335
		} else {
7336
			return false;
7337
		}
7338
	}
7339

    
7340
	if (!is_array($config['gateways']['gateway_group'])) {
7341
		return false;
7342
	}
7343

    
7344
	if ($family == 6) {
7345
		$dhcp_string = "_DHCP6";
7346
	} else {
7347
		$dhcp_string = "_DHCP";
7348
	}
7349

    
7350
	foreach ($config['gateways']['gateway_group'] as $group) {
7351
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7352
			continue;
7353
		}
7354
		foreach ($group['item'] as $item) {
7355
			$item_data = explode("|", $item);
7356
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7357
				return true;
7358
			}
7359
		}
7360
	}
7361

    
7362
	return false;
7363
}
7364

    
7365
function remove_ifindex($ifname) {
7366
	return preg_replace("/[0-9]+$/", "", $ifname);
7367
}
7368

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

    
7372
	$viplist = get_configured_vip_list($family, $type);
7373
	foreach ($viplist as $vip => $address) {
7374
		$interfaces[$vip] = $address;
7375
		if ($type = VIP_CARP) {
7376
			$vip = get_configured_vip($vipid);
7377
			if (isset($vip) && is_array($vip) ) {
7378
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7379
			}
7380
		}
7381
		if (get_vip_descr($address)) {
7382
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
7383
		}
7384
	}
7385
	return $interfaces;
7386
}
7387

    
7388
function return_gateway_groups_array_with_descr() {
7389
	$interfaces = array();
7390
	$grouplist = return_gateway_groups_array();
7391
	foreach ($grouplist as $name => $group) {
7392
		if ($group[0]['vip'] != "") {
7393
			$vipif = $group[0]['vip'];
7394
		} else {
7395
			$vipif = $group[0]['int'];
7396
		}
7397

    
7398
		$interfaces[$name] = "GW Group {$name}";
7399
	}
7400
	return $interfaces;
7401
}
7402

    
7403
function get_serial_ports() {
7404
	$linklist = array();
7405
	if (!is_dir("/var/spool/lock")) {
7406
		mwexec("/bin/mkdir -p /var/spool/lock");
7407
	}
7408
	$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);
7409
	foreach ($serialports as $port) {
7410
		$linklist[$port] = trim($port);
7411
	}
7412
	return $linklist;
7413
}
7414

    
7415
function get_interface_ports() {
7416
	global $config;
7417
	$linklist = array();
7418
	$portlist = get_interface_list();
7419
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7420
		foreach ($config['vlans']['vlan'] as $vlan) {
7421
			$portlist[$vlan['vlanif']] = $vlan;
7422
		}
7423
	}
7424

    
7425
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7426
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7427
			$members = explode(" ", $qinq['members']);
7428
			foreach ($members as $mem) {
7429
				$qentry = $qinq['vlanif'] . "." . $mem;
7430
				$portlist[$qentry] = $qentry;
7431
			}
7432
		}
7433
	}
7434

    
7435
	foreach ($portlist as $ifn => $ifinfo) {
7436
		$string = "";
7437
		if (is_array($ifinfo)) {
7438
			$string .= $ifn;
7439
			if ($ifinfo['mac']) {
7440
				$string .= " ({$ifinfo['mac']})";
7441
			}
7442
			if ($ifinfo['friendly']) {
7443
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7444
			} elseif ($ifinfo['descr']) {
7445
				$string .= " - {$ifinfo['descr']}";
7446
			}
7447
		} else {
7448
			$string .= $ifinfo;
7449
		}
7450

    
7451
		$linklist[$ifn] = $string;
7452
	}
7453
	return $linklist;
7454
}
7455

    
7456
function build_ppps_link_list() {
7457
	global $pconfig;
7458

    
7459
	$linklist = array('list' => array(), 'selected' => array());
7460

    
7461
	if ($pconfig['type'] == 'ppp') {
7462
		$linklist['list'] = get_serial_ports();
7463
	} else {
7464
		$iflist = get_interface_ports();
7465

    
7466
		$viplist = array();
7467
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7468
		foreach ($carplist as $vid => $vaddr) {
7469
			$vip = get_configured_vip($vid);
7470
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7471
		}
7472

    
7473
		$linklist['list'] = array_merge($iflist, $viplist);
7474

    
7475
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7476
		$lagglist = get_lagg_interface_list();
7477
		foreach ($lagglist as $laggif => $lagg) {
7478
			/* LAGG members cannot be assigned */
7479
			$laggmembers = explode(',', $lagg['members']);
7480
			foreach ($laggmembers as $lagm) {
7481
				if (isset($linklist['list'][$lagm])) {
7482
					unset($linklist['list'][$lagm]);
7483
				}
7484
			}
7485
		}
7486
	}
7487

    
7488
	$selected_ports = array();
7489
	if (is_array($pconfig['interfaces'])) {
7490
		$selected_ports = $pconfig['interfaces'];
7491
	} elseif (!empty($pconfig['interfaces'])) {
7492
		$selected_ports = explode(',', $pconfig['interfaces']);
7493
	}
7494
	foreach ($selected_ports as $port) {
7495
		if (isset($linklist['list'][$port])) {
7496
			array_push($linklist['selected'], $port);
7497
		}
7498
	}
7499
	return($linklist);
7500
}
7501

    
7502
function create_interface_list() {
7503
	global $config;
7504

    
7505
	$iflist = array();
7506

    
7507
	// add group interfaces
7508
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7509
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7510
			if (have_ruleint_access($ifgen['ifname'])) {
7511
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7512
			}
7513
		}
7514
	}
7515

    
7516
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7517
		if (have_ruleint_access($ifent)) {
7518
			$iflist[$ifent] = $ifdesc;
7519
		}
7520
	}
7521

    
7522
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
7523
		$iflist['l2tp'] = gettext('L2TP VPN');
7524
	}
7525

    
7526
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
7527
		$iflist['pppoe'] = gettext("PPPoE Server");
7528
	}
7529

    
7530
	// add ipsec interfaces
7531
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
7532
		$iflist["enc0"] = gettext("IPsec");
7533
	}
7534

    
7535
	// add openvpn/tun interfaces
7536
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7537
		$iflist["openvpn"] = gettext("OpenVPN");
7538
	}
7539

    
7540
	return($iflist);
7541
}
7542

    
7543
function is_pseudo_interface($inf, $tap=true) {
7544
	global $config;
7545
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7546
	foreach ($psifs as $pif) {
7547
		if (substr($inf, 0, strlen($pif)) == $pif) {
7548
			if (($pif == 'ovpn') && $tap) {
7549
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7550
				$type = ($m[1] == 'c') ? 'client' : 'server';
7551
				foreach ($config['openvpn']['openvpn-'.$type] as $ovpn) {
7552
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7553
						return false; 	
7554
					} elseif ($ovpn['vpnid'] == $m[2]) {
7555
						return true;
7556
					}
7557
				}
7558
			} else {
7559
				return true;
7560
			}
7561
		}
7562
	}
7563
	return false;
7564
}
7565

    
7566
function is_stf_interface($inf) {
7567
	global $config;
7568

    
7569
	if (is_array($config['interfaces'][$inf]) &&
7570
	    (($config['interfaces'][$inf]['ipaddrv6'] == '6rd') ||
7571
	    ($config['interfaces'][$inf]['ipaddrv6'] == '6to4'))) {
7572
	    return true;
7573
	}
7574

    
7575
	return false;
7576
}
7577

    
7578
?>
(22-22/61)