Project

General

Profile

Download (217 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 = true) {
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);
434
		}
435
	}
436
	if (platform_booting()) {
437
		echo gettext("done.") . "\n";
438
	}
439
}
440

    
441
function interface_vlan_configure(&$vlan) {
442
	global $config, $g;
443

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

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

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

    
467
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
468
		pfSense_interface_destroy($vlanif);
469
	}
470

    
471
	$tmpvlanif = pfSense_interface_create("vlan");
472
	pfSense_interface_rename($tmpvlanif, $vlanif);
473
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
474

    
475
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
476

    
477
	interfaces_bring_up($vlanif);
478

    
479
	/* invalidate interface cache */
480
	get_interface_arr(true);
481

    
482
	/* configure interface if assigned */
483
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
484
	if ($assignedif) {
485
		if (isset($config['interfaces'][$assignedif]['enable'])) {
486
			interface_configure($assignedif, true);
487
		}
488
	}
489

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

    
493
	return $vlanif;
494
}
495

    
496
function interface_qinq_configure(&$qinq, $fd = NULL) {
497
	global $config, $g;
498

    
499
	if (!is_array($qinq)) {
500
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
501
		return;
502
	}
503

    
504
	$qinqif = $qinq['if'];
505
	$tag = $qinq['tag'];
506
	if (empty($qinqif)) {
507
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
508
		return;
509
	}
510

    
511
	if (!does_interface_exist($qinqif)) {
512
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
513
		return;
514
	}
515

    
516
	$vlanif = interface_vlan_configure($qinq);
517
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
518
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
519
		return;
520
	}
521

    
522
	if ($fd == NULL) {
523
		$exec = true;
524
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
525
	} else {
526
		$exec = false;
527
	}
528
	/* make sure the parent is converted to ng_vlan(4) and is up */
529
	interfaces_bring_up($qinqif);
530

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

    
547
	/* invalidate interface cache */
548
	get_interface_arr(true);
549

    
550
	if (interface_is_vlan($qinqif) == NULL) {
551
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
552
	}
553

    
554
	$macaddr = get_interface_mac($qinqif);
555
	if (!empty($qinq['members'])) {
556
		$qinqcmdbuf = "";
557
		$members = explode(" ", $qinq['members']);
558
		foreach ($members as $qtag) {
559
			$qinq2 = array();
560
			$qinq2['tag'] = $qtag;
561
			$qinq2['if'] = $vlanif;
562
			interface_qinq2_configure($qinq2, $qinqcmdbuf, $macaddr);
563
			unset($qinq2);
564
		}
565
		if (strlen($qinqcmdbuf) > 0) {
566
			fwrite($fd, $qinqcmdbuf);
567
		}
568
	}
569
	if ($exec == true) {
570
		fclose($fd);
571
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd > /dev/null 2>&1");
572
	}
573

    
574
	interfaces_bring_up($qinqif);
575
	if (!empty($qinq['members'])) {
576
		$members = explode(" ", $qinq['members']);
577
		foreach ($members as $qtag) {
578
			interfaces_bring_up(qinq_interface($qinq, $qtag));
579
		}
580
	}
581

    
582
	return $vlanif;
583
}
584

    
585
function interfaces_qinq_configure() {
586
	global $config, $g;
587
	if (platform_booting()) {
588
		echo gettext("Configuring QinQ interfaces...");
589
	}
590
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
591
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
592
			/* XXX: Maybe we should report any errors?! */
593
			interface_qinq_configure($qinq);
594
		}
595
	}
596
	if (platform_booting()) {
597
		echo gettext("done.") . "\n";
598
	}
599
}
600

    
601
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr) {
602
	global $config, $g;
603

    
604
	if (!is_array($qinq)) {
605
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
606
		return;
607
	}
608

    
609
	$if = $qinq['if'];
610
	if (empty($if)) {
611
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
612
		return;
613
	}
614
	$tag = $qinq['tag'];
615
	$vlanif = "{$if}.{$tag}";
616
	$ngif = str_replace(".", "_", $if);
617
	if (strlen($vlanif) > IF_NAMESIZE) {
618
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
619
		    $vlanif, IF_NAMESIZE, "\n"));
620
		return;
621
	}
622

    
623
	exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1");
624
	$cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n";
625
	$cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n";
626
	$cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n";
627
	$cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n";
628
	$cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n";
629

    
630
	/* invalidate interface cache */
631
	get_interface_arr(true);
632

    
633
	return $vlanif;
634
}
635

    
636
function interfaces_create_wireless_clones() {
637
	global $config, $g;
638

    
639
	if (platform_booting()) {
640
		echo gettext("Creating wireless clone interfaces...");
641
	}
642

    
643
	$iflist = get_configured_interface_list();
644

    
645
	foreach ($iflist as $if) {
646
		$realif = $config['interfaces'][$if]['if'];
647
		if (is_interface_wireless($realif)) {
648
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
649
		}
650
	}
651

    
652
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
653
		foreach ($config['wireless']['clone'] as $clone) {
654
			if (empty($clone['cloneif'])) {
655
				continue;
656
			}
657
			if (does_interface_exist($clone['cloneif'])) {
658
				continue;
659
			}
660
			/* XXX: Maybe we should report any errors?! */
661
			interface_wireless_clone($clone['cloneif'], $clone);
662
		}
663
	}
664
	if (platform_booting()) {
665
		echo gettext("done.") . "\n";
666
	}
667

    
668
}
669

    
670
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
671
	global $config;
672

    
673
	$i = 0;
674
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
675
		foreach ($config['bridges']['bridged'] as $bridge) {
676
			if (empty($bridge['bridgeif'])) {
677
				$bridge['bridgeif'] = "bridge{$i}";
678
			}
679
			if (!empty($realif) && ($realif != $bridge['bridgeif'])) {
680
				continue;
681
			}
682
			$ifname = false;
683
			foreach ($config['interfaces'] as $intname => $intpar) {
684
				if ($intpar['if'] == $bridge['bridgeif']) {
685
					$ifname = $intname;
686
					break;
687
				}
688
			}
689

    
690
			if (($checkmember == 1) && $ifname &&
691
			    ($config['interfaces'][$ifname]['ipaddrv6'] == "track6")) {
692
				continue;
693
			} elseif (($checkmember == 2) && !$ifname) {
694
				continue;
695
			}
696

    
697
			/* XXX: Maybe we should report any errors?! */
698
			interface_bridge_configure($bridge, $checkmember);
699
			$i++;
700
		}
701
	}
702
}
703

    
704
function interface_bridge_configure(&$bridge, $checkmember = 0) {
705
	global $config, $g;
706

    
707
	if (!is_array($bridge)) {
708
		return;
709
	}
710

    
711
	if (empty($bridge['members'])) {
712
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
713
		return;
714
	}
715

    
716
	$members = explode(',', $bridge['members']);
717
	if (!count($members)) {
718
		return;
719
	}
720

    
721
	/* Calculate smaller mtu and enforce it */
722
	$smallermtu = 0;
723
	$foundgif = false;
724
	foreach ($members as $member) {
725
		$realif = get_real_interface($member);
726
		$mtu = get_interface_mtu($realif);
727
		if (substr($realif, 0, 3) == "gif") {
728
			$foundgif = true;
729
			if ($checkmember == 1) {
730
				return;
731
			}
732
			if ($mtu <= 1500) {
733
				continue;
734
			}
735
		}
736
		if ($smallermtu == 0 && !empty($mtu)) {
737
			$smallermtu = $mtu;
738
		} else if (!empty($mtu) && $mtu < $smallermtu) {
739
			$smallermtu = $mtu;
740
		}
741
	}
742
	if ($foundgif == false && $checkmember == 2) {
743
		return;
744
	}
745

    
746
	/* Just in case anything is not working well */
747
	if ($smallermtu == 0) {
748
		$smallermtu = 1500;
749
	}
750

    
751
	if (!empty($bridge['bridgeif'])) {
752
		pfSense_interface_destroy($bridge['bridgeif']);
753
		pfSense_interface_create($bridge['bridgeif']);
754
		$bridgeif = escapeshellarg($bridge['bridgeif']);
755
	} else {
756
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
757
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
758
		$bridgeif = pfSense_interface_create("bridge");
759
		$bridge['bridgeif'] = $bridgeif;
760
	}
761

    
762
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
763
	if ($bridgemtu > $smallermtu) {
764
		$smallermtu = $bridgemtu;
765
	}
766

    
767
	$checklist = get_configured_interface_list();
768

    
769
	/* Add interfaces to bridge */
770
	foreach ($members as $member) {
771
		if (empty($checklist[$member])) {
772
			continue;
773
		}
774
		$realif = get_real_interface($member);
775
		if (!$realif) {
776
			log_error(gettext("realif not defined in interfaces bridge - up"));
777
			continue;
778
		}
779
		/* make sure the parent interface is up */
780
		pfSense_interface_mtu($realif, $smallermtu);
781
		interfaces_bring_up($realif);
782
		enable_hardware_offloading($member);
783
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
784
	}
785

    
786
	if (isset($bridge['enablestp'])) {
787
		interface_bridge_configure_stp($bridge);
788
	}
789

    
790
	interface_bridge_configure_advanced($bridge);
791

    
792
	interface_bridge_configure_ip6linklocal($bridge);
793

    
794
	if ($bridge['bridgeif']) {
795
		interfaces_bring_up($bridge['bridgeif']);
796
	} else {
797
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
798
	}
799
}
800

    
801
function interface_bridge_configure_stp($bridge) {
802
	if (isset($bridge['enablestp'])) {
803
		$bridgeif = trim($bridge['bridgeif']);
804
		/* configure spanning tree proto */
805
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
806

    
807
		if (!empty($bridge['stp'])) {
808
			$stpifs = explode(',', $bridge['stp']);
809
			foreach ($stpifs as $stpif) {
810
				$realif = get_real_interface($stpif);
811
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
812
			}
813
		}
814
		if (!empty($bridge['maxage'])) {
815
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
816
		}
817
		if (!empty($bridge['fwdelay'])) {
818
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
819
		}
820
		if (!empty($bridge['hellotime'])) {
821
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
822
		}
823
		if (!empty($bridge['priority'])) {
824
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
825
		}
826
		if (!empty($bridge['holdcnt'])) {
827
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
828
		}
829
		if (!empty($bridge['ifpriority'])) {
830
			$pconfig = explode(",", $bridge['ifpriority']);
831
			$ifpriority = array();
832
			foreach ($pconfig as $cfg) {
833
				$embcfg = explode_assoc(":", $cfg);
834
				foreach ($embcfg as $key => $value) {
835
					$ifpriority[$key] = $value;
836
				}
837
			}
838
			foreach ($ifpriority as $key => $value) {
839
				$realif = get_real_interface($key);
840
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
841
			}
842
		}
843
		if (!empty($bridge['ifpathcost'])) {
844
			$pconfig = explode(",", $bridge['ifpathcost']);
845
			$ifpathcost = array();
846
			foreach ($pconfig as $cfg) {
847
				$embcfg = explode_assoc(":", $cfg);
848
				foreach ($embcfg as $key => $value) {
849
					$ifpathcost[$key] = $value;
850
				}
851
			}
852
			foreach ($ifpathcost as $key => $value) {
853
				$realif = get_real_interface($key);
854
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
855
			}
856
		}
857
	}
858
}
859

    
860
function interface_bridge_configure_advanced($bridge) {
861
	$bridgeif = trim($bridge['bridgeif']);
862

    
863
	if ($bridge['maxaddr'] <> "") {
864
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
865
	}
866
	if ($bridge['timeout'] <> "") {
867
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
868
	}
869
	if (!empty($bridge['span'])) {
870
		$spanifs = explode(",", $bridge['span']);
871
		foreach ($spanifs as $spanif) {
872
			$realif = get_real_interface($spanif);
873
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
874
		}
875
	}
876
	if (!empty($bridge['edge'])) {
877
		$edgeifs = explode(',', $bridge['edge']);
878
		foreach ($edgeifs as $edgeif) {
879
			$realif = get_real_interface($edgeif);
880
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
881
		}
882
	}
883
	if (!empty($bridge['autoedge'])) {
884
		$edgeifs = explode(',', $bridge['autoedge']);
885
		foreach ($edgeifs as $edgeif) {
886
			$realif = get_real_interface($edgeif);
887
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
888
		}
889
	}
890
	if (!empty($bridge['ptp'])) {
891
		$ptpifs = explode(',', $bridge['ptp']);
892
		foreach ($ptpifs as $ptpif) {
893
			$realif = get_real_interface($ptpif);
894
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
895
		}
896
	}
897
	if (!empty($bridge['autoptp'])) {
898
		$ptpifs = explode(',', $bridge['autoptp']);
899
		foreach ($ptpifs as $ptpif) {
900
			$realif = get_real_interface($ptpif);
901
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
902
		}
903
	}
904
	if (!empty($bridge['static'])) {
905
		$stickyifs = explode(',', $bridge['static']);
906
		foreach ($stickyifs as $stickyif) {
907
			$realif = get_real_interface($stickyif);
908
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
909
		}
910
	}
911
	if (!empty($bridge['private'])) {
912
		$privateifs = explode(',', $bridge['private']);
913
		foreach ($privateifs as $privateif) {
914
			$realif = get_real_interface($privateif);
915
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
916
		}
917
	}
918
}
919

    
920
function interface_bridge_configure_ip6linklocal($bridge) {
921
	$bridgeif = trim($bridge['bridgeif']);
922

    
923
	$members = explode(',', $bridge['members']);
924
	if (!count($members)) {
925
		return;
926
	}
927

    
928
	$auto_linklocal = isset($bridge['ip6linklocal']);
929
	$bridgeop = $auto_linklocal ? '' : '-';
930
	$memberop = $auto_linklocal ? '-' : '';
931

    
932
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
933
	foreach ($members as $member) {
934
		$realif = get_real_interface($member);
935
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
936
	}
937
}
938

    
939
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
940
	global $config;
941

    
942
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
943
		return;
944
	}
945

    
946
	if ($flagsapplied == false) {
947
		$mtu = get_interface_mtu($bridgeif);
948
		$mtum = get_interface_mtu($interface);
949
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
950
			pfSense_interface_mtu($interface, $mtu);
951
		}
952

    
953
		hardware_offloading_applyflags($interface);
954
		interfaces_bring_up($interface);
955
	}
956

    
957
	pfSense_bridge_add_member($bridgeif, $interface);
958
	if (is_array($config['bridges']['bridged'])) {
959
		foreach ($config['bridges']['bridged'] as $bridge) {
960
			if ($bridgeif == $bridge['bridgeif']) {
961
				interface_bridge_configure_stp($bridge);
962
				interface_bridge_configure_advanced($bridge);
963
			}
964
		}
965
	}
966
}
967

    
968
function interfaces_lagg_configure($realif = "") {
969
	global $config, $g;
970
	if (platform_booting()) {
971
		echo gettext("Configuring LAGG interfaces...");
972
	}
973
	$i = 0;
974
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
975
		foreach ($config['laggs']['lagg'] as $lagg) {
976
			if (empty($lagg['laggif'])) {
977
				$lagg['laggif'] = "lagg{$i}";
978
			}
979
			if (!empty($realif) && $realif != $lagg['laggif']) {
980
				continue;
981
			}
982
			/* XXX: Maybe we should report any errors?! */
983
			interface_lagg_configure($lagg);
984
			$i++;
985
		}
986
	}
987
	if (platform_booting()) {
988
		echo gettext("done.") . "\n";
989
	}
990
}
991

    
992
function interface_lagg_configure($lagg) {
993
	global $config, $g;
994

    
995
	if (!is_array($lagg)) {
996
		return -1;
997
	}
998

    
999
	$members = explode(',', $lagg['members']);
1000
	if (!count($members)) {
1001
		return -1;
1002
	}
1003

    
1004
	if (platform_booting() || !(empty($lagg['laggif']))) {
1005
		pfSense_interface_destroy($lagg['laggif']);
1006
		pfSense_interface_create($lagg['laggif']);
1007
		$laggif = $lagg['laggif'];
1008
	} else {
1009
		$laggif = pfSense_interface_create("lagg");
1010
	}
1011

    
1012
	/* Check if MTU was defined for this lagg interface */
1013
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
1014
	if ($lagg_mtu == 0 &&
1015
	    is_array($config['interfaces'])) {
1016
		foreach ($config['interfaces'] as $tmpinterface) {
1017
			if ($tmpinterface['if'] == $lagg['laggif'] &&
1018
			    !empty($tmpinterface['mtu'])) {
1019
				$lagg_mtu = $tmpinterface['mtu'];
1020
				break;
1021
			}
1022
		}
1023
	}
1024

    
1025
	/* Just in case anything is not working well */
1026
	if ($lagg_mtu == 0) {
1027
		$lagg_mtu = 1500;
1028
	}
1029

    
1030
	// put failover master interface on top of list
1031
	if (($lagg['proto'] == 'failover') && isset($lagg['failovermaster']) &&
1032
	    ($lagg['failovermaster'] != 'auto')) {
1033
		unset($members[array_search($lagg['failovermaster'], $members)]);
1034
		$members = array_merge(array($lagg['failovermaster']), $members);
1035
	}
1036

    
1037
	if (($lagg['proto'] == 'lacp') && isset($lagg['lacptimeout']) &&
1038
	    ($lagg['lacptimeout'] != 'slow')) {
1039
		$lacptimeout = 'lacp_fast_timeout';
1040
	} else {
1041
		$lacptimeout = '';
1042
	}
1043

    
1044
	foreach ($members as $member) {
1045
		if (!does_interface_exist($member)) {
1046
			continue;
1047
		}
1048

    
1049
		/* make sure the parent interface is up */
1050
		pfSense_interface_mtu($member, $lagg_mtu);
1051
		interfaces_bring_up($member);
1052
		hardware_offloading_applyflags($member);
1053

    
1054
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
1055
		$laggif = str_replace("\0", "", $laggif);
1056
		$member = str_replace("\0", "", $member);
1057
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
1058
	}
1059

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

    
1062
	interfaces_bring_up($laggif);
1063

    
1064
	return $laggif;
1065
}
1066

    
1067
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
1068
function interface_gre_configure(&$gre, $grekey = "") {
1069
	global $config, $g;
1070

    
1071
	if (!is_array($gre)) {
1072
		return -1;
1073
	}
1074

    
1075
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1076
	if (!interface_is_vlan($realif)) {
1077
		$realif = get_real_interface($gre['if']);
1078
	}
1079
	$realifip = get_interface_ip($gre['if']);
1080
	$realifip6 = get_interface_ipv6($gre['if']);
1081

    
1082
	/* make sure the parent interface is up */
1083
	interfaces_bring_up($realif);
1084

    
1085
	if (platform_booting() || !(empty($gre['greif']))) {
1086
		pfSense_interface_destroy($gre['greif']);
1087
		pfSense_interface_create($gre['greif']);
1088
		$greif = $gre['greif'];
1089
	} else {
1090
		$greif = pfSense_interface_create("gre");
1091
	}
1092

    
1093
	$tunnel_type = '';
1094
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1095
		$tunnel_type = 'v4';
1096
	}
1097
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1098
		$tunnel_type .= 'v6';
1099
	}
1100

    
1101
	/* Do not change the order here for more see gre(4) NOTES section. */
1102
	if (is_ipaddrv6($gre['remote-addr'])) {
1103
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1104
	} else {
1105
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1106
	}
1107
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1108
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1109
	}
1110
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1111
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1112
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr6']) . " " . escapeshellarg($gre['tunnel-remote-addr6']) . " prefixlen 128");
1113
	}
1114

    
1115
	$parentif = get_real_interface($gre['if']);
1116
	if ($parentif) {
1117
		interfaces_bring_up($parentif);
1118
	} else {
1119
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1120
	}
1121

    
1122
	if (isset($gre['link1'])) {
1123
		if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1124
			mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1125
		}
1126
		if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1127
			mwexec("/sbin/route -6 add " . escapeshellarg($gre['tunnel-remote-addr6']) . "/" . escapeshellarg($gre['tunnel-remote-net6']) . " " . escapeshellarg($gre['tunnel-local-addr6']));
1128
		}
1129
	}
1130
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1131
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1132
	}
1133
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1134
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr6']);
1135
	}
1136

    
1137
	interfaces_bring_up($greif);
1138

    
1139
	return $greif;
1140
}
1141

    
1142
function interface_is_type($if = NULL, $type) {
1143
	global $config;
1144
	switch ($type) {
1145
		case "gre":
1146
			$list = 'gres';
1147
			$entry = 'gre';
1148
			$entif = 'greif';
1149
			break;
1150
		case "gif":
1151
			$list = 'gifs';
1152
			$entry = 'gif';
1153
			$entif = 'gifif';
1154
			break;
1155
		case "lagg":
1156
			$list = 'laggs';
1157
			$entry = 'lagg';
1158
			$entif = 'laggif';
1159
			break;
1160
		case "vxlan":
1161
			$list = 'vxlans';
1162
			$entry = 'vxlan';
1163
			$entif = 'vxlanif';
1164
			break;
1165
		default:
1166
			break;
1167
	}
1168

    
1169
	if (!isset($config[$list][$entry]) || !is_array($config[$list][$entry])) {
1170
		return (NULL);
1171
	}
1172

    
1173
	foreach ($config[$list][$entry] as $ent) {
1174
		if ($ent[$entif] == $if) {
1175
			return ($ent);
1176
		}
1177
	}
1178
	return (NULL);
1179
}
1180

    
1181
function is_greipsec($if) {
1182
	global $config;
1183

    
1184
	if (ipsec_enabled() && is_array($config['gres']) && 
1185
	    is_array($config['gres']['gre']) &&
1186
	    is_array($config['ipsec']['phase2'])) {
1187
		foreach ($config['gres']['gre'] as $gre) {
1188
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
1189
				foreach ($config['ipsec']['phase2'] as $ph2ent) {
1190
					if (($ph1ent['ikeid'] == $ph2ent['ikeid']) && ($ph2ent['mode'] == 'transport') && 
1191
					    !isset($ph1ent['disabled']) && !isset($ph2ent['disabled']) && 
1192
					    ($ph1ent['interface'] == $gre['if']) && ($gre['greif'] == $if) &&
1193
					    ($ph1ent['remote-gateway'] == $gre['remote-addr'])) {
1194
						    return true;
1195
					}
1196
				}
1197
			}
1198
		}
1199
	}
1200
	return false;
1201
}
1202

    
1203
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1204
function interface_gif_configure(&$gif, $gifkey = "") {
1205
	global $config, $g;
1206

    
1207
	if (!is_array($gif)) {
1208
		return -1;
1209
	}
1210

    
1211
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1212
	if (!interface_is_vlan($realif)) {
1213
		$realif = get_real_interface($gif['if']);
1214
	}
1215
	$ipaddr = get_interface_ip($gif['if']);
1216

    
1217
	if (is_ipaddrv4($gif['remote-addr'])) {
1218
		if (is_ipaddrv4($ipaddr)) {
1219
			$realifip = $ipaddr;
1220
		} else {
1221
			$realifip = get_interface_ip($gif['if']);
1222
		}
1223
		$realifgw = get_interface_gateway($gif['if']);
1224
	} else if (is_ipaddrv6($gif['remote-addr'])) {
1225
		if (is_ipaddrv6($ipaddr)) {
1226
			$realifip = $ipaddr;
1227
		} else {
1228
			$realifip = get_interface_ipv6($gif['if']);
1229
		}
1230
		$realifgw = get_interface_gateway_v6($gif['if']);
1231
	}
1232
	/* make sure the parent interface is up */
1233
	$parentif = get_real_interface($gif['if']);
1234
	if ($parentif) {
1235
		interfaces_bring_up($parentif);
1236
	} else {
1237
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gif_configure()"));
1238
	}
1239

    
1240
	if (platform_booting() || !(empty($gif['gifif']))) {
1241
		pfSense_interface_destroy($gif['gifif']);
1242
		pfSense_interface_create($gif['gifif']);
1243
		$gifif = $gif['gifif'];
1244
	} else {
1245
		$gifif = pfSense_interface_create("gif");
1246
	}
1247

    
1248
	/* Do not change the order here for more see gif(4) NOTES section. */
1249
	if (is_ipaddrv6($gif['remote-addr'])) {
1250
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1251
	} else {
1252
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1253
	}
1254
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1255
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1256
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1257
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1258
	} else {
1259
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1260
	}
1261
	if (isset($gif['link1'])) {
1262
		pfSense_interface_flags($gifif, IFF_LINK1);
1263
	}
1264
	if (isset($gif['link2'])) {
1265
		pfSense_interface_flags($gifif, IFF_LINK2);
1266
	}
1267
	if ($gifif) {
1268
		interfaces_bring_up($gifif);
1269
		$gifmtu = "";
1270
		$currentgifmtu = get_interface_mtu($gifif);
1271
		foreach ($config['interfaces'] as $tmpinterface) {
1272
			if ($tmpinterface['if'] == $gifif) {
1273
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1274
					$gifmtu = $tmpinterface['mtu'];
1275
				}
1276
			}
1277
		}
1278
		if (is_numericint($gifmtu)) {
1279
			if ($gifmtu != $currentgifmtu) {
1280
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1281
			}
1282
		}
1283
	} else {
1284
		log_error(gettext("could not bring gifif up -- variable not defined"));
1285
	}
1286

    
1287
	if (!platform_booting()) {
1288
		$iflist = get_configured_interface_list();
1289
		foreach ($iflist as $ifname) {
1290
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1291
				if (get_interface_gateway($ifname)) {
1292
					system_routing_configure($ifname);
1293
					break;
1294
				}
1295
				if (get_interface_gateway_v6($ifname)) {
1296
					system_routing_configure($ifname);
1297
					break;
1298
				}
1299
			}
1300
		}
1301
	}
1302

    
1303

    
1304
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1305
		file_put_contents("{$g['tmp_path']}/{$gifif}_router",
1306
		    $gif['tunnel-remote-addr']);
1307
	} else if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1308
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6",
1309
		    $gif['tunnel-remote-addr']);
1310
	}
1311

    
1312
	route_add_or_change($gif['remote-addr'], $realifgw);
1313
	interfaces_bring_up($gifif);
1314

    
1315
	return $gifif;
1316
}
1317

    
1318
/*
1319
 * $ipsecifnum = get_ipsecifnum($ikeid, $idx);
1320
 * locates and returns an ipsecifnum in the config.
1321
 */
1322
function get_ipsecifnum($ikeid, $idx) {
1323
	global $config;
1324

    
1325
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1326
	foreach ($config['ipsec']['vtimaps']['item'] as $vtimap) {
1327
		if (($vtimap['reqid'] == $ikeid) &&
1328
		    ($vtimap['index'] == $idx)) {
1329
			return $vtimap['ifnum'];
1330
		}
1331
	}
1332

    
1333
	return false;
1334
}
1335
	
1336
function ipsec_create_vtimap($ikeid, $idx) {
1337
	global $config;
1338

    
1339
	if ((($ikeid < 33) && ($idx < 10)) || (($ikeid < 10) && ($idx < 100))) {
1340
		$oldformat = "{$ikeid}00{$idx}";
1341
		return array(
1342
			"reqid" => $ikeid,
1343
			"index" => $idx,
1344
			"ifnum" => $oldformat
1345
		);
1346
	}
1347

    
1348
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1349

    
1350
	if (count($config['ipsec']['vtimaps']['item']) == 0) {
1351
		return array(
1352
			"reqid" => $ikeid,
1353
			"index" => $idx,
1354
			"ifnum" => 1
1355
		);
1356
	}
1357

    
1358
	$assigned = array_column($config['ipsec']['vtimaps']['item'], 'ifnum');
1359
	asort($assigned, SORT_NUMERIC);
1360
	$new = 1;
1361
	foreach($assigned as $ipsecifnum) {
1362
		if ($ipsecifnum != $new) {
1363
			return array(
1364
				"reqid" => $ikeid,
1365
				"index" => $idx,
1366
				"ifnum" => $new
1367
			);
1368
		}
1369
		if ($new <= 32767) {
1370
			$new++;
1371
		} else {
1372
			log_error(gettext("All 32767 ipsec interface numbers " .
1373
			    "have been assigned!"));
1374
			return(NULL);
1375
		}
1376
	}
1377
}
1378

    
1379
function ipsec_del_vtimap($phase2) {
1380
	global $config;
1381

    
1382
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1383

    
1384
	if (count($config['ipsec']['vtimaps']['item']) == 0) {
1385
		return;
1386
	}
1387

    
1388
	$a_vtimaps = &$config['ipsec']['vtimaps']['item'];
1389
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1390
	$last = '';
1391
	foreach ($a_vtimaps as $id => $vtimap) {
1392
		if ($vtimap['reqid'] == $phase1['ikeid']) {
1393
			$last = $id;
1394
		}
1395
	}
1396
	if (!is_numeric($last)) {
1397
		return false;
1398
	}
1399

    
1400
	$vtisubnet_spec = ipsec_vti($phase1, true);
1401
	if (($phase1['iketype'] == 'ikev1') || isset($phase1['splitconn']) ||
1402
	    (count($vtisubnet_spec) == 1)) {
1403
		unset($a_vtimaps[$last]);
1404
		return true;
1405
	}
1406
}
1407

    
1408
/* NOTE: $vxlankey is not used but useful for passing this function to array_walk. */
1409
function interface_vxlan_configure(&$vxlan, $vxlankey = "") {
1410
	global $config, $g;
1411

    
1412
	if (!is_array($vxlan)) {
1413
		return -1;
1414
	}
1415

    
1416
	$realif = convert_friendly_interface_to_real_interface_name($vxlan['if']);
1417
	if (!interface_is_vlan($realif)) {
1418
		$realif = get_real_interface($vxlan['if']);
1419
	}
1420
	$realifip = get_interface_ip($vxlan['if']);
1421
	$realifip6 = get_interface_ipv6($vxlan['if']);
1422

    
1423
	/* make sure the parent interface is up */
1424
	if ($realif) {
1425
		interfaces_bring_up($realif);
1426
	} else {
1427
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_vxlan_configure()"));
1428
	}
1429

    
1430
	if (!platform_booting() && !(empty($vxlan['vxlanif']))) {
1431
		pfSense_interface_destroy($vxlan['vxlanif']);
1432
		pfSense_interface_create($vxlan['vxlanif']);
1433
		$vxlanif = $vxlan['vxlanif'];
1434
	} else {
1435
		$vxlanif = pfSense_interface_create("vxlan");
1436
	}
1437

    
1438
	$ifconfigcmd = "/sbin/ifconfig " . escapeshellarg($vxlanif) . " vxlanid " .
1439
	    escapeshellarg($vxlan['vxlanid']) . " vxlandev " . escapeshellarg($realif);
1440

    
1441
	if (is_mcast($vxlan['remote-addr'])) {
1442
		$ifconfigcmd .= " vxlangroup " . escapeshellarg($vxlan['remote-addr']);
1443
	} else {
1444
		$ifconfigcmd .= " vxlanremote " . escapeshellarg($vxlan['remote-addr']);
1445
	}
1446

    
1447
	if (is_ipaddrv6($vxlan['remote-addr']) && $realifip6) {
1448
		$ifconfigcmd .= " vxlanlocal " . escapeshellarg($realifip6);
1449
	} elseif (is_ipaddrv4($vxlan['remote-addr']) && $realifip) {
1450
		$ifconfigcmd .= " vxlanlocal " . escapeshellarg($realifip);
1451
	} else {
1452
		return;
1453
	}
1454

    
1455
	if (!empty($vxlan['vxlanlocalport'])) {
1456
		$ifconfigcmd .= " vxlanlocalport " . escapeshellarg($vxlan['vxlanlocalport']);
1457
	}
1458

    
1459
	if (!empty($vxlan['vxlanremoteport'])) {
1460
		$ifconfigcmd .= " vxlanremoteport " . escapeshellarg($vxlan['vxlanremoteport']);
1461
	}
1462

    
1463
	if (!empty($vxlan['vxlanttl'])) {
1464
		$ifconfigcmd .= " vxlanttl " . escapeshellarg($vxlan['vxlanttl']);
1465
	}
1466

    
1467
	if (isset($vxlan['vxlanlearn'])) {
1468
		$ifconfigcmd .= " vxlanlearn ";
1469
	} else {
1470
		$ifconfigcmd .= " -vxlanlearn ";
1471
	}
1472

    
1473
	mwexec($ifconfigcmd);
1474

    
1475
	interfaces_bring_up($vxlanif);
1476

    
1477
	return $vxlanif;
1478
}
1479

    
1480
function interfaces_tunnel_configure($checkparent = 0, $realif = "", $type = "") {
1481
	global $config;
1482

    
1483
	if (!in_array($type, array('gre', 'gif', 'vxlan'))) {
1484
		return;
1485
	}
1486

    
1487
	if (is_array($config["{$type}s"][$type]) && count($config["{$type}s"][$type])) {
1488
		foreach ($config["{$type}s"][$type] as $i => $tunnel) {
1489
			if (empty($tunnel["{$type}if"])) {
1490
				$tunnel["{$type}if"] = $type . $i;
1491
			}
1492
			if (!empty($realif) && $realif != $tunnel["{$type}if"]) {
1493
				continue;
1494
			}
1495

    
1496
			if ($checkparent == 1) {
1497
				if (substr($tunnel['if'], 0, 4) == '_vip') {
1498
					continue;
1499
				}
1500
				if (substr($tunnel['if'], 0, 5) == '_lloc') {
1501
					continue;
1502
				}
1503
				if (!empty($config['interfaces'][$tunnel['if']]) &&
1504
				    $config['interfaces'][$tunnel['if']]['ipaddrv6'] == "track6") {
1505
					continue;
1506
				}
1507
			}
1508
			else if ($checkparent == 2) {
1509
				if ((substr($tunnel['if'], 0, 4) != '_vip' &&
1510
				    substr($tunnel['if'], 0, 5) != '_lloc') &&
1511
				    (empty($config['interfaces'][$tunnel['if']]) ||
1512
				    $config['interfaces'][$tunnel['if']]['ipaddrv6'] != "track6")) {
1513
					continue;
1514
				}
1515
			}
1516
			if ($type == 'gif') {
1517
				interface_gif_configure($tunnel);
1518
			} elseif ($type == 'gre') {
1519
				interface_gre_configure($tunnel);
1520
			} elseif ($type == 'vxlan') {
1521
				interface_vxlan_configure($tunnel);
1522
			}
1523
		}
1524
	}
1525
}
1526

    
1527
/* Build a list of IPsec interfaces */
1528
function interface_ipsec_vti_list_p1($ph1ent) {
1529
	global $config;
1530
	$iface_list = array();
1531

    
1532
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1533
		return $iface_list;
1534
	}
1535

    
1536
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1537
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1538
		return $iface_list;
1539
	}
1540

    
1541
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1542
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1543
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1544
			$iface_list["ipsec".get_ipsecifnum($ph1ent['ikeid'], $idx)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1545
		}
1546
	} else {
1547
		/* For IKEv2, only create one interface with additional addresses as aliases */
1548
		$iface_list["ipsec".get_ipsecifnum($ph1ent['ikeid'], 0)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1549
	}
1550
	return $iface_list;
1551
}
1552
function interface_ipsec_vti_list_all() {
1553
	global $config;
1554
	$iface_list = array();
1555
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1556
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1557
			if ($ph1ent['disabled']) {
1558
				continue;
1559
			}
1560
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1561
		}
1562
	}
1563
	return $iface_list;
1564
}
1565

    
1566
function is_interface_ipsec_vti_assigned($phase2) {
1567
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1568
	$vti_interface = null;
1569
	$vtisubnet_spec = ipsec_vti($phase1, true);
1570
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1571
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1572
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1573
			foreach ($vtisubnet_spec as $idx => $vtisub) {
1574
				/* Is this for this P2? */
1575
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1576
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1577
					$vti_interface = "ipsec".get_ipsecifnum($phase1['ikeid'], $idx);
1578
				}
1579
			}
1580
		} else {
1581
			$vti_interface = "ipsec".get_ipsecifnum($phase1['ikeid'], 0);
1582
		}
1583
	}
1584
	/* Check if this interface is assigned */
1585
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1586
}
1587
function interface_ipsec_vti_configure($ph1ent) {
1588
	global $config;
1589

    
1590
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1591
		return false;
1592
	}
1593

    
1594
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1595
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1596
		return false;
1597
	}
1598

    
1599
	$left_spec = ipsec_get_phase1_src($ph1ent);
1600
	$right_spec = $ph1ent['remote-gateway'];
1601

    
1602
	$iface_addrs = array();
1603

    
1604
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1605
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1606
		/* Form a single interface for each P2 entry */
1607
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1608
			$ipsecifnum = get_ipsecifnum($ph1ent['ikeid'], $idx);
1609
			if (!is_array($iface_addrs[$ipsecifnum])) {
1610
				$iface_addrs[$ipsecifnum] = array();
1611
			}
1612
			$vtisub['alias'] = "";
1613
			$iface_addrs[$ipsecifnum][] = $vtisub;
1614
		}
1615
	} else {
1616
		/* For IKEv2, only create one interface with additional addresses as aliases */
1617
		$ipsecifnum = get_ipsecifnum($ph1ent['ikeid'], 0);
1618
		if (!is_array($iface_addrs[$ipsecifnum])) {
1619
			$iface_addrs[$ipsecifnum] = array();
1620
		}
1621
		$have_v4 = false;
1622
		$have_v6 = false;
1623
		foreach ($vtisubnet_spec as $vtisub) {
1624
			// Alias stuff
1625
			$vtisub['alias'] = "";
1626
			if (is_ipaddrv6($vtisub['left'])) {
1627
				if ($have_v6) {
1628
					$vtisub['alias'] = " alias";
1629
				}
1630
				$have_v6 = true;
1631
			} else {
1632
				if ($have_v4) {
1633
					$vtisub['alias'] = " alias";
1634
				}
1635
				$have_v4 = true;
1636
			}
1637
			$iface_addrs[$ipsecifnum][] = $vtisub;
1638
		}
1639
	}
1640

    
1641
	foreach ($iface_addrs as $ipsecifnum => $addrs) {
1642
		$ipsecif = "ipsec{$ipsecifnum}";
1643
		if (!is_array($addrs)) {
1644
			continue;
1645
		}
1646
		// Create IPsec interface
1647
		if (does_interface_exist($ipsecif)) {
1648
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy", false);
1649
		}
1650
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1651

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

    
1656
		/* Loop through all of the addresses for this interface and apply them as needed */
1657
		foreach ($addrs as $addr) {
1658
			// apply interface addresses
1659
			if (is_v6($addr['left'])) {
1660
				$inet = "inet6";
1661
				$gwtype = "v6";
1662
				$right = '';
1663
			} else {
1664
				$inet = "inet";
1665
				$gwtype = "";
1666
				$right = escapeshellarg($addr['right']);
1667
			}
1668

    
1669
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias'], false);
1670
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1671
			if (empty($addr['alias'])) {
1672
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1673
			}
1674
		}
1675
		/* Check/set the MTU if the user configured a custom value.
1676
		 * https://redmine.pfsense.org/issues/9111 */
1677
		$currentvtimtu = get_interface_mtu($ipsecif);
1678
		foreach ($config['interfaces'] as $tmpinterface) {
1679
			if ($tmpinterface['if'] == $ipsecif) {
1680
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1681
					$vtimtu = $tmpinterface['mtu'];
1682
				}
1683
			}
1684
		}
1685
		if (is_numericint($vtimtu)) {
1686
			if ($vtimtu != $currentvtimtu) {
1687
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1688
			}
1689
		}
1690
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1691
	}
1692
}
1693

    
1694
function interfaces_ipsec_vti_configure() {
1695
	global $config;
1696
	if (platform_booting()) {
1697
		echo gettext("Configuring IPsec VTI interfaces...");
1698
	}
1699
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1700
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1701
			if ($ph1ent['disabled']) {
1702
				continue;
1703
			}
1704
			interface_ipsec_vti_configure($ph1ent);
1705
		}
1706
	}
1707
	if (platform_booting()) {
1708
		echo gettext("done.") . "\n";
1709
	}
1710
}
1711

    
1712
function interfaces_configure() {
1713
	global $config, $g;
1714

    
1715
	/* Set up our loopback interface */
1716
	interfaces_loopback_configure();
1717

    
1718
	/* create the unconfigured wireless clones */
1719
	interfaces_create_wireless_clones();
1720

    
1721
	/* set up LAGG virtual interfaces */
1722
	interfaces_lagg_configure();
1723

    
1724
	/* set up VLAN virtual interfaces */
1725
	interfaces_vlan_configure();
1726

    
1727
	interfaces_qinq_configure();
1728

    
1729
	/* set up IPsec VTI interfaces */
1730
	interfaces_ipsec_vti_configure();
1731

    
1732
	$iflist = get_configured_interface_with_descr();
1733
	$delayed_list = array();
1734
	$bridge_list = array();
1735
	$track6_list = array();
1736

    
1737
	/* This is needed to speedup interfaces on bootup. */
1738
	$reload = false;
1739
	if (!platform_booting()) {
1740
		$reload = true;
1741
	}
1742

    
1743
	foreach ($iflist as $if => $ifname) {
1744
		$realif = $config['interfaces'][$if]['if'];
1745
		if (strstr($realif, "bridge")) {
1746
			$bridge_list[$if] = $ifname;
1747
		} else if (strstr($realif, "gre")) {
1748
			$delayed_list[$if] = $ifname;
1749
		} else if (strstr($realif, "gif")) {
1750
			$delayed_list[$if] = $ifname;
1751
		} else if (strstr($realif, "ovpn")) {
1752
			//echo "Delaying OpenVPN interface configuration...done.\n";
1753
			continue;
1754
		} else if (strstr($realif, "ipsec")) {
1755
			continue;
1756
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1757
			$track6_list[$if] = $ifname;
1758
		} else {
1759
			if (platform_booting()) {
1760
				printf(gettext("Configuring %s interface..."), $ifname);
1761
			}
1762

    
1763
			if ($g['debug']) {
1764
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1765
			}
1766
			interface_configure($if, $reload);
1767
			if (platform_booting()) {
1768
				echo gettext("done.") . "\n";
1769
			}
1770
		}
1771
	}
1772

    
1773
	/*
1774
	 * NOTE: The following function parameter consists of
1775
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1776
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1777
	 */
1778

    
1779
	/* set up GRE virtual interfaces */
1780
	interfaces_tunnel_configure(1,'','gre');
1781

    
1782
	/* set up GIF virtual interfaces */
1783
	interfaces_tunnel_configure(1,'','gif');
1784

    
1785
	/* set up VXLAN virtual interfaces */
1786
	interfaces_tunnel_configure(1,'','vxlan');
1787

    
1788
	/* set up BRIDGe virtual interfaces */
1789
	interfaces_bridge_configure(1);
1790

    
1791
	foreach ($track6_list as $if => $ifname) {
1792
		if (platform_booting()) {
1793
			printf(gettext("Configuring %s interface..."), $ifname);
1794
		}
1795
		if ($g['debug']) {
1796
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1797
		}
1798

    
1799
		interface_configure($if, $reload);
1800

    
1801
		if (platform_booting()) {
1802
			echo gettext("done.") . "\n";
1803
		}
1804
	}
1805

    
1806
	/* bring up vip interfaces */
1807
	interfaces_vips_configure();
1808

    
1809
	/* set up GRE virtual interfaces */
1810
	interfaces_tunnel_configure(2,'','gre');
1811

    
1812
	/* set up GIF virtual interfaces */
1813
	interfaces_tunnel_configure(2,'','gif');
1814

    
1815
	/* set up VXLAN virtual interfaces */
1816
	interfaces_tunnel_configure(2,'','vxlan');
1817

    
1818
	foreach ($delayed_list as $if => $ifname) {
1819
		if (platform_booting()) {
1820
			printf(gettext("Configuring %s interface..."), $ifname);
1821
		}
1822
		if ($g['debug']) {
1823
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1824
		}
1825

    
1826
		interface_configure($if, $reload);
1827

    
1828
		if (platform_booting()) {
1829
			echo gettext("done.") . "\n";
1830
		}
1831
	}
1832

    
1833
	/* set up BRIDGe virtual interfaces */
1834
	interfaces_bridge_configure(2);
1835

    
1836
	foreach ($bridge_list as $if => $ifname) {
1837
		if (platform_booting()) {
1838
			printf(gettext("Configuring %s interface..."), $ifname);
1839
		}
1840
		if ($g['debug']) {
1841
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1842
		}
1843

    
1844
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1845
		// redmine #3997
1846
		interface_reconfigure($if, $reload);
1847
		interfaces_vips_configure($if);
1848

    
1849
		if (platform_booting()) {
1850
			echo gettext("done.") . "\n";
1851
		}
1852
	}
1853

    
1854
	/* configure interface groups */
1855
	interfaces_group_setup();
1856

    
1857
	if (!platform_booting()) {
1858
		/* reconfigure static routes (kernel may have deleted them) */
1859
		system_routing_configure();
1860

    
1861
		/* reload IPsec tunnels */
1862
		ipsec_configure();
1863

    
1864
		/* restart dns servers (defering dhcpd reload) */
1865
		if (isset($config['dnsmasq']['enable'])) {
1866
			services_dnsmasq_configure(false);
1867
		}
1868
		if (isset($config['unbound']['enable'])) {
1869
			services_unbound_configure(false);
1870
		}
1871

    
1872
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1873
		services_dhcpd_configure();
1874
	}
1875

    
1876
	return 0;
1877
}
1878

    
1879
function interface_reconfigure($interface = "wan", $reloadall = false) {
1880
	interface_bring_down($interface);
1881
	interface_configure($interface, $reloadall);
1882
}
1883

    
1884
function interface_vip_bring_down($vip) {
1885
	global $g;
1886

    
1887
	$vipif = get_real_interface($vip['interface']);
1888
	switch ($vip['mode']) {
1889
		case "proxyarp":
1890
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1891
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1892
			}
1893
			break;
1894
		case "ipalias":
1895
			if (does_interface_exist($vipif)) {
1896
				if (is_ipaddrv6($vip['subnet'])) {
1897
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1898
				} else {
1899
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1900
				}
1901
			}
1902
			break;
1903
		case "carp":
1904
			/* XXX: Is enough to delete ip address? */
1905
			if (does_interface_exist($vipif)) {
1906
				if (is_ipaddrv6($vip['subnet'])) {
1907
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1908
				} else {
1909
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1910
				}
1911
			}
1912
			break;
1913
	}
1914
}
1915

    
1916
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1917
	global $config, $g;
1918

    
1919
	if (!isset($config['interfaces'][$interface])) {
1920
		return;
1921
	}
1922

    
1923
	if ($g['debug']) {
1924
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1925
	}
1926

    
1927
	/*
1928
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1929
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1930
	 * Keep this in mind while doing changes here!
1931
	 */
1932
	if ($ifacecfg === false) {
1933
		$ifcfg = $config['interfaces'][$interface];
1934
		$ppps = $config['ppps']['ppp'];
1935
		$realif = get_real_interface($interface);
1936
		$realifv6 = get_real_interface($interface, "inet6", true);
1937
	} elseif (!is_array($ifacecfg)) {
1938
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1939
		$ifcfg = $config['interfaces'][$interface];
1940
		$ppps = $config['ppps']['ppp'];
1941
		$realif = get_real_interface($interface);
1942
		$realifv6 = get_real_interface($interface, "inet6", true);
1943
	} else {
1944
		$ifcfg = $ifacecfg['ifcfg'];
1945
		$ppps = $ifacecfg['ppps'];
1946
		if (isset($ifacecfg['ifcfg']['realif'])) {
1947
			$realif = $ifacecfg['ifcfg']['realif'];
1948
			/* XXX: Any better way? */
1949
			$realifv6 = $realif;
1950
		} else {
1951
			$realif = get_real_interface($interface);
1952
			$realifv6 = get_real_interface($interface, "inet6", true);
1953
		}
1954
	}
1955

    
1956
	switch ($ifcfg['ipaddr']) {
1957
		case "ppp":
1958
		case "pppoe":
1959
		case "pptp":
1960
		case "l2tp":
1961
			if (is_array($ppps) && count($ppps)) {
1962
				foreach ($ppps as $pppid => $ppp) {
1963
					if ($realif == $ppp['if']) {
1964
						if (isset($ppp['ondemand']) && !$destroy) {
1965
							send_event("interface reconfigure {$interface}");
1966
							break;
1967
						}
1968
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1969
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1970
							sleep(2);
1971
						}
1972
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1973
						break;
1974
					}
1975
				}
1976
			}
1977
			break;
1978
		case "dhcp":
1979
			kill_dhclient_process($realif);
1980
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1981
			if (does_interface_exist("$realif")) {
1982
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1983
				interface_vip_cleanup($interface, "inet4");
1984
				if ($destroy == true) {
1985
					pfSense_interface_flags($realif, -IFF_UP);
1986
				}
1987
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1988
			}
1989
			break;
1990
		default:
1991
			if (does_interface_exist("$realif")) {
1992
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1993
				interface_vip_cleanup($interface, "inet4");
1994
				if ($destroy == true) {
1995
					pfSense_interface_flags($realif, -IFF_UP);
1996
				}
1997
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1998
			}
1999
			break;
2000
	}
2001

    
2002
	$track6 = array();
2003
	switch ($ifcfg['ipaddrv6']) {
2004
		case "slaac":
2005
		case "dhcp6":
2006
			kill_dhcp6client_process($realif, $destroy, false);
2007
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
2008
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
2009
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
2010
			if (does_interface_exist($realifv6)) {
2011
				$ip6 = find_interface_ipv6($realifv6);
2012
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
2013
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
2014
				}
2015
				interface_vip_cleanup($interface, "inet6");
2016
				if ($destroy == true) {
2017
					pfSense_interface_flags($realif, -IFF_UP);
2018
				}
2019
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2020
			}
2021
			$track6 = link_interface_to_track6($interface);
2022
			break;
2023
		case "6rd":
2024
		case "6to4":
2025
			$realif = "{$interface}_stf";
2026
			if (does_interface_exist("$realif")) {
2027
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
2028
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
2029
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
2030
					$destroy = true;
2031
				} else {
2032
					/* get_interface_ipv6() returns empty value if interface is being disabled */
2033
					$ip6 = get_interface_ipv6($interface);
2034
					if (is_ipaddrv6($ip6)) {
2035
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2036
					}
2037
				}
2038
				interface_vip_cleanup($interface, "inet6");
2039
				if ($destroy == true) {
2040
					pfSense_interface_flags($realif, -IFF_UP);
2041
				}
2042
			}
2043
			$track6 = link_interface_to_track6($interface);
2044
			break;
2045
		default:
2046
			if (does_interface_exist("$realif")) {
2047
				$ip6 = get_interface_ipv6($interface);
2048
				if (is_ipaddrv6($ip6)) {
2049
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2050
				}
2051
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
2052
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
2053
				}
2054
				interface_vip_cleanup($interface, "inet6");
2055
				if ($destroy == true) {
2056
					pfSense_interface_flags($realif, -IFF_UP);
2057
				}
2058
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2059
			}
2060
			$track6 = link_interface_to_track6($interface);
2061
			break;
2062
	}
2063

    
2064
	if (!empty($track6) && is_array($track6)) {
2065
		if (!function_exists('services_dhcpd_configure')) {
2066
			require_once('services.inc');
2067
		}
2068
		/* Bring down radvd and dhcp6 on these interfaces */
2069
		services_dhcpd_configure('inet6', $track6);
2070
	}
2071

    
2072
	$old_router = '';
2073
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
2074
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
2075
	}
2076

    
2077
	/* remove interface up file if it exists */
2078
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
2079
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
2080
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
2081
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
2082
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
2083
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
2084
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
2085

    
2086
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
2087
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
2088
	if (is_array($ifcfg['wireless'])) {
2089
		kill_hostapd($realif);
2090
		mwexec(kill_wpasupplicant($realif));
2091
	}
2092

    
2093
	if ($destroy == true) {
2094
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^ipsec|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
2095
			pfSense_interface_destroy($realif);
2096
		}
2097
	}
2098

    
2099
	return;
2100
}
2101

    
2102
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
2103
	global $config;
2104
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
2105
		unset($config["virtualip_carp_maintenancemode"]);
2106
		write_config("Leave CARP maintenance mode");
2107
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
2108
		$config["virtualip_carp_maintenancemode"] = true;
2109
		write_config(gettext("Enter CARP maintenance mode"));
2110
	}
2111
	init_config_arr(array('virtualip', 'vip'));
2112
	$viparr = &$config['virtualip']['vip'];
2113

    
2114
	if (is_array($viparr)) {
2115
		foreach ($viparr as $vip) {
2116
			if ($vip['mode'] == "carp") {
2117
				interface_carp_configure($vip, true);
2118
			}
2119
		}
2120
	}
2121
}
2122

    
2123
function interface_wait_tentative($interface, $timeout = 10) {
2124
	if (!does_interface_exist($interface)) {
2125
		return false;
2126
	}
2127

    
2128
	$time = 0;
2129
	while ($time <= $timeout) {
2130
		$if = pfSense_get_interface_addresses($interface);
2131
		if (!isset($if['tentative'])) {
2132
			return true;
2133
		}
2134
		sleep(1);
2135
		$time++;
2136
	}
2137

    
2138
	return false;
2139
}
2140

    
2141
function interface_isppp_type($interface) {
2142
	global $config;
2143

    
2144
	if (!is_array($config['interfaces'][$interface])) {
2145
		return false;
2146
	}
2147

    
2148
	switch ($config['interfaces'][$interface]['ipaddr']) {
2149
		case 'pptp':
2150
		case 'l2tp':
2151
		case 'pppoe':
2152
		case 'ppp':
2153
			return true;
2154
			break;
2155
		default:
2156
			return false;
2157
			break;
2158
	}
2159
}
2160

    
2161
function interfaces_ptpid_used($ptpid) {
2162
	global $config;
2163

    
2164
	if (is_array($config['ppps']['ppp'])) {
2165
		foreach ($config['ppps']['ppp'] as & $settings) {
2166
			if ($ptpid == $settings['ptpid']) {
2167
				return true;
2168
			}
2169
		}
2170
	}
2171

    
2172
	return false;
2173
}
2174

    
2175
function interfaces_ptpid_next() {
2176

    
2177
	$ptpid = 0;
2178
	while (interfaces_ptpid_used($ptpid)) {
2179
		$ptpid++;
2180
	}
2181

    
2182
	return $ptpid;
2183
}
2184

    
2185
function getMPDCRONSettings($pppif) {
2186
	global $config;
2187

    
2188
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2189
	if (is_array($config['cron']['item'])) {
2190
		foreach ($config['cron']['item'] as $i => $item) {
2191
			if (stripos($item['command'], $cron_cmd_file) !== false) {
2192
				return array("ID" => $i, "ITEM" => $item);
2193
			}
2194
		}
2195
	}
2196

    
2197
	return NULL;
2198
}
2199

    
2200
function handle_pppoe_reset($post_array) {
2201
	global $config, $g;
2202

    
2203
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2204
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2205

    
2206
	if (!is_array($config['cron']['item'])) {
2207
		$config['cron']['item'] = array();
2208
	}
2209

    
2210
	$itemhash = getMPDCRONSettings($pppif);
2211

    
2212
	// reset cron items if necessary and return
2213
	if (empty($post_array['pppoe-reset-type'])) {
2214
		if (isset($itemhash)) {
2215
			unset($config['cron']['item'][$itemhash['ID']]);
2216
		}
2217
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2218
		return;
2219
	}
2220

    
2221
	if (empty($itemhash)) {
2222
		$itemhash = array();
2223
	}
2224
	$item = array();
2225
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2226
		$item['minute'] = $post_array['pppoe_resetminute'];
2227
		$item['hour'] = $post_array['pppoe_resethour'];
2228
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2229
			$date = explode("/", $post_array['pppoe_resetdate']);
2230
			$item['mday'] = $date[1];
2231
			$item['month'] = $date[0];
2232
		} else {
2233
			$item['mday'] = "*";
2234
			$item['month'] = "*";
2235
		}
2236
		$item['wday'] = "*";
2237
		$item['who'] = "root";
2238
		$item['command'] = $cron_cmd_file;
2239
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2240
		switch ($post_array['pppoe_pr_preset_val']) {
2241
			case "monthly":
2242
				$item['minute'] = "0";
2243
				$item['hour'] = "0";
2244
				$item['mday'] = "1";
2245
				$item['month'] = "*";
2246
				$item['wday'] = "*";
2247
				break;
2248
			case "weekly":
2249
				$item['minute'] = "0";
2250
				$item['hour'] = "0";
2251
				$item['mday'] = "*";
2252
				$item['month'] = "*";
2253
				$item['wday'] = "0";
2254
				break;
2255
			case "daily":
2256
				$item['minute'] = "0";
2257
				$item['hour'] = "0";
2258
				$item['mday'] = "*";
2259
				$item['month'] = "*";
2260
				$item['wday'] = "*";
2261
				break;
2262
			case "hourly":
2263
				$item['minute'] = "0";
2264
				$item['hour'] = "*";
2265
				$item['mday'] = "*";
2266
				$item['month'] = "*";
2267
				$item['wday'] = "*";
2268
				break;
2269
		} // end switch
2270
		$item['who'] = "root";
2271
		$item['command'] = $cron_cmd_file;
2272
	}
2273
	if (empty($item)) {
2274
		return;
2275
	}
2276
	if (isset($itemhash['ID'])) {
2277
		$config['cron']['item'][$itemhash['ID']] = $item;
2278
	} else {
2279
		$config['cron']['item'][] = $item;
2280
	}
2281
}
2282

    
2283
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2284
	global $config;
2285
	$ppp_list = array();
2286
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2287
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2288
			$ports = explode(",", $ppp['ports']);
2289
			foreach($ports as $port) {
2290
				foreach($triggerinterfaces as $vip) {
2291
					if ($port == "_vip{$vip['uniqid']}") {
2292
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2293
						$ppp_list[$if] = 1;
2294
					}
2295
				}
2296
			}
2297
		}
2298
	}
2299
	foreach($ppp_list as $pppif => $dummy) {
2300
		interface_ppps_configure($pppif);
2301
	}
2302
}
2303

    
2304
/*
2305
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2306
 * It writes the mpd config file to /var/etc every time the link is opened.
2307
 */
2308
function interface_ppps_configure($interface) {
2309
	global $config, $g;
2310

    
2311
	/* Return for unassigned interfaces. This is a minimum requirement. */
2312
	if (empty($config['interfaces'][$interface])) {
2313
		return 0;
2314
	}
2315
	$ifcfg = $config['interfaces'][$interface];
2316
	if (!isset($ifcfg['enable'])) {
2317
		return 0;
2318
	}
2319

    
2320
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2321
	if (!is_dir("/var/spool/lock")) {
2322
		mkdir("/var/spool/lock", 0777, true);
2323
	}
2324
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2325
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2326
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2327
	}
2328

    
2329
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2330
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2331
			if ($ifcfg['if'] == $ppp['if']) {
2332
				break;
2333
			}
2334
		}
2335
	}
2336
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2337
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2338
		return 0;
2339
	}
2340
	$pppif = $ifcfg['if'];
2341
	if ($ppp['type'] == "ppp") {
2342
		$type = "modem";
2343
	} else {
2344
		$type = $ppp['type'];
2345
	}
2346
	$upper_type = strtoupper($ppp['type']);
2347

    
2348
	$confports = explode(',', $ppp['ports']);
2349
	if ($type == "modem") {
2350
		$ports = $confports;
2351
	} else {
2352
		$ports = array();
2353
		foreach ($confports as $pid => $port) {
2354
			if (strstr($port, "_vip")) {
2355
				if (get_carp_interface_status($port) != "MASTER") {
2356
					continue;
2357
				}
2358
			}
2359
			$ports[$pid] = get_real_interface($port);
2360
			if (empty($ports[$pid])) {
2361
				return 0;
2362
			}
2363
		}
2364
	}
2365
	$localips = explode(',', $ppp['localip']);
2366
	$gateways = explode(',', $ppp['gateway']);
2367
	$subnets = explode(',', $ppp['subnet']);
2368

    
2369
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2370
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2371
	 */
2372
	foreach ($ports as $pid => $port) {
2373
		switch ($ppp['type']) {
2374
			case "pppoe":
2375
				/* Bring the parent interface up */
2376
				interfaces_bring_up($port);
2377
				pfSense_ngctl_attach(".", $port);
2378
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2379
				$ngif = str_replace(".", "_", $port);
2380
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2381
				break;
2382
			case "pptp":
2383
			case "l2tp":
2384
				/* configure interface */
2385
				if (is_ipaddr($localips[$pid])) {
2386
					// Manually configure interface IP/subnet
2387
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2388
					interfaces_bring_up($port);
2389
				} else if (empty($localips[$pid])) {
2390
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2391
				}
2392

    
2393
				if (!is_ipaddr($localips[$pid])) {
2394
					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));
2395
					$localips[$pid] = "0.0.0.0";
2396
				}
2397
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2398
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2399
				}
2400
				if (!is_ipaddr($gateways[$pid])) {
2401
					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));
2402
					return 0;
2403
				}
2404
				pfSense_ngctl_attach(".", $port);
2405
				break;
2406
			case "ppp":
2407
				if (!file_exists("{$port}")) {
2408
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2409
					return 0;
2410
				}
2411
				break;
2412
			default:
2413
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2414
				break;
2415
		}
2416
	}
2417

    
2418
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2419
	    (is_array($ports) && count($ports) > 1)) {
2420
		$multilink = "enable";
2421
	} else {
2422
		$multilink = "disable";
2423
	}
2424

    
2425
	if ($type == "modem") {
2426
		if (is_ipaddr($ppp['localip'])) {
2427
			$localip = $ppp['localip'];
2428
		} else {
2429
			$localip = '0.0.0.0';
2430
		}
2431

    
2432
		if (is_ipaddr($ppp['gateway'])) {
2433
			$gateway = $ppp['gateway'];
2434
		} else {
2435
			$gateway = "10.64.64.{$pppid}";
2436
		}
2437
		$ranges = "{$localip}/0 {$gateway}/0";
2438

    
2439
		if (empty($ppp['apnum'])) {
2440
			$ppp['apnum'] = 1;
2441
		}
2442
	} else {
2443
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2444
	}
2445

    
2446
	if (isset($ppp['ondemand'])) {
2447
		$ondemand = "enable";
2448
	} else {
2449
		$ondemand = "disable";
2450
	}
2451
	if (!isset($ppp['idletimeout'])) {
2452
		$ppp['idletimeout'] = 0;
2453
	}
2454

    
2455
	if (empty($ppp['username']) && $type == "modem") {
2456
		$ppp['username'] = "user";
2457
		$ppp['password'] = "none";
2458
	}
2459
	if (empty($ppp['password']) && $type == "modem") {
2460
		$passwd = "none";
2461
	} else {
2462
		$passwd = base64_decode($ppp['password']);
2463
	}
2464

    
2465
	$bandwidths = explode(',', $ppp['bandwidth']);
2466
	$defaultmtu = "1492";
2467
	if (!empty($ifcfg['mtu'])) {
2468
		$defaultmtu = intval($ifcfg['mtu']);
2469
	}
2470
	if (isset($ppp['mtu'])) {
2471
		$mtus = explode(',', $ppp['mtu']);
2472
	}
2473
	if (isset($ppp['mru'])) {
2474
		$mrus = explode(',', $ppp['mru']);
2475
	}
2476
	if (isset($ppp['mrru'])) {
2477
		$mrrus = explode(',', $ppp['mrru']);
2478
	}
2479
	if (!empty($ifcfg['ipaddrv6'])) {
2480
		$ipv6cp = "set bundle enable ipv6cp";
2481
	}
2482

    
2483
	// Construct the mpd.conf file
2484
	$mpdconf = <<<EOD
2485
startup:
2486
	# configure the console
2487
	set console close
2488
	# configure the web server
2489
	set web close
2490

    
2491
default:
2492
{$ppp['type']}client:
2493
	create bundle static {$interface}
2494
	{$ipv6cp}
2495
	set iface name {$pppif}
2496

    
2497
EOD;
2498
	$setdefaultgw = false;
2499
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2500
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2501
	if ($defgw4['interface'] == $interface) {
2502
		$setdefaultgw = true;
2503
	}
2504

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

    
2514
EOD;
2515
	}
2516

    
2517
	$mpdconf .= <<<EOD
2518
	set iface {$ondemand} on-demand
2519
	set iface idle {$ppp['idletimeout']}
2520

    
2521
EOD;
2522

    
2523
	if (isset($ppp['ondemand'])) {
2524
		$mpdconf .= <<<EOD
2525
	set iface addrs 10.10.1.1 10.10.1.2
2526

    
2527
EOD;
2528
	}
2529

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

    
2550
EOD;
2551
	}
2552

    
2553
	if (isset($ppp['tcpmssfix'])) {
2554
		$tcpmss = "disable";
2555
	} else {
2556
		$tcpmss = "enable";
2557
	}
2558
	$mpdconf .= <<<EOD
2559
	set iface {$tcpmss} tcpmssfix
2560

    
2561
EOD;
2562

    
2563
	$mpdconf .= <<<EOD
2564
	set iface up-script /usr/local/sbin/ppp-linkup
2565
	set iface down-script /usr/local/sbin/ppp-linkdown
2566
	set ipcp ranges {$ranges}
2567

    
2568
EOD;
2569
	if (isset($ppp['vjcomp'])) {
2570
		$mpdconf .= <<<EOD
2571
	set ipcp no vjcomp
2572

    
2573
EOD;
2574
	}
2575

    
2576
	if (isset($config['system']['dnsallowoverride'])) {
2577
		$mpdconf .= <<<EOD
2578
	set ipcp enable req-pri-dns
2579
	set ipcp enable req-sec-dns
2580

    
2581
EOD;
2582
	}
2583

    
2584
	if (!isset($ppp['verbose_log'])) {
2585
		$mpdconf .= <<<EOD
2586
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2587

    
2588
EOD;
2589
	}
2590

    
2591
	foreach ($ports as $pid => $port) {
2592
		$port = get_real_interface($port);
2593
		$mpdconf .= <<<EOD
2594

    
2595
	create link static {$interface}_link{$pid} {$type}
2596
	set link action bundle {$interface}
2597
	set link {$multilink} multilink
2598
	set link keep-alive 10 60
2599
	set link max-redial 0
2600

    
2601
EOD;
2602
		if (isset($ppp['shortseq'])) {
2603
			$mpdconf .= <<<EOD
2604
	set link no shortseq
2605

    
2606
EOD;
2607
		}
2608

    
2609
		if (isset($ppp['acfcomp'])) {
2610
			$mpdconf .= <<<EOD
2611
	set link no acfcomp
2612

    
2613
EOD;
2614
		}
2615

    
2616
		if (isset($ppp['protocomp'])) {
2617
			$mpdconf .= <<<EOD
2618
	set link no protocomp
2619

    
2620
EOD;
2621
		}
2622

    
2623
		$mpdconf .= <<<EOD
2624
	set link disable chap pap
2625
	set link accept chap pap eap
2626
	set link disable incoming
2627

    
2628
EOD;
2629

    
2630

    
2631
		if (!empty($bandwidths[$pid])) {
2632
			$mpdconf .= <<<EOD
2633
	set link bandwidth {$bandwidths[$pid]}
2634

    
2635
EOD;
2636
		}
2637

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

    
2653
EOD;
2654
		}
2655

    
2656
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2657
		    !isset($ppp['mtu-override']) &&
2658
		    !empty($mrus[$pid])) {
2659
			$mpdconf .= <<<EOD
2660
	set link mru {$mrus[$pid]}
2661

    
2662
EOD;
2663
		}
2664

    
2665
		if (!empty($mrrus[$pid])) {
2666
			$mpdconf .= <<<EOD
2667
	set link mrru {$mrrus[$pid]}
2668

    
2669
EOD;
2670
		}
2671

    
2672
		$mpdconf .= <<<EOD
2673
	set auth authname "{$ppp['username']}"
2674
	set auth password {$passwd}
2675

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

    
2686
EOD;
2687
		}
2688
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2689
			$mpdconf .= <<<EOD
2690
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2691

    
2692
EOD;
2693
		}
2694
		if (isset($ppp['initstr']) && $type == "modem") {
2695
			$initstr = base64_decode($ppp['initstr']);
2696
			$mpdconf .= <<<EOD
2697
	set modem var \$InitString "{$initstr}"
2698

    
2699
EOD;
2700
		}
2701
		if (isset($ppp['simpin']) && $type == "modem") {
2702
			if ($ppp['pin-wait'] == "") {
2703
				$ppp['pin-wait'] = 0;
2704
			}
2705
			$mpdconf .= <<<EOD
2706
	set modem var \$SimPin "{$ppp['simpin']}"
2707
	set modem var \$PinWait "{$ppp['pin-wait']}"
2708

    
2709
EOD;
2710
		}
2711
		if (isset($ppp['apn']) && $type == "modem") {
2712
			$mpdconf .= <<<EOD
2713
	set modem var \$APN "{$ppp['apn']}"
2714
	set modem var \$APNum "{$ppp['apnum']}"
2715

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

    
2732
EOD;
2733
		}
2734
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2735
			$mpdconf .= <<<EOD
2736
	set pppoe max-payload {$mtus[$pid]}
2737

    
2738
EOD;
2739
		}
2740
		if ($type == "pppoe") {
2741
			$mpdconf .= <<<EOD
2742
	set pppoe iface {$port}
2743

    
2744
EOD;
2745
		}
2746

    
2747
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2748
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2749
			$mpdconf .= <<<EOD
2750
	set l2tp secret "{$secret}"
2751

    
2752
EOD;
2753
		}
2754

    
2755
		if (($type == "pptp") || ($type == "l2tp")) {
2756
			$mpdconf .= <<<EOD
2757
	set {$type} self {$localips[$pid]}
2758
	set {$type} peer {$gateways[$pid]}
2759

    
2760
EOD;
2761
		}
2762

    
2763
		$mpdconf .= "\topen\n";
2764
	} //end foreach ($port)
2765

    
2766

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

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

    
2793
	/* clean up old lock files */
2794
	foreach ($ports as $port) {
2795
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2796
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2797
		}
2798
	}
2799

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

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

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

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

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

    
2873
	return 1;
2874
}
2875

    
2876
function interfaces_sync_setup() {
2877
	global $g, $config;
2878

    
2879
	if (isset($config['system']['developerspew'])) {
2880
		$mt = microtime();
2881
		echo "interfaces_sync_setup() being called $mt\n";
2882
	}
2883

    
2884
	if (platform_booting()) {
2885
		echo gettext("Configuring CARP settings...");
2886
		mute_kernel_msgs();
2887
	}
2888

    
2889
	/* suck in configuration items */
2890
	if ($config['hasync']) {
2891
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2892
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2893
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2894
	} else {
2895
		unset($pfsyncinterface);
2896
		unset($pfsyncenabled);
2897
	}
2898

    
2899
	set_sysctl(array(
2900
		"net.inet.carp.preempt" => "1",
2901
		"net.inet.carp.log" => "1")
2902
	);
2903

    
2904
	if (!empty($pfsyncinterface)) {
2905
		$carp_sync_int = get_real_interface($pfsyncinterface);
2906
	} else {
2907
		unset($carp_sync_int);
2908
	}
2909

    
2910
	/* setup pfsync interface */
2911
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2912
		if (is_ipaddr($pfsyncpeerip)) {
2913
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2914
		} else {
2915
			$syncpeer = "-syncpeer";
2916
		}
2917

    
2918
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2919
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2920

    
2921
		sleep(1);
2922

    
2923
		/* 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
2924
		 * for existing sessions.
2925
		 */
2926
		log_error(gettext("waiting for pfsync..."));
2927
		$i = 0;
2928
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2929
			$i++;
2930
			sleep(1);
2931
		}
2932
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2933
		log_error(gettext("Configuring CARP settings finalize..."));
2934
	} else {
2935
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2936
	}
2937

    
2938
	$carplist = get_configured_vip_list('all', VIP_CARP);
2939
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2940
		set_single_sysctl("net.inet.carp.allow", "1");
2941
	} else {
2942
		set_single_sysctl("net.inet.carp.allow", "0");
2943
	}
2944

    
2945
	if (platform_booting()) {
2946
		unmute_kernel_msgs();
2947
		echo gettext("done.") . "\n";
2948
	}
2949
}
2950

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

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

    
2968
	$paa = array();
2969
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2970

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

    
2980
				if (!empty($interface) && $interface != $proxyif) {
2981
					continue;
2982
				}
2983

    
2984
				if (!is_array($paa[$proxyif])) {
2985
					$paa[$proxyif] = array();
2986
				}
2987

    
2988
				$paa[$proxyif][] = $vipent;
2989
			}
2990
		}
2991
	}
2992

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

    
3032
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
3033
	global $g, $config;
3034

    
3035
	if (is_array($config['virtualip']['vip'])) {
3036
		foreach ($config['virtualip']['vip'] as $vip) {
3037

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

    
3054
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
3055
				interface_vip_bring_down($vip);
3056
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
3057
				interface_vip_bring_down($vip);
3058
			else if ($inet == "all")
3059
				interface_vip_bring_down($vip);
3060
		}
3061
	}
3062
}
3063

    
3064
function interfaces_vips_configure($interface = "") {
3065
	global $g, $config;
3066
	if (isset($config['system']['developerspew'])) {
3067
		$mt = microtime();
3068
		echo "interfaces_vips_configure() being called $mt\n";
3069
	}
3070
	$paa = array();
3071
	if (is_array($config['virtualip']['vip'])) {
3072
		$carp_setuped = false;
3073
		$anyproxyarp = false;
3074
		foreach ($config['virtualip']['vip'] as $vip) {
3075
			if ($interface <> "" && get_root_interface($vip['interface']) <> $interface) {
3076
				continue;
3077
			}
3078
			switch ($vip['mode']) {
3079
				case "proxyarp":
3080
					/* nothing it is handled on interface_proxyarp_configure() */
3081
					$anyproxyarp = true;
3082
					break;
3083
				case "ipalias":
3084
					interface_ipalias_configure($vip);
3085
					break;
3086
				case "carp":
3087
					if ($carp_setuped == false) {
3088
						$carp_setuped = true;
3089
					}
3090
					interface_carp_configure($vip);
3091
					break;
3092
			}
3093
		}
3094
		if ($carp_setuped == true) {
3095
			interfaces_sync_setup();
3096
		}
3097
		if ($anyproxyarp == true) {
3098
			interface_proxyarp_configure();
3099
		}
3100
	}
3101
}
3102

    
3103
function interface_ipalias_configure(&$vip) {
3104
	global $config;
3105

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

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

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

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

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

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

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

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

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

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

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

    
3204
	return $realif;
3205
}
3206

    
3207
function interface_wireless_clone($realif, $wlcfg) {
3208
	global $config, $g;
3209
	/*   Check to see if interface has been cloned as of yet.
3210
	 *   If it has not been cloned then go ahead and clone it.
3211
	 */
3212
	$needs_clone = false;
3213
	if (is_array($wlcfg['wireless'])) {
3214
		$wlcfg_mode = $wlcfg['wireless']['mode'];
3215
	} else {
3216
		$wlcfg_mode = $wlcfg['mode'];
3217
	}
3218
	switch ($wlcfg_mode) {
3219
		case "hostap":
3220
			$mode = "wlanmode hostap";
3221
			break;
3222
		case "adhoc":
3223
			$mode = "wlanmode adhoc";
3224
			break;
3225
		default:
3226
			$mode = "";
3227
			break;
3228
	}
3229
	$baseif = interface_get_wireless_base($wlcfg['if']);
3230
	if (does_interface_exist($realif)) {
3231
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
3232
		$ifconfig_str = implode($output);
3233
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
3234
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
3235
			$needs_clone = true;
3236
		}
3237
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
3238
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
3239
			$needs_clone = true;
3240
		}
3241
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3242
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3243
			$needs_clone = true;
3244
		}
3245
	} else {
3246
		$needs_clone = true;
3247
	}
3248

    
3249
	if ($needs_clone == true) {
3250
		/* remove previous instance if it exists */
3251
		if (does_interface_exist($realif)) {
3252
			pfSense_interface_destroy($realif);
3253
		}
3254

    
3255
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3256
		// Create the new wlan interface. FreeBSD returns the new interface name.
3257
		// example:  wlan2
3258
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3259
		if ($ret <> 0) {
3260
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3261
			return false;
3262
		}
3263
		$newif = trim($out[0]);
3264
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3265
		pfSense_interface_rename($newif, $realif);
3266
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3267
	}
3268
	return true;
3269
}
3270

    
3271
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3272
	global $config, $g;
3273

    
3274
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3275
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3276
				 'regdomain', 'regcountry', 'reglocation');
3277

    
3278
	if (!is_interface_wireless($ifcfg['if'])) {
3279
		return;
3280
	}
3281

    
3282
	$baseif = interface_get_wireless_base($ifcfg['if']);
3283

    
3284
	// Sync shared settings for assigned clones
3285
	$iflist = get_configured_interface_list(true);
3286
	foreach ($iflist as $if) {
3287
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
3288
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
3289
				foreach ($shared_settings as $setting) {
3290
					if ($sync_changes) {
3291
						if (isset($ifcfg['wireless'][$setting])) {
3292
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
3293
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3294
							unset($config['interfaces'][$if]['wireless'][$setting]);
3295
						}
3296
					} else {
3297
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3298
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
3299
						} else if (isset($ifcfg['wireless'][$setting])) {
3300
							unset($ifcfg['wireless'][$setting]);
3301
						}
3302
					}
3303
				}
3304
				if (!$sync_changes) {
3305
					break;
3306
				}
3307
			}
3308
		}
3309
	}
3310

    
3311
	// Read or write settings at shared area
3312
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3313
		foreach ($shared_settings as $setting) {
3314
			if ($sync_changes) {
3315
				if (isset($ifcfg['wireless'][$setting])) {
3316
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3317
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3318
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3319
				}
3320
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3321
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3322
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3323
				} else if (isset($ifcfg['wireless'][$setting])) {
3324
					unset($ifcfg['wireless'][$setting]);
3325
				}
3326
			}
3327
		}
3328
	}
3329

    
3330
	// Sync the mode on the clone creation page with the configured mode on the interface
3331
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3332
		foreach ($config['wireless']['clone'] as &$clone) {
3333
			if ($clone['cloneif'] == $ifcfg['if']) {
3334
				if ($sync_changes) {
3335
					$clone['mode'] = $ifcfg['wireless']['mode'];
3336
				} else {
3337
					$ifcfg['wireless']['mode'] = $clone['mode'];
3338
				}
3339
				break;
3340
			}
3341
		}
3342
		unset($clone);
3343
	}
3344
}
3345

    
3346
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3347
	global $config, $g;
3348

    
3349
	/*    open up a shell script that will be used to output the commands.
3350
	 *    since wireless is changing a lot, these series of commands are fragile
3351
	 *    and will sometimes need to be verified by a operator by executing the command
3352
	 *    and returning the output of the command to the developers for inspection.  please
3353
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3354
	 */
3355

    
3356
	// Remove script file
3357
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3358

    
3359
	// Clone wireless nic if needed.
3360
	interface_wireless_clone($if, $wl);
3361

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

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

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

    
3371
	/* set values for /path/program */
3372
	if (file_exists("/usr/local/sbin/hostapd")) {
3373
		$hostapd = "/usr/local/sbin/hostapd";
3374
	} else {
3375
		$hostapd = "/usr/sbin/hostapd";
3376
	}
3377
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3378
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3379
	} else {
3380
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3381
	}
3382
	$ifconfig = "/sbin/ifconfig";
3383
	$sysctl = "/sbin/sysctl";
3384
	$sysctl_args = "-q";
3385
	$killall = "/usr/bin/killall";
3386

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

    
3389
	$wlcmd = array();
3390
	$wl_sysctl = array();
3391
	/* Set a/b/g standard */
3392
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3393
	/* skip mode entirely for "auto" */
3394
	if ($wlcfg['standard'] != "auto") {
3395
		$wlcmd[] = "mode " . escapeshellarg($standard);
3396
	}
3397

    
3398
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3399
	 * to prevent massive packet loss under certain conditions. */
3400
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3401
		$wlcmd[] = "-ampdu";
3402
	}
3403

    
3404
	/* Set ssid */
3405
	if ($wlcfg['ssid']) {
3406
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3407
	}
3408

    
3409
	/* Set 802.11g protection mode */
3410
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3411

    
3412
	/* set wireless channel value */
3413
	if (isset($wlcfg['channel'])) {
3414
		if ($wlcfg['channel'] == "0") {
3415
			$wlcmd[] = "channel any";
3416
		} else {
3417
			if ($wlcfg['channel_width'] != "0") {
3418
				$channel_width = ":" . $wlcfg['channel_width'];
3419
			} else {
3420
				$channel_width = '';
3421
			}
3422
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3423
		}
3424
	}
3425

    
3426
	/* Set antenna diversity value */
3427
	if (isset($wlcfg['diversity'])) {
3428
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3429
	}
3430

    
3431
	/* Set txantenna value */
3432
	if (isset($wlcfg['txantenna'])) {
3433
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3434
	}
3435

    
3436
	/* Set rxantenna value */
3437
	if (isset($wlcfg['rxantenna'])) {
3438
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3439
	}
3440

    
3441
	/* set Distance value */
3442
	if ($wlcfg['distance']) {
3443
		$distance = escapeshellarg($wlcfg['distance']);
3444
	}
3445

    
3446
	/* Set wireless hostap mode */
3447
	if ($wlcfg['mode'] == "hostap") {
3448
		$wlcmd[] = "mediaopt hostap";
3449
	} else {
3450
		$wlcmd[] = "-mediaopt hostap";
3451
	}
3452

    
3453
	/* Set wireless adhoc mode */
3454
	if ($wlcfg['mode'] == "adhoc") {
3455
		$wlcmd[] = "mediaopt adhoc";
3456
	} else {
3457
		$wlcmd[] = "-mediaopt adhoc";
3458
	}
3459

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

    
3462
	/* handle hide ssid option */
3463
	if (isset($wlcfg['hidessid']['enable'])) {
3464
		$wlcmd[] = "hidessid";
3465
	} else {
3466
		$wlcmd[] = "-hidessid";
3467
	}
3468

    
3469
	/* handle pureg (802.11g) only option */
3470
	if (isset($wlcfg['pureg']['enable'])) {
3471
		$wlcmd[] = "mode 11g pureg";
3472
	} else {
3473
		$wlcmd[] = "-pureg";
3474
	}
3475

    
3476
	/* handle puren (802.11n) only option */
3477
	if (isset($wlcfg['puren']['enable'])) {
3478
		$wlcmd[] = "puren";
3479
	} else {
3480
		$wlcmd[] = "-puren";
3481
	}
3482

    
3483
	/* enable apbridge option */
3484
	if (isset($wlcfg['apbridge']['enable'])) {
3485
		$wlcmd[] = "apbridge";
3486
	} else {
3487
		$wlcmd[] = "-apbridge";
3488
	}
3489

    
3490
	/* handle turbo option */
3491
	if (isset($wlcfg['turbo']['enable'])) {
3492
		$wlcmd[] = "mediaopt turbo";
3493
	} else {
3494
		$wlcmd[] = "-mediaopt turbo";
3495
	}
3496

    
3497
	/* handle txpower setting */
3498
	// or don't. this has issues at the moment.
3499
	/*
3500
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3501
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3502
	}*/
3503

    
3504
	/* handle wme option */
3505
	if (isset($wlcfg['wme']['enable'])) {
3506
		$wlcmd[] = "wme";
3507
	} else {
3508
		$wlcmd[] = "-wme";
3509
	}
3510

    
3511
	/* Enable wpa if it's configured. No WEP support anymore. */
3512
	if (isset($wlcfg['wpa']['enable'])) {
3513
		$wlcmd[] = "authmode wpa wepmode off ";
3514
	} else {
3515
		$wlcmd[] = "authmode open wepmode off ";
3516
	}
3517

    
3518
	kill_hostapd($if);
3519
	mwexec(kill_wpasupplicant("{$if}"));
3520

    
3521
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3522

    
3523
	switch ($wlcfg['mode']) {
3524
		case 'bss':
3525
			if (isset($wlcfg['wpa']['enable'])) {
3526
				$wpa .= <<<EOD
3527
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3528
ctrl_interface_group=0
3529
ap_scan=1
3530
#fast_reauth=1
3531
network={
3532
ssid="{$wlcfg['ssid']}"
3533
scan_ssid=1
3534
priority=5
3535
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3536
psk="{$wlcfg['wpa']['passphrase']}"
3537
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3538
group={$wlcfg['wpa']['wpa_pairwise']}
3539
}
3540
EOD;
3541

    
3542
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
3543
				unset($wpa);
3544
			}
3545
			break;
3546
		case 'hostap':
3547
			if (!empty($wlcfg['wpa']['passphrase'])) {
3548
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3549
			} else {
3550
				$wpa_passphrase = "";
3551
			}
3552
			if (isset($wlcfg['wpa']['enable'])) {
3553
				$wpa .= <<<EOD
3554
interface={$if}
3555
driver=bsd
3556
logger_syslog=-1
3557
logger_syslog_level=0
3558
logger_stdout=-1
3559
logger_stdout_level=0
3560
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3561
ctrl_interface={$g['varrun_path']}/hostapd
3562
ctrl_interface_group=wheel
3563
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3564
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3565
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3566
ssid={$wlcfg['ssid']}
3567
debug={$wlcfg['wpa']['debug_mode']}
3568
wpa={$wlcfg['wpa']['wpa_mode']}
3569
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3570
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3571
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3572
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3573
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3574
{$wpa_passphrase}
3575

    
3576
EOD;
3577

    
3578
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3579
					$wpa .= <<<EOD
3580
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3581
rsn_preauth=1
3582
rsn_preauth_interfaces={$if}
3583

    
3584
EOD;
3585
				}
3586
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3587
					$wpa .= "ieee8021x=1\n";
3588

    
3589
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3590
						$auth_server_port = "1812";
3591
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3592
							$auth_server_port = intval($wlcfg['auth_server_port']);
3593
						}
3594
						$wpa .= <<<EOD
3595

    
3596
auth_server_addr={$wlcfg['auth_server_addr']}
3597
auth_server_port={$auth_server_port}
3598
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3599

    
3600
EOD;
3601
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3602
							$auth_server_port2 = "1812";
3603
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3604
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3605
							}
3606

    
3607
							$wpa .= <<<EOD
3608
auth_server_addr={$wlcfg['auth_server_addr2']}
3609
auth_server_port={$auth_server_port2}
3610
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3611

    
3612
EOD;
3613
						}
3614
					}
3615
				}
3616

    
3617
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3618
				unset($wpa);
3619
			}
3620
			break;
3621
	}
3622

    
3623
	/*
3624
	 *    all variables are set, lets start up everything
3625
	 */
3626

    
3627
	$baseif = interface_get_wireless_base($if);
3628
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3629
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3630

    
3631
	/* set sysctls for the wireless interface */
3632
	if (!empty($wl_sysctl)) {
3633
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3634
		foreach ($wl_sysctl as $wl_sysctl_line) {
3635
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3636
		}
3637
	}
3638

    
3639
	/* set ack timers according to users preference (if he/she has any) */
3640
	if ($distance) {
3641
		fwrite($fd_set, "# Enable ATH distance settings\n");
3642
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3643
	}
3644

    
3645
	if (isset($wlcfg['wpa']['enable'])) {
3646
		if ($wlcfg['mode'] == "bss") {
3647
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3648
		}
3649
		if ($wlcfg['mode'] == "hostap") {
3650
			/* add line to script to restore old mac to make hostapd happy */
3651
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3652
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3653
				$if_curmac = get_interface_mac($if);
3654
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3655
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3656
						" link " . escapeshellarg($if_oldmac) . "\n");
3657
				}
3658
			}
3659

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

    
3662
			/* add line to script to restore spoofed mac after running hostapd */
3663
			if ($wl['spoofmac']) {
3664
				$if_curmac = get_interface_mac($if);
3665
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3666
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3667
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3668
				}
3669
			}
3670
		}
3671
	}
3672

    
3673
	fclose($fd_set);
3674

    
3675
	/* Making sure regulatory settings have actually changed
3676
	 * before applying, because changing them requires bringing
3677
	 * down all wireless networks on the interface. */
3678
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3679
	$ifconfig_str = implode($output);
3680
	unset($output);
3681
	$reg_changing = false;
3682

    
3683
	/* special case for the debug country code */
3684
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3685
		$reg_changing = true;
3686
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3687
		$reg_changing = true;
3688
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3689
		$reg_changing = true;
3690
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3691
		$reg_changing = true;
3692
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3693
		$reg_changing = true;
3694
	}
3695

    
3696
	if ($reg_changing) {
3697
		/* set regulatory domain */
3698
		if ($wlcfg['regdomain']) {
3699
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3700
		}
3701

    
3702
		/* set country */
3703
		if ($wlcfg['regcountry']) {
3704
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3705
		}
3706

    
3707
		/* set location */
3708
		if ($wlcfg['reglocation']) {
3709
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3710
		}
3711

    
3712
		$wlregcmd_args = implode(" ", $wlregcmd);
3713

    
3714
		/* build a complete list of the wireless clones for this interface */
3715
		$clone_list = array();
3716
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3717
			$clone_list[] = interface_get_wireless_clone($baseif);
3718
		}
3719
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3720
			foreach ($config['wireless']['clone'] as $clone) {
3721
				if ($clone['if'] == $baseif) {
3722
					$clone_list[] = $clone['cloneif'];
3723
				}
3724
			}
3725
		}
3726

    
3727
		/* find which clones are up and bring them down */
3728
		$clones_up = array();
3729
		foreach ($clone_list as $clone_if) {
3730
			$clone_status = pfSense_get_interface_addresses($clone_if);
3731
			if ($clone_status['status'] == 'up') {
3732
				$clones_up[] = $clone_if;
3733
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3734
			}
3735
		}
3736

    
3737
		/* apply the regulatory settings */
3738
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3739
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3740

    
3741
		/* bring the clones back up that were previously up */
3742
		foreach ($clones_up as $clone_if) {
3743
			interfaces_bring_up($clone_if);
3744

    
3745
			/*
3746
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3747
			 * is in infrastructure mode, and WPA is enabled.
3748
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3749
			 */
3750
			if ($clone_if != $if) {
3751
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3752
				if ((!empty($friendly_if)) &&
3753
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3754
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3755
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3756
				}
3757
			}
3758
		}
3759
	}
3760

    
3761
	/* The mode must be specified in a separate command before ifconfig
3762
	 * will allow the mode and channel at the same time in the next.
3763
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3764
	 */
3765
	if ($wlcfg['mode'] == "hostap") {
3766
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3767
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3768
	}
3769

    
3770
	/* configure wireless */
3771
	$wlcmd_args = implode(" ", $wlcmd);
3772
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3773
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3774
	/* Bring the interface up only after setting up all the other parameters. */
3775
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3776
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3777
	fclose($wlan_setup_log);
3778

    
3779
	unset($wlcmd_args, $wlcmd);
3780

    
3781

    
3782
	sleep(1);
3783
	/* execute hostapd and wpa_supplicant if required in shell */
3784
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3785

    
3786
	return 0;
3787

    
3788
}
3789

    
3790
function kill_hostapd($interface) {
3791
	global $g;
3792

    
3793
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3794
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3795
	}
3796
}
3797

    
3798
function kill_wpasupplicant($interface) {
3799
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3800
}
3801

    
3802
function find_dhclient_process($interface) {
3803
	if ($interface) {
3804
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3805
	} else {
3806
		$pid = 0;
3807
	}
3808

    
3809
	return intval($pid);
3810
}
3811

    
3812
function kill_dhclient_process($interface) {
3813
	if (empty($interface) || !does_interface_exist($interface)) {
3814
		return;
3815
	}
3816

    
3817
	$i = 0;
3818
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3819
		/* 3rd time make it die for sure */
3820
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3821
		posix_kill($pid, $sig);
3822
		sleep(1);
3823
		$i++;
3824
	}
3825
	unset($i);
3826
}
3827

    
3828
function find_dhcp6c_process($interface) {
3829
	global $g;
3830

    
3831
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3832
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3833
	} else {
3834
		return(false);
3835
	}
3836

    
3837
	return intval($pid);
3838
}
3839

    
3840
function kill_dhcp6client_process($interface, $force, $release = false) {
3841
	global $g;
3842

    
3843
	$i = 0;
3844

    
3845
	/*
3846
	Beware of the following: Reason, the interface may be down, but
3847
	dhcp6c may still be running, it just complains it cannot send
3848
	and carries on. Commented out as will stop the call to kill.
3849

    
3850
	if (empty($interface) || !does_interface_exist($interface)) {
3851
		return;
3852
	}
3853
	*/
3854

    
3855
	/*********** Notes on signals for dhcp6c and this function *************
3856

    
3857
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3858
	a release and waiting for the response that never comes.
3859
	So we need to tell it that the interface is down and to just die quickly
3860
	otherwise a new client may launch and we have duplicate proceses.
3861
	In this case use SIGUSR1.
3862

    
3863
	If we want to exit normally obeying the no release flag then use SIGTERM.
3864
	If we want to exit with a release overiding the no release flag then
3865
	use SIGUSR2.
3866

    
3867
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3868
	exit quickly without sending release signals.
3869

    
3870
	If $Force is set to false and $release is also set to false dhcp6c will
3871
	follow the no-release flag.
3872

    
3873
	If $Force is set to false and $release is true then dhcp6c will send a
3874
	release regardless of the no-release flag.
3875
	***********************************************************************/
3876

    
3877
	if ($force == true) {
3878
		$psig=SIGUSR1;
3879
	} else if ($release == false) {
3880
		$psig=SIGTERM;
3881
	} else {
3882
		$psig=SIGUSR2;
3883
	}
3884

    
3885
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3886
		/* 3rd time make it die for sure */
3887
		$sig = ($i == 2 ? SIGKILL : $psig);
3888
		posix_kill($pid, $sig);
3889
		sleep(1);
3890
		$i++;
3891
	}
3892
	/* Clear the RTSOLD script created lock & tidy up */
3893
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3894
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
3895
}
3896
function reset_dhcp6client_process($interface) {
3897

    
3898
	$pid = find_dhcp6c_process($interface);
3899

    
3900
	if($pid != 0) {
3901
		posix_kill($pid, SIGHUP);
3902
	}
3903
}
3904

    
3905
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3906
	global $g;
3907

    
3908
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3909
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3910

    
3911
	/*
3912
	 * Only run this if the lock does not exist. In theory the lock being
3913
	 * there in this mode means the user has selected dhcp6withoutRA while
3914
	 * a session is active in the other mode.
3915
	 *
3916
	 * It should not happen as the process should have been killed and the
3917
	 * lock deleted.
3918
	 */
3919

    
3920
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
3921
		kill_dhcp6client_process($interface, true);
3922
		/* Lock it to avoid multiple runs */
3923
		touch("/tmp/dhcp6c_{$interface}_lock");
3924
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3925
		    "{$noreleaseOption} " .
3926
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
3927
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
3928
		    $interface);
3929
		log_error(sprintf(gettext(
3930
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
3931
		    $interface));
3932
	}
3933
}
3934

    
3935
function interface_virtual_create($interface) {
3936
	global $config;
3937

    
3938
	if (interface_is_vlan($interface) != NULL) {
3939
		interfaces_vlan_configure($interface);
3940
	} else if (substr($interface, 0, 3) == "gre") {
3941
		interfaces_tunnel_configure(0, $interface, 'gre');
3942
	} else if (substr($interface, 0, 3) == "gif") {
3943
		interfaces_tunnel_configure(0, $interface, 'gif');
3944
	} else if (substr($interface, 0, 5) == "ovpns") {
3945
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3946
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3947
				if ($interface == "ovpns{$server['vpnid']}") {
3948
					if (!function_exists('openvpn_resync')) {
3949
						require_once('openvpn.inc');
3950
					}
3951
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3952
					openvpn_resync('server', $server);
3953
				}
3954
			}
3955
			unset($server);
3956
		}
3957
	} else if (substr($interface, 0, 5) == "ovpnc") {
3958
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3959
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3960
				if ($interface == "ovpnc{$client['vpnid']}") {
3961
					if (!function_exists('openvpn_resync')) {
3962
						require_once('openvpn.inc');
3963
					}
3964
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3965
					openvpn_resync('client', $client);
3966
				}
3967
			}
3968
			unset($client);
3969
		}
3970
	} else if (substr($interface, 0, 5) == "ipsec") {
3971
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
3972
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
3973
				if ($ph1ent['disabled']) {
3974
					continue;
3975
				}
3976
				if ($interface == "ipsec{$ph1ent['ikeid']}") {
3977
					interface_ipsec_vti_configure($ph1ent);
3978
				}
3979
			}
3980
		}
3981
	} else if (substr($interface, 0, 4) == "lagg") {
3982
		interfaces_lagg_configure($interface);
3983
	} else if (substr($interface, 0, 6) == "bridge") {
3984
		interfaces_bridge_configure(0, $interface);
3985
	}
3986
}
3987

    
3988
function interface_vlan_mtu_configured($iface) {
3989
	global $config;
3990

    
3991
	$mtu = 0;
3992
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3993
		foreach ($config['vlans']['vlan'] as $vlan) {
3994

    
3995
			if ($vlan['vlanif'] != $iface)
3996
				continue;
3997

    
3998
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3999
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
4000
				/* VLAN MTU */
4001
				$mtu = $config['interfaces'][$assignedport]['mtu'];
4002
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
4003
				/* Parent MTU */
4004
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
4005
			}
4006
		}
4007
	}
4008

    
4009
	return $mtu;
4010
}
4011

    
4012
function interface_mtu_wanted_for_pppoe($realif) {
4013
	global $config;
4014

    
4015
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
4016
		return 0;
4017

    
4018
	$mtu = 0;
4019
	foreach ($config['ppps']['ppp'] as $ppp) {
4020
		if ($ppp['type'] != "pppoe") {
4021
			continue;
4022
		}
4023

    
4024
		$mtus = array();
4025
		if (!empty($ppp['mtu'])) {
4026
			$mtus = explode(',', $ppp['mtu']);
4027
		}
4028
		$ports = explode(',', $ppp['ports']);
4029

    
4030
		foreach ($ports as $pid => $port) {
4031
			$parentifa = get_parent_interface($port);
4032
			$parentif = $parentifa[0];
4033
			if ($parentif != $realif)
4034
				continue;
4035

    
4036
			// there is an MTU configured on the port in question
4037
			if (!empty($mtus[$pid])) {
4038
				$mtu = intval($mtus[$pid]) + 8;
4039
			// or use the MTU configured on the interface ...
4040
			} elseif (is_array($config['interfaces'])) {
4041
				foreach ($config['interfaces'] as $interface) {
4042
					if ($interface['if'] == $ppp['if'] &&
4043
					    !empty($interface['mtu'])) {
4044
						$mtu = intval($interface['mtu']) + 8;
4045
						break;
4046
					}
4047
				}
4048
			}
4049
		}
4050
	}
4051

    
4052
	return $mtu;
4053
}
4054

    
4055
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
4056
	global $config, $g;
4057
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
4058
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
4059

    
4060
	$wancfg = $config['interfaces'][$interface];
4061

    
4062
	if (!isset($wancfg['enable'])) {
4063
		return;
4064
	}
4065

    
4066
	$realif = get_real_interface($interface);
4067
	$realhwif_array = get_parent_interface($interface);
4068
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
4069
	$realhwif = $realhwif_array[0];
4070

    
4071
	$mac_if_cfg = $wancfg;
4072
	if (interface_is_vlan($realif)) {
4073
		$mac_if = convert_real_interface_to_friendly_interface_name(
4074
		    $realhwif);
4075
		if (is_array($config['interfaces'][$mac_if])) {
4076
			$mac_if_cfg = $config['interfaces'][$mac_if];
4077
		} else {
4078
			$mac_if = $interface;
4079
		}
4080
	}
4081

    
4082
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn") && !(substr($realif, 0, 5) == "ipsec")) {
4083
		/* remove all IPv4 and IPv6 addresses */
4084
		$tmpifaces = pfSense_getall_interface_addresses($realif);
4085
		if (is_array($tmpifaces)) {
4086
			foreach ($tmpifaces as $tmpiface) {
4087
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
4088
					if (!is_linklocal($tmpiface)) {
4089
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
4090
					}
4091
				} elseif (strstr($tmpiface, "fe80::1:1")) {
4092
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 fe80::1:1 -alias");
4093
				} else {
4094
					if (is_subnetv4($tmpiface)) {
4095
						$tmpip = explode('/', $tmpiface);
4096
						$tmpip = $tmpip[0];
4097
					} else {
4098
						$tmpip = $tmpiface;
4099
					}
4100
					pfSense_interface_deladdress($realif, $tmpip);
4101
				}
4102
			}
4103
		}
4104

    
4105
		/* only bring down the interface when both v4 and v6 are set to NONE */
4106
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4107
			interface_bring_down($interface);
4108
		}
4109
	}
4110

    
4111
	$interface_to_check = $realif;
4112
	if (interface_isppp_type($interface)) {
4113
		$interface_to_check = $realhwif;
4114
	}
4115

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

    
4121
	/* Disable Accepting router advertisements unless specifically requested */
4122
	if ($g['debug']) {
4123
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
4124
	}
4125
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
4126
	{
4127
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
4128
	}
4129
	/* wireless configuration? */
4130
	if (is_array($wancfg['wireless']) && !$linkupevent) {
4131
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
4132
	}
4133

    
4134
	$current_mac = get_interface_mac($realhwif);
4135
	$vendor_mac = get_interface_vendor_mac($realhwif);
4136

    
4137
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4138
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4139

    
4140
		interface_set_macaddr($realhwif, $mac_addr);
4141
	} else {
4142
		/*
4143
		 * this is not a valid mac address.  generate a
4144
		 * temporary mac address so the machine can get online.
4145
		 */
4146
		echo gettext("Generating new MAC address.");
4147
		$random_mac = generate_random_mac_address();
4148
		interface_set_macaddr($realhwif, $random_mac);
4149
		$config['interfaces'][$mac_if]['spoofmac'] = $random_mac;
4150
		write_config(sprintf(gettext('The invalid MAC address ' .
4151
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
4152
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
4153
		file_notice("MAC Address altered", sprintf(gettext('The ' .
4154
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
4155
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
4156
		    $random_mac), "Interfaces");
4157
	}
4158

    
4159
	/* media */
4160
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4161
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4162
		if ($wancfg['media']) {
4163
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4164
		}
4165
		if ($wancfg['mediaopt']) {
4166
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4167
		}
4168
		mwexec($cmd);
4169
	}
4170

    
4171
	/* Apply hw offloading policies as configured */
4172
	enable_hardware_offloading($interface);
4173

    
4174
	/* invalidate interface/ip/sn cache */
4175
	get_interface_arr(true);
4176
	unset($interface_ip_arr_cache[$realif]);
4177
	unset($interface_sn_arr_cache[$realif]);
4178
	unset($interface_ipv6_arr_cache[$realif]);
4179
	unset($interface_snv6_arr_cache[$realif]);
4180

    
4181
	$tunnelif = substr($realif, 0, 3);
4182

    
4183
	$mtuif = $realif;
4184
	$mtuhwif = $realhwif;
4185

    
4186
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4187
	if (interface_isppp_type($interface)) {
4188
		$mtuif = $realhwif;
4189
		$mtuhwif_array = get_parent_interface($mtuif);
4190
		$mtuhwif = $mtuhwif_array[0];
4191
	}
4192

    
4193
	$wantedmtu = 0;
4194
	if (is_array($config['interfaces'])) {
4195
		foreach ($config['interfaces'] as $tmpinterface) {
4196
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4197
				$wantedmtu = $tmpinterface['mtu'];
4198
				break;
4199
			}
4200
		}
4201
	}
4202

    
4203
	/* MTU is not specified for interface, try the pppoe settings. */
4204
	if ($wantedmtu == 0) {
4205
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4206
	}
4207
	if (($wantedmtu == 0) && (interface_is_vlan($mtuif) != NULL) && interface_isppp_type($interface)) {
4208
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4209
	}
4210
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4211
		/* set MTU to 1400 for GRE over IPsec */
4212
		if (is_greipsec($mtuif)) {
4213
			$wantedmtu = 1400;
4214
		} else {
4215
			$wantedmtu = 1476;
4216
		}
4217
	}
4218
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4219
		$wantedmtu = 1280;
4220
	}
4221
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'vxlan')) {
4222
		$wantedmtu = 1450;
4223
	}
4224

    
4225
	/* Set the MTU to 1500 if no explicit MTU configured. */
4226
	if ($wantedmtu == 0) {
4227
		$wantedmtu = 1500; /* Default */
4228
	}
4229

    
4230
	if (interface_is_vlan($mtuif) != NULL) {
4231
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4232
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
4233
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
4234
			if ($wancfg['mtu'] > $parentmtu) {
4235
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4236
			}
4237
		}
4238

    
4239
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4240

    
4241
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4242
			$configuredmtu = $parentmtu;
4243
		if ($configuredmtu != 0)
4244
			$mtu = $configuredmtu;
4245
		else
4246
			$mtu = $wantedmtu;
4247

    
4248
		/* Set the parent MTU. */
4249
		if (get_interface_mtu($mtuhwif) < $mtu)
4250
			set_interface_mtu($mtuhwif, $mtu);
4251
		/* Set the VLAN MTU. */
4252
		if (get_interface_mtu($mtuif) != $mtu)
4253
			set_interface_mtu($mtuif, $mtu);
4254
	} else if (substr($mtuif, 0, 4) == 'lagg') {
4255
		/* LAGG interface must be destroyed and re-created to change MTU */
4256
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4257
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
4258
				foreach ($config['laggs']['lagg'] as $lagg) {
4259
					if ($lagg['laggif'] == $mtuif) {
4260
						interface_lagg_configure($lagg);
4261
						break;
4262
					}
4263
				}
4264
			}
4265
		}
4266
	} else {
4267
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4268
			pfSense_interface_mtu($mtuif, $wantedmtu);
4269
			set_ipv6routes_mtu($mtuif, $wantedmtu);
4270
		}
4271
	}
4272
	/* XXX: What about gre/gif/.. ? */
4273

    
4274
	if (does_interface_exist($wancfg['if'])) {
4275
		interfaces_bring_up($wancfg['if']);
4276
	}
4277

    
4278
	switch ($wancfg['ipaddr']) {
4279
		case 'dhcp':
4280
			interface_dhcp_configure($interface);
4281
			break;
4282
		case 'pppoe':
4283
		case 'l2tp':
4284
		case 'pptp':
4285
		case 'ppp':
4286
			interface_ppps_configure($interface);
4287
			break;
4288
		default:
4289
			/* XXX: Kludge for now related to #3280 */
4290
			if (!in_array($tunnelif, array("gif", "gre", "vxlan", "ovp", "ips"))) {
4291
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4292
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4293
				}
4294
			}
4295
			break;
4296
	}
4297

    
4298
	switch ($wancfg['ipaddrv6']) {
4299
		case 'slaac':
4300
		case 'dhcp6':
4301
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4302
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4303
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4304
			/* Remove the check file. Should not be there but just in case */
4305
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
4306
			log_error(gettext("calling interface_dhcpv6_configure."));
4307
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
4308
				interface_dhcpv6_configure($interface, $wancfg);
4309
			}
4310
			break;
4311
		case '6rd':
4312
			interface_6rd_configure($interface, $wancfg);
4313
			break;
4314
		case '6to4':
4315
			interface_6to4_configure($interface, $wancfg);
4316
			break;
4317
		case 'track6':
4318
			interface_track6_configure($interface, $wancfg, $linkupevent);
4319
			break;
4320
		default:
4321
			/* XXX: Kludge for now related to #3280 */
4322
			if (!in_array($tunnelif, array("gif", "gre", "vxlan", "ovp", "ips"))) {
4323
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4324
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4325
					// FIXME: Add IPv6 Support to the pfSense module
4326
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4327
				}
4328
			}
4329
			break;
4330
	}
4331

    
4332
	interface_netgraph_needed($interface);
4333

    
4334
	if (!platform_booting()) {
4335
		link_interface_to_vips($interface, "update");
4336

    
4337
		if ($tunnelif != 'gre') {
4338
			unset($gre);
4339
			$gre = link_interface_to_tunnelif($interface, 'gre');
4340
			if (!empty($gre)) {
4341
				array_walk($gre, 'interface_gre_configure');
4342
			}
4343
		}
4344

    
4345
		if ($tunnelif != 'gif') {
4346
			unset($gif);
4347
			$gif = link_interface_to_tunnelif($interface, 'gif');
4348
			if (!empty($gif)) {
4349
				array_walk($gif, 'interface_gif_configure');
4350
			}
4351
		}
4352

    
4353
		if ($tunnelif != 'vxlan') {
4354
			unset($vxlan);
4355
			$vxlan = link_interface_to_tunnelif($interface, 'vxlan');
4356
			if (!empty($vxlan)) {
4357
				array_walk($vxlan, 'interface_vxlan_configure');
4358
			}
4359
		}
4360

    
4361
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4362
			unset($bridgetmp);
4363
			$bridgetmp = link_interface_to_bridge($interface);
4364
			if (!empty($bridgetmp)) {
4365
				interface_bridge_add_member($bridgetmp, $realif);
4366
			}
4367
		}
4368

    
4369
		$grouptmp = link_interface_to_group($interface);
4370
		if (!empty($grouptmp)) {
4371
			array_walk($grouptmp, 'interface_group_add_member');
4372
		}
4373

    
4374
		if ($interface == "lan") {
4375
			/* make new hosts file */
4376
			system_hosts_generate();
4377
		}
4378

    
4379
		if ($reloadall == true) {
4380

    
4381
			/* reconfigure static routes (kernel may have deleted them) */
4382
			system_routing_configure($interface);
4383

    
4384
			/* reload ipsec tunnels */
4385
			send_event("service reload ipsecdns");
4386

    
4387
			if (isset($config['dnsmasq']['enable'])) {
4388
				services_dnsmasq_configure();
4389
			}
4390

    
4391
			if (isset($config['unbound']['enable'])) {
4392
				services_unbound_configure();
4393
			}
4394

    
4395
			/* update dyndns */
4396
			send_event("service reload dyndns {$interface}");
4397

    
4398
			/* reload captive portal */
4399
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4400
				require_once('captiveportal.inc');
4401
			}
4402
			captiveportal_init_rules_byinterface($interface);
4403
		}
4404
	}
4405

    
4406
	if (!empty($wancfg['descr'])) {
4407
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4408
	};
4409

    
4410
	interfaces_staticarp_configure($interface);
4411
	return 0;
4412
}
4413

    
4414
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4415
	global $config, $g;
4416

    
4417
	if (!is_array($wancfg)) {
4418
		return;
4419
	}
4420

    
4421
	if (!isset($wancfg['enable'])) {
4422
		return;
4423
	}
4424

    
4425
	/* If the interface is not configured via another, exit */
4426
	if (empty($wancfg['track6-interface'])) {
4427
		return;
4428
	}
4429

    
4430
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4431
	$realif = get_real_interface($interface);
4432
	$linklocal = find_interface_ipv6_ll($realif, true);
4433
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4434
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4435
	}
4436

    
4437
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4438
	if (!isset($trackcfg['enable'])) {
4439
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4440
		return;
4441
	}
4442

    
4443
	switch ($trackcfg['ipaddrv6']) {
4444
		case "6to4":
4445
			if ($g['debug']) {
4446
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4447
			}
4448
			interface_track6_6to4_configure($interface, $wancfg);
4449
			break;
4450
		case "6rd":
4451
			if ($g['debug']) {
4452
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4453
			}
4454
			interface_track6_6rd_configure($interface, $wancfg);
4455
			break;
4456
		case "dhcp6":
4457
			if ($linkupevent == true) {
4458
				/*
4459
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4460
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4461
				 *
4462
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4463
				 */
4464
				$parentrealif = get_real_interface($wancfg['track6-interface']);
4465
				$pidv6 = find_dhcp6c_process($parentrealif);
4466
				if ($pidv6) {
4467
					posix_kill($pidv6, SIGHUP);
4468
				}
4469
			}
4470
			break;
4471
	}
4472

    
4473
	if ($linkupevent == false && !platform_booting()) {
4474
		if (!function_exists('services_dhcpd_configure')) {
4475
			require_once("services.inc");
4476
		}
4477

    
4478
		/* restart dns servers (defering dhcpd reload) */
4479
		if (isset($config['unbound']['enable'])) {
4480
			services_unbound_configure(false);
4481
		}
4482
		if (isset($config['dnsmasq']['enable'])) {
4483
			services_dnsmasq_configure(false);
4484
		}
4485

    
4486
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4487
		services_dhcpd_configure("inet6");
4488
	}
4489

    
4490
	return 0;
4491
}
4492

    
4493
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4494
	global $config, $g;
4495
	global $interface_ipv6_arr_cache;
4496
	global $interface_snv6_arr_cache;
4497

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

    
4502
	/* If the interface is not configured via another, exit */
4503
	if (empty($lancfg['track6-interface'])) {
4504
		return;
4505
	}
4506

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

    
4513
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4514
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4515
		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']));
4516
		return;
4517
	}
4518
	$hexwanv4 = return_hex_ipv4($ip4address);
4519

    
4520
	/* create the long prefix notation for math, save the prefix length */
4521
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4522
	$rd6prefixlen = $rd6prefix[1];
4523
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4524

    
4525
	/* binary presentation of the prefix for all 128 bits. */
4526
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4527

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

    
4533
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4534
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4535
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4536
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4537
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4538
	/* fill the rest out with zeros */
4539
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4540

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

    
4544
	$lanif = get_real_interface($interface);
4545
	$oip = find_interface_ipv6($lanif);
4546
	if (is_ipaddrv6($oip)) {
4547
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4548
	}
4549
	unset($interface_ipv6_arr_cache[$lanif]);
4550
	unset($interface_snv6_arr_cache[$lanif]);
4551
	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));
4552
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4553

    
4554
	return 0;
4555
}
4556

    
4557
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4558
	global $config, $g;
4559
	global $interface_ipv6_arr_cache;
4560
	global $interface_snv6_arr_cache;
4561

    
4562
	if (!is_array($lancfg)) {
4563
		return;
4564
	}
4565

    
4566
	/* If the interface is not configured via another, exit */
4567
	if (empty($lancfg['track6-interface'])) {
4568
		return;
4569
	}
4570

    
4571
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4572
	if (empty($wancfg)) {
4573
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4574
		return;
4575
	}
4576

    
4577
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4578
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4579
		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']));
4580
		return;
4581
	}
4582
	$hexwanv4 = return_hex_ipv4($ip4address);
4583

    
4584
	/* create the long prefix notation for math, save the prefix length */
4585
	$sixto4prefix = "2002::";
4586
	$sixto4prefixlen = 16;
4587
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4588

    
4589
	/* binary presentation of the prefix for all 128 bits. */
4590
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4591

    
4592
	/* just save the left prefix length bits */
4593
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4594
	/* add the v4 address */
4595
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4596
	/* add the custom prefix id */
4597
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4598
	/* fill the rest out with zeros */
4599
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4600

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

    
4604
	$lanif = get_real_interface($interface);
4605
	$oip = find_interface_ipv6($lanif);
4606
	if (is_ipaddrv6($oip)) {
4607
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4608
	}
4609
	unset($interface_ipv6_arr_cache[$lanif]);
4610
	unset($interface_snv6_arr_cache[$lanif]);
4611
	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));
4612
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4613

    
4614
	return 0;
4615
}
4616

    
4617
function interface_6rd_configure($interface = "wan", $wancfg) {
4618
	global $config, $g;
4619

    
4620
	/* because this is a tunnel interface we can only function
4621
	 *	with a public IPv4 address on the interface */
4622

    
4623
	if (!is_array($wancfg)) {
4624
		return;
4625
	}
4626

    
4627
	if (!is_module_loaded('if_stf.ko')) {
4628
		mwexec('/sbin/kldload if_stf.ko');
4629
	}
4630

    
4631
	$wanif = get_real_interface($interface);
4632
	$ip4address = find_interface_ip($wanif);
4633
	if (!is_ipaddrv4($ip4address)) {
4634
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4635
		return false;
4636
	}
4637
	$hexwanv4 = return_hex_ipv4($ip4address);
4638

    
4639
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4640
		$wancfg['prefix-6rd-v4plen'] = 0;
4641
	}
4642

    
4643
	/* create the long prefix notation for math, save the prefix length */
4644
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4645
	$rd6prefixlen = $rd6prefix[1];
4646
	$brgw = explode('.', $wancfg['gateway-6rd']);
4647
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4648
	$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);
4649
	if (strlen($rd6brgw) < 128) {
4650
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4651
	}
4652
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4653
	unset($brgw);
4654
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4655

    
4656
	/* binary presentation of the prefix for all 128 bits. */
4657
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4658

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

    
4666
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4667
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4668

    
4669

    
4670
	/* XXX: need to extend to support variable prefix size for v4 */
4671
	$stfiface = "{$interface}_stf";
4672
	if (does_interface_exist($stfiface)) {
4673
		pfSense_interface_destroy($stfiface);
4674
	}
4675
	$tmpstfiface = pfSense_interface_create("stf");
4676
	pfSense_interface_rename($tmpstfiface, $stfiface);
4677
	pfSense_interface_flags($stfiface, IFF_LINK2);
4678
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4679
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4680
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4681
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4682
	}
4683
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4684
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4685
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4686
	} elseif ($parentmtu > 1300) {
4687
		set_interface_mtu($stfiface, $parentmtu - 20);
4688
	}
4689
	if ($g['debug']) {
4690
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4691
	}
4692

    
4693
	/* write out a default router file */
4694
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4695
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4696

    
4697
	$ip4gateway = get_interface_gateway($interface);
4698
	if (is_ipaddrv4($ip4gateway)) {
4699
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4700
	}
4701

    
4702
	/* configure dependent interfaces */
4703
	if (!platform_booting()) {
4704
		link_interface_to_track6($interface, "update");
4705
	}
4706

    
4707
	return 0;
4708
}
4709

    
4710
function interface_6to4_configure($interface = "wan", $wancfg) {
4711
	global $config, $g;
4712

    
4713
	/* because this is a tunnel interface we can only function
4714
	 *	with a public IPv4 address on the interface */
4715

    
4716
	if (!is_array($wancfg)) {
4717
		return;
4718
	}
4719

    
4720
	$wanif = get_real_interface($interface);
4721
	$ip4address = find_interface_ip($wanif);
4722
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4723
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4724
		return false;
4725
	}
4726

    
4727
	/* create the long prefix notation for math, save the prefix length */
4728
	$stfprefixlen = 16;
4729
	$stfprefix = Net_IPv6::uncompress("2002::");
4730
	$stfarr = explode(":", $stfprefix);
4731
	$v4prefixlen = "0";
4732

    
4733
	/* we need the hex form of the interface IPv4 address */
4734
	$ip4arr = explode(".", $ip4address);
4735
	$hexwanv4 = "";
4736
	foreach ($ip4arr as $octet) {
4737
		$hexwanv4 .= sprintf("%02x", $octet);
4738
	}
4739

    
4740
	/* we need the hex form of the broker IPv4 address */
4741
	$ip4arr = explode(".", "192.88.99.1");
4742
	$hexbrv4 = "";
4743
	foreach ($ip4arr as $octet) {
4744
		$hexbrv4 .= sprintf("%02x", $octet);
4745
	}
4746

    
4747
	/* binary presentation of the prefix for all 128 bits. */
4748
	$stfprefixbin = "";
4749
	foreach ($stfarr as $element) {
4750
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4751
	}
4752
	/* just save the left prefix length bits */
4753
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4754

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

    
4759
	/* for the local subnet too. */
4760
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4761
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4762

    
4763
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4764
	$stfbrarr = array();
4765
	$stfbrbinarr = array();
4766
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4767
	foreach ($stfbrbinarr as $bin) {
4768
		$stfbrarr[] = dechex(bindec($bin));
4769
	}
4770
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4771

    
4772
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4773
	$stflanarr = array();
4774
	$stflanbinarr = array();
4775
	$stflanbinarr = str_split($stflanbin, 16);
4776
	foreach ($stflanbinarr as $bin) {
4777
		$stflanarr[] = dechex(bindec($bin));
4778
	}
4779
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4780
	$stflanarr[7] = 1;
4781
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4782

    
4783
	/* setup the stf interface */
4784
	if (!is_module_loaded("if_stf")) {
4785
		mwexec("/sbin/kldload if_stf.ko");
4786
	}
4787
	$stfiface = "{$interface}_stf";
4788
	if (does_interface_exist($stfiface)) {
4789
		pfSense_interface_destroy($stfiface);
4790
	}
4791
	$tmpstfiface = pfSense_interface_create("stf");
4792
	pfSense_interface_rename($tmpstfiface, $stfiface);
4793
	pfSense_interface_flags($stfiface, IFF_LINK2);
4794
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4795

    
4796
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4797
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4798
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4799
	} elseif ($parentmtu > 1300) {
4800
		set_interface_mtu($stfiface, $parentmtu - 20);
4801
	}
4802
	if ($g['debug']) {
4803
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4804
	}
4805

    
4806
	/* write out a default router file */
4807
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4808
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4809

    
4810
	$ip4gateway = get_interface_gateway($interface);
4811
	if (is_ipaddrv4($ip4gateway)) {
4812
		route_add_or_change("192.88.99.1", $ip4gateway);
4813
	}
4814

    
4815
	if (!platform_booting()) {
4816
		link_interface_to_track6($interface, "update");
4817
	}
4818

    
4819
	return 0;
4820
}
4821

    
4822
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4823
	global $config, $g;
4824

    
4825
	if (!is_array($wancfg)) {
4826
		return;
4827
	}
4828

    
4829
	$wanif = get_real_interface($interface, "inet6");
4830
	$dhcp6cconf = "";
4831

    
4832
	if (!empty($config['system']['global-v6duid'])) {
4833
		// Write the DUID file
4834
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4835
		    log_error(gettext("Failed to write user DUID file!"));
4836
		}
4837
	}
4838

    
4839
	/* accept router advertisements for this interface                 */
4840
	/* Moved to early in the function as sometimes interface not ready */
4841
	/* RTSOLD fails as interface does not accept .....                 */
4842

    
4843
	log_error("Accept router advertisements on interface {$wanif} ");
4844
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4845

    
4846
	if ($wancfg['adv_dhcp6_config_file_override']) {
4847
		// DHCP6 Config File Override
4848
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4849
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4850
		// DHCP6 Config File Advanced
4851
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4852
	} else {
4853
		// DHCP6 Config File Basic
4854
		$dhcp6cconf .= "interface {$wanif} {\n";
4855

    
4856
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4857
		if ($wancfg['ipaddrv6'] == "slaac") {
4858
			$dhcp6cconf .= "\tinformation-only;\n";
4859
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4860
			$dhcp6cconf .= "\trequest domain-name;\n";
4861
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4862
			$dhcp6cconf .= "};\n";
4863
		} else {
4864
			$trackiflist = array();
4865
			$iflist = link_interface_to_track6($interface);
4866
			foreach ($iflist as $ifname => $ifcfg) {
4867
				if (is_numeric($ifcfg['track6-prefix-id'])) {
4868
					$trackiflist[$ifname] = $ifcfg;
4869
				}
4870
			}
4871

    
4872
			/* skip address request if this is set */
4873
			if (!isset($wancfg['dhcp6prefixonly'])) {
4874
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4875
			}
4876
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4877
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4878
			}
4879

    
4880
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4881
			$dhcp6cconf .= "\trequest domain-name;\n";
4882

    
4883
			/*
4884
			 * dhcp6c will run different scripts depending on
4885
			 * whether dhcpwithoutra is set or unset.
4886
			 */
4887
			if (isset($wancfg['dhcp6withoutra'])) {
4888
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4889
			} else {
4890
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4891
			}
4892
			$dhcp6cconf .= "};\n";
4893

    
4894
			if (!isset($wancfg['dhcp6prefixonly'])) {
4895
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4896
			}
4897

    
4898
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4899
				/* Setup the prefix delegation */
4900
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4901
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4902
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4903
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4904
				}
4905
				foreach ($trackiflist as $friendly => $ifcfg) {
4906
					if ($g['debug']) {
4907
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4908
					}
4909
					$realif = get_real_interface($friendly);
4910
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4911
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4912
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4913
					$dhcp6cconf .= "\t};\n";
4914
				}
4915
				unset($preflen, $iflist, $ifcfg, $ifname);
4916
				$dhcp6cconf .= "};\n";
4917
			}
4918
			unset($trackiflist);
4919
		}
4920
	}
4921

    
4922
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4923
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4924

    
4925
	/* wide-dhcp6c works for now. */
4926
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4927
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4928
		unset($dhcp6cconf);
4929
		return 1;
4930
	}
4931
	unset($dhcp6cconf);
4932

    
4933
	/*************** Script Debug Logging ***************************
4934
	Both dhcp6 scripts now have a logging message built in.
4935
	These logging messages ONLY appear if dhcp6c debug logging is set.
4936
	The logging messages appear in the dhcp section of the logs,
4937
	not in system.
4938

    
4939
	These scripts now also take advantage of the REASON= env vars
4940
	supplied by dhcp6c.
4941
	****************************************************************/
4942

    
4943
	/* Script create for dhcp6withoutRA mode */
4944
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4945
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4946
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4947
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4948
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4949
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4950
	// Need to pass params to  the final script
4951
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4952
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4953
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4954
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4955
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
4956
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
4957
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4958
	if ($debugOption == '-D') {
4959
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rtsold\"\n";
4960
	}
4961
	$dhcp6cscriptwithoutra .= ";;\n";
4962
	$dhcp6cscriptwithoutra .= "REBIND)\n";
4963
	if ($debugOption == '-D') {
4964
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4965
	}
4966
	$dhcp6cscriptwithoutra .= ";;\n";
4967
	if (isset($wancfg['dhcp6norelease'])) {
4968
		$dhcp6cscriptwithoutra .= "EXIT)\n";
4969
	} else {
4970
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
4971
	}
4972
	if ($debugOption == '-D') {
4973
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4974
	}
4975
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4976
	$dhcp6cscriptwithoutra .= ";;\n";
4977
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
4978
	if ($debugOption == '-D') {
4979
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4980
	}
4981
	$dhcp6cscriptwithoutra .= "esac\n";
4982
	if (!@file_put_contents(
4983
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4984
	    $dhcp6cscriptwithoutra)) {
4985
		printf("Error: cannot open " .
4986
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4987
		    "interface_dhcpv6_configure() for writing.\n");
4988
		unset($dhcp6cscriptwithoutra);
4989
		return 1;
4990
	}
4991

    
4992
	unset($dhcp6cscriptwithoutra);
4993
	@chmod(
4994
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4995
	    0755);
4996

    
4997
	/*
4998
	 * Dual mode wan_dhcp6c script with variations depending on node
4999
	 * dhcp6 will run the wan ipv6 configure
5000
	 */
5001
	$dhcp6cscript  = "#!/bin/sh\n";
5002
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
5003
	if (!isset($wancfg['dhcp6withoutra'])) {
5004
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
5005
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
5006
		$dhcp6cscript .= "case \$REASON in\n";
5007
		$dhcp6cscript .= "REBIND)\n";
5008
		if ($debugOption == '-D') {
5009
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5010
		}
5011
		$dhcp6cscript .= ";;\n";
5012
		if (isset($wancfg['dhcp6norelease'])) {
5013
			$dhcp6cscript .= "EXIT)\n";
5014
		} else {
5015
			$dhcp6cscript .= "RELEASE)\n";
5016
		}
5017
		if ($debugOption == '-D') {
5018
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
5019
		}
5020
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5021
		$dhcp6cscript .= ";;\n";
5022
		$dhcp6cscript .= "RENEW|REQUEST|INFO)\n";
5023
		if ($debugOption == '-D') {
5024
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5025
		}
5026
		$dhcp6cscript .= "esac\n";
5027
	} else {
5028
		// Need to get the parameters from the dhcp6cwithoutRA run
5029
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
5030
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
5031
		$dhcp6cscript .= "/bin/sleep 1\n";
5032
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5033
	}
5034

    
5035
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5036
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
5037
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
5038
		unset($dhcp6cscript);
5039
		return 1;
5040
	}
5041
	unset($dhcp6cscript);
5042
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
5043

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

    
5050
	/* non ipoe Process */
5051
	if (!isset($wancfg['dhcp6withoutra'])) {
5052
		/*
5053
		 * We only want this script to run once, and if it runs twice
5054
		 * then do not launch dhcp6c again, this only happens if
5055
		 * dhcpwithoutra is not set.
5056
		 *
5057
		 * Check for a lock file, trying to prevent multiple instances
5058
		 * of dhcp6c being launched
5059
		 */
5060
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
5061
		/*
5062
		 * Create the lock file, trying to prevent multiple instances
5063
		 * of dhcp6c being launched
5064
		 */
5065
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
5066
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
5067
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
5068
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
5069
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
5070
		$rtsoldscript .= "\tfi\n";
5071
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
5072
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
5073
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
5074
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
5075
		$rtsoldscript .= "else\n";
5076
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
5077
		$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c_{$wanif}.pid\")\n";
5078
		$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
5079
		$rtsoldscript .= "fi\n";
5080
	} else {
5081
		/*
5082
		 * The script needs to run in dhcp6withoutra mode as RA may
5083
		 * not have been received, or there can be a delay with
5084
		 * certain ISPs
5085
		 */
5086
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
5087
		$rtsoldscript .= "/bin/sleep 1\n";
5088
	}
5089
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5090
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
5091
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
5092
		unset($rtsoldscript);
5093
		return 1;
5094
	}
5095
	unset($rtsoldscript);
5096
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
5097

    
5098
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
5099
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
5100
		log_error("Killing running rtsold process");
5101
		sleep(2);
5102
	}
5103

    
5104
	if (isset($wancfg['dhcp6withoutra'])) {
5105
		/*
5106
		 * Start dhcp6c here if we don't want to wait for ra - calls
5107
		 * separate function
5108
		 *
5109
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
5110
		 * will then run the configure on receipt of the RA.
5111
		 *
5112
		 * Already started. interface_dhcpv6_configure() appears to get
5113
		 * called multiple times.
5114
		 *
5115
		 * Taking the interface down or releasing will kill the client.
5116
		 */
5117
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
5118
		{
5119
			/*
5120
			 * If the interface is being brought up, wait for the
5121
			 * interface to configure accept RA before launching.
5122
			 * Otherwise it is not ready to accept and will fail.
5123
			 */
5124
			sleep(3);
5125
			run_dhcp6client_process($wanif,$interface,$wancfg);
5126
		}
5127
	} else {
5128
		/*
5129
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
5130
		 * ( it does not background, it exits! ) It will launch dhcp6c
5131
		 * if dhcpwihtoutra is not set
5132
		 */
5133
		log_error("Starting rtsold process");
5134
		sleep(2);
5135
		mwexec("/usr/sbin/rtsold -1 " .
5136
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
5137
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
5138
		    $wanif);
5139
	}
5140
	/*
5141
	 * NOTE: will be called from rtsold invoked script
5142
	 * link_interface_to_track6($interface, "update");
5143
	 */
5144

    
5145
	return 0;
5146
}
5147

    
5148
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5149
	global $g;
5150

    
5151
	$send_options = "";
5152
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5153
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5154
		foreach ($options as $option) {
5155
			$send_options .= "\tsend " . trim($option) . ";\n";
5156
		}
5157
	}
5158

    
5159
	$request_options = "";
5160
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5161
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5162
		foreach ($options as $option) {
5163
			$request_options .= "\trequest " . trim($option) . ";\n";
5164
		}
5165
	}
5166

    
5167
	$information_only = "";
5168
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5169
		$information_only = "\tinformation-only;\n";
5170
	}
5171

    
5172
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5173
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5174
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5175
	}
5176

    
5177
	$interface_statement  = "interface";
5178
	$interface_statement .= " {$wanif}";
5179
	$interface_statement .= " {\n";
5180
	$interface_statement .= "$send_options";
5181
	$interface_statement .= "$request_options";
5182
	$interface_statement .= "$information_only";
5183
	$interface_statement .= "$script";
5184
	$interface_statement .= "};\n";
5185

    
5186
	$id_assoc_statement_address = "";
5187
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5188
		$id_assoc_statement_address .= "id-assoc";
5189
		$id_assoc_statement_address .= " na";
5190
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5191
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5192
		}
5193
		$id_assoc_statement_address .= " { ";
5194

    
5195
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5196
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5197
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5198
			$id_assoc_statement_address .= "\n\taddress";
5199
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5200
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5201
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5202
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5203
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5204
			}
5205
			$id_assoc_statement_address .= ";\n";
5206
		}
5207

    
5208
		$id_assoc_statement_address .= "};\n";
5209
	}
5210

    
5211
	$id_assoc_statement_prefix = "";
5212
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5213
		$id_assoc_statement_prefix .= "id-assoc";
5214
		$id_assoc_statement_prefix .= " pd";
5215
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5216
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5217
		}
5218
		$id_assoc_statement_prefix .= " { ";
5219

    
5220
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5221
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5222
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5223
			$id_assoc_statement_prefix .= "\n\tprefix";
5224
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5225
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5226
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5227
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5228
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5229
			}
5230
			$id_assoc_statement_prefix .= ";";
5231
		}
5232

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

    
5246
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5247
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5248
			$id_assoc_statement_prefix .= "\n";
5249
		}
5250

    
5251
		$id_assoc_statement_prefix .= "};\n";
5252
	}
5253

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

    
5270
	$key_info_statement = "";
5271
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5272
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5273
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5274
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5275
		$key_info_statement .= "keyinfo";
5276
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5277
		$key_info_statement .= " {\n";
5278
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5279
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5280
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5281
		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'])) {
5282
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5283
		}
5284
		$key_info_statement .= "};\n";
5285
	}
5286

    
5287
	$dhcp6cconf  = $interface_statement;
5288
	$dhcp6cconf .= $id_assoc_statement_address;
5289
	$dhcp6cconf .= $id_assoc_statement_prefix;
5290
	$dhcp6cconf .= $authentication_statement;
5291
	$dhcp6cconf .= $key_info_statement;
5292

    
5293
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5294

    
5295
	return $dhcp6cconf;
5296
}
5297

    
5298

    
5299
function DHCP6_Config_File_Override($wancfg, $wanif) {
5300

    
5301
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5302

    
5303
	if ($dhcp6cconf === false) {
5304
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5305
		return '';
5306
	} else {
5307
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5308
	}
5309
}
5310

    
5311

    
5312
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5313

    
5314
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5315

    
5316
	return $dhcp6cconf;
5317
}
5318

    
5319

    
5320
function interface_dhcp_configure($interface = "wan") {
5321
	global $config, $g, $vlanprio_values;
5322

    
5323
	$ifcfg = $config['interfaces'][$interface];
5324
	if (empty($ifcfg)) {
5325
		$ifcfg = array();
5326
	}
5327

    
5328
	$dhclientconf_vlantag = "";
5329
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5330
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5331
	}
5332

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

    
5340
	if ($ifcfg['dhcphostname']) {
5341
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5342
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5343
	} else {
5344
		$dhclientconf_hostname = "";
5345
	}
5346

    
5347
	$realif = get_real_interface($interface);
5348
	if (empty($realif)) {
5349
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5350
		return 0;
5351
	}
5352
	$dhclientconf = "";
5353

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

    
5366
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5367
		$dhclientconf .= <<<EOD
5368

    
5369
	reject {$ifcfg['dhcprejectfrom']};
5370
EOD;
5371
	}
5372
	$dhclientconf .= <<<EOD
5373

    
5374
}
5375

    
5376
EOD;
5377

    
5378
	// DHCP Config File Advanced
5379
	if ($ifcfg['adv_dhcp_config_advanced']) {
5380
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5381
	}
5382

    
5383
	if (is_ipaddr($ifcfg['alias-address'])) {
5384
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5385
		$dhclientconf .= <<<EOD
5386
alias {
5387
	interface "{$realif}";
5388
	fixed-address {$ifcfg['alias-address']};
5389
	option subnet-mask {$subnetmask};
5390
}
5391

    
5392
EOD;
5393
	}
5394

    
5395
	// DHCP Config File Override
5396
	if ($ifcfg['adv_dhcp_config_file_override']) {
5397
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5398
	}
5399

    
5400
	fwrite($fd, $dhclientconf);
5401
	fclose($fd);
5402

    
5403
	/* bring wan interface up before starting dhclient */
5404
	if ($realif) {
5405
		interfaces_bring_up($realif);
5406
	}
5407

    
5408
	/* Make sure dhclient is not running */
5409
	kill_dhclient_process($realif);
5410

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

    
5414
	return 0;
5415
}
5416

    
5417
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5418

    
5419
	$hostname = "";
5420
	if ($ifcfg['dhcphostname'] != '') {
5421
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5422
	}
5423

    
5424
	/* DHCP Protocol Timings */
5425
	$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");
5426
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5427
		$pt_variable = "{$Protocol_Timing}";
5428
		${$pt_variable} = "";
5429
		if ($ifcfg[$Protocol_Timing] != "") {
5430
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5431
		}
5432
	}
5433

    
5434
	$send_options = "";
5435
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5436
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5437
		foreach ($options as $option) {
5438
			$send_options .= "\tsend " . trim($option) . ";\n";
5439
		}
5440
	}
5441

    
5442
	$request_options = "";
5443
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5444
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5445
	}
5446

    
5447
	$required_options = "";
5448
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5449
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5450
	}
5451

    
5452
	$option_modifiers = "";
5453
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5454
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5455
		foreach ($modifiers as $modifier) {
5456
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5457
		}
5458
	}
5459

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

    
5484
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5485

    
5486
	return $dhclientconf;
5487
}
5488

    
5489
function DHCP_Config_Option_Split($option_string) {
5490
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5491
	return $matches ? $matches[0] : [];
5492
}
5493

    
5494
function DHCP_Config_File_Override($ifcfg, $realif) {
5495

    
5496
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5497

    
5498
	if ($dhclientconf === false) {
5499
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5500
		return '';
5501
	} else {
5502
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5503
	}
5504
}
5505

    
5506

    
5507
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5508

    
5509
	/* Apply Interface Substitutions */
5510
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5511

    
5512
	/* Apply Hostname Substitutions */
5513
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5514

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

    
5521
	/* Apply MAC Address Substitutions */
5522
	foreach ($various_mac_types as $various_mac_type) {
5523
		foreach ($various_mac_cases as $various_mac_case) {
5524
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5525

    
5526
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5527
				if ($res !== false) {
5528

    
5529
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5530
					if ("$various_mac_case" == "U") {
5531
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5532
					}
5533
					if ("$various_mac_case" == "L") {
5534
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5535
					}
5536

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

    
5549
					/* MAC Address Delimiter Substitutions */
5550
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5551

    
5552
					/* Apply MAC Address Substitutions */
5553
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5554
				}
5555
			}
5556
		}
5557
	}
5558

    
5559
	return $dhclientconf;
5560
}
5561

    
5562
function interfaces_group_setup() {
5563
	global $config;
5564

    
5565
	if (!isset($config['ifgroups']['ifgroupentry']) || !is_array($config['ifgroups']['ifgroupentry'])) {
5566
		return;
5567
	}
5568

    
5569
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5570
		interface_group_setup($groupar);
5571
	}
5572

    
5573
	return;
5574
}
5575

    
5576
function interface_group_setup(&$groupname /* The parameter is an array */) {
5577
	global $config;
5578

    
5579
	if (!is_array($groupname)) {
5580
		return;
5581
	}
5582
	$members = explode(" ", $groupname['members']);
5583
	foreach ($members as $ifs) {
5584
		$realif = get_real_interface($ifs);
5585
		if ($realif && does_interface_exist($realif)) {
5586
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5587
		}
5588
	}
5589

    
5590
	return;
5591
}
5592

    
5593
function is_interface_group($if) {
5594
	global $config;
5595

    
5596
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5597
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5598
			if ($groupentry['ifname'] === $if) {
5599
				return true;
5600
			}
5601
		}
5602
	}
5603

    
5604
	return false;
5605
}
5606

    
5607
function interface_group_add_member($interface, $groupname) {
5608
	$interface = get_real_interface($interface);
5609
	if (does_interface_exist($interface)) {
5610
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5611
	}
5612
}
5613

    
5614
/* COMPAT Function */
5615
function convert_friendly_interface_to_real_interface_name($interface) {
5616
	return get_real_interface($interface);
5617
}
5618

    
5619
/* COMPAT Function */
5620
function get_real_wan_interface($interface = "wan") {
5621
	return get_real_interface($interface);
5622
}
5623

    
5624
/* COMPAT Function */
5625
function get_current_wan_address($interface = "wan") {
5626
	return get_interface_ip($interface);
5627
}
5628

    
5629
/*
5630
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5631
 */
5632
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5633
	global $config;
5634

    
5635
	/* XXX: For speed reasons reference directly the interface array */
5636
	init_config_arr(array('interfaces'));
5637
	$ifdescrs = &$config['interfaces'];
5638
	//$ifdescrs = get_configured_interface_list(true);
5639

    
5640
	foreach ($ifdescrs as $if => $ifname) {
5641
		if ($if == $interface || $ifname['if'] == $interface) {
5642
			return $if;
5643
		}
5644

    
5645
		if (get_real_interface($if) == $interface) {
5646
			return $if;
5647
		}
5648

    
5649
		if ($checkparent == false) {
5650
			continue;
5651
		}
5652

    
5653
		$int = get_parent_interface($if, true);
5654
		if (is_array($int)) {
5655
			foreach ($int as $iface) {
5656
				if ($iface == $interface) {
5657
					return $if;
5658
				}
5659
			}
5660
		}
5661
	}
5662

    
5663
	if ($interface == "enc0") {
5664
		return 'IPsec';
5665
	}
5666
}
5667

    
5668
/* attempt to resolve interface to friendly descr */
5669
function convert_friendly_interface_to_friendly_descr($interface) {
5670
	global $config;
5671

    
5672
	switch ($interface) {
5673
		case "l2tp":
5674
			$ifdesc = "L2TP";
5675
			break;
5676
		case "pptp":
5677
			$ifdesc = "PPTP";
5678
			break;
5679
		case "pppoe":
5680
			$ifdesc = "PPPoE";
5681
			break;
5682
		case "openvpn":
5683
			$ifdesc = "OpenVPN";
5684
			break;
5685
		case "lo0":
5686
			$ifdesc = "Loopback";
5687
			break;
5688
		case "enc0":
5689
		case "ipsec":
5690
		case "IPsec":
5691
			$ifdesc = "IPsec";
5692
			break;
5693
		default:
5694
			if (isset($config['interfaces'][$interface])) {
5695
				if (empty($config['interfaces'][$interface]['descr'])) {
5696
					$ifdesc = strtoupper($interface);
5697
				} else {
5698
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5699
				}
5700
				break;
5701
			} else if (substr($interface, 0, 4) == '_vip') {
5702
				if (is_array($config['virtualip']['vip'])) {
5703
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5704
						if ($vip['mode'] == "carp") {
5705
							if ($interface == "_vip{$vip['uniqid']}") {
5706
								$descr = $vip['subnet'];
5707
								$descr .= " (vhid {$vip['vhid']})";
5708
								if (!empty($vip['descr'])) {
5709
									$descr .= " - " .$vip['descr'];
5710
								}
5711
								return $descr;
5712
							}
5713
						}
5714
					}
5715
				}
5716
			} else if (substr($interface, 0, 5) == '_lloc') {
5717
				return get_interface_linklocal($interface);
5718
			} else {
5719
				if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5720
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5721
						if ($ifgen['ifname'] === $interface) {
5722
							return $ifgen['ifname'];
5723
						}
5724
					}
5725
				}
5726

    
5727
				/* if list */
5728
				$ifdescrs = get_configured_interface_with_descr(true);
5729
				foreach ($ifdescrs as $if => $ifname) {
5730
					if ($if == $interface || $ifname == $interface) {
5731
						return $ifname;
5732
					}
5733
				}
5734
			}
5735
			break;
5736
	}
5737

    
5738
	return $ifdesc;
5739
}
5740

    
5741
function convert_real_interface_to_friendly_descr($interface) {
5742

    
5743
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5744

    
5745
	if (!empty($ifdesc)) {
5746
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5747
	}
5748

    
5749
	return $interface;
5750
}
5751

    
5752
/*
5753
 *  get_parent_interface($interface):
5754
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5755
 *				or virtual interface (i.e. vlan)
5756
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5757
 *			-- returns $interface passed in if $interface parent is not found
5758
 *			-- returns empty array if an invalid interface is passed
5759
 *	(Only handles ppps and vlans now.)
5760
 */
5761
function get_parent_interface($interface, $avoidrecurse = false) {
5762
	global $config;
5763

    
5764
	$parents = array();
5765
	//Check that we got a valid interface passed
5766
	$realif = get_real_interface($interface);
5767
	if ($realif == NULL) {
5768
		return $parents;
5769
	}
5770

    
5771
	// If we got a real interface, find it's friendly assigned name
5772
	if ($interface == $realif && $avoidrecurse == false) {
5773
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5774
	}
5775

    
5776
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5777
		$ifcfg = $config['interfaces'][$interface];
5778
		switch ($ifcfg['ipaddr']) {
5779
			case "ppp":
5780
			case "pppoe":
5781
			case "pptp":
5782
			case "l2tp":
5783
				if (empty($parents)) {
5784
					if (is_array($config['ppps']['ppp'])) {
5785
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5786
							if ($ifcfg['if'] == $ppp['if']) {
5787
								$ports = explode(',', $ppp['ports']);
5788
								foreach ($ports as $pid => $parent_if) {
5789
									$parents[$pid] = get_real_interface($parent_if);
5790
								}
5791
								break;
5792
							}
5793
						}
5794
					}
5795
				}
5796
				break;
5797
			case "dhcp":
5798
			case "static":
5799
			default:
5800
				// Handle _vlans
5801
				$vlan = interface_is_vlan($ifcfg['if']);
5802
				if ($vlan != NULL) {
5803
					$parents[0] = $vlan['if'];
5804
				}
5805
				break;
5806
		}
5807
	}
5808

    
5809
	if (empty($parents)) {
5810
		// Handle _vlans not assigned to an interface
5811
		$vlan = interface_is_vlan($realif);
5812
		if ($vlan != NULL) {
5813
			$parents[0] = $vlan['if'];
5814
		}
5815
	}
5816

    
5817
	if (empty($parents)) {
5818
		/* Handle LAGGs. */
5819
		$lagg = interface_is_type($realif, 'lagg');
5820
		if ($lagg != NULL && isset($lagg['members'])) {
5821
			$parents = explode(",", $lagg['members']);
5822
		}
5823
	}
5824

    
5825
	if (empty($parents)) {
5826
		$parents[0] = $realif;
5827
	}
5828

    
5829
	return $parents;
5830
}
5831

    
5832
/*
5833
 *  get_parent_physical_interface($interface):
5834
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5835
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5836
 */
5837
function get_parent_physical_interface($interface) {
5838
	global $config;
5839

    
5840
	$realif = get_parent_interface($interface);
5841

    
5842
	if (substr($realif[0], 0, 4) == "lagg") {
5843
		foreach ($config['laggs']['lagg'] as $lagg) {
5844
			if ($realif[0] == $lagg['laggif']) {
5845
				return explode(",", $lagg['members']);
5846
			}
5847
		}
5848
	} else {
5849
		return $realif;
5850
	}
5851
}
5852

    
5853
function interface_is_wireless_clone($wlif) {
5854
	if (!stristr($wlif, "_wlan")) {
5855
		return false;
5856
	} else {
5857
		return true;
5858
	}
5859
}
5860

    
5861
function interface_get_wireless_base($wlif) {
5862
	if (!stristr($wlif, "_wlan")) {
5863
		return $wlif;
5864
	} else {
5865
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5866
	}
5867
}
5868

    
5869
function interface_get_wireless_clone($wlif) {
5870
	if (!stristr($wlif, "_wlan")) {
5871
		return $wlif . "_wlan0";
5872
	} else {
5873
		return $wlif;
5874
	}
5875
}
5876

    
5877
function interface_list_wireless() {
5878
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5879

    
5880
	$result = array();
5881
	foreach ($portlist as $port) {
5882
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5883
			continue;
5884
		}
5885

    
5886
		$desc = $port . " ( " . get_single_sysctl(
5887
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5888

    
5889
		$result[] = array(
5890
		    "if" => $port,
5891
		    "descr" => $desc
5892
		);
5893
	}
5894

    
5895
	return $result;
5896
}
5897

    
5898
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
5899
	global $config, $g;
5900

    
5901
	$wanif = NULL;
5902

    
5903
	switch ($interface) {
5904
		case "l2tp":
5905
			$wanif = "l2tp";
5906
			break;
5907
		case "pptp":
5908
			$wanif = "pptp";
5909
			break;
5910
		case "pppoe":
5911
			$wanif = "pppoe";
5912
			break;
5913
		case "openvpn":
5914
			$wanif = "openvpn";
5915
			break;
5916
		case "IPsec":
5917
		case "ipsec":
5918
		case "enc0":
5919
			$wanif = "enc0";
5920
			break;
5921
		case "ppp":
5922
			$wanif = "ppp";
5923
			break;
5924
		default:
5925
			if (substr($interface, 0, 4) == '_vip') {
5926
				$wanif = get_configured_vip_interface($interface);
5927
				if (!empty($wanif)) {
5928
					$wanif = get_real_interface($wanif);
5929
				}
5930
				break;
5931
			} else if (substr($interface, 0, 5) == '_lloc') {
5932
				$interface = substr($interface, 5);
5933
			} else if (interface_is_vlan($interface) != NULL ||
5934
			    does_interface_exist($interface, $flush)) {
5935
				/*
5936
				 * If a real interface was already passed simply
5937
				 * pass the real interface back.  This encourages
5938
				 * the usage of this function in more cases so that
5939
				 * we can combine logic for more flexibility.
5940
				 */
5941
				$wanif = $interface;
5942
				break;
5943
			}
5944

    
5945
			if (empty($config['interfaces'][$interface])) {
5946
				break;
5947
			}
5948

    
5949
			$cfg = &$config['interfaces'][$interface];
5950

    
5951
			if ($family == "inet6") {
5952
				switch ($cfg['ipaddrv6']) {
5953
					case "6rd":
5954
					case "6to4":
5955
						$wanif = "{$interface}_stf";
5956
						break;
5957
					case 'pppoe':
5958
					case 'ppp':
5959
					case 'l2tp':
5960
					case 'pptp':
5961
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5962
							$wanif = interface_get_wireless_clone($cfg['if']);
5963
						} else {
5964
							$wanif = $cfg['if'];
5965
						}
5966
						break;
5967
					default:
5968
						switch ($cfg['ipaddr']) {
5969
							case 'pppoe':
5970
							case 'ppp':
5971
							case 'l2tp':
5972
							case 'pptp':
5973
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
5974
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) || 
5975
								    isset($cfg['ipv6usev4iface']) || isset($cfg['slaacusev4iface'])) {
5976
									$wanif = $cfg['if'];
5977
								} else {
5978
									$parents = get_parent_interface($interface);
5979
									if (!empty($parents[0])) {
5980
										$wanif = $parents[0];
5981
									} else {
5982
										$wanif = $cfg['if'];
5983
									}
5984
								}
5985
								break;
5986
							default:
5987
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5988
									$wanif = interface_get_wireless_clone($cfg['if']);
5989
								} else {
5990
									$wanif = $cfg['if'];
5991
								}
5992
								break;
5993
						}
5994
						break;
5995
				}
5996
			} else {
5997
				// Wireless cloned NIC support (FreeBSD 8+)
5998
				// interface name format: $parentnic_wlanparentnic#
5999
				// example: ath0_wlan0
6000
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6001
					$wanif = interface_get_wireless_clone($cfg['if']);
6002
				} else {
6003
					$wanif = $cfg['if'];
6004
				}
6005
			}
6006
			break;
6007
	}
6008

    
6009
	return $wanif;
6010
}
6011

    
6012
/* Guess the physical interface by providing a IP address */
6013
function guess_interface_from_ip($ipaddress) {
6014

    
6015
	if (!is_ipaddr($ipaddress)) {
6016
		return false;
6017
	}
6018

    
6019
	$route = route_get($ipaddress);
6020
	if (empty($route)) {
6021
		return false;
6022
	}
6023

    
6024
	if (!empty($route[0]['interface-name'])) {
6025
		return $route[0]['interface-name'];
6026
	}
6027

    
6028
	return false;
6029
}
6030

    
6031
/*
6032
 * find_ip_interface($ip): return the interface where an ip is defined
6033
 *   (or if $bits is specified, where an IP within the subnet is defined)
6034
 */
6035
function find_ip_interface($ip, $bits = null) {
6036
	if (!is_ipaddr($ip)) {
6037
		return false;
6038
	}
6039

    
6040
	$isv6ip = is_ipaddrv6($ip);
6041

    
6042
	/* if list */
6043
	$ifdescrs = get_configured_interface_list();
6044

    
6045
	foreach ($ifdescrs as $ifdescr => $ifname) {
6046
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
6047
		if (is_null($ifip)) {
6048
			continue;
6049
		}
6050
		if (is_null($bits)) {
6051
			if ($ip == $ifip) {
6052
				$int = get_real_interface($ifname);
6053
				return $int;
6054
			}
6055
		} else {
6056
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
6057
				$int = get_real_interface($ifname);
6058
				return $int;
6059
			}
6060
		}
6061
	}
6062

    
6063
	return false;
6064
}
6065

    
6066
/*
6067
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6068
 *   (or if $bits is specified, where an IP within the subnet is found)
6069
 */
6070
function find_virtual_ip_alias($ip, $bits = null) {
6071
	global $config;
6072

    
6073
	if (!is_array($config['virtualip']['vip'])) {
6074
		return false;
6075
	}
6076
	if (!is_ipaddr($ip)) {
6077
		return false;
6078
	}
6079

    
6080
	$isv6ip = is_ipaddrv6($ip);
6081

    
6082
	foreach ($config['virtualip']['vip'] as $vip) {
6083
		if ($vip['mode'] === "ipalias") {
6084
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
6085
				continue;
6086
			}
6087
			if (is_null($bits)) {
6088
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
6089
					return $vip;
6090
				}
6091
			} else {
6092
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
6093
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
6094
					return $vip;
6095
				}
6096
			}
6097
		}
6098
	}
6099
	return false;
6100
}
6101

    
6102
function link_interface_to_track6($int, $action = "") {
6103
	global $config;
6104

    
6105
	if (empty($int)) {
6106
		return;
6107
	}
6108

    
6109
	if (is_array($config['interfaces'])) {
6110
		$list = array();
6111
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
6112
			if (!isset($ifcfg['enable'])) {
6113
				continue;
6114
			}
6115
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
6116
				if ($action == "update") {
6117
					interface_track6_configure($ifname, $ifcfg);
6118
				} else if ($action == "") {
6119
					$list[$ifname] = $ifcfg;
6120
				}
6121
			}
6122
		}
6123
		return $list;
6124
	}
6125
}
6126

    
6127
function interface_find_child_cfgmtu($realiface) {
6128
	global $config;
6129

    
6130
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6131
	$vlans = link_interface_to_vlans($realiface);
6132
	$qinqs = link_interface_to_qinqs($realiface);
6133
	$bridge = link_interface_to_bridge($realiface);
6134
	if (!empty($interface)) {
6135
		$gifs = link_interface_to_tunnelif($interface, 'gif');
6136
		$gres = link_interface_to_tunnelif($interface, 'gre');
6137
		$vxlans = link_interface_to_tunnelif($interface, 'vxlan');
6138
	} else {
6139
		$gifs = array();
6140
		$gres = array();
6141
		$vxlans = array();
6142
	}
6143

    
6144
	$mtu = 0;
6145
	if (is_array($vlans)) {
6146
		foreach ($vlans as $vlan) {
6147
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
6148
			if (empty($ifass)) {
6149
				continue;
6150
			}
6151
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6152
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6153
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6154
				}
6155
			}
6156
		}
6157
	}
6158
	if (is_array($qinqs)) {
6159
		foreach ($qinqs as $qinq) {
6160
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
6161
			if (empty($ifass)) {
6162
				continue;
6163
			}
6164
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6165
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6166
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6167
				}
6168
			}
6169
		}
6170
	}
6171
	if (is_array($gifs)) {
6172
		foreach ($gifs as $gif) {
6173
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
6174
			if (empty($ifass)) {
6175
				continue;
6176
			}
6177
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6178
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6179
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6180
				}
6181
			}
6182
		}
6183
	}
6184
	if (is_array($gres)) {
6185
		foreach ($gres as $gre) {
6186
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
6187
			if (empty($ifass)) {
6188
				continue;
6189
			}
6190
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6191
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6192
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6193
				}
6194
			}
6195
		}
6196
	}
6197
	if (is_array($vxlans)) {
6198
		foreach ($vxlans as $vxlan) {
6199
			$ifass = convert_real_interface_to_friendly_interface_name($vxlan['vxlanif']);
6200
			if (empty($ifass)) {
6201
				continue;
6202
			}
6203
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6204
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6205
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6206
				}
6207
			}
6208
		}
6209
	}
6210
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
6211
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
6212
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6213
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
6214
		}
6215
	}
6216
	unset($vlans, $bridge, $gifs, $gres, $vxlans, $ifass, $vlan);
6217

    
6218
	return $mtu;
6219
}
6220

    
6221
function link_interface_to_vlans($int, $action = "") {
6222
	global $config;
6223

    
6224
	if (empty($int)) {
6225
		return;
6226
	}
6227

    
6228
	if (is_array($config['vlans']['vlan'])) {
6229
		$ifaces = array();
6230
		foreach ($config['vlans']['vlan'] as $vlan) {
6231
			if ($int == $vlan['if']) {
6232
				if ($action == "update") {
6233
					interfaces_bring_up($int);
6234
				} else {
6235
					$ifaces[$vlan['tag']] = $vlan;
6236
				}
6237
			}
6238
		}
6239
		if (!empty($ifaces)) {
6240
			return $ifaces;
6241
		}
6242
	}
6243
}
6244

    
6245
function link_interface_to_qinqs($int, $action = "") {
6246
	global $config;
6247

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

    
6252
	if (is_array($config['qinqs']['qinqentry'])) {
6253
		$ifaces = array();
6254
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
6255
			if ($int == $qinq['if']) {
6256
				if ($action == "update") {
6257
					interfaces_bring_up($int);
6258
				} else {
6259
					$ifaces[$qinq['tag']] = $qinq;
6260
				}
6261
			}
6262
		}
6263
		if (!empty($ifaces)) {
6264
			return $ifaces;
6265
		}
6266
	}
6267
}
6268

    
6269
function link_interface_to_vips($int, $action = "", $vhid = '') {
6270
	global $config;
6271

    
6272
	$updatevips = false;
6273
	if (is_array($config['virtualip']['vip'])) {
6274
		$result = array();
6275
		foreach ($config['virtualip']['vip'] as $vip) {
6276
			if (substr($vip['interface'], 0, 4) == "_vip") {
6277
				$iface = get_configured_vip_interface($vip['interface']);
6278
			} else {
6279
				$iface = $vip['interface'];
6280
			}
6281
			if ($int != $iface) {
6282
				continue;
6283
			}
6284
			if ($action == "update") {
6285
				$updatevips = true;
6286
			} else {
6287
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
6288
				    substr($vip['interface'], 0, 4) == "_vip") {
6289
					$result[] = $vip;
6290
				}
6291
			}
6292
		}
6293
		if ($updatevips === true) {
6294
			interfaces_vips_configure($int);
6295
		}
6296
		return $result;
6297
	}
6298

    
6299
	return NULL;
6300
}
6301

    
6302
/****f* interfaces/link_interface_to_bridge
6303
 * NAME
6304
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6305
 * INPUTS
6306
 *   $ip
6307
 * RESULT
6308
 *   bridge[0-99]
6309
 ******/
6310
function link_interface_to_bridge($int) {
6311
	global $config;
6312

    
6313
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6314
		foreach ($config['bridges']['bridged'] as $bridge) {
6315
			if (in_array($int, explode(',', $bridge['members']))) {
6316
				return "{$bridge['bridgeif']}";
6317
			}
6318
		}
6319
	}
6320
}
6321

    
6322
function link_interface_to_lagg($int) {
6323
	global $config;
6324

    
6325
	if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
6326
		foreach ($config['laggs']['lagg'] as $lagg) {
6327
			if (in_array($int, explode(',', $lagg['members']))) {
6328
				return "{$lagg['laggif']}";
6329
			}
6330
		}
6331
	}
6332
}
6333

    
6334
function link_interface_to_group($int) {
6335
	global $config;
6336

    
6337
	$result = array();
6338

    
6339
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6340
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6341
			if (in_array($int, explode(" ", $group['members']))) {
6342
				$result[$group['ifname']] = $int;
6343
			}
6344
		}
6345
	}
6346

    
6347
	return $result;
6348
}
6349

    
6350
function link_interface_to_tunnelif($interface, $type) {
6351
	global $config;
6352

    
6353
	if (!in_array($type, array('gre', 'gif', 'vxlan'))) {
6354
		return;
6355
	}
6356

    
6357
	$result = array();
6358

    
6359
	if (is_array($config["{$type}s"][$type])) {
6360
		foreach ($config["{$type}s"][$type] as $tunnel) {
6361
			if ($tunnel['if'] == $interface) {
6362
				$result[] = $tunnel;
6363
			}
6364
		}
6365
	}
6366

    
6367
	return $result;
6368
}
6369

    
6370
/*
6371
 * find_interface_ip($interface): return the interface ip (first found)
6372
 */
6373
function find_interface_ip($interface, $flush = false) {
6374
	global $interface_ip_arr_cache;
6375
	global $interface_sn_arr_cache;
6376

    
6377
	$interface = str_replace("\n", "", $interface);
6378

    
6379
	if (!does_interface_exist($interface)) {
6380
		return;
6381
	}
6382

    
6383
	/* Setup IP cache */
6384
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6385
		if (file_exists("/var/db/${interface}_ip")) {
6386
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6387
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6388
			foreach ($ifaddrs as $ifaddr) {
6389
				list($ip, $mask) = explode("/", $ifaddr);
6390
				if ($ip == $ifip) {
6391
					$interface_ip_arr_cache[$interface] = $ip;
6392
					$interface_sn_arr_cache[$interface] = $mask;
6393
					break;
6394
				}
6395
			}
6396
		}
6397
		if (!isset($interface_ip_arr_cache[$interface])) {
6398
			$ifinfo = pfSense_get_interface_addresses($interface);
6399
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6400
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6401
		}
6402
	}
6403

    
6404
	return $interface_ip_arr_cache[$interface];
6405
}
6406

    
6407
/*
6408
 * find_interface_ipv6($interface): return the interface ip (first found)
6409
 */
6410
function find_interface_ipv6($interface, $flush = false) {
6411
	global $interface_ipv6_arr_cache;
6412
	global $interface_snv6_arr_cache;
6413
	global $config;
6414

    
6415
	$interface = trim($interface);
6416
	$interface = get_real_interface($interface);
6417

    
6418
	if (!does_interface_exist($interface)) {
6419
		return;
6420
	}
6421

    
6422
	/* Setup IP cache */
6423
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6424
		$ifinfo = pfSense_get_interface_addresses($interface);
6425
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6426
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6427
	}
6428

    
6429
	return $interface_ipv6_arr_cache[$interface];
6430
}
6431

    
6432
/*
6433
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6434
 */
6435
function find_interface_ipv6_ll($interface, $flush = false) {
6436
	global $interface_llv6_arr_cache;
6437
	global $config;
6438

    
6439
	$interface = str_replace("\n", "", $interface);
6440

    
6441
	if (!does_interface_exist($interface)) {
6442
		return;
6443
	}
6444

    
6445
	/* Setup IP cache */
6446
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6447
		$ifinfo = pfSense_getall_interface_addresses($interface);
6448
		foreach ($ifinfo as $line) {
6449
			if (strstr($line, ":")) {
6450
				$parts = explode("/", $line);
6451
				if (is_linklocal($parts[0])) {
6452
					$ifinfo['linklocal'] = $parts[0];
6453
				}
6454
			}
6455
		}
6456
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6457
	}
6458
	return $interface_llv6_arr_cache[$interface];
6459
}
6460

    
6461
function find_interface_subnet($interface, $flush = false) {
6462
	global $interface_sn_arr_cache;
6463
	global $interface_ip_arr_cache;
6464

    
6465
	$interface = str_replace("\n", "", $interface);
6466
	if (does_interface_exist($interface) == false) {
6467
		return;
6468
	}
6469

    
6470
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6471
		$ifinfo = pfSense_get_interface_addresses($interface);
6472
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6473
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6474
	}
6475

    
6476
	return $interface_sn_arr_cache[$interface];
6477
}
6478

    
6479
function find_interface_subnetv6($interface, $flush = false) {
6480
	global $interface_snv6_arr_cache;
6481
	global $interface_ipv6_arr_cache;
6482

    
6483
	$interface = str_replace("\n", "", $interface);
6484
	if (does_interface_exist($interface) == false) {
6485
		return;
6486
	}
6487

    
6488
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6489
		$ifinfo = pfSense_get_interface_addresses($interface);
6490
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6491
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6492
	}
6493

    
6494
	return $interface_snv6_arr_cache[$interface];
6495
}
6496

    
6497
function ip_in_interface_alias_subnet($interface, $ipalias) {
6498
	global $config;
6499

    
6500
	if (empty($interface) || !is_ipaddr($ipalias)) {
6501
		return false;
6502
	}
6503
	if (is_array($config['virtualip']['vip'])) {
6504
		foreach ($config['virtualip']['vip'] as $vip) {
6505
			switch ($vip['mode']) {
6506
				case "ipalias":
6507
					if ($vip['interface'] <> $interface) {
6508
						break;
6509
					}
6510
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6511
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6512
						return true;
6513
					}
6514
					break;
6515
			}
6516
		}
6517
	}
6518

    
6519
	return false;
6520
}
6521

    
6522
function get_possible_listen_ips($include_ipv6_link_local=false) {
6523

    
6524
	$interfaces = get_configured_interface_with_descr();
6525
	foreach ($interfaces as $iface => $ifacename) {
6526
		if ($include_ipv6_link_local) {
6527
			/* This is to avoid going though added ll below */
6528
			if (substr($iface, 0, 5) == '_lloc') {
6529
				continue;
6530
			}
6531
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6532
			if (!empty($llip)) {
6533
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6534
			}
6535
		}
6536
	}
6537
	$viplist = get_configured_vip_list();
6538
	foreach ($viplist as $vip => $address) {
6539
		$interfaces[$vip] = $address;
6540
		if (get_vip_descr($address)) {
6541
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6542
		}
6543
	}
6544

    
6545
	$interfaces['lo0'] = 'Localhost';
6546

    
6547
	return $interfaces;
6548
}
6549

    
6550
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6551
	global $config;
6552

    
6553
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6554
	foreach (array('server', 'client') as $mode) {
6555
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6556
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6557
				if (!isset($setting['disable'])) {
6558
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6559
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6560
				}
6561
			}
6562
		}
6563
	}
6564
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
6565
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
6566
			if ($ph1ent['disabled']) {
6567
				continue;
6568
			}
6569
			if (ipsec_vti($ph1ent)) {
6570
				$sourceips_key = "ipsec{$ph1ent['ikeid']}";
6571
				$sourceips[$sourceips_key] = gettext("IPsec VTI") . ": " . htmlspecialchars($ph1ent['descr']);
6572
			}
6573
		}
6574
	}
6575
	return $sourceips;
6576
}
6577

    
6578
function get_interface_ip($interface = "wan") {
6579
	global $config;
6580

    
6581
	if (substr($interface, 0, 4) == '_vip') {
6582
		return get_configured_vip_ipv4($interface);
6583
	} else if (substr($interface, 0, 5) == '_lloc') {
6584
		/* No link-local address for v4. */
6585
		return null;
6586
	}
6587

    
6588
	$realif = get_failover_interface($interface, 'inet');
6589
	if (!$realif) {
6590
		return null;
6591
	}
6592

    
6593
	if (substr($realif, 0, 4) == '_vip') {
6594
		return get_configured_vip_ipv4($realif);
6595
	} else if (substr($realif, 0, 5) == '_lloc') {
6596
		/* No link-local address for v4. */
6597
		return null;
6598
	}
6599

    
6600
	if (is_array($config['interfaces'][$interface]) &&
6601
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6602
		return ($config['interfaces'][$interface]['ipaddr']);
6603
	}
6604

    
6605
	/*
6606
	 * Beaware that find_interface_ip() is our last option, it will
6607
	 * return the first IP it find on interface, not necessarily the
6608
	 * main IP address.
6609
	 */
6610
	$curip = find_interface_ip($realif);
6611
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6612
		return $curip;
6613
	} else {
6614
		return null;
6615
	}
6616
}
6617

    
6618
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6619
	global $config;
6620

    
6621
	if (substr($interface, 0, 4) == '_vip') {
6622
		return get_configured_vip_ipv6($interface);
6623
	} else if (substr($interface, 0, 5) == '_lloc') {
6624
		return get_interface_linklocal($interface);
6625
	}
6626

    
6627
	$realif = get_failover_interface($interface, 'inet6');
6628
	if (!$realif) {
6629
		return null;
6630
	}
6631

    
6632
	if (substr($realif, 0, 4) == '_vip') {
6633
		return get_configured_vip_ipv6($realif);
6634
	} else if (substr($realif, 0, 5) == '_lloc') {
6635
		return get_interface_linklocal($realif);
6636
	}
6637

    
6638
	if (is_array($config['interfaces'][$interface])) {
6639
		switch ($config['interfaces'][$interface]['ipaddr']) {
6640
			case 'pppoe':
6641
			case 'l2tp':
6642
			case 'pptp':
6643
			case 'ppp':
6644
				if (($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') ||
6645
				    ($config['interfaces'][$interface]['ipaddrv6'] == 'slaac')) {
6646
					$realif = get_real_interface($interface, 'inet6', false);
6647
				}
6648
				break;
6649
		}
6650
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6651
			return ($config['interfaces'][$interface]['ipaddrv6']);
6652
		}
6653
	}
6654

    
6655
	/*
6656
	 * Beaware that find_interface_ip() is our last option, it will
6657
	 * return the first IP it find on interface, not necessarily the
6658
	 * main IP address.
6659
	 */
6660
	$curip = find_interface_ipv6($realif, $flush);
6661
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6662
		return $curip;
6663
	} else {
6664
		/*
6665
		 * NOTE: On the case when only the prefix is requested,
6666
		 * the communication on WAN will be done over link-local.
6667
		 */
6668
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6669
			$curip = find_interface_ipv6_ll($realif, $flush);
6670
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6671
				return $curip;
6672
			}
6673
		}
6674
	}
6675
	return null;
6676
}
6677

    
6678
function get_interface_linklocal($interface = "wan") {
6679

    
6680
	$realif = get_failover_interface($interface, 'inet6');
6681
	if (!$realif) {
6682
		return null;
6683
	}
6684

    
6685
	if (substr($interface, 0, 4) == '_vip') {
6686
		$realif = get_real_interface($interface);
6687
	} else if (substr($interface, 0, 5) == '_lloc') {
6688
		$realif = get_real_interface(substr($interface, 5));
6689
	}
6690

    
6691
	$curip = find_interface_ipv6_ll($realif);
6692
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6693
		return $curip;
6694
	} else {
6695
		return null;
6696
	}
6697
}
6698

    
6699
function get_interface_subnet($interface = "wan") {
6700
	global $config;
6701

    
6702
	if (substr($interface, 0, 4) == '_vip') {
6703
		return (get_configured_vip_subnetv4($interface));
6704
	}
6705

    
6706
	if (is_array($config['interfaces'][$interface]) &&
6707
	    !empty($config['interfaces'][$interface]['subnet']) &&
6708
	    is_ipaddrv4($config['interfaces'][$interface]['ipaddr'])) {
6709
		return ($config['interfaces'][$interface]['subnet']);
6710
	}
6711

    
6712
	$realif = get_real_interface($interface);
6713
	if (!$realif) {
6714
		return (NULL);
6715
	}
6716

    
6717
	$cursn = find_interface_subnet($realif);
6718
	if (!empty($cursn)) {
6719
		return ($cursn);
6720
	}
6721

    
6722
	return (NULL);
6723
}
6724

    
6725
function get_interface_subnetv6($interface = "wan") {
6726
	global $config;
6727

    
6728
	if (substr($interface, 0, 4) == '_vip') {
6729
		return (get_configured_vip_subnetv6($interface));
6730
	} else if (substr($interface, 0, 5) == '_lloc') {
6731
		$interface = substr($interface, 5);
6732
	}
6733

    
6734
	if (is_array($config['interfaces'][$interface]) &&
6735
	    !empty($config['interfaces'][$interface]['subnetv6']) &&
6736
	    is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6737
		return ($config['interfaces'][$interface]['subnetv6']);
6738
	}
6739

    
6740
	$realif = get_real_interface($interface, 'inet6');
6741
	if (!$realif) {
6742
		return (NULL);
6743
	}
6744

    
6745
	$cursn = find_interface_subnetv6($realif);
6746
	if (!empty($cursn)) {
6747
		return ($cursn);
6748
	}
6749

    
6750
	return (NULL);
6751
}
6752

    
6753
/* return outside interfaces with a gateway */
6754
function get_interfaces_with_gateway() {
6755
	global $config;
6756

    
6757
	$ints = array();
6758

    
6759
	/* loop interfaces, check config for outbound */
6760
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6761
		switch ($ifname['ipaddr']) {
6762
			case "dhcp":
6763
			case "pppoe":
6764
			case "pptp":
6765
			case "l2tp":
6766
			case "ppp":
6767
				$ints[$ifdescr] = $ifdescr;
6768
				break;
6769
			default:
6770
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6771
				    !empty($ifname['gateway'])) {
6772
					$ints[$ifdescr] = $ifdescr;
6773
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6774
				    !empty($ifname['gateway'])) {
6775
					$ints[$ifdescr] = $ifdescr;
6776
				}
6777

    
6778
				break;
6779
		}
6780
	}
6781
	return $ints;
6782
}
6783

    
6784
/* return true if interface has a gateway */
6785
function interface_has_gateway($friendly) {
6786
	global $config;
6787

    
6788
	if (!empty($config['interfaces'][$friendly])) {
6789
		$ifname = &$config['interfaces'][$friendly];
6790
		switch ($ifname['ipaddr']) {
6791
			case "dhcp":
6792
			case "pppoe":
6793
			case "pptp":
6794
			case "l2tp":
6795
			case "ppp":
6796
				return true;
6797
			break;
6798
			default:
6799
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6800
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6801
					return true;
6802
				}
6803
				$tunnelif = substr($ifname['if'], 0, 3);
6804
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6805
					if (find_interface_ip($ifname['if'])) {
6806
						return true;
6807
					}
6808
				}
6809
				if (!empty($ifname['gateway'])) {
6810
					return true;
6811
				}
6812
			break;
6813
		}
6814
	}
6815

    
6816
	return false;
6817
}
6818

    
6819
/* return true if interface has a gateway */
6820
function interface_has_gatewayv6($friendly) {
6821
	global $config;
6822

    
6823
	if (!empty($config['interfaces'][$friendly])) {
6824
		$ifname = &$config['interfaces'][$friendly];
6825
		switch ($ifname['ipaddrv6']) {
6826
			case "slaac":
6827
			case "dhcp6":
6828
			case "6to4":
6829
			case "6rd":
6830
				return true;
6831
				break;
6832
			default:
6833
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6834
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6835
					return true;
6836
				}
6837
				$tunnelif = substr($ifname['if'], 0, 3);
6838
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6839
					if (find_interface_ipv6($ifname['if'])) {
6840
						return true;
6841
					}
6842
				}
6843
				if (!empty($ifname['gatewayv6'])) {
6844
					return true;
6845
				}
6846
				break;
6847
		}
6848
	}
6849

    
6850
	return false;
6851
}
6852

    
6853
/****f* interfaces/is_altq_capable
6854
 * NAME
6855
 *   is_altq_capable - Test if interface is capable of using ALTQ
6856
 * INPUTS
6857
 *   $int            - string containing interface name
6858
 * RESULT
6859
 *   boolean         - true or false
6860
 ******/
6861

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

    
6877
	$int_family = remove_ifindex($int);
6878

    
6879
	if (in_array($int_family, $capable)) {
6880
		return true;
6881
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6882
		return true;
6883
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6884
		return true;
6885
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6886
		return true;
6887
	} else {
6888
		return false;
6889
	}
6890
}
6891

    
6892
/****f* interfaces/is_interface_wireless
6893
 * NAME
6894
 *   is_interface_wireless - Returns if an interface is wireless
6895
 * RESULT
6896
 *   $tmp       - Returns if an interface is wireless
6897
 ******/
6898
function is_interface_wireless($interface) {
6899
	global $config, $g;
6900

    
6901
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6902
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6903
		if (preg_match($g['wireless_regex'], $interface)) {
6904
			if (isset($config['interfaces'][$friendly])) {
6905
				$config['interfaces'][$friendly]['wireless'] = array();
6906
			}
6907
			return true;
6908
		}
6909
		return false;
6910
	} else {
6911
		return true;
6912
	}
6913
}
6914

    
6915
function get_wireless_modes($interface) {
6916
	/* return wireless modes and channels */
6917
	$wireless_modes = array();
6918

    
6919
	$cloned_interface = get_real_interface($interface);
6920

    
6921
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6922
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6923
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6924
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6925

    
6926
		$interface_channels = "";
6927
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6928
		$interface_channel_count = count($interface_channels);
6929

    
6930
		$c = 0;
6931
		while ($c < $interface_channel_count) {
6932
			$channel_line = explode(",", $interface_channels["$c"]);
6933
			$wireless_mode = trim($channel_line[0]);
6934
			$wireless_channel = trim($channel_line[1]);
6935
			if (trim($wireless_mode) != "") {
6936
				/* if we only have 11g also set 11b channels */
6937
				if ($wireless_mode == "11g") {
6938
					if (!isset($wireless_modes["11b"])) {
6939
						$wireless_modes["11b"] = array();
6940
					}
6941
				} else if ($wireless_mode == "11g ht") {
6942
					if (!isset($wireless_modes["11b"])) {
6943
						$wireless_modes["11b"] = array();
6944
					}
6945
					if (!isset($wireless_modes["11g"])) {
6946
						$wireless_modes["11g"] = array();
6947
					}
6948
					$wireless_mode = "11ng";
6949
				} else if ($wireless_mode == "11a ht") {
6950
					if (!isset($wireless_modes["11a"])) {
6951
						$wireless_modes["11a"] = array();
6952
					}
6953
					$wireless_mode = "11na";
6954
				}
6955
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6956
			}
6957
			$c++;
6958
		}
6959
	}
6960
	return($wireless_modes);
6961
}
6962

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

    
6968
		$interface_channels = "";
6969
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6970
		return $interface_channels;
6971
}
6972

    
6973
/* return wireless HT modes */
6974
function get_wireless_ht_modes($interface) {
6975
	$wireless_hts_supported = array(0 => gettext('Auto'));
6976

    
6977
	$cloned_interface = get_real_interface($interface);
6978

    
6979
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6980
		$interface_channels = get_wireless_channels($cloned_interface);
6981

    
6982
		foreach ($interface_channels as $channel) {
6983
			$channel_line = explode(",", $channel);
6984
			$wireless_ht = trim($channel_line[1]);
6985
			if (!empty($wireless_ht)) {
6986
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
6987
			}
6988
		}
6989
	}
6990
	return($wireless_hts_supported);
6991
}
6992

    
6993
/* return wireless HT by channel/standard */
6994
function get_wireless_ht_list($interface) {
6995
	$wireless_hts = array();
6996

    
6997
	$cloned_interface = get_real_interface($interface);
6998

    
6999
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7000
		$interface_channels = get_wireless_channels($cloned_interface);
7001
		$interface_channel_count = count($interface_channels);
7002

    
7003
		$c = 0;
7004
		while ($c < $interface_channel_count) {
7005
			$channel_line = explode(",", $interface_channels["$c"]);
7006
			$wireless_mode = trim($channel_line[0]);
7007
			$wireless_ht = trim($channel_line[1]);
7008
			$wireless_channel = trim($channel_line[2]);
7009
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
7010
				if ($wireless_mode == "11g") {
7011
					if (!isset($wireless_modes["11g"])) {
7012
						$wireless_hts["11g"] = array();
7013
					}
7014
					$wireless_mode = "11ng";
7015
				} elseif ($wireless_mode == "11a") {
7016
					if (!isset($wireless_modes["11a"])) {
7017
						$wireless_hts["11a"] = array();
7018
					}
7019
					$wireless_mode = "11na";
7020
				}
7021
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
7022
			}
7023
			$c++;
7024
		}
7025
	}
7026
	return($wireless_hts);
7027
}
7028

    
7029
/* return channel numbers, frequency, max txpower, and max regulation txpower */
7030
function get_wireless_channel_info($interface) {
7031
	$wireless_channels = array();
7032

    
7033
	$cloned_interface = get_real_interface($interface);
7034

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

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

    
7043
		foreach ($interface_channels as $channel_line) {
7044
			$channel_line = explode(",", $channel_line);
7045
			if (!isset($wireless_channels[$channel_line[0]])) {
7046
				$wireless_channels[$channel_line[0]] = $channel_line;
7047
			}
7048
		}
7049
	}
7050
	return($wireless_channels);
7051
}
7052

    
7053
function set_interface_mtu($interface, $mtu) {
7054

    
7055
	/* LAGG interface must be destroyed and re-created to change MTU */
7056
	if ((substr($interface, 0, 4) == 'lagg') &&
7057
	    (!strstr($interface, "."))) {
7058
		if (isset($config['laggs']['lagg']) &&
7059
		    is_array($config['laggs']['lagg'])) {
7060
			foreach ($config['laggs']['lagg'] as $lagg) {
7061
				if ($lagg['laggif'] == $interface) {
7062
					interface_lagg_configure($lagg);
7063
					break;
7064
				}
7065
			}
7066
		}
7067
	} else {
7068
		pfSense_interface_mtu($interface, $mtu);
7069
		set_ipv6routes_mtu($interface, $mtu);
7070
	}
7071
}
7072

    
7073
/****f* interfaces/get_interface_mtu
7074
 * NAME
7075
 *   get_interface_mtu - Return the mtu of an interface
7076
 * RESULT
7077
 *   $tmp       - Returns the mtu of an interface
7078
 ******/
7079
function get_interface_mtu($interface) {
7080
	$mtu = pfSense_interface_getmtu($interface);
7081
	return $mtu['mtu'];
7082
}
7083

    
7084
function get_interface_mac($interface) {
7085
	$macinfo = pfSense_get_interface_addresses($interface);
7086
	return $macinfo["macaddr"];
7087
}
7088

    
7089
function get_interface_vendor_mac($interface) {
7090
	global $config, $g;
7091

    
7092
	$macinfo = pfSense_get_interface_addresses($interface);
7093
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7094
	    "00:00:00:00:00:00") {
7095
		return ($macinfo["hwaddr"]);
7096
	}
7097

    
7098
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7099
	if (file_exists($hwaddr_file)) {
7100
		$macaddr = trim(file_get_contents($hwaddr_file));
7101
		if (is_macaddr($macaddr)) {
7102
			return ($macaddr);
7103
		}
7104
	} elseif (is_macaddr($macinfo['macaddr'])) {
7105
		/* Save original macaddress to be restored when necessary */
7106
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7107
	}
7108

    
7109
	return (NULL);
7110
}
7111

    
7112
/****f* pfsense-utils/generate_random_mac_address
7113
 * NAME
7114
 *   generate_random_mac - generates a random mac address
7115
 * INPUTS
7116
 *   none
7117
 * RESULT
7118
 *   $mac - a random mac address
7119
 ******/
7120
function generate_random_mac_address() {
7121
	$mac = "02";
7122
	for ($x = 0; $x < 5; $x++) {
7123
		$mac .= ":" . dechex(rand(16, 255));
7124
	}
7125
	return $mac;
7126
}
7127

    
7128
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7129
	global $g;
7130

    
7131
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7132

    
7133
	if (!empty($iface) && !empty($pppif)) {
7134
		$cron_cmd = <<<EOD
7135
#!/bin/sh
7136
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7137
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7138

    
7139
EOD;
7140

    
7141
		@file_put_contents($cron_file, $cron_cmd);
7142
		chmod($cron_file, 0755);
7143
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7144
	} else {
7145
		unlink_if_exists($cron_file);
7146
	}
7147
}
7148

    
7149
function get_interface_default_mtu($type = "ethernet") {
7150
	switch ($type) {
7151
		case "gre":
7152
			return 1476;
7153
			break;
7154
		case "gif":
7155
			return 1280;
7156
			break;
7157
		case "tun":
7158
		case "vlan":
7159
		case "tap":
7160
		case "ethernet":
7161
		default:
7162
			return 1500;
7163
			break;
7164
	}
7165

    
7166
	/* Never reached */
7167
	return 1500;
7168
}
7169

    
7170
function get_vip_descr($ipaddress) {
7171
	global $config;
7172

    
7173
	foreach ($config['virtualip']['vip'] as $vip) {
7174
		if ($vip['subnet'] == $ipaddress) {
7175
			return ($vip['descr']);
7176
		}
7177
	}
7178
	return "";
7179
}
7180

    
7181
function interfaces_staticarp_configure($if) {
7182
	global $config, $g;
7183
	if (isset($config['system']['developerspew'])) {
7184
		$mt = microtime();
7185
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7186
	}
7187

    
7188
	$ifcfg = $config['interfaces'][$if];
7189

    
7190
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
7191
		return 0;
7192
	}
7193

    
7194
	/* Enable staticarp, if enabled */
7195
	if (isset($config['dhcpd'][$if]['staticarp'])) {
7196
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7197
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7198
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
7199
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
7200
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
7201
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7202
				}
7203
			}
7204
		}
7205
	} else {
7206
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7207
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7208
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
7209
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
7210
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
7211
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7212
				}
7213
			}
7214
		}
7215
	}
7216

    
7217
	return 0;
7218
}
7219

    
7220
function get_failover_interface($interface, $family = "all") {
7221
	global $config;
7222

    
7223
	/* shortcut to get_real_interface if we find it in the config */
7224
	if (is_array($config['interfaces'][$interface])) {
7225
		return get_real_interface($interface, $family);
7226
	}
7227

    
7228
	/* compare against gateway groups */
7229
	$a_groups = return_gateway_groups_array(true);
7230
	if (is_array($a_groups[$interface])) {
7231
		/* we found a gateway group, fetch the interface or vip */
7232
		if (!empty($a_groups[$interface][0]['vip'])) {
7233
			return $a_groups[$interface][0]['vip'];
7234
		} else {
7235
			return $a_groups[$interface][0]['int'];
7236
		}
7237
	}
7238
	/* fall through to get_real_interface */
7239
	/* XXX: Really needed? */
7240
	return get_real_interface($interface, $family);
7241
}
7242

    
7243
/****f* interfaces/interface_has_dhcp
7244
 * NAME
7245
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7246
 * INPUTS
7247
 *   interface or gateway group name
7248
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7249
 * RESULT
7250
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7251
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7252
 ******/
7253
function interface_has_dhcp($interface, $family = 4) {
7254
	global $config;
7255

    
7256
	if ($config['interfaces'][$interface]) {
7257
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
7258
			return true;
7259
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
7260
			return true;
7261
		} else {
7262
			return false;
7263
		}
7264
	}
7265

    
7266
	if (!is_array($config['gateways']['gateway_group'])) {
7267
		return false;
7268
	}
7269

    
7270
	if ($family == 6) {
7271
		$dhcp_string = "_DHCP6";
7272
	} else {
7273
		$dhcp_string = "_DHCP";
7274
	}
7275

    
7276
	foreach ($config['gateways']['gateway_group'] as $group) {
7277
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7278
			continue;
7279
		}
7280
		foreach ($group['item'] as $item) {
7281
			$item_data = explode("|", $item);
7282
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7283
				return true;
7284
			}
7285
		}
7286
	}
7287

    
7288
	return false;
7289
}
7290

    
7291
function remove_ifindex($ifname) {
7292
	return preg_replace("/[0-9]+$/", "", $ifname);
7293
}
7294

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

    
7298
	$viplist = get_configured_vip_list($family, $type);
7299
	foreach ($viplist as $vip => $address) {
7300
		$interfaces[$vip] = $address;
7301
		if ($type = VIP_CARP) {
7302
			$vip = get_configured_vip($vipid);
7303
			if (isset($vip) && is_array($vip) ) {
7304
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7305
			}
7306
		}
7307
		if (get_vip_descr($address)) {
7308
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
7309
		}
7310
	}
7311
	return $interfaces;
7312
}
7313

    
7314
function return_gateway_groups_array_with_descr() {
7315
	$interfaces = array();
7316
	$grouplist = return_gateway_groups_array();
7317
	foreach ($grouplist as $name => $group) {
7318
		if ($group[0]['vip'] != "") {
7319
			$vipif = $group[0]['vip'];
7320
		} else {
7321
			$vipif = $group[0]['int'];
7322
		}
7323

    
7324
		$interfaces[$name] = "GW Group {$name}";
7325
	}
7326
	return $interfaces;
7327
}
7328

    
7329
function get_serial_ports() {
7330
	$linklist = array();
7331
	if (!is_dir("/var/spool/lock")) {
7332
		mwexec("/bin/mkdir -p /var/spool/lock");
7333
	}
7334
	$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);
7335
	foreach ($serialports as $port) {
7336
		$linklist[$port] = trim($port);
7337
	}
7338
	return $linklist;
7339
}
7340

    
7341
function get_interface_ports() {
7342
	global $config;
7343
	$linklist = array();
7344
	$portlist = get_interface_list();
7345
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7346
		foreach ($config['vlans']['vlan'] as $vlan) {
7347
			$portlist[$vlan['vlanif']] = $vlan;
7348
		}
7349
	}
7350

    
7351
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7352
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7353
			$members = explode(" ", $qinq['members']);
7354
			foreach ($members as $mem) {
7355
				$qentry = $qinq['vlanif'] . "." . $mem;
7356
				$portlist[$qentry] = $qentry;
7357
			}
7358
		}
7359
	}
7360

    
7361
	foreach ($portlist as $ifn => $ifinfo) {
7362
		$string = "";
7363
		if (is_array($ifinfo)) {
7364
			$string .= $ifn;
7365
			if ($ifinfo['mac']) {
7366
				$string .= " ({$ifinfo['mac']})";
7367
			}
7368
			if ($ifinfo['friendly']) {
7369
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7370
			} elseif ($ifinfo['descr']) {
7371
				$string .= " - {$ifinfo['descr']}";
7372
			}
7373
		} else {
7374
			$string .= $ifinfo;
7375
		}
7376

    
7377
		$linklist[$ifn] = $string;
7378
	}
7379
	return $linklist;
7380
}
7381

    
7382
function build_ppps_link_list() {
7383
	global $pconfig;
7384

    
7385
	$linklist = array('list' => array(), 'selected' => array());
7386

    
7387
	if ($pconfig['type'] == 'ppp') {
7388
		$linklist['list'] = get_serial_ports();
7389
	} else {
7390
		$iflist = get_interface_ports();
7391

    
7392
		$viplist = array();
7393
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7394
		foreach ($carplist as $vid => $vaddr) {
7395
			$vip = get_configured_vip($vid);
7396
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7397
		}
7398

    
7399
		$linklist['list'] = array_merge($iflist, $viplist);
7400

    
7401
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7402
		$lagglist = get_lagg_interface_list();
7403
		foreach ($lagglist as $laggif => $lagg) {
7404
			/* LAGG members cannot be assigned */
7405
			$laggmembers = explode(',', $lagg['members']);
7406
			foreach ($laggmembers as $lagm) {
7407
				if (isset($linklist['list'][$lagm])) {
7408
					unset($linklist['list'][$lagm]);
7409
				}
7410
			}
7411
		}
7412
	}
7413

    
7414
	$selected_ports = array();
7415
	if (is_array($pconfig['interfaces'])) {
7416
		$selected_ports = $pconfig['interfaces'];
7417
	} elseif (!empty($pconfig['interfaces'])) {
7418
		$selected_ports = explode(',', $pconfig['interfaces']);
7419
	}
7420
	foreach ($selected_ports as $port) {
7421
		if (isset($linklist['list'][$port])) {
7422
			array_push($linklist['selected'], $port);
7423
		}
7424
	}
7425
	return($linklist);
7426
}
7427

    
7428
function create_interface_list() {
7429
	global $config;
7430

    
7431
	$iflist = array();
7432

    
7433
	// add group interfaces
7434
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7435
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7436
			if (have_ruleint_access($ifgen['ifname'])) {
7437
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7438
			}
7439
		}
7440
	}
7441

    
7442
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7443
		if (have_ruleint_access($ifent)) {
7444
			$iflist[$ifent] = $ifdesc;
7445
		}
7446
	}
7447

    
7448
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
7449
		$iflist['l2tp'] = gettext('L2TP VPN');
7450
	}
7451

    
7452
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
7453
		$iflist['pppoe'] = gettext("PPPoE Server");
7454
	}
7455

    
7456
	// add ipsec interfaces
7457
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
7458
		$iflist["enc0"] = gettext("IPsec");
7459
	}
7460

    
7461
	// add openvpn/tun interfaces
7462
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7463
		$iflist["openvpn"] = gettext("OpenVPN");
7464
	}
7465

    
7466
	return($iflist);
7467
}
7468

    
7469
function is_pseudo_interface($inf, $tap=true) {
7470
	global $config;
7471
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7472
	foreach ($psifs as $pif) {
7473
		if (substr($inf, 0, strlen($pif)) == $pif) {
7474
			if (($pif == 'ovpn') && $tap) {
7475
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7476
				$type = ($m[1] == 'c') ? 'client' : 'server';
7477
				foreach ($config['openvpn']['openvpn-'.$type] as $ovpn) {
7478
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7479
						return false; 	
7480
					} elseif ($ovpn['vpnid'] == $m[2]) {
7481
						return true;
7482
					}
7483
				}
7484
			} else {
7485
				return true;
7486
			}
7487
		}
7488
	}
7489
	return false;
7490
}
7491

    
7492
function is_stf_interface($inf) {
7493
	global $config;
7494

    
7495
	if (is_array($config['interfaces'][$inf]) &&
7496
	    (($config['interfaces'][$inf]['ipaddrv6'] == '6rd') ||
7497
	    ($config['interfaces'][$inf]['ipaddrv6'] == '6to4'))) {
7498
	    return true;
7499
	}
7500

    
7501
	return false;
7502
}
7503

    
7504
?>
(22-22/61)