Project

General

Profile

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

    
26
/* include all configuration functions */
27
require_once("globals.inc");
28
require_once("util.inc");
29
require_once("gwlb.inc");
30

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

    
40
/*
41
 * Validate comma-separated list of IPv4 addresses
42
 */
43
function validate_ipv4_list($value) {
44
	$value = trim($value);
45

    
46
	if (empty($value)) {
47
		return false;
48
	}
49

    
50
	$list = explode(',', $value);
51

    
52
	foreach ($list as $ip) {
53
		if (!is_ipaddrv4($ip)) {
54
			return false;
55
		}
56
	}
57

    
58
	return true;
59
}
60

    
61
/*
62
 * Return the interface array
63
 */
64
function get_interface_arr($flush = false) {
65
	global $interface_arr_cache;
66

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

    
72
	return $interface_arr_cache;
73
}
74

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

    
82
	if (!$interface) {
83
		return false;
84
	}
85

    
86
	$ints = get_interface_arr($flush);
87
	if (in_array($interface, $ints)) {
88
		return true;
89
	} else {
90
		return false;
91
	}
92
}
93

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

    
101
	if (!$vip) {
102
		return false;
103
	}
104

    
105

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

    
121
	$ifacedata = pfSense_getall_interface_addresses($realif);
122
	foreach ($ifacedata as $vipips) {
123
		if ($vipips == "{$vip['subnet']}/{$vip['subnet_bits']}") {
124
			return true;
125
		}
126
	}
127

    
128
	return false;
129
}
130

    
131
function interface_netgraph_needed($interface = "wan") {
132
	global $config;
133

    
134
	$found = false;
135
	if (!empty($config['l2tp']) &&
136
	    $config['l2tp']['mode'] == "server") {
137
		$found = true;
138
	}
139
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
140
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
141
			if ($pppoe['mode'] != "server") {
142
				continue;
143
			}
144
			if ($pppoe['interface'] == $interface) {
145
				$found = true;
146
				break;
147
			}
148
		}
149
	}
150
	if ($found == false) {
151
		$found = interface_isppp_type($interface);
152
	}
153

    
154
	if ($found == false) {
155
		$realif = get_real_interface($interface);
156
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
157
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
158
				$ports = explode(',', $ppp['ports']);
159
				foreach ($ports as $pid => $port) {
160
					$port = get_real_interface($port);
161
					if ($realif == $port) {
162
						$found = true;
163
						break;
164
					}
165
					/* Find the parent interfaces of the vlans in the MLPPP configs
166
					* there should be only one element in the array here
167
					* -- this could be better . . . */
168
					$parent_if = get_parent_interface($port);
169
					if ($realif == $parent_if[0]) {
170
						$found = true;
171
						break;
172
					}
173
				}
174
			}
175
		}
176
	}
177

    
178
	if ($found == false) {
179
		$realif = get_real_interface($interface);
180
		pfSense_ngctl_detach("{$realif}:", $realif);
181
	}
182
	/* NOTE: We make sure for this on interface_ppps_configure()
183
	 *	no need to do it here again.
184
	 *	else
185
	 *		pfSense_ngctl_attach(".", $realif);
186
	 */
187
}
188

    
189
function interfaces_loopback_configure() {
190
	global $g;
191

    
192
	if (platform_booting()) {
193
		echo gettext("Configuring loopback interface...");
194
	}
195
	pfSense_interface_setaddress("lo0", "127.0.0.1");
196
	interfaces_bring_up("lo0");
197
	if (platform_booting()) {
198
		echo gettext("done.") . "\n";
199
	}
200
	return 0;
201
}
202

    
203
function vlan_valid_tag($tag = NULL) {
204

    
205
	if ($tag == NULL || empty($tag) ||
206
	    !is_numericint($tag) || intval($tag) < 1 || intval($tag) > 4094) {
207
		return (false);
208
	}
209
	return (true);
210
}
211

    
212
function qinq_inuse($qinq = NULL, $inqtag = NULL) {
213
        global $config;
214

    
215
	if ($qinq == NULL || $inqtag == NULL ||
216
	    !is_array($qinq) || !vlan_valid_tag($inqtag)) {
217
		return (false);
218
	}
219

    
220
        $iflist = get_configured_interface_list(true);
221
        foreach ($iflist as $if) {
222
                if ($config['interfaces'][$if]['if'] == qinq_interface($qinq, $inqtag)) {
223
                        return (true);
224
                }
225
        }
226

    
227
        return (false);
228
}
229

    
230
function qinq_interface($qinq = NULL, $inqtag = NULL) {
231

    
232
	if ($qinq == NULL || $inqtag == NULL || !is_array($qinq) ||
233
	    !isset($qinq['if']) || !isset($qinq['tag']) ||
234
	    !vlan_valid_tag($qinq['tag']) || !vlan_valid_tag($inqtag)) {
235
		return (NULL);
236
	}
237
	return ("{$qinq['if']}.{$qinq['tag']}.{$inqtag}");
238
}
239

    
240
function interface_is_qinq($if = NULL) {
241
	global $config;
242

    
243
	if ($if == NULL || empty($if) || !is_array($config['qinqs']['qinqentry'])) {
244
		return (NULL);
245
	}
246

    
247
	/* Check basic format. */
248
	list($qinqif, $vlantag, $inqtag) = explode(".", $if);
249
	if (empty($qinqif) || empty($vlantag) || empty($inqtag) ||
250
	    !vlan_valid_tag($vlantag) || !vlan_valid_tag($inqtag)) {
251
		return (NULL);
252
	}
253

    
254
	foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
255
		if ("{$qinqif}.{$vlantag}" != $qinq['vlanif']) {
256
			continue;
257
		}
258
		if (empty($qinq['members'])) {
259
			continue;
260
		}
261
		foreach (explode(" ", $qinq['members']) as $tag) {
262
			if ($if == qinq_interface($qinq, $tag)) {
263
				return ($qinq);
264
			}
265
		}
266
	}
267

    
268
	return (NULL);
269
}
270

    
271
function vlan_inuse($vlan) {
272
	global $config;
273

    
274
	if ($vlan == NULL || !is_array($vlan)) {
275
		return (false);
276
	}
277

    
278
	$iflist = get_configured_interface_list(true);
279
	foreach ($iflist as $if) {
280
		if ($config['interfaces'][$if]['if'] == $vlan['vlanif']) {
281
			return (true);
282
		}
283
	}
284

    
285
	return (false);
286
}
287

    
288
function interface_is_vlan($if = NULL) {
289
	global $config;
290

    
291
	if ($if == NULL || empty($if)) {
292
		return (NULL);
293
	}
294

    
295
	/* Check basic format. */
296
	list($vlanif, $vlantag) = explode(".", $if);
297
	if (empty($vlanif) || empty($vlantag) || !vlan_valid_tag($vlantag)) {
298
		return (NULL);
299
	}
300

    
301
	/* Find the VLAN interface. */
302
	if (isset($config['vlans']['vlan']) && is_array($config['vlans']['vlan'])) {
303
		foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
304
			if ($if == $vlan['vlanif']) {
305
				return ($vlan);
306
			}
307
		}
308
	}
309

    
310
	/* Check for the first level tag in QinQ interfaces. */
311
	if (isset($config['qinqs']['qinqentry']) && is_array($config['qinqs']['qinqentry'])) {
312
		foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
313
			if ($if == $qinq['vlanif']) {
314
				return ($qinq);
315
			}
316
		}
317
	}
318

    
319
	return (NULL);
320
}
321

    
322
function vlan_interface($vlan = NULL) {
323

    
324
	if ($vlan == NULL || !is_array($vlan) || !isset($vlan['if']) ||
325
	    !isset($vlan['tag']) || !vlan_valid_tag($vlan['tag'])) {
326
		return (NULL);
327
	}
328
	return ("{$vlan['if']}.{$vlan['tag']}");
329
}
330

    
331
function interfaces_vlan_configure($realif = "") {
332
	global $config, $g;
333
	if (platform_booting()) {
334
		echo gettext("Configuring VLAN interfaces...");
335
	}
336
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
337
		foreach ($config['vlans']['vlan'] as $vlan) {
338
			if (empty($vlan['vlanif'])) {
339
				$vlan['vlanif'] = vlan_interface($vlan);
340
			}
341
			if (!empty($realif) && $realif != $vlan['vlanif']) {
342
				continue;
343
			}
344

    
345
			/* XXX: Maybe we should report any errors?! */
346
			interface_vlan_configure($vlan);
347
		}
348
	}
349
	if (platform_booting()) {
350
		echo gettext("done.") . "\n";
351
	}
352
}
353

    
354
function interface_vlan_configure(&$vlan) {
355
	global $config, $g;
356

    
357
	if (!is_array($vlan)) {
358
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
359
		return(NULL);
360
	}
361
	$if = $vlan['if'];
362
	if (empty($if)) {
363
		log_error(gettext("interface_vlan_configure called with if undefined."));
364
		return(NULL);
365
	}
366

    
367
	$vlanif = empty($vlan['vlanif']) ? vlan_interface($vlan) : $vlan['vlanif'];
368
	if ($vlanif == NULL) {
369
		log_error(gettext("vlan_interface called with if undefined var."));
370
		return(NULL);
371
	}
372
	$tag = $vlan['tag'];
373
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
374

    
375
	/* make sure the parent interface is up */
376
	interfaces_bring_up($if);
377
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
378
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
379

    
380
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
381
		pfSense_interface_destroy($vlanif);
382
	}
383

    
384
	$tmpvlanif = pfSense_interface_create("vlan");
385
	pfSense_interface_rename($tmpvlanif, $vlanif);
386
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
387

    
388
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
389

    
390
	interfaces_bring_up($vlanif);
391

    
392
	/* invalidate interface cache */
393
	get_interface_arr(true);
394

    
395
	/* configure interface if assigned */
396
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
397
	if ($assignedif) {
398
		if (isset($config['interfaces'][$assignedif]['enable'])) {
399
			interface_configure($assignedif, true);
400
		}
401
	}
402

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

    
406
	return $vlanif;
407
}
408

    
409
function interface_qinq_configure(&$qinq, $fd = NULL) {
410
	global $config, $g;
411

    
412
	if (!is_array($qinq)) {
413
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
414
		return;
415
	}
416

    
417
	$qinqif = $qinq['if'];
418
	$tag = $qinq['tag'];
419
	if (empty($qinqif)) {
420
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
421
		return;
422
	}
423

    
424
	if (!does_interface_exist($qinqif)) {
425
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
426
		return;
427
	}
428

    
429
	$vlanif = interface_vlan_configure($qinq);
430
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
431
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
432
		return;
433
	}
434

    
435
	if ($fd == NULL) {
436
		$exec = true;
437
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
438
	} else {
439
		$exec = false;
440
	}
441
	/* make sure the parent is converted to ng_vlan(4) and is up */
442
	interfaces_bring_up($qinqif);
443

    
444
	pfSense_ngctl_attach(".", $qinqif);
445
	$ngif = str_replace(".", "_", $vlanif);
446
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
447
		exec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1");
448
		exec("/usr/sbin/ngctl msg {$ngif}qinq: gettable > /dev/null 2>&1", $result);
449
		if (empty($result)) {
450
			fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
451
			fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
452
			fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
453
		}
454
	} else {
455
		fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
456
		fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
457
		fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
458
	}
459

    
460
	/* invalidate interface cache */
461
	get_interface_arr(true);
462

    
463
	if (interface_is_vlan($qinqif) == NULL) {
464
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
465
	}
466

    
467
	$macaddr = get_interface_mac($qinqif);
468
	if (!empty($qinq['members'])) {
469
		$qinqcmdbuf = "";
470
		$members = explode(" ", $qinq['members']);
471
		foreach ($members as $qtag) {
472
			$qinq2 = array();
473
			$qinq2['tag'] = $qtag;
474
			$qinq2['if'] = $vlanif;
475
			interface_qinq2_configure($qinq2, $qinqcmdbuf, $macaddr);
476
			unset($qinq2);
477
		}
478
		if (strlen($qinqcmdbuf) > 0) {
479
			fwrite($fd, $qinqcmdbuf);
480
		}
481
	}
482
	if ($exec == true) {
483
		fclose($fd);
484
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd > /dev/null 2>&1");
485
	}
486

    
487
	interfaces_bring_up($qinqif);
488
	if (!empty($qinq['members'])) {
489
		$members = explode(" ", $qinq['members']);
490
		foreach ($members as $qtag) {
491
			interfaces_bring_up(qinq_interface($qinq, $qtag));
492
		}
493
	}
494

    
495
	return $vlanif;
496
}
497

    
498
function interfaces_qinq_configure() {
499
	global $config, $g;
500
	if (platform_booting()) {
501
		echo gettext("Configuring QinQ interfaces...");
502
	}
503
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
504
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
505
			/* XXX: Maybe we should report any errors?! */
506
			interface_qinq_configure($qinq);
507
		}
508
	}
509
	if (platform_booting()) {
510
		echo gettext("done.") . "\n";
511
	}
512
}
513

    
514
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr) {
515
	global $config, $g;
516

    
517
	if (!is_array($qinq)) {
518
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
519
		return;
520
	}
521

    
522
	$if = $qinq['if'];
523
	if (empty($if)) {
524
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
525
		return;
526
	}
527
	$tag = $qinq['tag'];
528
	$vlanif = "{$if}.{$tag}";
529
	$ngif = str_replace(".", "_", $if);
530
	if (strlen($vlanif) > IF_NAMESIZE) {
531
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
532
		    $vlanif, IF_NAMESIZE, "\n"));
533
		return;
534
	}
535

    
536
	exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1");
537
	$cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n";
538
	$cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n";
539
	$cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n";
540
	$cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n";
541
	$cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n";
542

    
543
	/* invalidate interface cache */
544
	get_interface_arr(true);
545

    
546
	return $vlanif;
547
}
548

    
549
function interfaces_create_wireless_clones() {
550
	global $config, $g;
551

    
552
	if (platform_booting()) {
553
		echo gettext("Creating wireless clone interfaces...");
554
	}
555

    
556
	$iflist = get_configured_interface_list();
557

    
558
	foreach ($iflist as $if) {
559
		$realif = $config['interfaces'][$if]['if'];
560
		if (is_interface_wireless($realif)) {
561
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
562
		}
563
	}
564

    
565
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
566
		foreach ($config['wireless']['clone'] as $clone) {
567
			if (empty($clone['cloneif'])) {
568
				continue;
569
			}
570
			if (does_interface_exist($clone['cloneif'])) {
571
				continue;
572
			}
573
			/* XXX: Maybe we should report any errors?! */
574
			interface_wireless_clone($clone['cloneif'], $clone);
575
		}
576
	}
577
	if (platform_booting()) {
578
		echo gettext("done.") . "\n";
579
	}
580

    
581
}
582

    
583
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
584
	global $config;
585

    
586
	$i = 0;
587
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
588
		foreach ($config['bridges']['bridged'] as $bridge) {
589
			if (empty($bridge['bridgeif'])) {
590
				$bridge['bridgeif'] = "bridge{$i}";
591
			}
592
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
593
				continue;
594
			}
595

    
596
			if ($checkmember == 1) {
597
				/* XXX: It should not be possible no? */
598
				if (strstr($bridge['if'], '_vip')) {
599
					continue;
600
				}
601
				$members = explode(',', $bridge['members']);
602
				foreach ($members as $member) {
603
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6") {
604
						continue 2;
605
					}
606
				}
607
			}
608
			else if ($checkmember == 2) {
609
				$members = explode(',', $bridge['members']);
610
				foreach ($members as $member) {
611
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6") {
612
						continue 2;
613
					}
614
				}
615
			}
616
			/* XXX: Maybe we should report any errors?! */
617
			interface_bridge_configure($bridge, $checkmember);
618
			$i++;
619
		}
620
	}
621
}
622

    
623
function interface_bridge_configure(&$bridge, $checkmember = 0) {
624
	global $config, $g;
625

    
626
	if (!is_array($bridge)) {
627
		return;
628
	}
629

    
630
	if (empty($bridge['members'])) {
631
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
632
		return;
633
	}
634

    
635
	$members = explode(',', $bridge['members']);
636
	if (!count($members)) {
637
		return;
638
	}
639

    
640
	/* Calculate smaller mtu and enforce it */
641
	$smallermtu = 0;
642
	$foundgif = false;
643
	foreach ($members as $member) {
644
		$realif = get_real_interface($member);
645
		$mtu = get_interface_mtu($realif);
646
		if (substr($realif, 0, 3) == "gif") {
647
			$foundgif = true;
648
			if ($checkmember == 1) {
649
				return;
650
			}
651
			if ($mtu <= 1500) {
652
				continue;
653
			}
654
		}
655
		if ($smallermtu == 0 && !empty($mtu)) {
656
			$smallermtu = $mtu;
657
		} else if (!empty($mtu) && $mtu < $smallermtu) {
658
			$smallermtu = $mtu;
659
		}
660
	}
661
	if ($foundgif == false && $checkmember == 2) {
662
		return;
663
	}
664

    
665
	/* Just in case anything is not working well */
666
	if ($smallermtu == 0) {
667
		$smallermtu = 1500;
668
	}
669

    
670
	if (!empty($bridge['bridgeif'])) {
671
		pfSense_interface_destroy($bridge['bridgeif']);
672
		pfSense_interface_create($bridge['bridgeif']);
673
		$bridgeif = escapeshellarg($bridge['bridgeif']);
674
	} else {
675
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
676
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
677
		$bridgeif = pfSense_interface_create("bridge");
678
		$bridge['bridgeif'] = $bridgeif;
679
	}
680

    
681
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
682
	if ($bridgemtu > $smallermtu) {
683
		$smallermtu = $bridgemtu;
684
	}
685

    
686
	$checklist = get_configured_interface_list();
687

    
688
	/* Add interfaces to bridge */
689
	foreach ($members as $member) {
690
		if (empty($checklist[$member])) {
691
			continue;
692
		}
693
		$realif = get_real_interface($member);
694
		if (!$realif) {
695
			log_error(gettext("realif not defined in interfaces bridge - up"));
696
			continue;
697
		}
698
		/* make sure the parent interface is up */
699
		pfSense_interface_mtu($realif, $smallermtu);
700
		interfaces_bring_up($realif);
701
		enable_hardware_offloading($member);
702
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
703
	}
704

    
705
	if (isset($bridge['enablestp'])) {
706
		interface_bridge_configure_stp($bridge);
707
	}
708

    
709
	interface_bridge_configure_advanced($bridge);
710

    
711
	interface_bridge_configure_ip6linklocal($bridge);
712

    
713
	if ($bridge['bridgeif']) {
714
		interfaces_bring_up($bridge['bridgeif']);
715
	} else {
716
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
717
	}
718
}
719

    
720
function interface_bridge_configure_stp($bridge) {
721
	if (isset($bridge['enablestp'])) {
722
		$bridgeif = $bridge['bridgeif'];
723
		/* configure spanning tree proto */
724
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
725

    
726
		if (!empty($bridge['stp'])) {
727
			$stpifs = explode(',', $bridge['stp']);
728
			foreach ($stpifs as $stpif) {
729
				$realif = get_real_interface($stpif);
730
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
731
			}
732
		}
733
		if (!empty($bridge['maxage'])) {
734
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
735
		}
736
		if (!empty($bridge['fwdelay'])) {
737
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
738
		}
739
		if (!empty($bridge['hellotime'])) {
740
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
741
		}
742
		if (!empty($bridge['priority'])) {
743
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
744
		}
745
		if (!empty($bridge['holdcnt'])) {
746
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
747
		}
748
		if (!empty($bridge['ifpriority'])) {
749
			$pconfig = explode(",", $bridge['ifpriority']);
750
			$ifpriority = array();
751
			foreach ($pconfig as $cfg) {
752
				$embcfg = explode_assoc(":", $cfg);
753
				foreach ($embcfg as $key => $value) {
754
					$ifpriority[$key] = $value;
755
				}
756
			}
757
			foreach ($ifpriority as $key => $value) {
758
				$realif = get_real_interface($key);
759
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
760
			}
761
		}
762
		if (!empty($bridge['ifpathcost'])) {
763
			$pconfig = explode(",", $bridge['ifpathcost']);
764
			$ifpathcost = array();
765
			foreach ($pconfig as $cfg) {
766
				$embcfg = explode_assoc(":", $cfg);
767
				foreach ($embcfg as $key => $value) {
768
					$ifpathcost[$key] = $value;
769
				}
770
			}
771
			foreach ($ifpathcost as $key => $value) {
772
				$realif = get_real_interface($key);
773
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
774
			}
775
		}
776
	}
777
}
778

    
779
function interface_bridge_configure_advanced($bridge) {
780
	$bridgeif = $bridge['bridgeif'];
781

    
782
	if ($bridge['maxaddr'] <> "") {
783
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
784
	}
785
	if ($bridge['timeout'] <> "") {
786
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
787
	}
788
	if (!empty($bridge['span'])) {
789
		$spanifs = explode(",", $bridge['span']);
790
		foreach ($spanifs as $spanif) {
791
			$realif = get_real_interface($spanif);
792
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
793
		}
794
	}
795
	if (!empty($bridge['edge'])) {
796
		$edgeifs = explode(',', $bridge['edge']);
797
		foreach ($edgeifs as $edgeif) {
798
			$realif = get_real_interface($edgeif);
799
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
800
		}
801
	}
802
	if (!empty($bridge['autoedge'])) {
803
		$edgeifs = explode(',', $bridge['autoedge']);
804
		foreach ($edgeifs as $edgeif) {
805
			$realif = get_real_interface($edgeif);
806
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
807
		}
808
	}
809
	if (!empty($bridge['ptp'])) {
810
		$ptpifs = explode(',', $bridge['ptp']);
811
		foreach ($ptpifs as $ptpif) {
812
			$realif = get_real_interface($ptpif);
813
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
814
		}
815
	}
816
	if (!empty($bridge['autoptp'])) {
817
		$ptpifs = explode(',', $bridge['autoptp']);
818
		foreach ($ptpifs as $ptpif) {
819
			$realif = get_real_interface($ptpif);
820
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
821
		}
822
	}
823
	if (!empty($bridge['static'])) {
824
		$stickyifs = explode(',', $bridge['static']);
825
		foreach ($stickyifs as $stickyif) {
826
			$realif = get_real_interface($stickyif);
827
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
828
		}
829
	}
830
	if (!empty($bridge['private'])) {
831
		$privateifs = explode(',', $bridge['private']);
832
		foreach ($privateifs as $privateif) {
833
			$realif = get_real_interface($privateif);
834
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
835
		}
836
	}
837
}
838

    
839
function interface_bridge_configure_ip6linklocal($bridge) {
840
	$bridgeif = $bridge['bridgeif'];
841

    
842
	$members = explode(',', $bridge['members']);
843
	if (!count($members)) {
844
		return;
845
	}
846

    
847
	$auto_linklocal = isset($bridge['ip6linklocal']);
848
	$bridgeop = $auto_linklocal ? '' : '-';
849
	$memberop = $auto_linklocal ? '-' : '';
850

    
851
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
852
	foreach ($members as $member) {
853
		$realif = get_real_interface($member);
854
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
855
	}
856
}
857

    
858
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
859
	global $config;
860

    
861
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
862
		return;
863
	}
864

    
865
	if ($flagsapplied == false) {
866
		$mtu = get_interface_mtu($bridgeif);
867
		$mtum = get_interface_mtu($interface);
868
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
869
			pfSense_interface_mtu($interface, $mtu);
870
		}
871

    
872
		hardware_offloading_applyflags($interface);
873
		interfaces_bring_up($interface);
874
	}
875

    
876
	pfSense_bridge_add_member($bridgeif, $interface);
877
	if (is_array($config['bridges']['bridged'])) {
878
		foreach ($config['bridges']['bridged'] as $bridge) {
879
			if ($bridgeif == $bridge['bridgeif']) {
880
				interface_bridge_configure_stp($bridge);
881
				interface_bridge_configure_advanced($bridge);
882
			}
883
		}
884
	}
885
}
886

    
887
function interfaces_lagg_configure($realif = "") {
888
	global $config, $g;
889
	if (platform_booting()) {
890
		echo gettext("Configuring LAGG interfaces...");
891
	}
892
	$i = 0;
893
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
894
		foreach ($config['laggs']['lagg'] as $lagg) {
895
			if (empty($lagg['laggif'])) {
896
				$lagg['laggif'] = "lagg{$i}";
897
			}
898
			if (!empty($realif) && $realif != $lagg['laggif']) {
899
				continue;
900
			}
901
			/* XXX: Maybe we should report any errors?! */
902
			interface_lagg_configure($lagg);
903
			$i++;
904
		}
905
	}
906
	if (platform_booting()) {
907
		echo gettext("done.") . "\n";
908
	}
909
}
910

    
911
function interface_lagg_configure($lagg) {
912
	global $config, $g;
913

    
914
	if (!is_array($lagg)) {
915
		return -1;
916
	}
917

    
918
	$members = explode(',', $lagg['members']);
919
	if (!count($members)) {
920
		return -1;
921
	}
922

    
923
	if (platform_booting() || !(empty($lagg['laggif']))) {
924
		pfSense_interface_destroy($lagg['laggif']);
925
		pfSense_interface_create($lagg['laggif']);
926
		$laggif = $lagg['laggif'];
927
	} else {
928
		$laggif = pfSense_interface_create("lagg");
929
	}
930

    
931
	/* Check if MTU was defined for this lagg interface */
932
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
933
	if ($lagg_mtu == 0 &&
934
	    is_array($config['interfaces'])) {
935
		foreach ($config['interfaces'] as $tmpinterface) {
936
			if ($tmpinterface['if'] == $lagg['laggif'] &&
937
			    !empty($tmpinterface['mtu'])) {
938
				$lagg_mtu = $tmpinterface['mtu'];
939
				break;
940
			}
941
		}
942
	}
943

    
944
	/* Just in case anything is not working well */
945
	if ($lagg_mtu == 0) {
946
		$lagg_mtu = 1500;
947
	}
948

    
949
	foreach ($members as $member) {
950
		if (!does_interface_exist($member)) {
951
			continue;
952
		}
953

    
954
		/* make sure the parent interface is up */
955
		pfSense_interface_mtu($member, $lagg_mtu);
956
		interfaces_bring_up($member);
957
		hardware_offloading_applyflags($member);
958

    
959
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
960
		$laggif = str_replace("\0", "", $laggif);
961
		$member = str_replace("\0", "", $member);
962
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
963
	}
964

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

    
967
	interfaces_bring_up($laggif);
968

    
969
	return $laggif;
970
}
971

    
972
function interfaces_gre_configure($checkparent = 0, $realif = "") {
973
	global $config;
974

    
975
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
976
		foreach ($config['gres']['gre'] as $i => $gre) {
977
			if (empty($gre['greif'])) {
978
				$gre['greif'] = "gre{$i}";
979
			}
980
			if (!empty($realif) && $realif != $gre['greif']) {
981
				continue;
982
			}
983

    
984
			if ($checkparent == 1) {
985
				if (substr($gre['if'], 0, 4) == '_vip') {
986
					continue;
987
				}
988
				if (substr($gre['if'], 0, 5) == '_lloc') {
989
					continue;
990
				}
991
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6") {
992
					continue;
993
				}
994
			} else if ($checkparent == 2) {
995
				if ((substr($gre['if'], 0, 4) != '_vip' && substr($gre['if'], 0, 5) != '_lloc') &&
996
				    (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")) {
997
					continue;
998
				}
999
			}
1000
			/* XXX: Maybe we should report any errors?! */
1001
			interface_gre_configure($gre);
1002
		}
1003
	}
1004
}
1005

    
1006
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
1007
function interface_gre_configure(&$gre, $grekey = "") {
1008
	global $config, $g;
1009

    
1010
	if (!is_array($gre)) {
1011
		return -1;
1012
	}
1013

    
1014
	$realif = get_real_interface($gre['if']);
1015
	$realifip = get_interface_ip($gre['if']);
1016
	$realifip6 = get_interface_ipv6($gre['if']);
1017

    
1018
	/* make sure the parent interface is up */
1019
	interfaces_bring_up($realif);
1020

    
1021
	if (platform_booting() || !(empty($gre['greif']))) {
1022
		pfSense_interface_destroy($gre['greif']);
1023
		pfSense_interface_create($gre['greif']);
1024
		$greif = $gre['greif'];
1025
	} else {
1026
		$greif = pfSense_interface_create("gre");
1027
	}
1028

    
1029
	/* Do not change the order here for more see gre(4) NOTES section. */
1030
	if (is_ipaddrv6($gre['remote-addr'])) {
1031
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1032
	} else {
1033
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1034
	}
1035
	if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
1036
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1037
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
1038
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
1039
	} else {
1040
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1041
	}
1042

    
1043
	if ($greif) {
1044
		interfaces_bring_up($greif);
1045
	} else {
1046
		log_error(gettext("Could not bring greif up -- variable not defined."));
1047
	}
1048

    
1049
	if (isset($gre['link1']) && $gre['link1']) {
1050
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1051
	}
1052
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
1053
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1054
	}
1055
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
1056
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
1057
	}
1058

    
1059
	interfaces_bring_up($greif);
1060

    
1061
	return $greif;
1062
}
1063

    
1064
function interfaces_gif_configure($checkparent = 0, $realif = "") {
1065
	global $config;
1066

    
1067
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
1068
		foreach ($config['gifs']['gif'] as $i => $gif) {
1069
			if (empty($gif['gifif'])) {
1070
				$gre['gifif'] = "gif{$i}";
1071
			}
1072
			if (!empty($realif) && $realif != $gif['gifif']) {
1073
				continue;
1074
			}
1075

    
1076
			if ($checkparent == 1) {
1077
				if (substr($gif['if'], 0, 4) == '_vip') {
1078
					continue;
1079
				}
1080
				if (substr($gif['if'], 0, 5) == '_lloc') {
1081
					continue;
1082
				}
1083
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
1084
					continue;
1085
				}
1086
			}
1087
			else if ($checkparent == 2) {
1088
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
1089
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
1090
					continue;
1091
				}
1092
			}
1093
			/* XXX: Maybe we should report any errors?! */
1094
			interface_gif_configure($gif);
1095
		}
1096
	}
1097
}
1098

    
1099
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1100
function interface_gif_configure(&$gif, $gifkey = "") {
1101
	global $config, $g;
1102

    
1103
	if (!is_array($gif)) {
1104
		return -1;
1105
	}
1106

    
1107
	$realif = get_real_interface($gif['if']);
1108
	$ipaddr = get_interface_ip($gif['if']);
1109

    
1110
	if (is_ipaddrv4($gif['remote-addr'])) {
1111
		if (is_ipaddrv4($ipaddr)) {
1112
			$realifip = $ipaddr;
1113
		} else {
1114
			$realifip = get_interface_ip($gif['if']);
1115
		}
1116
		$realifgw = get_interface_gateway($gif['if']);
1117
	} else if (is_ipaddrv6($gif['remote-addr'])) {
1118
		if (is_ipaddrv6($ipaddr)) {
1119
			$realifip = $ipaddr;
1120
		} else {
1121
			$realifip = get_interface_ipv6($gif['if']);
1122
		}
1123
		$realifgw = get_interface_gateway_v6($gif['if']);
1124
	}
1125
	/* make sure the parent interface is up */
1126
	if ($realif) {
1127
		interfaces_bring_up($realif);
1128
	} else {
1129
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
1130
	}
1131

    
1132
	if (platform_booting() || !(empty($gif['gifif']))) {
1133
		pfSense_interface_destroy($gif['gifif']);
1134
		pfSense_interface_create($gif['gifif']);
1135
		$gifif = $gif['gifif'];
1136
	} else {
1137
		$gifif = pfSense_interface_create("gif");
1138
	}
1139

    
1140
	/* Do not change the order here for more see gif(4) NOTES section. */
1141
	if (is_ipaddrv6($gif['remote-addr'])) {
1142
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1143
	} else {
1144
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1145
	}
1146
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1147
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1148
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1149
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1150
	} else {
1151
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1152
	}
1153
	if (isset($gif['link1'])) {
1154
		pfSense_interface_flags($gifif, IFF_LINK1);
1155
	}
1156
	if (isset($gif['link2'])) {
1157
		pfSense_interface_flags($gifif, IFF_LINK2);
1158
	}
1159
	if ($gifif) {
1160
		interfaces_bring_up($gifif);
1161
		$gifmtu = "";
1162
		$currentgifmtu = get_interface_mtu($gifif);
1163
		foreach ($config['interfaces'] as $tmpinterface) {
1164
			if ($tmpinterface['if'] == $gifif) {
1165
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1166
					$gifmtu = $tmpinterface['mtu'];
1167
				}
1168
			}
1169
		}
1170
		if (is_numericint($gifmtu)) {
1171
			if ($gifmtu != $currentgifmtu) {
1172
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1173
			}
1174
		}
1175
	} else {
1176
		log_error(gettext("could not bring gifif up -- variable not defined"));
1177
	}
1178

    
1179
	if (!platform_booting()) {
1180
		$iflist = get_configured_interface_list();
1181
		foreach ($iflist as $ifname) {
1182
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1183
				if (get_interface_gateway($ifname)) {
1184
					system_routing_configure($ifname);
1185
					break;
1186
				}
1187
				if (get_interface_gateway_v6($ifname)) {
1188
					system_routing_configure($ifname);
1189
					break;
1190
				}
1191
			}
1192
		}
1193
	}
1194

    
1195

    
1196
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1197
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1198
	}
1199
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1200
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1201
	}
1202

    
1203
	if (is_ipaddrv4($realifgw)) {
1204
		route_add_or_change("-host {$gif['remote-addr']} {$realifgw}");
1205
	}
1206
	if (is_ipaddrv6($realifgw)) {
1207
		route_add_or_change("-host -inet6 {$gif['remote-addr']} {$realifgw}");
1208
	}
1209

    
1210
	interfaces_bring_up($gifif);
1211

    
1212
	return $gifif;
1213
}
1214

    
1215
/* Build a list of IPsec interfaces */
1216
function interface_ipsec_vti_list_p1($ph1ent) {
1217
	global $config;
1218
	$iface_list = array();
1219

    
1220
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1221
		return $iface_list;
1222
	}
1223

    
1224
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1225
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1226
		return $iface_list;
1227
	}
1228

    
1229
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1230
	if (!isset($ph1ent['mobile']) && ($keyexchange == 'ikev1' || isset($ph1ent['splitconn']))) {
1231
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1232
			$iface_list["ipsec{$ph1ent['ikeid']}00{$idx}"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1233
		}
1234
	} else {
1235
		/* For IKEv2, only create one interface with additional addresses as aliases */
1236
		$iface_list["ipsec{$ph1ent['ikeid']}000"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1237
	}
1238
	return $iface_list;
1239
}
1240
function interface_ipsec_vti_list_all() {
1241
	global $config;
1242
	$iface_list = array();
1243
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1244
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1245
			if ($ph1ent['disabled']) {
1246
				continue;
1247
			}
1248
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1249
		}
1250
	}
1251
	return $iface_list;
1252
}
1253

    
1254
function interface_ipsec_vti_configure($ph1ent) {
1255
	global $config;
1256

    
1257
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1258
		return false;
1259
	}
1260

    
1261
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1262
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1263
		return false;
1264
	}
1265

    
1266
	$left_spec = ipsec_get_phase1_src($ph1ent);
1267
	$right_spec = $ph1ent['remote-gateway'];
1268

    
1269
	$iface_addrs = array();
1270

    
1271
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1272
	if (!isset($ph1ent['mobile']) && ($keyexchange == 'ikev1' || isset($ph1ent['splitconn']))) {
1273
		/* Form a single interface for each P2 entry */
1274
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1275
			$ipsecifnum = "{$ph1ent['ikeid']}00{$idx}";
1276
			if (!is_array($iface_addrs[$ipsecifnum])) {
1277
				$iface_addrs[$ipsecifnum] = array();
1278
			}
1279
			$vtisub['alias'] = "";
1280
			$iface_addrs[$ipsecifnum][] = $vtisub;
1281
		}
1282
	} else {
1283
		/* For IKEv2, only create one interface with additional addresses as aliases */
1284
		$ipsecifnum = "{$ph1ent['ikeid']}000";
1285
		if (!is_array($iface_addrs[$ipsecifnum])) {
1286
			$iface_addrs[$ipsecifnum] = array();
1287
		}
1288
		$have_v4 = false;
1289
		$have_v6 = false;
1290
		foreach ($vtisubnet_spec as $vtisub) {
1291
			// Alias stuff
1292
			$vtisub['alias'] = "";
1293
			if (is_ipaddrv6($vtisub['left'])) {
1294
				if ($have_v6) {
1295
					$vtisub['alias'] = " alias";
1296
				}
1297
				$have_v6 = true;
1298
			} else {
1299
				if ($have_v4) {
1300
					$vtisub['alias'] = " alias";
1301
				}
1302
				$have_v4 = true;
1303
			}
1304
			$iface_addrs[$ipsecifnum][] = $vtisub;
1305
		}
1306
	}
1307

    
1308
	foreach ($iface_addrs as $ipsecifnum => $addrs) {
1309
		$ipsecif = "ipsec{$ipsecifnum}";
1310
		if (!is_array($addrs)) {
1311
			continue;
1312
		}
1313
		// Create IPsec interface
1314
		if (platform_booting() || !does_interface_exist($ipsecif)) {
1315
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy", false);
1316
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1317
		} else {
1318
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1319
		}
1320

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

    
1325
		/* Loop through all of the addresses for this interface and apply them as needed */
1326
		foreach ($addrs as $addr) {
1327
			// apply interface addresses
1328
			if (is_ipaddrv6($addr['left'])) {
1329
				$inet = "inet6";
1330
				$gwtype = "v6";
1331
			} else {
1332
				$inet = "inet";
1333
				$gwtype = "";
1334
			}
1335

    
1336
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . escapeshellarg($addr['right']) . $addr['alias'], false);
1337
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1338
			if (empty($addr['alias'])) {
1339
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1340
			}
1341
		}
1342
		if (!platform_booting()) {
1343
			system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1344
		}
1345
	}
1346
}
1347

    
1348
function interfaces_ipsec_vti_configure() {
1349
	global $config;
1350
	if (platform_booting()) {
1351
		echo gettext("Configuring IPsec VTI interfaces...");
1352
	}
1353
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1354
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1355
			if ($ph1ent['disabled']) {
1356
				continue;
1357
			}
1358
			interface_ipsec_vti_configure($ph1ent);
1359
		}
1360
	}
1361
	if (platform_booting()) {
1362
		echo gettext("done.") . "\n";
1363
	}
1364
}
1365

    
1366
function interfaces_configure() {
1367
	global $config, $g;
1368

    
1369
	/* Set up our loopback interface */
1370
	interfaces_loopback_configure();
1371

    
1372
	/* create the unconfigured wireless clones */
1373
	interfaces_create_wireless_clones();
1374

    
1375
	/* set up LAGG virtual interfaces */
1376
	interfaces_lagg_configure();
1377

    
1378
	/* set up VLAN virtual interfaces */
1379
	interfaces_vlan_configure();
1380

    
1381
	interfaces_qinq_configure();
1382

    
1383
	/* set up IPsec VTI interfaces */
1384
	interfaces_ipsec_vti_configure();
1385

    
1386
	$iflist = get_configured_interface_with_descr();
1387
	$delayed_list = array();
1388
	$bridge_list = array();
1389
	$track6_list = array();
1390

    
1391
	/* This is needed to speedup interfaces on bootup. */
1392
	$reload = false;
1393
	if (!platform_booting()) {
1394
		$reload = true;
1395
	}
1396

    
1397
	foreach ($iflist as $if => $ifname) {
1398
		$realif = $config['interfaces'][$if]['if'];
1399
		if (strstr($realif, "bridge")) {
1400
			$bridge_list[$if] = $ifname;
1401
		} else if (strstr($realif, "gre")) {
1402
			$delayed_list[$if] = $ifname;
1403
		} else if (strstr($realif, "gif")) {
1404
			$delayed_list[$if] = $ifname;
1405
		} else if (strstr($realif, "ovpn")) {
1406
			//echo "Delaying OpenVPN interface configuration...done.\n";
1407
			continue;
1408
		} else if (strstr($realif, "ipsec")) {
1409
			continue;
1410
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1411
			$track6_list[$if] = $ifname;
1412
		} else {
1413
			if (platform_booting()) {
1414
				printf(gettext("Configuring %s interface..."), $ifname);
1415
			}
1416

    
1417
			if ($g['debug']) {
1418
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1419
			}
1420
			interface_configure($if, $reload);
1421
			if (platform_booting()) {
1422
				echo gettext("done.") . "\n";
1423
			}
1424
		}
1425
	}
1426

    
1427
	/*
1428
	 * NOTE: The following function parameter consists of
1429
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1430
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1431
	 */
1432

    
1433
	/* set up GRE virtual interfaces */
1434
	interfaces_gre_configure(1);
1435

    
1436
	/* set up GIF virtual interfaces */
1437
	interfaces_gif_configure(1);
1438

    
1439
	/* set up BRIDGe virtual interfaces */
1440
	interfaces_bridge_configure(1);
1441

    
1442
	foreach ($track6_list as $if => $ifname) {
1443
		if (platform_booting()) {
1444
			printf(gettext("Configuring %s interface..."), $ifname);
1445
		}
1446
		if ($g['debug']) {
1447
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1448
		}
1449

    
1450
		interface_configure($if, $reload);
1451

    
1452
		if (platform_booting()) {
1453
			echo gettext("done.") . "\n";
1454
		}
1455
	}
1456

    
1457
	/* bring up vip interfaces */
1458
	interfaces_vips_configure();
1459

    
1460
	/* set up GRE virtual interfaces */
1461
	interfaces_gre_configure(2);
1462

    
1463
	/* set up GIF virtual interfaces */
1464
	interfaces_gif_configure(2);
1465

    
1466
	foreach ($delayed_list as $if => $ifname) {
1467
		if (platform_booting()) {
1468
			printf(gettext("Configuring %s interface..."), $ifname);
1469
		}
1470
		if ($g['debug']) {
1471
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1472
		}
1473

    
1474
		interface_configure($if, $reload);
1475

    
1476
		if (platform_booting()) {
1477
			echo gettext("done.") . "\n";
1478
		}
1479
	}
1480

    
1481
	/* set up BRIDGe virtual interfaces */
1482
	interfaces_bridge_configure(2);
1483

    
1484
	foreach ($bridge_list as $if => $ifname) {
1485
		if (platform_booting()) {
1486
			printf(gettext("Configuring %s interface..."), $ifname);
1487
		}
1488
		if ($g['debug']) {
1489
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1490
		}
1491

    
1492
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1493
		// redmine #3997
1494
		interface_reconfigure($if, $reload);
1495
		interfaces_vips_configure($if);
1496

    
1497
		if (platform_booting()) {
1498
			echo gettext("done.") . "\n";
1499
		}
1500
	}
1501

    
1502
	/* configure interface groups */
1503
	interfaces_group_setup();
1504

    
1505
	if (!platform_booting()) {
1506
		/* reconfigure static routes (kernel may have deleted them) */
1507
		system_routing_configure();
1508

    
1509
		/* reload IPsec tunnels */
1510
		vpn_ipsec_configure();
1511

    
1512
		/* restart dns servers (defering dhcpd reload) */
1513
		if (isset($config['dnsmasq']['enable'])) {
1514
			services_dnsmasq_configure(false);
1515
		}
1516
		if (isset($config['unbound']['enable'])) {
1517
			services_unbound_configure(false);
1518
		}
1519

    
1520
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1521
		services_dhcpd_configure();
1522
	}
1523

    
1524
	return 0;
1525
}
1526

    
1527
function interface_reconfigure($interface = "wan", $reloadall = false) {
1528
	interface_bring_down($interface);
1529
	interface_configure($interface, $reloadall);
1530
}
1531

    
1532
function interface_vip_bring_down($vip) {
1533
	global $g;
1534

    
1535
	$vipif = get_real_interface($vip['interface']);
1536
	switch ($vip['mode']) {
1537
		case "proxyarp":
1538
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1539
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1540
			}
1541
			break;
1542
		case "ipalias":
1543
			if (does_interface_exist($vipif)) {
1544
				if (is_ipaddrv6($vip['subnet'])) {
1545
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1546
				} else {
1547
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1548
				}
1549
			}
1550
			break;
1551
		case "carp":
1552
			/* XXX: Is enough to delete ip address? */
1553
			if (does_interface_exist($vipif)) {
1554
				if (is_ipaddrv6($vip['subnet'])) {
1555
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1556
				} else {
1557
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1558
				}
1559
			}
1560
			break;
1561
	}
1562
}
1563

    
1564
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1565
	global $config, $g;
1566

    
1567
	if (!isset($config['interfaces'][$interface])) {
1568
		return;
1569
	}
1570

    
1571
	if ($g['debug']) {
1572
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1573
	}
1574

    
1575
	/*
1576
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1577
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1578
	 * Keep this in mind while doing changes here!
1579
	 */
1580
	if ($ifacecfg === false) {
1581
		$ifcfg = $config['interfaces'][$interface];
1582
		$ppps = $config['ppps']['ppp'];
1583
		$realif = get_real_interface($interface);
1584
		$realifv6 = get_real_interface($interface, "inet6", true);
1585
	} elseif (!is_array($ifacecfg)) {
1586
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1587
		$ifcfg = $config['interfaces'][$interface];
1588
		$ppps = $config['ppps']['ppp'];
1589
		$realif = get_real_interface($interface);
1590
		$realifv6 = get_real_interface($interface, "inet6", true);
1591
	} else {
1592
		$ifcfg = $ifacecfg['ifcfg'];
1593
		$ppps = $ifacecfg['ppps'];
1594
		if (isset($ifacecfg['ifcfg']['realif'])) {
1595
			$realif = $ifacecfg['ifcfg']['realif'];
1596
			/* XXX: Any better way? */
1597
			$realifv6 = $realif;
1598
		} else {
1599
			$realif = get_real_interface($interface);
1600
			$realifv6 = get_real_interface($interface, "inet6", true);
1601
		}
1602
	}
1603

    
1604
	switch ($ifcfg['ipaddr']) {
1605
		case "ppp":
1606
		case "pppoe":
1607
		case "pptp":
1608
		case "l2tp":
1609
			if (is_array($ppps) && count($ppps)) {
1610
				foreach ($ppps as $pppid => $ppp) {
1611
					if ($realif == $ppp['if']) {
1612
						if (isset($ppp['ondemand']) && !$destroy) {
1613
							send_event("interface reconfigure {$interface}");
1614
							break;
1615
						}
1616
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1617
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1618
							sleep(2);
1619
						}
1620
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1621
						break;
1622
					}
1623
				}
1624
			}
1625
			break;
1626
		case "dhcp":
1627
			kill_dhclient_process($realif);
1628
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1629
			if (does_interface_exist("$realif")) {
1630
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1631
				interface_vip_cleanup($interface, "inet4");
1632
				if ($destroy == true) {
1633
					pfSense_interface_flags($realif, -IFF_UP);
1634
				}
1635
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1636
			}
1637
			break;
1638
		default:
1639
			if (does_interface_exist("$realif")) {
1640
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1641
				interface_vip_cleanup($interface, "inet4");
1642
				if ($destroy == true) {
1643
					pfSense_interface_flags($realif, -IFF_UP);
1644
				}
1645
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1646
			}
1647
			break;
1648
	}
1649

    
1650
	$track6 = array();
1651
	switch ($ifcfg['ipaddrv6']) {
1652
		case "slaac":
1653
		case "dhcp6":
1654
			kill_dhcp6client_process($realif, $destroy, false);
1655
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1656
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1657
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1658
			if (does_interface_exist($realifv6)) {
1659
				$ip6 = find_interface_ipv6($realifv6);
1660
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1661
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1662
				}
1663
				interface_vip_cleanup($interface, "inet6");
1664
				if ($destroy == true) {
1665
					pfSense_interface_flags($realif, -IFF_UP);
1666
				}
1667
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1668
			}
1669
			$track6 = link_interface_to_track6($interface);
1670
			break;
1671
		case "6rd":
1672
		case "6to4":
1673
			$realif = "{$interface}_stf";
1674
			if (does_interface_exist("$realif")) {
1675
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1676
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1677
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1678
					$destroy = true;
1679
				} else {
1680
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1681
					$ip6 = get_interface_ipv6($interface);
1682
					if (is_ipaddrv6($ip6)) {
1683
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1684
					}
1685
				}
1686
				interface_vip_cleanup($interface, "inet6");
1687
				if ($destroy == true) {
1688
					pfSense_interface_flags($realif, -IFF_UP);
1689
				}
1690
			}
1691
			$track6 = link_interface_to_track6($interface);
1692
			break;
1693
		default:
1694
			if (does_interface_exist("$realif")) {
1695
				$ip6 = get_interface_ipv6($interface);
1696
				if (is_ipaddrv6($ip6)) {
1697
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1698
				}
1699
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1700
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1701
				}
1702
				interface_vip_cleanup($interface, "inet6");
1703
				if ($destroy == true) {
1704
					pfSense_interface_flags($realif, -IFF_UP);
1705
				}
1706
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1707
			}
1708
			$track6 = link_interface_to_track6($interface);
1709
			break;
1710
	}
1711

    
1712
	if (!empty($track6) && is_array($track6)) {
1713
		if (!function_exists('services_dhcpd_configure')) {
1714
			require_once('services.inc');
1715
		}
1716
		/* Bring down radvd and dhcp6 on these interfaces */
1717
		services_dhcpd_configure('inet6', $track6);
1718
	}
1719

    
1720
	$old_router = '';
1721
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1722
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1723
	}
1724

    
1725
	/* remove interface up file if it exists */
1726
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1727
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1728
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1729
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1730
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1731
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1732
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1733

    
1734
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1735
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1736
	if (is_array($ifcfg['wireless'])) {
1737
		kill_hostapd($realif);
1738
		mwexec(kill_wpasupplicant($realif));
1739
	}
1740

    
1741
	if ($destroy == true) {
1742
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^ipsec|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1743
			pfSense_interface_destroy($realif);
1744
		}
1745
	}
1746

    
1747
	return;
1748
}
1749

    
1750
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1751
	global $config;
1752
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1753
		unset($config["virtualip_carp_maintenancemode"]);
1754
		write_config("Leave CARP maintenance mode");
1755
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1756
		$config["virtualip_carp_maintenancemode"] = true;
1757
		write_config(gettext("Enter CARP maintenance mode"));
1758
	}
1759

    
1760
	$viparr = &$config['virtualip']['vip'];
1761

    
1762
	if (is_array($viparr)) {
1763
		foreach ($viparr as $vip) {
1764
			if ($vip['mode'] == "carp") {
1765
				interface_carp_configure($vip);
1766
			}
1767
		}
1768
	}
1769
}
1770

    
1771
function interface_wait_tentative($interface, $timeout = 10) {
1772
	if (!does_interface_exist($interface)) {
1773
		return false;
1774
	}
1775

    
1776
	$time = 0;
1777
	while ($time <= $timeout) {
1778
		$if = pfSense_get_interface_addresses($interface);
1779
		if (!isset($if['tentative'])) {
1780
			return true;
1781
		}
1782
		sleep(1);
1783
		$time++;
1784
	}
1785

    
1786
	return false;
1787
}
1788

    
1789
function interface_isppp_type($interface) {
1790
	global $config;
1791

    
1792
	if (!is_array($config['interfaces'][$interface])) {
1793
		return false;
1794
	}
1795

    
1796
	switch ($config['interfaces'][$interface]['ipaddr']) {
1797
		case 'pptp':
1798
		case 'l2tp':
1799
		case 'pppoe':
1800
		case 'ppp':
1801
			return true;
1802
			break;
1803
		default:
1804
			return false;
1805
			break;
1806
	}
1807
}
1808

    
1809
function interfaces_ptpid_used($ptpid) {
1810
	global $config;
1811

    
1812
	if (is_array($config['ppps']['ppp'])) {
1813
		foreach ($config['ppps']['ppp'] as & $settings) {
1814
			if ($ptpid == $settings['ptpid']) {
1815
				return true;
1816
			}
1817
		}
1818
	}
1819

    
1820
	return false;
1821
}
1822

    
1823
function interfaces_ptpid_next() {
1824

    
1825
	$ptpid = 0;
1826
	while (interfaces_ptpid_used($ptpid)) {
1827
		$ptpid++;
1828
	}
1829

    
1830
	return $ptpid;
1831
}
1832

    
1833
function getMPDCRONSettings($pppif) {
1834
	global $config;
1835

    
1836
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1837
	if (is_array($config['cron']['item'])) {
1838
		foreach ($config['cron']['item'] as $i => $item) {
1839
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1840
				return array("ID" => $i, "ITEM" => $item);
1841
			}
1842
		}
1843
	}
1844

    
1845
	return NULL;
1846
}
1847

    
1848
function handle_pppoe_reset($post_array) {
1849
	global $config, $g;
1850

    
1851
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1852
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1853

    
1854
	if (!is_array($config['cron']['item'])) {
1855
		$config['cron']['item'] = array();
1856
	}
1857

    
1858
	$itemhash = getMPDCRONSettings($pppif);
1859

    
1860
	// reset cron items if necessary and return
1861
	if (empty($post_array['pppoe-reset-type'])) {
1862
		if (isset($itemhash)) {
1863
			unset($config['cron']['item'][$itemhash['ID']]);
1864
		}
1865
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1866
		return;
1867
	}
1868

    
1869
	if (empty($itemhash)) {
1870
		$itemhash = array();
1871
	}
1872
	$item = array();
1873
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1874
		$item['minute'] = $post_array['pppoe_resetminute'];
1875
		$item['hour'] = $post_array['pppoe_resethour'];
1876
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1877
			$date = explode("/", $post_array['pppoe_resetdate']);
1878
			$item['mday'] = $date[1];
1879
			$item['month'] = $date[0];
1880
		} else {
1881
			$item['mday'] = "*";
1882
			$item['month'] = "*";
1883
		}
1884
		$item['wday'] = "*";
1885
		$item['who'] = "root";
1886
		$item['command'] = $cron_cmd_file;
1887
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1888
		switch ($post_array['pppoe_pr_preset_val']) {
1889
			case "monthly":
1890
				$item['minute'] = "0";
1891
				$item['hour'] = "0";
1892
				$item['mday'] = "1";
1893
				$item['month'] = "*";
1894
				$item['wday'] = "*";
1895
				break;
1896
			case "weekly":
1897
				$item['minute'] = "0";
1898
				$item['hour'] = "0";
1899
				$item['mday'] = "*";
1900
				$item['month'] = "*";
1901
				$item['wday'] = "0";
1902
				break;
1903
			case "daily":
1904
				$item['minute'] = "0";
1905
				$item['hour'] = "0";
1906
				$item['mday'] = "*";
1907
				$item['month'] = "*";
1908
				$item['wday'] = "*";
1909
				break;
1910
			case "hourly":
1911
				$item['minute'] = "0";
1912
				$item['hour'] = "*";
1913
				$item['mday'] = "*";
1914
				$item['month'] = "*";
1915
				$item['wday'] = "*";
1916
				break;
1917
		} // end switch
1918
		$item['who'] = "root";
1919
		$item['command'] = $cron_cmd_file;
1920
	}
1921
	if (empty($item)) {
1922
		return;
1923
	}
1924
	if (isset($itemhash['ID'])) {
1925
		$config['cron']['item'][$itemhash['ID']] = $item;
1926
	} else {
1927
		$config['cron']['item'][] = $item;
1928
	}
1929
}
1930

    
1931
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
1932
	global $config;
1933
	$ppp_list = array();
1934
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1935
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1936
			$ports = explode(",", $ppp['ports']);
1937
			foreach($ports as $port) {
1938
				foreach($triggerinterfaces as $vip) {
1939
					if ($port == "_vip{$vip['uniqid']}") {
1940
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
1941
						$ppp_list[$if] = 1;
1942
					}
1943
				}
1944
			}
1945
		}
1946
	}
1947
	foreach($ppp_list as $pppif => $dummy) {
1948
		interface_ppps_configure($pppif);
1949
	}
1950
}
1951

    
1952
/*
1953
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1954
 * It writes the mpd config file to /var/etc every time the link is opened.
1955
 */
1956
function interface_ppps_configure($interface) {
1957
	global $config, $g;
1958

    
1959
	/* Return for unassigned interfaces. This is a minimum requirement. */
1960
	if (empty($config['interfaces'][$interface])) {
1961
		return 0;
1962
	}
1963
	$ifcfg = $config['interfaces'][$interface];
1964
	if (!isset($ifcfg['enable'])) {
1965
		return 0;
1966
	}
1967

    
1968
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1969
	if (!is_dir("/var/spool/lock")) {
1970
		mkdir("/var/spool/lock", 0777, true);
1971
	}
1972
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1973
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1974
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1975
	}
1976

    
1977
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1978
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1979
			if ($ifcfg['if'] == $ppp['if']) {
1980
				break;
1981
			}
1982
		}
1983
	}
1984
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
1985
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1986
		return 0;
1987
	}
1988
	$pppif = $ifcfg['if'];
1989
	if ($ppp['type'] == "ppp") {
1990
		$type = "modem";
1991
	} else {
1992
		$type = $ppp['type'];
1993
	}
1994
	$upper_type = strtoupper($ppp['type']);
1995

    
1996
	/* XXX: This does not make sense and may create trouble
1997
	 * comment it for now to be removed later on.
1998
	if (platform_booting()) {
1999
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
2000
		echo "starting {$pppif} link...";
2001
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
2002
			return 0;
2003
	}
2004
	*/
2005
	$confports = explode(',', $ppp['ports']);
2006
	if ($type == "modem") {
2007
		$ports = $confports;
2008
	} else {
2009
		$ports = array();
2010
		foreach ($confports as $pid => $port) {
2011
			if (strstr($port, "_vip")) {
2012
				if (get_carp_interface_status($port) != "MASTER") {
2013
					continue;
2014
				}
2015
			}
2016
			$ports[$pid] = get_real_interface($port);
2017
			if (empty($ports[$pid])) {
2018
				return 0;
2019
			}
2020
		}
2021
	}
2022
	$localips = explode(',', $ppp['localip']);
2023
	$gateways = explode(',', $ppp['gateway']);
2024
	$subnets = explode(',', $ppp['subnet']);
2025

    
2026
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2027
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2028
	 */
2029
	foreach ($ports as $pid => $port) {
2030
		switch ($ppp['type']) {
2031
			case "pppoe":
2032
				/* Bring the parent interface up */
2033
				interfaces_bring_up($port);
2034
				pfSense_ngctl_attach(".", $port);
2035
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2036
				$ngif = str_replace(".", "_", $port);
2037
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2038
				break;
2039
			case "pptp":
2040
			case "l2tp":
2041
				/* configure interface */
2042
				if (is_ipaddr($localips[$pid])) {
2043
					// Manually configure interface IP/subnet
2044
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2045
					interfaces_bring_up($port);
2046
				} else if (empty($localips[$pid])) {
2047
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2048
				}
2049

    
2050
				if (!is_ipaddr($localips[$pid])) {
2051
					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));
2052
					$localips[$pid] = "0.0.0.0";
2053
				}
2054
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2055
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2056
				}
2057
				if (!is_ipaddr($gateways[$pid])) {
2058
					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));
2059
					return 0;
2060
				}
2061
				pfSense_ngctl_attach(".", $port);
2062
				break;
2063
			case "ppp":
2064
				if (!file_exists("{$port}")) {
2065
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2066
					return 0;
2067
				}
2068
				break;
2069
			default:
2070
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2071
				break;
2072
		}
2073
	}
2074

    
2075
	if (is_array($ports) && count($ports) > 1) {
2076
		$multilink = "enable";
2077
	} else {
2078
		$multilink = "disable";
2079
	}
2080

    
2081
	if ($type == "modem") {
2082
		if (is_ipaddr($ppp['localip'])) {
2083
			$localip = $ppp['localip'];
2084
		} else {
2085
			$localip = '0.0.0.0';
2086
		}
2087

    
2088
		if (is_ipaddr($ppp['gateway'])) {
2089
			$gateway = $ppp['gateway'];
2090
		} else {
2091
			$gateway = "10.64.64.{$pppid}";
2092
		}
2093
		$ranges = "{$localip}/0 {$gateway}/0";
2094

    
2095
		if (empty($ppp['apnum'])) {
2096
			$ppp['apnum'] = 1;
2097
		}
2098
	} else {
2099
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2100
	}
2101

    
2102
	if (isset($ppp['ondemand'])) {
2103
		$ondemand = "enable";
2104
	} else {
2105
		$ondemand = "disable";
2106
	}
2107
	if (!isset($ppp['idletimeout'])) {
2108
		$ppp['idletimeout'] = 0;
2109
	}
2110

    
2111
	if (empty($ppp['username']) && $type == "modem") {
2112
		$ppp['username'] = "user";
2113
		$ppp['password'] = "none";
2114
	}
2115
	if (empty($ppp['password']) && $type == "modem") {
2116
		$passwd = "none";
2117
	} else {
2118
		$passwd = base64_decode($ppp['password']);
2119
	}
2120

    
2121
	$bandwidths = explode(',', $ppp['bandwidth']);
2122
	$defaultmtu = "1492";
2123
	if (!empty($ifcfg['mtu'])) {
2124
		$defaultmtu = intval($ifcfg['mtu']);
2125
	}
2126
	if (isset($ppp['mtu'])) {
2127
		$mtus = explode(',', $ppp['mtu']);
2128
	}
2129
	if (isset($ppp['mru'])) {
2130
		$mrus = explode(',', $ppp['mru']);
2131
	}
2132
	if (isset($ppp['mrru'])) {
2133
		$mrrus = explode(',', $ppp['mrru']);
2134
	}
2135

    
2136
	// Construct the mpd.conf file
2137
	$mpdconf = <<<EOD
2138
startup:
2139
	# configure the console
2140
	set console close
2141
	# configure the web server
2142
	set web close
2143

    
2144
default:
2145
{$ppp['type']}client:
2146
	create bundle static {$interface}
2147
	set bundle enable ipv6cp
2148
	set iface name {$pppif}
2149

    
2150
EOD;
2151
	$setdefaultgw = false;
2152
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2153
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2154
	if ($defgw4['interface'] == $interface) {
2155
		$setdefaultgw = true;
2156
	}
2157

    
2158
/* Omit this, we maintain the default route by other means, and it causes problems with
2159
 * default gateway switching. See redmine #1837 for original issue
2160
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2161
 * edge case. redmine #6495 open to address.
2162
 */
2163
	if ($setdefaultgw == true) {
2164
		$mpdconf .= <<<EOD
2165
	set iface route default
2166

    
2167
EOD;
2168
	}
2169

    
2170
	$mpdconf .= <<<EOD
2171
	set iface {$ondemand} on-demand
2172
	set iface idle {$ppp['idletimeout']}
2173

    
2174
EOD;
2175

    
2176
	if (isset($ppp['ondemand'])) {
2177
		$mpdconf .= <<<EOD
2178
	set iface addrs 10.10.1.1 10.10.1.2
2179

    
2180
EOD;
2181
	}
2182

    
2183
	if (isset($ppp['tcpmssfix'])) {
2184
		$tcpmss = "disable";
2185
	} else {
2186
		$tcpmss = "enable";
2187
	}
2188
	$mpdconf .= <<<EOD
2189
	set iface {$tcpmss} tcpmssfix
2190

    
2191
EOD;
2192

    
2193
	$mpdconf .= <<<EOD
2194
	set iface up-script /usr/local/sbin/ppp-linkup
2195
	set iface down-script /usr/local/sbin/ppp-linkdown
2196
	set ipcp ranges {$ranges}
2197

    
2198
EOD;
2199
	if (isset($ppp['vjcomp'])) {
2200
		$mpdconf .= <<<EOD
2201
	set ipcp no vjcomp
2202

    
2203
EOD;
2204
	}
2205

    
2206
	if (isset($config['system']['dnsallowoverride'])) {
2207
		$mpdconf .= <<<EOD
2208
	set ipcp enable req-pri-dns
2209
	set ipcp enable req-sec-dns
2210

    
2211
EOD;
2212
	}
2213

    
2214
	if (!isset($ppp['verbose_log'])) {
2215
		$mpdconf .= <<<EOD
2216
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2217

    
2218
EOD;
2219
	}
2220

    
2221
	foreach ($ports as $pid => $port) {
2222
		$port = get_real_interface($port);
2223
		$mpdconf .= <<<EOD
2224

    
2225
	create link static {$interface}_link{$pid} {$type}
2226
	set link action bundle {$interface}
2227
	set link {$multilink} multilink
2228
	set link keep-alive 10 60
2229
	set link max-redial 0
2230

    
2231
EOD;
2232
		if (isset($ppp['shortseq'])) {
2233
			$mpdconf .= <<<EOD
2234
	set link no shortseq
2235

    
2236
EOD;
2237
		}
2238

    
2239
		if (isset($ppp['acfcomp'])) {
2240
			$mpdconf .= <<<EOD
2241
	set link no acfcomp
2242

    
2243
EOD;
2244
		}
2245

    
2246
		if (isset($ppp['protocomp'])) {
2247
			$mpdconf .= <<<EOD
2248
	set link no protocomp
2249

    
2250
EOD;
2251
		}
2252

    
2253
		$mpdconf .= <<<EOD
2254
	set link disable chap pap
2255
	set link accept chap pap eap
2256
	set link disable incoming
2257

    
2258
EOD;
2259

    
2260

    
2261
		if (!empty($bandwidths[$pid])) {
2262
			$mpdconf .= <<<EOD
2263
	set link bandwidth {$bandwidths[$pid]}
2264

    
2265
EOD;
2266
		}
2267

    
2268
		if (empty($mtus[$pid])) {
2269
			$mtus[$pid] = $defaultmtu;
2270
		}
2271
		if ($type == "pppoe") {
2272
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2273
				$mtus[$pid] = get_interface_mtu($port) - 8;
2274
			}
2275
		}
2276
		if (! ($type == "pppoe" && $mtus[$pid] > 1492) ) {
2277
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2278
			$mpdconf .= <<<EOD
2279
	set link mtu {$mtus[$pid]}
2280

    
2281
EOD;
2282
		}
2283

    
2284
		if (!empty($mrus[$pid])) {
2285
			$mpdconf .= <<<EOD
2286
	set link mru {$mrus[$pid]}
2287

    
2288
EOD;
2289
		}
2290

    
2291
		if (!empty($mrrus[$pid])) {
2292
			$mpdconf .= <<<EOD
2293
	set link mrru {$mrrus[$pid]}
2294

    
2295
EOD;
2296
		}
2297

    
2298
		$mpdconf .= <<<EOD
2299
	set auth authname "{$ppp['username']}"
2300
	set auth password {$passwd}
2301

    
2302
EOD;
2303
		if ($type == "modem") {
2304
			$mpdconf .= <<<EOD
2305
	set modem device {$ppp['ports']}
2306
	set modem script DialPeer
2307
	set modem idle-script Ringback
2308
	set modem watch -cd
2309
	set modem var \$DialPrefix "DT"
2310
	set modem var \$Telephone "{$ppp['phone']}"
2311

    
2312
EOD;
2313
		}
2314
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2315
			$mpdconf .= <<<EOD
2316
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2317

    
2318
EOD;
2319
		}
2320
		if (isset($ppp['initstr']) && $type == "modem") {
2321
			$initstr = base64_decode($ppp['initstr']);
2322
			$mpdconf .= <<<EOD
2323
	set modem var \$InitString "{$initstr}"
2324

    
2325
EOD;
2326
		}
2327
		if (isset($ppp['simpin']) && $type == "modem") {
2328
			if ($ppp['pin-wait'] == "") {
2329
				$ppp['pin-wait'] = 0;
2330
			}
2331
			$mpdconf .= <<<EOD
2332
	set modem var \$SimPin "{$ppp['simpin']}"
2333
	set modem var \$PinWait "{$ppp['pin-wait']}"
2334

    
2335
EOD;
2336
		}
2337
		if (isset($ppp['apn']) && $type == "modem") {
2338
			$mpdconf .= <<<EOD
2339
	set modem var \$APN "{$ppp['apn']}"
2340
	set modem var \$APNum "{$ppp['apnum']}"
2341

    
2342
EOD;
2343
		}
2344
		if ($type == "pppoe") {
2345
			// Send a null service name if none is set.
2346
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2347
			$mpdconf .= <<<EOD
2348
	set pppoe service "{$provider}"
2349

    
2350
EOD;
2351
		}
2352
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
2353
			$mpdconf .= <<<EOD
2354
	set pppoe max-payload {$mtus[$pid]}
2355

    
2356
EOD;
2357
		}
2358
		if ($type == "pppoe") {
2359
			$mpdconf .= <<<EOD
2360
	set pppoe iface {$port}
2361

    
2362
EOD;
2363
		}
2364

    
2365
		if ($type == "pptp" || $type == "l2tp") {
2366
			$mpdconf .= <<<EOD
2367
	set {$type} self {$localips[$pid]}
2368
	set {$type} peer {$gateways[$pid]}
2369

    
2370
EOD;
2371
		}
2372

    
2373
		$mpdconf .= "\topen\n";
2374
	} //end foreach ($port)
2375

    
2376

    
2377
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2378
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2379
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2380
	} else {
2381
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2382
		if (!$fd) {
2383
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2384
			return 0;
2385
		}
2386
		// Write out mpd_ppp.conf
2387
		fwrite($fd, $mpdconf);
2388
		fclose($fd);
2389
		unset($mpdconf);
2390
	}
2391

    
2392
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2393
	if (isset($ppp['uptime'])) {
2394
		if (!file_exists("/conf/{$pppif}.log")) {
2395
			file_put_contents("/conf/{$pppif}.log", '');
2396
		}
2397
	} else {
2398
		if (file_exists("/conf/{$pppif}.log")) {
2399
			@unlink("/conf/{$pppif}.log");
2400
		}
2401
	}
2402

    
2403
	/* clean up old lock files */
2404
	foreach ($ports as $port) {
2405
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2406
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2407
		}
2408
	}
2409

    
2410
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2411
	/* random IPv6 interface identifier during boot. More details at */
2412
	/* https://forum.pfsense.org/index.php?topic=101967.msg570519#msg570519 */
2413
	if (platform_booting() && is_array($config['interfaces'])) {
2414
		$count = 0;
2415
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2416
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2417
				$tempaddr[$count]['if'] = $tempiface['if'];
2418
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2419
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2420
				$count++;
2421
			}
2422
			// Maximum /31 is is x.y.z.254/31
2423
			if ($count > 122) {
2424
				break;
2425
			}
2426
		}
2427
		unset($count);
2428
	}
2429

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

    
2435
	// Check for PPPoE periodic reset request
2436
	if ($type == "pppoe") {
2437
		if (!empty($ppp['pppoe-reset-type'])) {
2438
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2439
		} else {
2440
			interface_setup_pppoe_reset_file($ppp['if']);
2441
		}
2442
	}
2443
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2444
	$i = 0;
2445
	while ($i < 10) {
2446
		if (does_interface_exist($ppp['if'], true)) {
2447
			break;
2448
		}
2449
		sleep(3);
2450
		$i++;
2451
	}
2452

    
2453
	/* Remove all temporary bogon IPv4 addresses */
2454
	if (is_array($tempaddr)) {
2455
		foreach ($tempaddr as $tempiface) {
2456
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2457
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2458
			}
2459
		}
2460
		unset ($tempaddr);
2461
	}
2462

    
2463
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2464
	/* We should be able to launch the right version for each modem */
2465
	/* We can also guess the mondev from the manufacturer */
2466
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2467
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2468
	foreach ($ports as $port) {
2469
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2470
			$mondev = substr(basename($port), 0, -1);
2471
			$devlist = glob("/dev/{$mondev}?");
2472
			$mondev = basename(end($devlist));
2473
		}
2474
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2475
			$mondev = substr(basename($port), 0, -1) . "1";
2476
		}
2477
		if ($mondev != '') {
2478
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2479
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2480
		}
2481
	}
2482

    
2483
	return 1;
2484
}
2485

    
2486
function interfaces_sync_setup() {
2487
	global $g, $config;
2488

    
2489
	if (isset($config['system']['developerspew'])) {
2490
		$mt = microtime();
2491
		echo "interfaces_sync_setup() being called $mt\n";
2492
	}
2493

    
2494
	if (platform_booting()) {
2495
		echo gettext("Configuring CARP settings...");
2496
		mute_kernel_msgs();
2497
	}
2498

    
2499
	/* suck in configuration items */
2500
	if ($config['hasync']) {
2501
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2502
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2503
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2504
	} else {
2505
		unset($pfsyncinterface);
2506
		unset($pfsyncenabled);
2507
	}
2508

    
2509
	set_sysctl(array(
2510
		"net.inet.carp.preempt" => "1",
2511
		"net.inet.carp.log" => "1")
2512
	);
2513

    
2514
	if (!empty($pfsyncinterface)) {
2515
		$carp_sync_int = get_real_interface($pfsyncinterface);
2516
	} else {
2517
		unset($carp_sync_int);
2518
	}
2519

    
2520
	/* setup pfsync interface */
2521
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2522
		if (is_ipaddr($pfsyncpeerip)) {
2523
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2524
		} else {
2525
			$syncpeer = "-syncpeer";
2526
		}
2527

    
2528
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2529
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2530

    
2531
		sleep(1);
2532

    
2533
		/* 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
2534
		 * for existing sessions.
2535
		 */
2536
		log_error(gettext("waiting for pfsync..."));
2537
		$i = 0;
2538
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2539
			$i++;
2540
			sleep(1);
2541
		}
2542
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2543
		log_error(gettext("Configuring CARP settings finalize..."));
2544
	} else {
2545
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2546
	}
2547

    
2548
	$carplist = get_configured_vip_list('all', VIP_CARP);
2549
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2550
		set_single_sysctl("net.inet.carp.allow", "1");
2551
	} else {
2552
		set_single_sysctl("net.inet.carp.allow", "0");
2553
	}
2554

    
2555
	if (platform_booting()) {
2556
		unmute_kernel_msgs();
2557
		echo gettext("done.") . "\n";
2558
	}
2559
}
2560

    
2561
function interface_proxyarp_configure($interface = "") {
2562
	global $config, $g;
2563
	if (isset($config['system']['developerspew'])) {
2564
		$mt = microtime();
2565
		echo "interface_proxyarp_configure() being called $mt\n";
2566
	}
2567

    
2568
	/* kill any running choparp */
2569
	if (empty($interface)) {
2570
		killbyname("choparp");
2571
	} else {
2572
		$vipif = get_real_interface($interface);
2573
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2574
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2575
		}
2576
	}
2577

    
2578
	$paa = array();
2579
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2580

    
2581
		/* group by interface */
2582
		foreach ($config['virtualip']['vip'] as $vipent) {
2583
			if ($vipent['mode'] === "proxyarp") {
2584
				if ($vipent['interface']) {
2585
					$proxyif = $vipent['interface'];
2586
				} else {
2587
					$proxyif = "wan";
2588
				}
2589

    
2590
				if (!empty($interface) && $interface != $proxyif) {
2591
					continue;
2592
				}
2593

    
2594
				if (!is_array($paa[$proxyif])) {
2595
					$paa[$proxyif] = array();
2596
				}
2597

    
2598
				$paa[$proxyif][] = $vipent;
2599
			}
2600
		}
2601
	}
2602

    
2603
	if (!empty($interface)) {
2604
		if (is_array($paa[$interface])) {
2605
			$paaifip = get_interface_ip($interface);
2606
			if (!is_ipaddr($paaifip)) {
2607
				return;
2608
			}
2609
			$vipif = get_real_interface($interface);
2610
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2611
			$args .= $vipif . " auto";
2612
			foreach ($paa[$interface] as $paent) {
2613
				if (isset($paent['subnet'])) {
2614
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2615
				} else if (isset($paent['range'])) {
2616
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2617
				}
2618
			}
2619
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2620
		}
2621
	} else if (count($paa) > 0) {
2622
		foreach ($paa as $paif => $paents) {
2623
			$paaifip = get_interface_ip($paif);
2624
			if (!is_ipaddr($paaifip)) {
2625
				continue;
2626
			}
2627
			$vipif = get_real_interface($paif);
2628
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2629
			$args .= $vipif . " auto";
2630
			foreach ($paents as $paent) {
2631
				if (isset($paent['subnet'])) {
2632
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2633
				} else if (isset($paent['range'])) {
2634
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2635
				}
2636
			}
2637
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2638
		}
2639
	}
2640
}
2641

    
2642
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2643
	global $g, $config;
2644

    
2645
	if (is_array($config['virtualip']['vip'])) {
2646
		foreach ($config['virtualip']['vip'] as $vip) {
2647

    
2648
			$iface = $vip['interface'];
2649
			if (substr($iface, 0, 4) == "_vip")
2650
				$iface = get_configured_vip_interface($vip['interface']);
2651
			if ($iface != $interface)
2652
				continue;
2653
			if ($type == VIP_CARP) {
2654
				if ($vip['mode'] != "carp")
2655
					continue;
2656
			} elseif ($type == VIP_IPALIAS) {
2657
				if ($vip['mode'] != "ipalias")
2658
					continue;
2659
			} else {
2660
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2661
					continue;
2662
			}
2663

    
2664
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2665
				interface_vip_bring_down($vip);
2666
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2667
				interface_vip_bring_down($vip);
2668
			else if ($inet == "all")
2669
				interface_vip_bring_down($vip);
2670
		}
2671
	}
2672
}
2673

    
2674
function interfaces_vips_configure($interface = "") {
2675
	global $g, $config;
2676
	if (isset($config['system']['developerspew'])) {
2677
		$mt = microtime();
2678
		echo "interfaces_vips_configure() being called $mt\n";
2679
	}
2680
	$paa = array();
2681
	if (is_array($config['virtualip']['vip'])) {
2682
		$carp_setuped = false;
2683
		$anyproxyarp = false;
2684
		foreach ($config['virtualip']['vip'] as $vip) {
2685
			if ($interface <> "" && $vip['interface'] <> $interface) {
2686
				continue;
2687
			}
2688
			switch ($vip['mode']) {
2689
				case "proxyarp":
2690
					/* nothing it is handled on interface_proxyarp_configure() */
2691
					$anyproxyarp = true;
2692
					break;
2693
				case "ipalias":
2694
					interface_ipalias_configure($vip);
2695
					break;
2696
				case "carp":
2697
					if ($carp_setuped == false) {
2698
						$carp_setuped = true;
2699
					}
2700
					interface_carp_configure($vip);
2701
					break;
2702
			}
2703
		}
2704
		if ($carp_setuped == true) {
2705
			interfaces_sync_setup();
2706
		}
2707
		if ($anyproxyarp == true) {
2708
			interface_proxyarp_configure();
2709
		}
2710
	}
2711
}
2712

    
2713
function interface_ipalias_configure(&$vip) {
2714
	global $config;
2715

    
2716
	if ($vip['mode'] != 'ipalias') {
2717
		return;
2718
	}
2719

    
2720
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2721
	if ($realif != "lo0") {
2722
		$if = convert_real_interface_to_friendly_interface_name($realif);
2723
		if (!isset($config['interfaces'][$if]) ||
2724
		    !isset($config['interfaces'][$if]['enable'])) {
2725
			return;
2726
		}
2727
	}
2728

    
2729
	$af = 'inet';
2730
	if (is_ipaddrv6($vip['subnet'])) {
2731
		$af = 'inet6';
2732
	}
2733
	$iface = $vip['interface'];
2734
	$vhid = '';
2735
	if (substr($vip['interface'], 0, 4) == "_vip") {
2736
		$carpvip = get_configured_vip($vip['interface']);
2737
		$iface = $carpvip['interface'];
2738
		$vhid = "vhid {$carpvip['vhid']}";
2739
	}
2740
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2741
	unset($iface, $af, $realif, $carpvip, $vhid);
2742
}
2743

    
2744
function interface_carp_configure(&$vip) {
2745
	global $config, $g;
2746
	if (isset($config['system']['developerspew'])) {
2747
		$mt = microtime();
2748
		echo "interface_carp_configure() being called $mt\n";
2749
	}
2750

    
2751
	if ($vip['mode'] != "carp") {
2752
		return;
2753
	}
2754

    
2755
	$realif = get_real_interface($vip['interface']);
2756
	if (!does_interface_exist($realif)) {
2757
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2758
		return;
2759
	}
2760
	if ($realif != "lo0") {
2761
		if (!isset($config['interfaces'][$vip['interface']]) ||
2762
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
2763
			return;
2764
		}
2765
	}
2766

    
2767
	$vip_password = $vip['password'];
2768
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2769
	if ($vip['password'] != "") {
2770
		$password = " pass {$vip_password}";
2771
	}
2772

    
2773
	$advbase = "";
2774
	if (!empty($vip['advbase'])) {
2775
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2776
	}
2777

    
2778
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2779
	if ($carp_maintenancemode) {
2780
		$advskew = "advskew 254";
2781
	} else {
2782
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2783
	}
2784

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

    
2787
	if (is_ipaddrv4($vip['subnet'])) {
2788
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2789
	} else if (is_ipaddrv6($vip['subnet'])) {
2790
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2791
	}
2792

    
2793
	return $realif;
2794
}
2795

    
2796
function interface_wireless_clone($realif, $wlcfg) {
2797
	global $config, $g;
2798
	/*   Check to see if interface has been cloned as of yet.
2799
	 *   If it has not been cloned then go ahead and clone it.
2800
	 */
2801
	$needs_clone = false;
2802
	if (is_array($wlcfg['wireless'])) {
2803
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2804
	} else {
2805
		$wlcfg_mode = $wlcfg['mode'];
2806
	}
2807
	switch ($wlcfg_mode) {
2808
		case "hostap":
2809
			$mode = "wlanmode hostap";
2810
			break;
2811
		case "adhoc":
2812
			$mode = "wlanmode adhoc";
2813
			break;
2814
		default:
2815
			$mode = "";
2816
			break;
2817
	}
2818
	$baseif = interface_get_wireless_base($wlcfg['if']);
2819
	if (does_interface_exist($realif)) {
2820
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2821
		$ifconfig_str = implode($output);
2822
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2823
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2824
			$needs_clone = true;
2825
		}
2826
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2827
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2828
			$needs_clone = true;
2829
		}
2830
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2831
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2832
			$needs_clone = true;
2833
		}
2834
	} else {
2835
		$needs_clone = true;
2836
	}
2837

    
2838
	if ($needs_clone == true) {
2839
		/* remove previous instance if it exists */
2840
		if (does_interface_exist($realif)) {
2841
			pfSense_interface_destroy($realif);
2842
		}
2843

    
2844
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2845
		// Create the new wlan interface. FreeBSD returns the new interface name.
2846
		// example:  wlan2
2847
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2848
		if ($ret <> 0) {
2849
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2850
			return false;
2851
		}
2852
		$newif = trim($out[0]);
2853
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2854
		pfSense_interface_rename($newif, $realif);
2855
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2856
	}
2857
	return true;
2858
}
2859

    
2860
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2861
	global $config, $g;
2862

    
2863
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2864
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2865
				 'regdomain', 'regcountry', 'reglocation');
2866

    
2867
	if (!is_interface_wireless($ifcfg['if'])) {
2868
		return;
2869
	}
2870

    
2871
	$baseif = interface_get_wireless_base($ifcfg['if']);
2872

    
2873
	// Sync shared settings for assigned clones
2874
	$iflist = get_configured_interface_list(true);
2875
	foreach ($iflist as $if) {
2876
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2877
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2878
				foreach ($shared_settings as $setting) {
2879
					if ($sync_changes) {
2880
						if (isset($ifcfg['wireless'][$setting])) {
2881
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2882
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2883
							unset($config['interfaces'][$if]['wireless'][$setting]);
2884
						}
2885
					} else {
2886
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2887
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2888
						} else if (isset($ifcfg['wireless'][$setting])) {
2889
							unset($ifcfg['wireless'][$setting]);
2890
						}
2891
					}
2892
				}
2893
				if (!$sync_changes) {
2894
					break;
2895
				}
2896
			}
2897
		}
2898
	}
2899

    
2900
	// Read or write settings at shared area
2901
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2902
		foreach ($shared_settings as $setting) {
2903
			if ($sync_changes) {
2904
				if (isset($ifcfg['wireless'][$setting])) {
2905
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2906
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2907
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2908
				}
2909
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2910
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2911
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2912
				} else if (isset($ifcfg['wireless'][$setting])) {
2913
					unset($ifcfg['wireless'][$setting]);
2914
				}
2915
			}
2916
		}
2917
	}
2918

    
2919
	// Sync the mode on the clone creation page with the configured mode on the interface
2920
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2921
		foreach ($config['wireless']['clone'] as &$clone) {
2922
			if ($clone['cloneif'] == $ifcfg['if']) {
2923
				if ($sync_changes) {
2924
					$clone['mode'] = $ifcfg['wireless']['mode'];
2925
				} else {
2926
					$ifcfg['wireless']['mode'] = $clone['mode'];
2927
				}
2928
				break;
2929
			}
2930
		}
2931
		unset($clone);
2932
	}
2933
}
2934

    
2935
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2936
	global $config, $g;
2937

    
2938
	/*    open up a shell script that will be used to output the commands.
2939
	 *    since wireless is changing a lot, these series of commands are fragile
2940
	 *    and will sometimes need to be verified by a operator by executing the command
2941
	 *    and returning the output of the command to the developers for inspection.  please
2942
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2943
	 */
2944

    
2945
	// Remove script file
2946
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2947

    
2948
	// Clone wireless nic if needed.
2949
	interface_wireless_clone($if, $wl);
2950

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

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

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

    
2960
	/* set values for /path/program */
2961
	if (file_exists("/usr/local/sbin/hostapd")) {
2962
		$hostapd = "/usr/local/sbin/hostapd";
2963
	} else {
2964
		$hostapd = "/usr/sbin/hostapd";
2965
	}
2966
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
2967
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
2968
	} else {
2969
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2970
	}
2971
	$ifconfig = "/sbin/ifconfig";
2972
	$sysctl = "/sbin/sysctl";
2973
	$sysctl_args = "-q";
2974
	$killall = "/usr/bin/killall";
2975

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

    
2978
	$wlcmd = array();
2979
	$wl_sysctl = array();
2980
	/* Set a/b/g standard */
2981
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2982
	/* skip mode entirely for "auto" */
2983
	if ($wlcfg['standard'] != "auto") {
2984
		$wlcmd[] = "mode " . escapeshellarg($standard);
2985
	}
2986

    
2987
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2988
	 * to prevent massive packet loss under certain conditions. */
2989
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2990
		$wlcmd[] = "-ampdu";
2991
	}
2992

    
2993
	/* Set ssid */
2994
	if ($wlcfg['ssid']) {
2995
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2996
	}
2997

    
2998
	/* Set 802.11g protection mode */
2999
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3000

    
3001
	/* set wireless channel value */
3002
	if (isset($wlcfg['channel'])) {
3003
		if ($wlcfg['channel'] == "0") {
3004
			$wlcmd[] = "channel any";
3005
		} else {
3006
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
3007
		}
3008
	}
3009

    
3010
	/* Set antenna diversity value */
3011
	if (isset($wlcfg['diversity'])) {
3012
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3013
	}
3014

    
3015
	/* Set txantenna value */
3016
	if (isset($wlcfg['txantenna'])) {
3017
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3018
	}
3019

    
3020
	/* Set rxantenna value */
3021
	if (isset($wlcfg['rxantenna'])) {
3022
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3023
	}
3024

    
3025
	/* set Distance value */
3026
	if ($wlcfg['distance']) {
3027
		$distance = escapeshellarg($wlcfg['distance']);
3028
	}
3029

    
3030
	/* Set wireless hostap mode */
3031
	if ($wlcfg['mode'] == "hostap") {
3032
		$wlcmd[] = "mediaopt hostap";
3033
	} else {
3034
		$wlcmd[] = "-mediaopt hostap";
3035
	}
3036

    
3037
	/* Set wireless adhoc mode */
3038
	if ($wlcfg['mode'] == "adhoc") {
3039
		$wlcmd[] = "mediaopt adhoc";
3040
	} else {
3041
		$wlcmd[] = "-mediaopt adhoc";
3042
	}
3043

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

    
3046
	/* handle hide ssid option */
3047
	if (isset($wlcfg['hidessid']['enable'])) {
3048
		$wlcmd[] = "hidessid";
3049
	} else {
3050
		$wlcmd[] = "-hidessid";
3051
	}
3052

    
3053
	/* handle pureg (802.11g) only option */
3054
	if (isset($wlcfg['pureg']['enable'])) {
3055
		$wlcmd[] = "mode 11g pureg";
3056
	} else {
3057
		$wlcmd[] = "-pureg";
3058
	}
3059

    
3060
	/* handle puren (802.11n) only option */
3061
	if (isset($wlcfg['puren']['enable'])) {
3062
		$wlcmd[] = "puren";
3063
	} else {
3064
		$wlcmd[] = "-puren";
3065
	}
3066

    
3067
	/* enable apbridge option */
3068
	if (isset($wlcfg['apbridge']['enable'])) {
3069
		$wlcmd[] = "apbridge";
3070
	} else {
3071
		$wlcmd[] = "-apbridge";
3072
	}
3073

    
3074
	/* handle turbo option */
3075
	if (isset($wlcfg['turbo']['enable'])) {
3076
		$wlcmd[] = "mediaopt turbo";
3077
	} else {
3078
		$wlcmd[] = "-mediaopt turbo";
3079
	}
3080

    
3081
	/* handle txpower setting */
3082
	// or don't. this has issues at the moment.
3083
	/*
3084
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3085
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3086
	}*/
3087

    
3088
	/* handle wme option */
3089
	if (isset($wlcfg['wme']['enable'])) {
3090
		$wlcmd[] = "wme";
3091
	} else {
3092
		$wlcmd[] = "-wme";
3093
	}
3094

    
3095
	/* Enable wpa if it's configured. No WEP support anymore. */
3096
	if (isset($wlcfg['wpa']['enable'])) {
3097
		$wlcmd[] = "authmode wpa wepmode off ";
3098
	} else {
3099
		$wlcmd[] = "authmode open wepmode off ";
3100
	}
3101

    
3102
	kill_hostapd($if);
3103
	mwexec(kill_wpasupplicant("{$if}"));
3104

    
3105
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3106

    
3107
	switch ($wlcfg['mode']) {
3108
		case 'bss':
3109
			if (isset($wlcfg['wpa']['enable'])) {
3110
				$wpa .= <<<EOD
3111
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3112
ctrl_interface_group=0
3113
ap_scan=1
3114
#fast_reauth=1
3115
network={
3116
ssid="{$wlcfg['ssid']}"
3117
scan_ssid=1
3118
priority=5
3119
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3120
psk="{$wlcfg['wpa']['passphrase']}"
3121
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3122
group={$wlcfg['wpa']['wpa_pairwise']}
3123
}
3124
EOD;
3125

    
3126
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
3127
				unset($wpa);
3128
			}
3129
			break;
3130
		case 'hostap':
3131
			if (!empty($wlcfg['wpa']['passphrase'])) {
3132
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3133
			} else {
3134
				$wpa_passphrase = "";
3135
			}
3136
			if (isset($wlcfg['wpa']['enable'])) {
3137
				$wpa .= <<<EOD
3138
interface={$if}
3139
driver=bsd
3140
logger_syslog=-1
3141
logger_syslog_level=0
3142
logger_stdout=-1
3143
logger_stdout_level=0
3144
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3145
ctrl_interface={$g['varrun_path']}/hostapd
3146
ctrl_interface_group=wheel
3147
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3148
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3149
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3150
ssid={$wlcfg['ssid']}
3151
debug={$wlcfg['wpa']['debug_mode']}
3152
wpa={$wlcfg['wpa']['wpa_mode']}
3153
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3154
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3155
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3156
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3157
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3158
{$wpa_passphrase}
3159

    
3160
EOD;
3161

    
3162
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3163
					$wpa .= <<<EOD
3164
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3165
rsn_preauth=1
3166
rsn_preauth_interfaces={$if}
3167

    
3168
EOD;
3169
				}
3170
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3171
					$wpa .= "ieee8021x=1\n";
3172

    
3173
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3174
						$auth_server_port = "1812";
3175
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3176
							$auth_server_port = intval($wlcfg['auth_server_port']);
3177
						}
3178
						$wpa .= <<<EOD
3179

    
3180
auth_server_addr={$wlcfg['auth_server_addr']}
3181
auth_server_port={$auth_server_port}
3182
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3183

    
3184
EOD;
3185
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3186
							$auth_server_port2 = "1812";
3187
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3188
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3189
							}
3190

    
3191
							$wpa .= <<<EOD
3192
auth_server_addr={$wlcfg['auth_server_addr2']}
3193
auth_server_port={$auth_server_port2}
3194
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3195

    
3196
EOD;
3197
						}
3198
					}
3199
				}
3200

    
3201
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3202
				unset($wpa);
3203
			}
3204
			break;
3205
	}
3206

    
3207
	/*
3208
	 *    all variables are set, lets start up everything
3209
	 */
3210

    
3211
	$baseif = interface_get_wireless_base($if);
3212
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3213
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3214

    
3215
	/* set sysctls for the wireless interface */
3216
	if (!empty($wl_sysctl)) {
3217
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3218
		foreach ($wl_sysctl as $wl_sysctl_line) {
3219
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3220
		}
3221
	}
3222

    
3223
	/* set ack timers according to users preference (if he/she has any) */
3224
	if ($distance) {
3225
		fwrite($fd_set, "# Enable ATH distance settings\n");
3226
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3227
	}
3228

    
3229
	if (isset($wlcfg['wpa']['enable'])) {
3230
		if ($wlcfg['mode'] == "bss") {
3231
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3232
		}
3233
		if ($wlcfg['mode'] == "hostap") {
3234
			/* add line to script to restore old mac to make hostapd happy */
3235
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3236
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3237
				$if_curmac = get_interface_mac($if);
3238
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3239
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3240
						" link " . escapeshellarg($if_oldmac) . "\n");
3241
				}
3242
			}
3243

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

    
3246
			/* add line to script to restore spoofed mac after running hostapd */
3247
			if ($wl['spoofmac']) {
3248
				$if_curmac = get_interface_mac($if);
3249
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3250
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3251
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3252
				}
3253
			}
3254
		}
3255
	}
3256

    
3257
	fclose($fd_set);
3258

    
3259
	/* Making sure regulatory settings have actually changed
3260
	 * before applying, because changing them requires bringing
3261
	 * down all wireless networks on the interface. */
3262
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3263
	$ifconfig_str = implode($output);
3264
	unset($output);
3265
	$reg_changing = false;
3266

    
3267
	/* special case for the debug country code */
3268
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3269
		$reg_changing = true;
3270
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3271
		$reg_changing = true;
3272
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3273
		$reg_changing = true;
3274
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3275
		$reg_changing = true;
3276
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3277
		$reg_changing = true;
3278
	}
3279

    
3280
	if ($reg_changing) {
3281
		/* set regulatory domain */
3282
		if ($wlcfg['regdomain']) {
3283
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3284
		}
3285

    
3286
		/* set country */
3287
		if ($wlcfg['regcountry']) {
3288
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3289
		}
3290

    
3291
		/* set location */
3292
		if ($wlcfg['reglocation']) {
3293
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3294
		}
3295

    
3296
		$wlregcmd_args = implode(" ", $wlregcmd);
3297

    
3298
		/* build a complete list of the wireless clones for this interface */
3299
		$clone_list = array();
3300
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3301
			$clone_list[] = interface_get_wireless_clone($baseif);
3302
		}
3303
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3304
			foreach ($config['wireless']['clone'] as $clone) {
3305
				if ($clone['if'] == $baseif) {
3306
					$clone_list[] = $clone['cloneif'];
3307
				}
3308
			}
3309
		}
3310

    
3311
		/* find which clones are up and bring them down */
3312
		$clones_up = array();
3313
		foreach ($clone_list as $clone_if) {
3314
			$clone_status = pfSense_get_interface_addresses($clone_if);
3315
			if ($clone_status['status'] == 'up') {
3316
				$clones_up[] = $clone_if;
3317
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3318
			}
3319
		}
3320

    
3321
		/* apply the regulatory settings */
3322
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3323
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3324

    
3325
		/* bring the clones back up that were previously up */
3326
		foreach ($clones_up as $clone_if) {
3327
			interfaces_bring_up($clone_if);
3328

    
3329
			/*
3330
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3331
			 * is in infrastructure mode, and WPA is enabled.
3332
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3333
			 */
3334
			if ($clone_if != $if) {
3335
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3336
				if ((!empty($friendly_if)) &&
3337
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3338
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3339
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3340
				}
3341
			}
3342
		}
3343
	}
3344

    
3345
	/* The mode must be specified in a separate command before ifconfig
3346
	 * will allow the mode and channel at the same time in the next.
3347
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3348
	 */
3349
	if ($wlcfg['mode'] == "hostap") {
3350
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3351
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3352
	}
3353

    
3354
	/* configure wireless */
3355
	$wlcmd_args = implode(" ", $wlcmd);
3356
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3357
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3358
	/* Bring the interface up only after setting up all the other parameters. */
3359
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3360
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3361
	fclose($wlan_setup_log);
3362

    
3363
	unset($wlcmd_args, $wlcmd);
3364

    
3365

    
3366
	sleep(1);
3367
	/* execute hostapd and wpa_supplicant if required in shell */
3368
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3369

    
3370
	return 0;
3371

    
3372
}
3373

    
3374
function kill_hostapd($interface) {
3375
	global $g;
3376

    
3377
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3378
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3379
	}
3380
}
3381

    
3382
function kill_wpasupplicant($interface) {
3383
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3384
}
3385

    
3386
function find_dhclient_process($interface) {
3387
	if ($interface) {
3388
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3389
	} else {
3390
		$pid = 0;
3391
	}
3392

    
3393
	return intval($pid);
3394
}
3395

    
3396
function kill_dhclient_process($interface) {
3397
	if (empty($interface) || !does_interface_exist($interface)) {
3398
		return;
3399
	}
3400

    
3401
	$i = 0;
3402
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3403
		/* 3rd time make it die for sure */
3404
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3405
		posix_kill($pid, $sig);
3406
		sleep(1);
3407
		$i++;
3408
	}
3409
	unset($i);
3410
}
3411

    
3412
function find_dhcp6c_process($interface) {
3413
	global $g;
3414

    
3415
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3416
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3417
	} else {
3418
		return(false);
3419
	}
3420

    
3421
	return intval($pid);
3422
}
3423

    
3424
function kill_dhcp6client_process($interface, $force, $release = false) {
3425
	global $g;
3426

    
3427
	$i = 0;
3428

    
3429
	/*
3430
	Beware of the following: Reason, the interface may be down, but
3431
	dhcp6c may still be running, it just complains it cannot send
3432
	and carries on. Commented out as will stop the call to kill.
3433

    
3434
	if (empty($interface) || !does_interface_exist($interface)) {
3435
		return;
3436
	}
3437
	*/
3438

    
3439
	/*********** Notes on signals for dhcp6c and this function *************
3440

    
3441
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3442
	a release and waiting for the response that never comes.
3443
	So we need to tell it that the interface is down and to just die quickly
3444
	otherwise a new client may launch and we have duplicate proceses.
3445
	In this case use SIGUSR1.
3446

    
3447
	If we want to exit normally obeying the no release flag then use SIGTERM.
3448
	If we want to exit with a release overiding the no release flag then
3449
	use SIGUSR2.
3450

    
3451
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3452
	exit quickly without sending release signals.
3453

    
3454
	If $Force is set to false and $release is also set to false dhcp6c will
3455
	follow the no-release flag.
3456

    
3457
	If $Force is set to false and $release is true then dhcp6c will send a
3458
	release regardless of the no-release flag.
3459
	***********************************************************************/
3460

    
3461
	if ($force == true) {
3462
		$psig=SIGUSR1;
3463
	} else if ($release == false) {
3464
		$psig=SIGTERM;
3465
	} else {
3466
		$psig=SIGUSR2;
3467
	}
3468

    
3469
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3470
		/* 3rd time make it die for sure */
3471
		$sig = ($i == 2 ? SIGKILL : $psig);
3472
		posix_kill($pid, $sig);
3473
		sleep(1);
3474
		$i++;
3475
	}
3476
	/* Clear the RTSOLD script created lock & tidy up */
3477
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3478
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
3479
}
3480
function reset_dhcp6client_process($interface) {
3481

    
3482
	$pid = find_dhcp6c_process($interface);
3483

    
3484
	if($pid != 0) {
3485
		posix_kill($pid, SIGHUP);
3486
	}
3487
}
3488

    
3489
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3490
	global $g;
3491

    
3492
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3493
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3494

    
3495
	/*
3496
	 * Only run this if the lock does not exist. In theory the lock being
3497
	 * there in this mode means the user has selected dhcp6withoutRA while
3498
	 * a session is active in the other mode.
3499
	 *
3500
	 * It should not happen as the process should have been killed and the
3501
	 * lock deleted.
3502
	 */
3503

    
3504
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
3505
		kill_dhcp6client_process($interface, true);
3506
		/* Lock it to avoid multiple runs */
3507
		touch("/tmp/dhcp6c_{$interface}_lock");
3508
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3509
		    "{$noreleaseOption} " .
3510
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
3511
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
3512
		    $interface);
3513
		log_error(sprintf(gettext(
3514
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
3515
		    $interface));
3516
	}
3517
}
3518

    
3519
function interface_virtual_create($interface) {
3520
	global $config;
3521

    
3522
	if (interface_is_vlan($interface) != NULL) {
3523
		interfaces_vlan_configure($interface);
3524
	} else if (substr($interface, 0, 3) == "gre") {
3525
		interfaces_gre_configure(0, $interface);
3526
	} else if (substr($interface, 0, 3) == "gif") {
3527
		interfaces_gif_configure(0, $interface);
3528
	} else if (substr($interface, 0, 5) == "ovpns") {
3529
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3530
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3531
				if ($interface == "ovpns{$server['vpnid']}") {
3532
					if (!function_exists('openvpn_resync')) {
3533
						require_once('openvpn.inc');
3534
					}
3535
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3536
					openvpn_resync('server', $server);
3537
				}
3538
			}
3539
			unset($server);
3540
		}
3541
	} else if (substr($interface, 0, 5) == "ovpnc") {
3542
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3543
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3544
				if ($interface == "ovpnc{$client['vpnid']}") {
3545
					if (!function_exists('openvpn_resync')) {
3546
						require_once('openvpn.inc');
3547
					}
3548
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3549
					openvpn_resync('client', $client);
3550
				}
3551
			}
3552
			unset($client);
3553
		}
3554
	} else if (substr($interface, 0, 5) == "ipsec") {
3555
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
3556
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
3557
				if ($ph1ent['disabled']) {
3558
					continue;
3559
				}
3560
				if ($interface == "ipsec{$ph1ent['ikeid']}") {
3561
					interface_ipsec_vti_configure($ph1ent);
3562
				}
3563
			}
3564
		}
3565
	} else if (substr($interface, 0, 4) == "lagg") {
3566
		interfaces_lagg_configure($interface);
3567
	} else if (substr($interface, 0, 6) == "bridge") {
3568
		interfaces_bridge_configure(0, $interface);
3569
	}
3570
}
3571

    
3572
function interface_vlan_mtu_configured($iface) {
3573
	global $config;
3574

    
3575
	$mtu = 0;
3576
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3577
		foreach ($config['vlans']['vlan'] as $vlan) {
3578

    
3579
			if ($vlan['vlanif'] != $iface)
3580
				continue;
3581

    
3582
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3583
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3584
				/* VLAN MTU */
3585
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3586
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3587
				/* Parent MTU */
3588
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3589
			}
3590
		}
3591
	}
3592

    
3593
	return $mtu;
3594
}
3595

    
3596
function interface_mtu_wanted_for_pppoe($realif) {
3597
	global $config;
3598

    
3599
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3600
		return 0;
3601

    
3602
	$mtu = 0;
3603
	foreach ($config['ppps']['ppp'] as $ppp) {
3604
		if ($ppp['type'] != "pppoe") {
3605
			continue;
3606
		}
3607

    
3608
		$mtus = array();
3609
		if (!empty($ppp['mtu'])) {
3610
			$mtus = explode(',', $ppp['mtu']);
3611
		}
3612
		$ports = explode(',', $ppp['ports']);
3613

    
3614
		foreach ($ports as $pid => $port) {
3615
			$parentifa = get_parent_interface($port);
3616
			$parentif = $parentifa[0];
3617
			if ($parentif != $realif)
3618
				continue;
3619

    
3620
			// there is an MTU configured on the port in question
3621
			if (!empty($mtus[$pid])) {
3622
				$mtu = intval($mtus[$pid]) + 8;
3623
			// or use the MTU configured on the interface ...
3624
			} elseif (is_array($config['interfaces'])) {
3625
				foreach ($config['interfaces'] as $interface) {
3626
					if ($interface['if'] == $ppp['if'] &&
3627
					    !empty($interface['mtu'])) {
3628
						$mtu = intval($interface['mtu']) + 8;
3629
						break;
3630
					}
3631
				}
3632
			}
3633
		}
3634
	}
3635

    
3636
	return $mtu;
3637
}
3638

    
3639
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3640
	global $config, $g;
3641
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3642
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3643

    
3644
	$wancfg = $config['interfaces'][$interface];
3645

    
3646
	if (!isset($wancfg['enable'])) {
3647
		return;
3648
	}
3649

    
3650
	$realif = get_real_interface($interface);
3651
	$realhwif_array = get_parent_interface($interface);
3652
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3653
	$realhwif = $realhwif_array[0];
3654

    
3655
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn") && !(substr($realif, 0, 5) == "ipsec")) {
3656
		/* remove all IPv4 and IPv6 addresses */
3657
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3658
		if (is_array($tmpifaces)) {
3659
			foreach ($tmpifaces as $tmpiface) {
3660
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3661
					if (!is_linklocal($tmpiface)) {
3662
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3663
					}
3664
				} else {
3665
					if (is_subnetv4($tmpiface)) {
3666
						$tmpip = explode('/', $tmpiface);
3667
						$tmpip = $tmpip[0];
3668
					} else {
3669
						$tmpip = $tmpiface;
3670
					}
3671
					pfSense_interface_deladdress($realif, $tmpip);
3672
				}
3673
			}
3674
		}
3675

    
3676
		/* only bring down the interface when both v4 and v6 are set to NONE */
3677
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3678
			interface_bring_down($interface);
3679
		}
3680
	}
3681

    
3682
	$interface_to_check = $realif;
3683
	if (interface_isppp_type($interface)) {
3684
		$interface_to_check = $realhwif;
3685
	}
3686

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

    
3692
	/* Disable Accepting router advertisements unless specifically requested */
3693
	if ($g['debug']) {
3694
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3695
	}
3696
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
3697
	{
3698
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3699
	}
3700
	/* wireless configuration? */
3701
	if (is_array($wancfg['wireless']) && !$linkupevent) {
3702
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3703
	}
3704

    
3705
	$current_mac = get_interface_mac($realhwif);
3706
	$vendor_mac = get_interface_vendor_mac($realhwif);
3707
	/*
3708
	 * Do not change the MAC address if the interface does not store the original
3709
	 * vendor MAC address.
3710
	 */
3711
	if ($vendor_mac != NULL) {
3712
		/* Get the vendor MAC.  Use source dependent upon whether or not booting. */
3713
		if (platform_booting()) {
3714
			$vendor_mac = $current_mac;
3715
		}
3716
		$mac_addr = $wancfg['spoofmac'] ?: $vendor_mac;
3717
		/*
3718
		 * Don't try to reapply the MAC if it's already applied.
3719
		 * When ifconfig link is used, it cycles the interface down/up, which triggers
3720
		 * the interface config again, which attempts to apply the MAC again,
3721
		 * which cycles the link again...
3722
		 */
3723
		if (!empty($mac_addr) && ($mac_addr != $current_mac)) {
3724
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3725
				" link " . escapeshellarg($mac_addr));
3726
		}
3727
	} elseif ($current_mac == "ff:ff:ff:ff:ff:ff") {
3728
		/*   this is not a valid mac address.  generate a
3729
		 *   temporary mac address so the machine can get online.
3730
		 */
3731
		echo gettext("Generating new MAC address.");
3732
		$random_mac = generate_random_mac_address();
3733
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3734
			" link " . escapeshellarg($random_mac));
3735
		$wancfg['spoofmac'] = $random_mac;
3736
		write_config(sprintf(gettext('The invalid MAC address (ff:ff:ff:ff:ff:ff) on interface %1$s has been automatically replaced with %2$s'), $realif, $random_mac));
3737
		file_notice("MAC Address altered", sprintf(gettext('The invalid MAC address (ff:ff:ff:ff:ff:ff) on interface %1$s has been automatically replaced with %2$s'), $realif, $random_mac), "Interfaces");
3738
	}
3739

    
3740
	/* media */
3741
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3742
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3743
		if ($wancfg['media']) {
3744
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3745
		}
3746
		if ($wancfg['mediaopt']) {
3747
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3748
		}
3749
		mwexec($cmd);
3750
	}
3751

    
3752
	/* Apply hw offloading policies as configured */
3753
	enable_hardware_offloading($interface);
3754

    
3755
	/* invalidate interface/ip/sn cache */
3756
	get_interface_arr(true);
3757
	unset($interface_ip_arr_cache[$realif]);
3758
	unset($interface_sn_arr_cache[$realif]);
3759
	unset($interface_ipv6_arr_cache[$realif]);
3760
	unset($interface_snv6_arr_cache[$realif]);
3761

    
3762
	$tunnelif = substr($realif, 0, 3);
3763

    
3764
	$mtuif = $realif;
3765
	$mtuhwif = $realhwif;
3766

    
3767
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3768
	if (interface_isppp_type($interface)) {
3769
		$mtuif = $realhwif;
3770
		$mtuhwif_array = get_parent_interface($mtuif);
3771
		$mtuhwif = $mtuhwif_array[0];
3772
	}
3773

    
3774
	$wantedmtu = 0;
3775
	if (is_array($config['interfaces'])) {
3776
		foreach ($config['interfaces'] as $tmpinterface) {
3777
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3778
				$wantedmtu = $tmpinterface['mtu'];
3779
				break;
3780
			}
3781
		}
3782
	}
3783

    
3784
	/* MTU is not specified for interface, try the pppoe settings. */
3785
	if ($wantedmtu == 0) {
3786
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3787
	}
3788
	if ($wantedmtu == 0 && interface_is_vlan($mtuif) != NULL && interface_isppp_type($interface)) {
3789
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3790
	}
3791

    
3792
	/* Set the MTU to 1500 if no explicit MTU configured. */
3793
	if ($wantedmtu == 0) {
3794
		$wantedmtu = 1500; /* Default */
3795
	}
3796

    
3797
	if (interface_is_vlan($mtuif) != NULL) {
3798
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3799
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3800
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3801
			if ($wancfg['mtu'] > $parentmtu) {
3802
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3803
			}
3804
		}
3805

    
3806
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3807

    
3808
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3809
			$configuredmtu = $parentmtu;
3810
		if ($configuredmtu != 0)
3811
			$mtu = $configuredmtu;
3812
		else
3813
			$mtu = $wantedmtu;
3814

    
3815
		/* Set the parent MTU. */
3816
		if (get_interface_mtu($mtuhwif) < $mtu)
3817
			set_interface_mtu($mtuhwif, $mtu);
3818
		/* Set the VLAN MTU. */
3819
		if (get_interface_mtu($mtuif) != $mtu)
3820
			set_interface_mtu($mtuif, $mtu);
3821
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3822
		/* LAGG interface must be destroyed and re-created to change MTU */
3823
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3824
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3825
				foreach ($config['laggs']['lagg'] as $lagg) {
3826
					if ($lagg['laggif'] == $mtuif) {
3827
						interface_lagg_configure($lagg);
3828
						break;
3829
					}
3830
				}
3831
			}
3832
		}
3833
	} else {
3834
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3835
			pfSense_interface_mtu($mtuif, $wantedmtu);
3836
		}
3837
	}
3838
	/* XXX: What about gre/gif/.. ? */
3839

    
3840
	if (does_interface_exist($wancfg['if'])) {
3841
		interfaces_bring_up($wancfg['if']);
3842
	}
3843

    
3844
	switch ($wancfg['ipaddr']) {
3845
		case 'dhcp':
3846
			interface_dhcp_configure($interface);
3847
			break;
3848
		case 'pppoe':
3849
		case 'l2tp':
3850
		case 'pptp':
3851
		case 'ppp':
3852
			interface_ppps_configure($interface);
3853
			break;
3854
		default:
3855
			/* XXX: Kludge for now related to #3280 */
3856
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
3857
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3858
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3859
				}
3860
			}
3861
			break;
3862
	}
3863

    
3864
	switch ($wancfg['ipaddrv6']) {
3865
		case 'slaac':
3866
		case 'dhcp6':
3867
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
3868
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
3869
			// handles all non-PPP connections with 'dhcp6usev4iface' set
3870
			/* Remove the check file. Should not be there but just in case */
3871
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
3872
			log_error(gettext("calling interface_dhcpv6_configure."));
3873
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
3874
				interface_dhcpv6_configure($interface, $wancfg);
3875
			}
3876
			break;
3877
		case '6rd':
3878
			interface_6rd_configure($interface, $wancfg);
3879
			break;
3880
		case '6to4':
3881
			interface_6to4_configure($interface, $wancfg);
3882
			break;
3883
		case 'track6':
3884
			interface_track6_configure($interface, $wancfg, $linkupevent);
3885
			break;
3886
		default:
3887
			/* XXX: Kludge for now related to #3280 */
3888
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
3889
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3890
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3891
					// FIXME: Add IPv6 Support to the pfSense module
3892
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3893
				}
3894
			}
3895
			break;
3896
	}
3897

    
3898
	interface_netgraph_needed($interface);
3899

    
3900
	if (!platform_booting()) {
3901
		link_interface_to_vips($interface, "update");
3902

    
3903
		if ($tunnelif != 'gre') {
3904
			unset($gre);
3905
			$gre = link_interface_to_gre($interface);
3906
			if (!empty($gre)) {
3907
				array_walk($gre, 'interface_gre_configure');
3908
			}
3909
		}
3910

    
3911
		if ($tunnelif != 'gif') {
3912
			unset($gif);
3913
			$gif = link_interface_to_gif ($interface);
3914
			if (!empty($gif)) {
3915
				array_walk($gif, 'interface_gif_configure');
3916
			}
3917
		}
3918

    
3919
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
3920
			unset($bridgetmp);
3921
			$bridgetmp = link_interface_to_bridge($interface);
3922
			if (!empty($bridgetmp)) {
3923
				interface_bridge_add_member($bridgetmp, $realif);
3924
			}
3925
		}
3926

    
3927
		$grouptmp = link_interface_to_group($interface);
3928
		if (!empty($grouptmp)) {
3929
			array_walk($grouptmp, 'interface_group_add_member');
3930
		}
3931

    
3932
		if ($interface == "lan") {
3933
			/* make new hosts file */
3934
			system_hosts_generate();
3935
		}
3936

    
3937
		if ($reloadall == true) {
3938

    
3939
			/* reconfigure static routes (kernel may have deleted them) */
3940
			system_routing_configure($interface);
3941

    
3942
			/* reload ipsec tunnels */
3943
			send_event("service reload ipsecdns");
3944

    
3945
			if (isset($config['dnsmasq']['enable'])) {
3946
				services_dnsmasq_configure();
3947
			}
3948

    
3949
			if (isset($config['unbound']['enable'])) {
3950
				services_unbound_configure();
3951
			}
3952

    
3953
			/* update dyndns */
3954
			send_event("service reload dyndns {$interface}");
3955

    
3956
			/* reload captive portal */
3957
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3958
				require_once('captiveportal.inc');
3959
			}
3960
			captiveportal_init_rules_byinterface($interface);
3961
		}
3962
	}
3963

    
3964
	interfaces_staticarp_configure($interface);
3965
	return 0;
3966
}
3967

    
3968
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3969
	global $config, $g;
3970

    
3971
	if (!is_array($wancfg)) {
3972
		return;
3973
	}
3974

    
3975
	if (!isset($wancfg['enable'])) {
3976
		return;
3977
	}
3978

    
3979
	/* If the interface is not configured via another, exit */
3980
	if (empty($wancfg['track6-interface'])) {
3981
		return;
3982
	}
3983

    
3984
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3985
	$realif = get_real_interface($interface);
3986
	$linklocal = find_interface_ipv6_ll($realif, true);
3987
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
3988
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3989
	}
3990
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3991
	/* XXX: Probably should remove? */
3992
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3993

    
3994
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3995
	if (!isset($trackcfg['enable'])) {
3996
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
3997
		return;
3998
	}
3999

    
4000
	switch ($trackcfg['ipaddrv6']) {
4001
		case "6to4":
4002
			if ($g['debug']) {
4003
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4004
			}
4005
			interface_track6_6to4_configure($interface, $wancfg);
4006
			break;
4007
		case "6rd":
4008
			if ($g['debug']) {
4009
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4010
			}
4011
			interface_track6_6rd_configure($interface, $wancfg);
4012
			break;
4013
		case "dhcp6":
4014
			if ($linkupevent == true) {
4015
				/*
4016
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4017
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4018
				 *
4019
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4020
				 */
4021
				$parentrealif = get_real_interface($wancfg['track6-interface']);
4022
				$pidv6 = find_dhcp6c_process($parentrealif);
4023
				if ($pidv6) {
4024
					posix_kill($pidv6, SIGHUP);
4025
				}
4026
			}
4027
			break;
4028
	}
4029

    
4030
	if ($linkupevent == false && !platform_booting()) {
4031
		if (!function_exists('services_dhcpd_configure')) {
4032
			require_once("services.inc");
4033
		}
4034

    
4035
		/* restart dns servers (defering dhcpd reload) */
4036
		if (isset($config['unbound']['enable'])) {
4037
			services_unbound_configure(false);
4038
		}
4039
		if (isset($config['dnsmasq']['enable'])) {
4040
			services_dnsmasq_configure(false);
4041
		}
4042

    
4043
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4044
		services_dhcpd_configure("inet6");
4045
	}
4046

    
4047
	return 0;
4048
}
4049

    
4050
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4051
	global $config, $g;
4052
	global $interface_ipv6_arr_cache;
4053
	global $interface_snv6_arr_cache;
4054

    
4055
	if (!is_array($lancfg)) {
4056
		return;
4057
	}
4058

    
4059
	/* If the interface is not configured via another, exit */
4060
	if (empty($lancfg['track6-interface'])) {
4061
		return;
4062
	}
4063

    
4064
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4065
	if (empty($wancfg)) {
4066
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4067
		return;
4068
	}
4069

    
4070
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4071
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4072
		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']));
4073
		return;
4074
	}
4075
	$hexwanv4 = return_hex_ipv4($ip4address);
4076

    
4077
	/* create the long prefix notation for math, save the prefix length */
4078
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4079
	$rd6prefixlen = $rd6prefix[1];
4080
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4081

    
4082
	/* binary presentation of the prefix for all 128 bits. */
4083
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4084

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

    
4090
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4091
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4092
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4093
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4094
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4095
	/* fill the rest out with zeros */
4096
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4097

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

    
4101
	$lanif = get_real_interface($interface);
4102
	$oip = find_interface_ipv6($lanif);
4103
	if (is_ipaddrv6($oip)) {
4104
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4105
	}
4106
	unset($interface_ipv6_arr_cache[$lanif]);
4107
	unset($interface_snv6_arr_cache[$lanif]);
4108
	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));
4109
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4110

    
4111
	return 0;
4112
}
4113

    
4114
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4115
	global $config, $g;
4116
	global $interface_ipv6_arr_cache;
4117
	global $interface_snv6_arr_cache;
4118

    
4119
	if (!is_array($lancfg)) {
4120
		return;
4121
	}
4122

    
4123
	/* If the interface is not configured via another, exit */
4124
	if (empty($lancfg['track6-interface'])) {
4125
		return;
4126
	}
4127

    
4128
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4129
	if (empty($wancfg)) {
4130
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4131
		return;
4132
	}
4133

    
4134
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4135
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4136
		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']));
4137
		return;
4138
	}
4139
	$hexwanv4 = return_hex_ipv4($ip4address);
4140

    
4141
	/* create the long prefix notation for math, save the prefix length */
4142
	$sixto4prefix = "2002::";
4143
	$sixto4prefixlen = 16;
4144
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4145

    
4146
	/* binary presentation of the prefix for all 128 bits. */
4147
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4148

    
4149
	/* just save the left prefix length bits */
4150
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4151
	/* add the v4 address */
4152
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4153
	/* add the custom prefix id */
4154
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4155
	/* fill the rest out with zeros */
4156
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4157

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

    
4161
	$lanif = get_real_interface($interface);
4162
	$oip = find_interface_ipv6($lanif);
4163
	if (is_ipaddrv6($oip)) {
4164
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4165
	}
4166
	unset($interface_ipv6_arr_cache[$lanif]);
4167
	unset($interface_snv6_arr_cache[$lanif]);
4168
	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));
4169
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4170

    
4171
	return 0;
4172
}
4173

    
4174
function interface_6rd_configure($interface = "wan", $wancfg) {
4175
	global $config, $g;
4176

    
4177
	/* because this is a tunnel interface we can only function
4178
	 *	with a public IPv4 address on the interface */
4179

    
4180
	if (!is_array($wancfg)) {
4181
		return;
4182
	}
4183

    
4184
	if (!is_module_loaded('if_stf.ko')) {
4185
		mwexec('/sbin/kldload if_stf.ko');
4186
	}
4187

    
4188
	$wanif = get_real_interface($interface);
4189
	$ip4address = find_interface_ip($wanif);
4190
	if (!is_ipaddrv4($ip4address)) {
4191
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4192
		return false;
4193
	}
4194
	$hexwanv4 = return_hex_ipv4($ip4address);
4195

    
4196
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4197
		$wancfg['prefix-6rd-v4plen'] = 0;
4198
	}
4199

    
4200
	/* create the long prefix notation for math, save the prefix length */
4201
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4202
	$rd6prefixlen = $rd6prefix[1];
4203
	$brgw = explode('.', $wancfg['gateway-6rd']);
4204
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4205
	$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);
4206
	if (strlen($rd6brgw) < 128) {
4207
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4208
	}
4209
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4210
	unset($brgw);
4211
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4212

    
4213
	/* binary presentation of the prefix for all 128 bits. */
4214
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4215

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

    
4223
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4224
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4225

    
4226

    
4227
	/* XXX: need to extend to support variable prefix size for v4 */
4228
	$stfiface = "{$interface}_stf";
4229
	if (does_interface_exist($stfiface)) {
4230
		pfSense_interface_destroy($stfiface);
4231
	}
4232
	$tmpstfiface = pfSense_interface_create("stf");
4233
	pfSense_interface_rename($tmpstfiface, $stfiface);
4234
	pfSense_interface_flags($stfiface, IFF_LINK2);
4235
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4236
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4237
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4238
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4239
	}
4240
	if ($g['debug']) {
4241
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4242
	}
4243

    
4244
	/* write out a default router file */
4245
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4246
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4247

    
4248
	$ip4gateway = get_interface_gateway($interface);
4249
	if (is_ipaddrv4($ip4gateway)) {
4250
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
4251
	}
4252

    
4253
	/* configure dependent interfaces */
4254
	if (!platform_booting()) {
4255
		link_interface_to_track6($interface, "update");
4256
	}
4257

    
4258
	return 0;
4259
}
4260

    
4261
function interface_6to4_configure($interface = "wan", $wancfg) {
4262
	global $config, $g;
4263

    
4264
	/* because this is a tunnel interface we can only function
4265
	 *	with a public IPv4 address on the interface */
4266

    
4267
	if (!is_array($wancfg)) {
4268
		return;
4269
	}
4270

    
4271
	$wanif = get_real_interface($interface);
4272
	$ip4address = find_interface_ip($wanif);
4273
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4274
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4275
		return false;
4276
	}
4277

    
4278
	/* create the long prefix notation for math, save the prefix length */
4279
	$stfprefixlen = 16;
4280
	$stfprefix = Net_IPv6::uncompress("2002::");
4281
	$stfarr = explode(":", $stfprefix);
4282
	$v4prefixlen = "0";
4283

    
4284
	/* we need the hex form of the interface IPv4 address */
4285
	$ip4arr = explode(".", $ip4address);
4286
	$hexwanv4 = "";
4287
	foreach ($ip4arr as $octet) {
4288
		$hexwanv4 .= sprintf("%02x", $octet);
4289
	}
4290

    
4291
	/* we need the hex form of the broker IPv4 address */
4292
	$ip4arr = explode(".", "192.88.99.1");
4293
	$hexbrv4 = "";
4294
	foreach ($ip4arr as $octet) {
4295
		$hexbrv4 .= sprintf("%02x", $octet);
4296
	}
4297

    
4298
	/* binary presentation of the prefix for all 128 bits. */
4299
	$stfprefixbin = "";
4300
	foreach ($stfarr as $element) {
4301
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4302
	}
4303
	/* just save the left prefix length bits */
4304
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4305

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

    
4310
	/* for the local subnet too. */
4311
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4312
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4313

    
4314
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4315
	$stfbrarr = array();
4316
	$stfbrbinarr = array();
4317
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4318
	foreach ($stfbrbinarr as $bin) {
4319
		$stfbrarr[] = dechex(bindec($bin));
4320
	}
4321
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4322

    
4323
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4324
	$stflanarr = array();
4325
	$stflanbinarr = array();
4326
	$stflanbinarr = str_split($stflanbin, 16);
4327
	foreach ($stflanbinarr as $bin) {
4328
		$stflanarr[] = dechex(bindec($bin));
4329
	}
4330
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4331
	$stflanarr[7] = 1;
4332
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4333

    
4334
	/* setup the stf interface */
4335
	if (!is_module_loaded("if_stf")) {
4336
		mwexec("/sbin/kldload if_stf.ko");
4337
	}
4338
	$stfiface = "{$interface}_stf";
4339
	if (does_interface_exist($stfiface)) {
4340
		pfSense_interface_destroy($stfiface);
4341
	}
4342
	$tmpstfiface = pfSense_interface_create("stf");
4343
	pfSense_interface_rename($tmpstfiface, $stfiface);
4344
	pfSense_interface_flags($stfiface, IFF_LINK2);
4345
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4346

    
4347
	if ($g['debug']) {
4348
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4349
	}
4350

    
4351
	/* write out a default router file */
4352
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4353
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4354

    
4355
	$ip4gateway = get_interface_gateway($interface);
4356
	if (is_ipaddrv4($ip4gateway)) {
4357
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
4358
	}
4359

    
4360
	if (!platform_booting()) {
4361
		link_interface_to_track6($interface, "update");
4362
	}
4363

    
4364
	return 0;
4365
}
4366

    
4367
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4368
	global $config, $g;
4369

    
4370
	if (!is_array($wancfg)) {
4371
		return;
4372
	}
4373

    
4374
	$wanif = get_real_interface($interface, "inet6");
4375
	$dhcp6cconf = "";
4376

    
4377
	if (!empty($config['system']['global-v6duid'])) {
4378
		// Write the DUID file
4379
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4380
		    log_error(gettext("Failed to write user DUID file!"));
4381
		}
4382
	}
4383

    
4384
	/* accept router advertisements for this interface                 */
4385
	/* Moved to early in the function as sometimes interface not ready */
4386
	/* RTSOLD fails as interface does not accept .....                 */
4387

    
4388
	log_error("Accept router advertisements on interface {$wanif} ");
4389
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4390

    
4391
	if ($wancfg['adv_dhcp6_config_file_override']) {
4392
		// DHCP6 Config File Override
4393
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4394
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4395
		// DHCP6 Config File Advanced
4396
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4397
	} else {
4398
		// DHCP6 Config File Basic
4399
		$dhcp6cconf .= "interface {$wanif} {\n";
4400

    
4401
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4402
		if ($wancfg['ipaddrv6'] == "slaac") {
4403
			$dhcp6cconf .= "\tinformation-only;\n";
4404
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4405
			$dhcp6cconf .= "\trequest domain-name;\n";
4406
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4407
			$dhcp6cconf .= "};\n";
4408
		} else {
4409
			$trackiflist = array();
4410
			$iflist = link_interface_to_track6($interface);
4411
			foreach ($iflist as $ifname => $ifcfg) {
4412
				if (is_numeric($ifcfg['track6-prefix-id'])) {
4413
					$trackiflist[$ifname] = $ifcfg;
4414
				}
4415
			}
4416

    
4417
			/* skip address request if this is set */
4418
			if (!isset($wancfg['dhcp6prefixonly'])) {
4419
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4420
			}
4421
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4422
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4423
			}
4424

    
4425
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4426
			$dhcp6cconf .= "\trequest domain-name;\n";
4427

    
4428
			/*
4429
			 * dhcp6c will run different scripts depending on
4430
			 * whether dhcpwithoutra is set or unset.
4431
			 */
4432
			if (isset($wancfg['dhcp6withoutra'])) {
4433
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4434
			} else {
4435
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4436
			}
4437
			$dhcp6cconf .= "};\n";
4438

    
4439
			if (!isset($wancfg['dhcp6prefixonly'])) {
4440
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4441
			}
4442

    
4443
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4444
				/* Setup the prefix delegation */
4445
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4446
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4447
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4448
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4449
				}
4450
				foreach ($trackiflist as $friendly => $ifcfg) {
4451
					if ($g['debug']) {
4452
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4453
					}
4454
					$realif = get_real_interface($friendly);
4455
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4456
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4457
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4458
					$dhcp6cconf .= "\t};\n";
4459
				}
4460
				unset($preflen, $iflist, $ifcfg, $ifname);
4461
				$dhcp6cconf .= "};\n";
4462
			}
4463
			unset($trackiflist);
4464
		}
4465
	}
4466

    
4467
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4468
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4469

    
4470
	/* wide-dhcp6c works for now. */
4471
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4472
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4473
		unset($dhcp6cconf);
4474
		return 1;
4475
	}
4476
	unset($dhcp6cconf);
4477

    
4478
	/*************** Script Debug Logging ***************************
4479
	Both dhcp6 scripts now have a logging message built in.
4480
	These logging messages ONLY appear if dhcp6c debug logging is set.
4481
	The logging messages appear in the dhcp section of the logs,
4482
	not in system.
4483

    
4484
	These scripts now also take advantage of the REASON= env vars
4485
	supplied by dhcp6c.
4486
	****************************************************************/
4487

    
4488
	/* Script create for dhcp6withoutRA mode */
4489
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4490
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4491
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4492
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4493
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4494
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4495
	// Need to pass params to  the final script
4496
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4497
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4498
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4499
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4500
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
4501
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
4502
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4503
	if ($debugOption == '-D') {
4504
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4505
	}
4506
	$dhcp6cscriptwithoutra .= ";;\n";
4507
	$dhcp6cscriptwithoutra .= "REBIND)\n";
4508
	if ($debugOption == '-D') {
4509
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4510
	}
4511
	$dhcp6cscriptwithoutra .= ";;\n";
4512
	if (isset($wancfg['dhcp6norelease'])) {
4513
		$dhcp6cscriptwithoutra .= "EXIT)\n";
4514
	} else {
4515
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
4516
	}
4517
	if ($debugOption == '-D') {
4518
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4519
	}
4520
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4521
	$dhcp6cscriptwithoutra .= ";;\n";
4522
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
4523
	if ($debugOption == '-D') {
4524
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4525
	}
4526
	$dhcp6cscriptwithoutra .= "esac\n";
4527
	if (!@file_put_contents(
4528
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4529
	    $dhcp6cscriptwithoutra)) {
4530
		printf("Error: cannot open " .
4531
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4532
		    "interface_dhcpv6_configure() for writing.\n");
4533
		unset($dhcp6cscriptwithoutra);
4534
		return 1;
4535
	}
4536

    
4537
	unset($dhcp6cscriptwithoutra);
4538
	@chmod(
4539
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4540
	    0755);
4541

    
4542
	/*
4543
	 * Dual mode wan_dhcp6c script with variations depending on node
4544
	 * dhcp6 will run the wan ipv6 configure
4545
	 */
4546
	$dhcp6cscript  = "#!/bin/sh\n";
4547
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4548
	if (!isset($wancfg['dhcp6withoutra'])) {
4549
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4550
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4551
		$dhcp6cscript .= "case \$REASON in\n";
4552
		$dhcp6cscript .= "REQUEST)\n";
4553
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4554
		if ($debugOption == '-D') {
4555
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4556
		}
4557
		$dhcp6cscript .= ";;\n";
4558
		$dhcp6cscript .= "REBIND)\n";
4559
		if ($debugOption == '-D') {
4560
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4561
		}
4562
		$dhcp6cscript .= ";;\n";
4563
		if (isset($wancfg['dhcp6norelease'])) {
4564
			$dhcp6cscript .= "EXIT)\n";
4565
		} else {
4566
			$dhcp6cscript .= "RELEASE)\n";
4567
		}
4568
		if ($debugOption == '-D') {
4569
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4570
		}
4571
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4572
		$dhcp6cscript .= ";;\n";
4573
		$dhcp6cscript .= "RENEW|INFO)\n";
4574
		if ($debugOption == '-D') {
4575
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4576
		}
4577
		$dhcp6cscript .= "esac\n";
4578
	} else {
4579
		// Need to get the parameters from the dhcp6cwithoutRA run
4580
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
4581
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
4582
		$dhcp6cscript .= "/bin/sleep 1\n";
4583
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4584
	}
4585

    
4586
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4587
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4588
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4589
		unset($dhcp6cscript);
4590
		return 1;
4591
	}
4592
	unset($dhcp6cscript);
4593
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4594

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

    
4601
	/* non ipoe Process */
4602
	if (!isset($wancfg['dhcp6withoutra'])) {
4603
		/*
4604
		 * We only want this script to run once, and if it runs twice
4605
		 * then do not launch dhcp6c again, this only happens if
4606
		 * dhcpwithoutra is not set.
4607
		 *
4608
		 * Check for a lock file, trying to prevent multiple instances
4609
		 * of dhcp6c being launched
4610
		 */
4611
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
4612
		/*
4613
		 * Create the lock file, trying to prevent multiple instances
4614
		 * of dhcp6c being launched
4615
		 */
4616
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
4617
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
4618
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4619
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4620
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
4621
		$rtsoldscript .= "\tfi\n";
4622
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
4623
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
4624
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4625
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4626
		$rtsoldscript .= "else\n";
4627
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
4628
		$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c_{$wanif}.pid\")\n";
4629
		$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
4630
		$rtsoldscript .= "fi\n";
4631
	} else {
4632
		/*
4633
		 * The script needs to run in dhcp6withoutra mode as RA may
4634
		 * not have been received, or there can be a delay with
4635
		 * certain ISPs
4636
		 */
4637
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
4638
		$rtsoldscript .= "/bin/sleep 1\n";
4639
	}
4640
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4641
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4642
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4643
		unset($rtsoldscript);
4644
		return 1;
4645
	}
4646
	unset($rtsoldscript);
4647
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4648

    
4649
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4650
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4651
		log_error("Killing running rtsold process");
4652
		sleep(2);
4653
	}
4654

    
4655
	if (isset($wancfg['dhcp6withoutra'])) {
4656
		/*
4657
		 * Start dhcp6c here if we don't want to wait for ra - calls
4658
		 * seperate function
4659
		 *
4660
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
4661
		 * will then run the configure on receipt of the RA.
4662
		 *
4663
		 * Already started. interface_dhcpv6_configure() appears to get
4664
		 * called multiple times.
4665
		 *
4666
		 * Taking the interface down or releasing will kill the client.
4667
		 */
4668
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
4669
		{
4670
			/*
4671
			 * If the interface is being brought up, wait for the
4672
			 * interface to configure accept RA before launching.
4673
			 * Otherwise it is not ready to accept and will fail.
4674
			 */
4675
			sleep(3);
4676
			run_dhcp6client_process($wanif,$interface,$wancfg);
4677
		}
4678
	} else {
4679
		/*
4680
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
4681
		 * ( it does not background, it exits! ) It will launch dhcp6c
4682
		 * if dhcpwihtoutra is not set
4683
		 */
4684
		log_error("Starting rtsold process");
4685
		sleep(2);
4686
		mwexec("/usr/sbin/rtsold -1 " .
4687
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
4688
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
4689
		    $wanif);
4690
	}
4691
	/*
4692
	 * NOTE: will be called from rtsold invoked script
4693
	 * link_interface_to_track6($interface, "update");
4694
	 */
4695

    
4696
	return 0;
4697
}
4698

    
4699
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4700
	global $g;
4701

    
4702
	$send_options = "";
4703
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4704
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4705
		foreach ($options as $option) {
4706
			$send_options .= "\tsend " . trim($option) . ";\n";
4707
		}
4708
	}
4709

    
4710
	$request_options = "";
4711
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4712
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4713
		foreach ($options as $option) {
4714
			$request_options .= "\trequest " . trim($option) . ";\n";
4715
		}
4716
	}
4717

    
4718
	$information_only = "";
4719
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4720
		$information_only = "\tinformation-only;\n";
4721
	}
4722

    
4723
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4724
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4725
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4726
	}
4727

    
4728
	$interface_statement  = "interface";
4729
	$interface_statement .= " {$wanif}";
4730
	$interface_statement .= " {\n";
4731
	$interface_statement .= "$send_options";
4732
	$interface_statement .= "$request_options";
4733
	$interface_statement .= "$information_only";
4734
	$interface_statement .= "$script";
4735
	$interface_statement .= "};\n";
4736

    
4737
	$id_assoc_statement_address = "";
4738
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4739
		$id_assoc_statement_address .= "id-assoc";
4740
		$id_assoc_statement_address .= " na";
4741
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4742
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4743
		}
4744
		$id_assoc_statement_address .= " { ";
4745

    
4746
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4747
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4748
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4749
			$id_assoc_statement_address .= "\n\taddress";
4750
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4751
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4752
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4753
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4754
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4755
			}
4756
			$id_assoc_statement_address .= ";\n";
4757
		}
4758

    
4759
		$id_assoc_statement_address .= "};\n";
4760
	}
4761

    
4762
	$id_assoc_statement_prefix = "";
4763
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4764
		$id_assoc_statement_prefix .= "id-assoc";
4765
		$id_assoc_statement_prefix .= " pd";
4766
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4767
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4768
		}
4769
		$id_assoc_statement_prefix .= " { ";
4770

    
4771
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4772
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4773
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4774
			$id_assoc_statement_prefix .= "\n\tprefix";
4775
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4776
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4777
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4778
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4779
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4780
			}
4781
			$id_assoc_statement_prefix .= ";";
4782
		}
4783

    
4784
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
4785
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4786
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4787
			$id_assoc_statement_prefix .= " {$realif}";
4788
			$id_assoc_statement_prefix .= " {\n";
4789
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4790
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4791
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4792
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4793
			}
4794
			$id_assoc_statement_prefix .= "\t};";
4795
		}
4796

    
4797
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4798
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4799
			$id_assoc_statement_prefix .= "\n";
4800
		}
4801

    
4802
		$id_assoc_statement_prefix .= "};\n";
4803
	}
4804

    
4805
	$authentication_statement = "";
4806
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4807
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4808
		$authentication_statement .= "authentication";
4809
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4810
		$authentication_statement .= " {\n";
4811
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4812
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4813
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4814
		}
4815
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4816
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4817
		}
4818
		$authentication_statement .= "};\n";
4819
	}
4820

    
4821
	$key_info_statement = "";
4822
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4823
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4824
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4825
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4826
		$key_info_statement .= "keyinfo";
4827
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4828
		$key_info_statement .= " {\n";
4829
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4830
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4831
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4832
		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'])) {
4833
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4834
		}
4835
		$key_info_statement .= "};\n";
4836
	}
4837

    
4838
	$dhcp6cconf  = $interface_statement;
4839
	$dhcp6cconf .= $id_assoc_statement_address;
4840
	$dhcp6cconf .= $id_assoc_statement_prefix;
4841
	$dhcp6cconf .= $authentication_statement;
4842
	$dhcp6cconf .= $key_info_statement;
4843

    
4844
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4845

    
4846
	return $dhcp6cconf;
4847
}
4848

    
4849

    
4850
function DHCP6_Config_File_Override($wancfg, $wanif) {
4851

    
4852
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4853

    
4854
	if ($dhcp6cconf === false) {
4855
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4856
		return '';
4857
	} else {
4858
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4859
	}
4860
}
4861

    
4862

    
4863
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4864

    
4865
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4866

    
4867
	return $dhcp6cconf;
4868
}
4869

    
4870

    
4871
function interface_dhcp_configure($interface = "wan") {
4872
	global $config, $g;
4873

    
4874
	$ifcfg = $config['interfaces'][$interface];
4875
	if (empty($ifcfg)) {
4876
		$ifcfg = array();
4877
	}
4878

    
4879
	/* generate dhclient_wan.conf */
4880
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4881
	if (!$fd) {
4882
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4883
		return 1;
4884
	}
4885

    
4886
	if ($ifcfg['dhcphostname']) {
4887
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
4888
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
4889
	} else {
4890
		$dhclientconf_hostname = "";
4891
	}
4892

    
4893
	$realif = get_real_interface($interface);
4894
	if (empty($realif)) {
4895
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4896
		return 0;
4897
	}
4898
	$dhclientconf = "";
4899

    
4900
	$dhclientconf .= <<<EOD
4901
interface "{$realif}" {
4902
	supersede interface-mtu 0;
4903
	timeout 60;
4904
	retry 15;
4905
	select-timeout 0;
4906
	initial-interval 1;
4907
	{$dhclientconf_hostname}
4908
	script "/usr/local/sbin/pfSense-dhclient-script";
4909
EOD;
4910

    
4911
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
4912
		$dhclientconf .= <<<EOD
4913

    
4914
	reject {$ifcfg['dhcprejectfrom']};
4915
EOD;
4916
	}
4917
	$dhclientconf .= <<<EOD
4918

    
4919
}
4920

    
4921
EOD;
4922

    
4923
	// DHCP Config File Advanced
4924
	if ($ifcfg['adv_dhcp_config_advanced']) {
4925
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
4926
	}
4927

    
4928
	if (is_ipaddr($ifcfg['alias-address'])) {
4929
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
4930
		$dhclientconf .= <<<EOD
4931
alias {
4932
	interface "{$realif}";
4933
	fixed-address {$ifcfg['alias-address']};
4934
	option subnet-mask {$subnetmask};
4935
}
4936

    
4937
EOD;
4938
	}
4939

    
4940
	// DHCP Config File Override
4941
	if ($ifcfg['adv_dhcp_config_file_override']) {
4942
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
4943
	}
4944

    
4945
	fwrite($fd, $dhclientconf);
4946
	fclose($fd);
4947

    
4948
	/* bring wan interface up before starting dhclient */
4949
	if ($realif) {
4950
		interfaces_bring_up($realif);
4951
	}
4952

    
4953
	/* Make sure dhclient is not running */
4954
	kill_dhclient_process($realif);
4955

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

    
4959
	return 0;
4960
}
4961

    
4962
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
4963

    
4964
	$hostname = "";
4965
	if ($ifcfg['dhcphostname'] != '') {
4966
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
4967
	}
4968

    
4969
	/* DHCP Protocol Timings */
4970
	$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");
4971
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4972
		$pt_variable = "{$Protocol_Timing}";
4973
		${$pt_variable} = "";
4974
		if ($ifcfg[$Protocol_Timing] != "") {
4975
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
4976
		}
4977
	}
4978

    
4979
	$send_options = "";
4980
	if ($ifcfg['adv_dhcp_send_options'] != '') {
4981
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
4982
		foreach ($options as $option) {
4983
			$send_options .= "\tsend " . trim($option) . ";\n";
4984
		}
4985
	}
4986

    
4987
	$request_options = "";
4988
	if ($ifcfg['adv_dhcp_request_options'] != '') {
4989
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
4990
	}
4991

    
4992
	$required_options = "";
4993
	if ($ifcfg['adv_dhcp_required_options'] != '') {
4994
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
4995
	}
4996

    
4997
	$option_modifiers = "";
4998
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
4999
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5000
		foreach ($modifiers as $modifier) {
5001
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5002
		}
5003
	}
5004

    
5005
	$dhclientconf  = "interface \"{$realif}\" {\n";
5006
	$dhclientconf .= "\n";
5007
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5008
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5009
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5010
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5011
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5012
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5013
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5014
	$dhclientconf .= "\n";
5015
	$dhclientconf .= "# DHCP Protocol Options\n";
5016
	$dhclientconf .= "{$hostname}";
5017
	$dhclientconf .= "{$send_options}";
5018
	$dhclientconf .= "{$request_options}";
5019
	$dhclientconf .= "{$required_options}";
5020
	$dhclientconf .= "{$option_modifiers}";
5021
	$dhclientconf .= "\n";
5022
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5023
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5024
	}
5025
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5026
	$dhclientconf .= "}\n";
5027

    
5028
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5029

    
5030
	return $dhclientconf;
5031
}
5032

    
5033
function DHCP_Config_Option_Split($option_string) {
5034
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5035
	return $matches ? $matches[0] : [];
5036
}
5037

    
5038
function DHCP_Config_File_Override($ifcfg, $realif) {
5039

    
5040
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5041

    
5042
	if ($dhclientconf === false) {
5043
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5044
		return '';
5045
	} else {
5046
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5047
	}
5048
}
5049

    
5050

    
5051
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5052

    
5053
	/* Apply Interface Substitutions */
5054
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5055

    
5056
	/* Apply Hostname Substitutions */
5057
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5058

    
5059
	/* Arrays of MAC Address Types, Cases, Delimiters */
5060
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5061
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5062
	$various_mac_cases      = array("U", "L");
5063
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5064

    
5065
	/* Apply MAC Address Substitutions */
5066
	foreach ($various_mac_types as $various_mac_type) {
5067
		foreach ($various_mac_cases as $various_mac_case) {
5068
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5069

    
5070
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5071
				if ($res !== false) {
5072

    
5073
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5074
					if ("$various_mac_case" == "U") {
5075
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5076
					}
5077
					if ("$various_mac_case" == "L") {
5078
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5079
					}
5080

    
5081
					if ("$various_mac_type" == "mac_addr_hex") {
5082
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5083
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5084
						$dhcpclientconf_mac_hex = "";
5085
						$delimiter = "";
5086
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5087
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5088
							$delimiter = ":";
5089
						}
5090
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5091
					}
5092

    
5093
					/* MAC Address Delimiter Substitutions */
5094
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5095

    
5096
					/* Apply MAC Address Substitutions */
5097
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5098
				}
5099
			}
5100
		}
5101
	}
5102

    
5103
	return $dhclientconf;
5104
}
5105

    
5106
function interfaces_group_setup() {
5107
	global $config;
5108

    
5109
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
5110
		return;
5111
	}
5112

    
5113
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5114
		interface_group_setup($groupar);
5115
	}
5116

    
5117
	return;
5118
}
5119

    
5120
function interface_group_setup(&$groupname /* The parameter is an array */) {
5121
	global $config;
5122

    
5123
	if (!is_array($groupname)) {
5124
		return;
5125
	}
5126
	$members = explode(" ", $groupname['members']);
5127
	foreach ($members as $ifs) {
5128
		$realif = get_real_interface($ifs);
5129
		if ($realif && does_interface_exist($realif)) {
5130
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5131
		}
5132
	}
5133

    
5134
	return;
5135
}
5136

    
5137
function is_interface_group($if) {
5138
	global $config;
5139

    
5140
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5141
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5142
			if ($groupentry['ifname'] === $if) {
5143
				return true;
5144
			}
5145
		}
5146
	}
5147

    
5148
	return false;
5149
}
5150

    
5151
function interface_group_add_member($interface, $groupname) {
5152
	$interface = get_real_interface($interface);
5153
	if (does_interface_exist($interface)) {
5154
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5155
	}
5156
}
5157

    
5158
/* COMPAT Function */
5159
function convert_friendly_interface_to_real_interface_name($interface) {
5160
	return get_real_interface($interface);
5161
}
5162

    
5163
/* COMPAT Function */
5164
function get_real_wan_interface($interface = "wan") {
5165
	return get_real_interface($interface);
5166
}
5167

    
5168
/* COMPAT Function */
5169
function get_current_wan_address($interface = "wan") {
5170
	return get_interface_ip($interface);
5171
}
5172

    
5173
/*
5174
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5175
 */
5176
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5177
	global $config;
5178

    
5179
	/* XXX: For speed reasons reference directly the interface array */
5180
	$ifdescrs = &$config['interfaces'];
5181
	//$ifdescrs = get_configured_interface_list(true);
5182

    
5183
	foreach ($ifdescrs as $if => $ifname) {
5184
		if ($if == $interface || $ifname['if'] == $interface) {
5185
			return $if;
5186
		}
5187

    
5188
		if (get_real_interface($if) == $interface) {
5189
			return $if;
5190
		}
5191

    
5192
		if ($checkparent == false) {
5193
			continue;
5194
		}
5195

    
5196
		$int = get_parent_interface($if, true);
5197
		if (is_array($int)) {
5198
			foreach ($int as $iface) {
5199
				if ($iface == $interface) {
5200
					return $if;
5201
				}
5202
			}
5203
		}
5204
	}
5205

    
5206
	if ($interface == "enc0") {
5207
		return 'IPsec';
5208
	}
5209
}
5210

    
5211
/* attempt to resolve interface to friendly descr */
5212
function convert_friendly_interface_to_friendly_descr($interface) {
5213
	global $config;
5214

    
5215
	switch ($interface) {
5216
		case "l2tp":
5217
			$ifdesc = "L2TP";
5218
			break;
5219
		case "pptp":
5220
			$ifdesc = "PPTP";
5221
			break;
5222
		case "pppoe":
5223
			$ifdesc = "PPPoE";
5224
			break;
5225
		case "openvpn":
5226
			$ifdesc = "OpenVPN";
5227
			break;
5228
		case "lo0":
5229
			$ifdesc = "Loopback";
5230
			break;
5231
		case "enc0":
5232
		case "ipsec":
5233
		case "IPsec":
5234
			$ifdesc = "IPsec";
5235
			break;
5236
		default:
5237
			if (isset($config['interfaces'][$interface])) {
5238
				if (empty($config['interfaces'][$interface]['descr'])) {
5239
					$ifdesc = strtoupper($interface);
5240
				} else {
5241
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5242
				}
5243
				break;
5244
			} else if (substr($interface, 0, 4) == '_vip') {
5245
				if (is_array($config['virtualip']['vip'])) {
5246
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5247
						if ($vip['mode'] == "carp") {
5248
							if ($interface == "_vip{$vip['uniqid']}") {
5249
								$descr = $vip['subnet'];
5250
								$descr .= " (vhid {$vip['vhid']})";
5251
								if (!empty($vip['descr'])) {
5252
									$descr .= " - " .$vip['descr'];
5253
								}
5254
								return $descr;
5255
							}
5256
						}
5257
					}
5258
				}
5259
			} else if (substr($interface, 0, 5) == '_lloc') {
5260
				return get_interface_linklocal($interface);
5261
			} else {
5262
				if (is_array($config['ifgroups']['ifgroupentry'])) {
5263
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5264
						if ($ifgen['ifname'] === $interface) {
5265
							return $ifgen['ifname'];
5266
						}
5267
					}
5268
				}
5269

    
5270
				/* if list */
5271
				$ifdescrs = get_configured_interface_with_descr(true);
5272
				foreach ($ifdescrs as $if => $ifname) {
5273
					if ($if == $interface || $ifname == $interface) {
5274
						return $ifname;
5275
					}
5276
				}
5277
			}
5278
			break;
5279
	}
5280

    
5281
	return $ifdesc;
5282
}
5283

    
5284
function convert_real_interface_to_friendly_descr($interface) {
5285

    
5286
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5287

    
5288
	if (!empty($ifdesc)) {
5289
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5290
	}
5291

    
5292
	return $interface;
5293
}
5294

    
5295
/*
5296
 *  get_parent_interface($interface):
5297
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5298
 *				or virtual interface (i.e. vlan)
5299
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5300
 *			-- returns $interface passed in if $interface parent is not found
5301
 *			-- returns empty array if an invalid interface is passed
5302
 *	(Only handles ppps and vlans now.)
5303
 */
5304
function get_parent_interface($interface, $avoidrecurse = false) {
5305
	global $config;
5306

    
5307
	$parents = array();
5308
	//Check that we got a valid interface passed
5309
	$realif = get_real_interface($interface);
5310
	if ($realif == NULL) {
5311
		return $parents;
5312
	}
5313

    
5314
	// If we got a real interface, find it's friendly assigned name
5315
	if ($interface == $realif && $avoidrecurse == false) {
5316
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5317
	}
5318

    
5319
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5320
		$ifcfg = $config['interfaces'][$interface];
5321
		switch ($ifcfg['ipaddr']) {
5322
			case "ppp":
5323
			case "pppoe":
5324
			case "pptp":
5325
			case "l2tp":
5326
				if (empty($parents)) {
5327
					if (is_array($config['ppps']['ppp'])) {
5328
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5329
							if ($ifcfg['if'] == $ppp['if']) {
5330
								$ports = explode(',', $ppp['ports']);
5331
								foreach ($ports as $pid => $parent_if) {
5332
									$parents[$pid] = get_real_interface($parent_if);
5333
								}
5334
								break;
5335
							}
5336
						}
5337
					}
5338
				}
5339
				break;
5340
			case "dhcp":
5341
			case "static":
5342
			default:
5343
				// Handle _vlans
5344
				$vlan = interface_is_vlan($ifcfg['if']);
5345
				if ($vlan != NULL) {
5346
					$parents[0] = $vlan['if'];
5347
				}
5348
				break;
5349
		}
5350
	}
5351

    
5352
	if (empty($parents)) {
5353
		// Handle _vlans not assigned to an interface
5354
		$vlan = interface_is_vlan($realif);
5355
		if ($vlan != NULL) {
5356
			$parents[0] = $vlan['if'];
5357
		}
5358
	}
5359

    
5360
	if (empty($parents)) {
5361
		$parents[0] = $realif;
5362
	}
5363

    
5364
	return $parents;
5365
}
5366

    
5367
/*
5368
 *  get_parent_physical_interface($interface):
5369
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5370
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5371
 */
5372
function get_parent_physical_interface($interface) {
5373
	global $config;
5374

    
5375
	$realif = get_parent_interface($interface);
5376

    
5377
	if (substr($realif[0], 0, 4) == "lagg") {
5378
		foreach ($config['laggs']['lagg'] as $lagg) {
5379
			if ($realif[0] == $lagg['laggif']) {
5380
				return explode(",", $lagg['members']);
5381
			}
5382
		}
5383
	} else {
5384
		return $realif;
5385
	}
5386
}
5387

    
5388
function interface_is_wireless_clone($wlif) {
5389
	if (!stristr($wlif, "_wlan")) {
5390
		return false;
5391
	} else {
5392
		return true;
5393
	}
5394
}
5395

    
5396
function interface_get_wireless_base($wlif) {
5397
	if (!stristr($wlif, "_wlan")) {
5398
		return $wlif;
5399
	} else {
5400
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5401
	}
5402
}
5403

    
5404
function interface_get_wireless_clone($wlif) {
5405
	if (!stristr($wlif, "_wlan")) {
5406
		return $wlif . "_wlan0";
5407
	} else {
5408
		return $wlif;
5409
	}
5410
}
5411

    
5412
function interface_list_wireless() {
5413
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5414

    
5415
	$result = array();
5416
	foreach ($portlist as $port) {
5417
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5418
			continue;
5419
		}
5420

    
5421
		$desc = $port . " ( " . get_single_sysctl(
5422
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5423

    
5424
		$result[] = array(
5425
		    "if" => $port,
5426
		    "descr" => $desc
5427
		);
5428
	}
5429

    
5430
	return $result;
5431
}
5432

    
5433
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
5434
	global $config, $g;
5435

    
5436
	$wanif = NULL;
5437

    
5438
	switch ($interface) {
5439
		case "l2tp":
5440
			$wanif = "l2tp";
5441
			break;
5442
		case "pptp":
5443
			$wanif = "pptp";
5444
			break;
5445
		case "pppoe":
5446
			$wanif = "pppoe";
5447
			break;
5448
		case "openvpn":
5449
			$wanif = "openvpn";
5450
			break;
5451
		case "IPsec":
5452
		case "ipsec":
5453
		case "enc0":
5454
			$wanif = "enc0";
5455
			break;
5456
		case "ppp":
5457
			$wanif = "ppp";
5458
			break;
5459
		default:
5460
			if (substr($interface, 0, 4) == '_vip') {
5461
				$wanif = get_configured_vip_interface($interface);
5462
				if (!empty($wanif)) {
5463
					$wanif = get_real_interface($wanif);
5464
				}
5465
				break;
5466
			} else if (substr($interface, 0, 5) == '_lloc') {
5467
				$interface = substr($interface, 5);
5468
			} else if (interface_is_vlan($interface) != NULL ||
5469
			    does_interface_exist($interface, $flush)) {
5470
				/*
5471
				 * If a real interface was already passed simply
5472
				 * pass the real interface back.  This encourages
5473
				 * the usage of this function in more cases so that
5474
				 * we can combine logic for more flexibility.
5475
				 */
5476
				$wanif = $interface;
5477
				break;
5478
			}
5479

    
5480
			if (empty($config['interfaces'][$interface])) {
5481
				break;
5482
			}
5483

    
5484
			$cfg = &$config['interfaces'][$interface];
5485

    
5486
			if ($family == "inet6") {
5487
				switch ($cfg['ipaddrv6']) {
5488
					case "6rd":
5489
					case "6to4":
5490
						$wanif = "{$interface}_stf";
5491
						break;
5492
					case 'pppoe':
5493
					case 'ppp':
5494
					case 'l2tp':
5495
					case 'pptp':
5496
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5497
							$wanif = interface_get_wireless_clone($cfg['if']);
5498
						} else {
5499
							$wanif = $cfg['if'];
5500
						}
5501
						break;
5502
					default:
5503
						switch ($cfg['ipaddr']) {
5504
							case 'pppoe':
5505
							case 'ppp':
5506
							case 'l2tp':
5507
							case 'pptp':
5508
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
5509
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) || isset($cfg['ipv6usev4iface'])) {
5510
									$wanif = $cfg['if'];
5511
								} else {
5512
									$parents = get_parent_interface($interface);
5513
									if (!empty($parents[0])) {
5514
										$wanif = $parents[0];
5515
									} else {
5516
										$wanif = $cfg['if'];
5517
									}
5518
								}
5519
								break;
5520
							default:
5521
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5522
									$wanif = interface_get_wireless_clone($cfg['if']);
5523
								} else {
5524
									$wanif = $cfg['if'];
5525
								}
5526
								break;
5527
						}
5528
						break;
5529
				}
5530
			} else {
5531
				// Wireless cloned NIC support (FreeBSD 8+)
5532
				// interface name format: $parentnic_wlanparentnic#
5533
				// example: ath0_wlan0
5534
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5535
					$wanif = interface_get_wireless_clone($cfg['if']);
5536
				} else {
5537
					$wanif = $cfg['if'];
5538
				}
5539
			}
5540
			break;
5541
	}
5542

    
5543
	return $wanif;
5544
}
5545

    
5546
/* Guess the physical interface by providing a IP address */
5547
function guess_interface_from_ip($ipaddress) {
5548

    
5549
	$family = '';
5550
	if (is_ipaddrv4($ipaddress)) {
5551
		$family = 'inet';
5552
	}
5553
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5554
		$family = 'inet6';
5555
	}
5556

    
5557
	if (empty($family)) {
5558
		return false;
5559
	}
5560

    
5561
	/* create a route table we can search */
5562
	$output = '';
5563
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
5564
	$output[0] = trim($output[0], " \n");
5565
	if (!empty($output[0])) {
5566
		return $output[0];
5567
	}
5568

    
5569
	return false;
5570
}
5571

    
5572
/*
5573
 * find_ip_interface($ip): return the interface where an ip is defined
5574
 *   (or if $bits is specified, where an IP within the subnet is defined)
5575
 */
5576
function find_ip_interface($ip, $bits = null) {
5577
	if (!is_ipaddr($ip)) {
5578
		return false;
5579
	}
5580

    
5581
	$isv6ip = is_ipaddrv6($ip);
5582

    
5583
	/* if list */
5584
	$ifdescrs = get_configured_interface_list();
5585

    
5586
	foreach ($ifdescrs as $ifdescr => $ifname) {
5587
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
5588
		if (is_null($ifip)) {
5589
			continue;
5590
		}
5591
		if (is_null($bits)) {
5592
			if ($ip == $ifip) {
5593
				$int = get_real_interface($ifname);
5594
				return $int;
5595
			}
5596
		} else {
5597
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
5598
				$int = get_real_interface($ifname);
5599
				return $int;
5600
			}
5601
		}
5602
	}
5603

    
5604
	return false;
5605
}
5606

    
5607
/*
5608
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5609
 *   (or if $bits is specified, where an IP within the subnet is found)
5610
 */
5611
function find_virtual_ip_alias($ip, $bits = null) {
5612
	global $config;
5613

    
5614
	if (!is_array($config['virtualip']['vip'])) {
5615
		return false;
5616
	}
5617
	if (!is_ipaddr($ip)) {
5618
		return false;
5619
	}
5620

    
5621
	$isv6ip = is_ipaddrv6($ip);
5622

    
5623
	foreach ($config['virtualip']['vip'] as $vip) {
5624
		if ($vip['mode'] === "ipalias") {
5625
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
5626
				continue;
5627
			}
5628
			if (is_null($bits)) {
5629
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
5630
					return $vip;
5631
				}
5632
			} else {
5633
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5634
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5635
					return $vip;
5636
				}
5637
			}
5638
		}
5639
	}
5640
	return false;
5641
}
5642

    
5643
function link_interface_to_track6($int, $action = "") {
5644
	global $config;
5645

    
5646
	if (empty($int)) {
5647
		return;
5648
	}
5649

    
5650
	if (is_array($config['interfaces'])) {
5651
		$list = array();
5652
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5653
			if (!isset($ifcfg['enable'])) {
5654
				continue;
5655
			}
5656
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5657
				if ($action == "update") {
5658
					interface_track6_configure($ifname, $ifcfg);
5659
				} else if ($action == "") {
5660
					$list[$ifname] = $ifcfg;
5661
				}
5662
			}
5663
		}
5664
		return $list;
5665
	}
5666
}
5667

    
5668
function interface_find_child_cfgmtu($realiface) {
5669
	global $config;
5670

    
5671
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5672
	$vlans = link_interface_to_vlans($realiface);
5673
	$qinqs = link_interface_to_qinqs($realiface);
5674
	$bridge = link_interface_to_bridge($realiface);
5675
	if (!empty($interface)) {
5676
		$gifs = link_interface_to_gif($interface);
5677
		$gres = link_interface_to_gre($interface);
5678
	} else {
5679
		$gifs = array();
5680
		$gres = array();
5681
	}
5682

    
5683
	$mtu = 0;
5684
	if (is_array($vlans)) {
5685
		foreach ($vlans as $vlan) {
5686
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5687
			if (empty($ifass)) {
5688
				continue;
5689
			}
5690
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5691
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5692
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5693
				}
5694
			}
5695
		}
5696
	}
5697
	if (is_array($qinqs)) {
5698
		foreach ($qinqs as $qinq) {
5699
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5700
			if (empty($ifass)) {
5701
				continue;
5702
			}
5703
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5704
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5705
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5706
				}
5707
			}
5708
		}
5709
	}
5710
	if (is_array($gifs)) {
5711
		foreach ($gifs as $gif) {
5712
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5713
			if (empty($ifass)) {
5714
				continue;
5715
			}
5716
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5717
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5718
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5719
				}
5720
			}
5721
		}
5722
	}
5723
	if (is_array($gres)) {
5724
		foreach ($gres as $gre) {
5725
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5726
			if (empty($ifass)) {
5727
				continue;
5728
			}
5729
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5730
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5731
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5732
				}
5733
			}
5734
		}
5735
	}
5736
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5737
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5738
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5739
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5740
		}
5741
	}
5742
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5743

    
5744
	return $mtu;
5745
}
5746

    
5747
function link_interface_to_vlans($int, $action = "") {
5748
	global $config;
5749

    
5750
	if (empty($int)) {
5751
		return;
5752
	}
5753

    
5754
	if (is_array($config['vlans']['vlan'])) {
5755
		$ifaces = array();
5756
		foreach ($config['vlans']['vlan'] as $vlan) {
5757
			if ($int == $vlan['if']) {
5758
				if ($action == "update") {
5759
					interfaces_bring_up($int);
5760
				} else {
5761
					$ifaces[$vlan['tag']] = $vlan;
5762
				}
5763
			}
5764
		}
5765
		if (!empty($ifaces)) {
5766
			return $ifaces;
5767
		}
5768
	}
5769
}
5770

    
5771
function link_interface_to_qinqs($int, $action = "") {
5772
	global $config;
5773

    
5774
	if (empty($int)) {
5775
		return;
5776
	}
5777

    
5778
	if (is_array($config['qinqs']['qinqentry'])) {
5779
		$ifaces = array();
5780
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5781
			if ($int == $qinq['if']) {
5782
				if ($action == "update") {
5783
					interfaces_bring_up($int);
5784
				} else {
5785
					$ifaces[$qinq['tag']] = $qinq;
5786
				}
5787
			}
5788
		}
5789
		if (!empty($ifaces)) {
5790
			return $ifaces;
5791
		}
5792
	}
5793
}
5794

    
5795
function link_interface_to_vips($int, $action = "", $vhid = '') {
5796
	global $config;
5797

    
5798
	$updatevips = false;
5799
	if (is_array($config['virtualip']['vip'])) {
5800
		$result = array();
5801
		foreach ($config['virtualip']['vip'] as $vip) {
5802
			if (substr($vip['interface'], 0, 4) == "_vip") {
5803
				$iface = get_configured_vip_interface($vip['interface']);
5804
			} else {
5805
				$iface = $vip['interface'];
5806
			}
5807
			if ($int != $iface) {
5808
				continue;
5809
			}
5810
			if ($action == "update") {
5811
				$updatevips = true;
5812
			} else {
5813
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5814
				    substr($vip['interface'], 0, 4) == "_vip") {
5815
					$result[] = $vip;
5816
				}
5817
			}
5818
		}
5819
		if ($updatevips === true) {
5820
			interfaces_vips_configure($int);
5821
		}
5822
		return $result;
5823
	}
5824

    
5825
	return NULL;
5826
}
5827

    
5828
/****f* interfaces/link_interface_to_bridge
5829
 * NAME
5830
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5831
 * INPUTS
5832
 *   $ip
5833
 * RESULT
5834
 *   bridge[0-99]
5835
 ******/
5836
function link_interface_to_bridge($int) {
5837
	global $config;
5838

    
5839
	if (is_array($config['bridges']['bridged'])) {
5840
		foreach ($config['bridges']['bridged'] as $bridge) {
5841
			if (in_array($int, explode(',', $bridge['members']))) {
5842
				return "{$bridge['bridgeif']}";
5843
			}
5844
		}
5845
	}
5846
}
5847

    
5848
function link_interface_to_group($int) {
5849
	global $config;
5850

    
5851
	$result = array();
5852

    
5853
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5854
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5855
			if (in_array($int, explode(" ", $group['members']))) {
5856
				$result[$group['ifname']] = $int;
5857
			}
5858
		}
5859
	}
5860

    
5861
	return $result;
5862
}
5863

    
5864
function link_interface_to_gre($interface) {
5865
	global $config;
5866

    
5867
	$result = array();
5868

    
5869
	if (is_array($config['gres']['gre'])) {
5870
		foreach ($config['gres']['gre'] as $gre) {
5871
			if ($gre['if'] == $interface) {
5872
				$result[] = $gre;
5873
			}
5874
		}
5875
	}
5876

    
5877
	return $result;
5878
}
5879

    
5880
function link_interface_to_gif($interface) {
5881
	global $config;
5882

    
5883
	$result = array();
5884

    
5885
	if (is_array($config['gifs']['gif'])) {
5886
		foreach ($config['gifs']['gif'] as $gif) {
5887
			if ($gif['if'] == $interface) {
5888
				$result[] = $gif;
5889
			}
5890
		}
5891
	}
5892

    
5893
	return $result;
5894
}
5895

    
5896
/*
5897
 * find_interface_ip($interface): return the interface ip (first found)
5898
 */
5899
function find_interface_ip($interface, $flush = false) {
5900
	global $interface_ip_arr_cache;
5901
	global $interface_sn_arr_cache;
5902

    
5903
	$interface = str_replace("\n", "", $interface);
5904

    
5905
	if (!does_interface_exist($interface)) {
5906
		return;
5907
	}
5908

    
5909
	/* Setup IP cache */
5910
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5911
		if (file_exists("/var/db/${interface}_ip")) {
5912
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
5913
			$ifaddrs = pfSense_getall_interface_addresses($interface);
5914
			foreach ($ifaddrs as $ifaddr) {
5915
				list($ip, $mask) = explode("/", $ifaddr);
5916
				if ($ip == $ifip) {
5917
					$interface_ip_arr_cache[$interface] = $ip;
5918
					$interface_sn_arr_cache[$interface] = $mask;
5919
					break;
5920
				}
5921
			}
5922
		}
5923
		if (!isset($interface_ip_arr_cache[$interface])) {
5924
			$ifinfo = pfSense_get_interface_addresses($interface);
5925
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5926
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5927
		}
5928
	}
5929

    
5930
	return $interface_ip_arr_cache[$interface];
5931
}
5932

    
5933
/*
5934
 * find_interface_ipv6($interface): return the interface ip (first found)
5935
 */
5936
function find_interface_ipv6($interface, $flush = false) {
5937
	global $interface_ipv6_arr_cache;
5938
	global $interface_snv6_arr_cache;
5939
	global $config;
5940

    
5941
	$interface = trim($interface);
5942
	$interface = get_real_interface($interface);
5943

    
5944
	if (!does_interface_exist($interface)) {
5945
		return;
5946
	}
5947

    
5948
	/* Setup IP cache */
5949
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5950
		$ifinfo = pfSense_get_interface_addresses($interface);
5951
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5952
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5953
	}
5954

    
5955
	return $interface_ipv6_arr_cache[$interface];
5956
}
5957

    
5958
/*
5959
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5960
 */
5961
function find_interface_ipv6_ll($interface, $flush = false) {
5962
	global $interface_llv6_arr_cache;
5963
	global $config;
5964

    
5965
	$interface = str_replace("\n", "", $interface);
5966

    
5967
	if (!does_interface_exist($interface)) {
5968
		return;
5969
	}
5970

    
5971
	/* Setup IP cache */
5972
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5973
		$ifinfo = pfSense_getall_interface_addresses($interface);
5974
		foreach ($ifinfo as $line) {
5975
			if (strstr($line, ":")) {
5976
				$parts = explode("/", $line);
5977
				if (is_linklocal($parts[0])) {
5978
					$ifinfo['linklocal'] = $parts[0];
5979
				}
5980
			}
5981
		}
5982
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5983
	}
5984
	return $interface_llv6_arr_cache[$interface];
5985
}
5986

    
5987
function find_interface_subnet($interface, $flush = false) {
5988
	global $interface_sn_arr_cache;
5989
	global $interface_ip_arr_cache;
5990

    
5991
	$interface = str_replace("\n", "", $interface);
5992
	if (does_interface_exist($interface) == false) {
5993
		return;
5994
	}
5995

    
5996
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5997
		$ifinfo = pfSense_get_interface_addresses($interface);
5998
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5999
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6000
	}
6001

    
6002
	return $interface_sn_arr_cache[$interface];
6003
}
6004

    
6005
function find_interface_subnetv6($interface, $flush = false) {
6006
	global $interface_snv6_arr_cache;
6007
	global $interface_ipv6_arr_cache;
6008

    
6009
	$interface = str_replace("\n", "", $interface);
6010
	if (does_interface_exist($interface) == false) {
6011
		return;
6012
	}
6013

    
6014
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6015
		$ifinfo = pfSense_get_interface_addresses($interface);
6016
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6017
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6018
	}
6019

    
6020
	return $interface_snv6_arr_cache[$interface];
6021
}
6022

    
6023
function ip_in_interface_alias_subnet($interface, $ipalias) {
6024
	global $config;
6025

    
6026
	if (empty($interface) || !is_ipaddr($ipalias)) {
6027
		return false;
6028
	}
6029
	if (is_array($config['virtualip']['vip'])) {
6030
		foreach ($config['virtualip']['vip'] as $vip) {
6031
			switch ($vip['mode']) {
6032
				case "ipalias":
6033
					if ($vip['interface'] <> $interface) {
6034
						break;
6035
					}
6036
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6037
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6038
						return true;
6039
					}
6040
					break;
6041
			}
6042
		}
6043
	}
6044

    
6045
	return false;
6046
}
6047

    
6048
function get_possible_listen_ips($include_ipv6_link_local=false) {
6049

    
6050
	$interfaces = get_configured_interface_with_descr();
6051
	foreach ($interfaces as $iface => $ifacename) {
6052
		if ($include_ipv6_link_local) {
6053
			/* This is to avoid going though added ll below */
6054
			if (substr($iface, 0, 5) == '_lloc') {
6055
				continue;
6056
			}
6057
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6058
			if (!empty($llip)) {
6059
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6060
			}
6061
		}
6062
	}
6063
	$viplist = get_configured_vip_list();
6064
	foreach ($viplist as $vip => $address) {
6065
		$interfaces[$vip] = $address;
6066
		if (get_vip_descr($address)) {
6067
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6068
		}
6069
	}
6070

    
6071
	$interfaces['lo0'] = 'Localhost';
6072

    
6073
	return $interfaces;
6074
}
6075

    
6076
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6077
	global $config;
6078

    
6079
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6080
	foreach (array('server', 'client') as $mode) {
6081
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6082
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6083
				if (!isset($setting['disable'])) {
6084
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6085
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6086
				}
6087
			}
6088
		}
6089
	}
6090
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
6091
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
6092
			if ($ph1ent['disabled']) {
6093
				continue;
6094
			}
6095
			if (ipsec_vti($ph1ent)) {
6096
				$sourceips_key = "ipsec{$ph1ent['ikeid']}";
6097
				$sourceips[$sourceips_key] = gettext("IPsec VTI") . ": " . htmlspecialchars($ph1ent['descr']);
6098
			}
6099
		}
6100
	}
6101
	return $sourceips;
6102
}
6103

    
6104
function get_interface_ip($interface = "wan") {
6105
	global $config;
6106

    
6107
	if (substr($interface, 0, 4) == '_vip') {
6108
		return get_configured_vip_ipv4($interface);
6109
	} else if (substr($interface, 0, 5) == '_lloc') {
6110
		/* No link-local address for v4. */
6111
		return null;
6112
	}
6113

    
6114
	$realif = get_failover_interface($interface, 'inet');
6115
	if (!$realif) {
6116
		return null;
6117
	}
6118

    
6119
	if (substr($realif, 0, 4) == '_vip') {
6120
		return get_configured_vip_ipv4($realif);
6121
	} else if (substr($realif, 0, 5) == '_lloc') {
6122
		/* No link-local address for v4. */
6123
		return null;
6124
	}
6125

    
6126
	if (is_array($config['interfaces'][$interface]) &&
6127
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6128
		return ($config['interfaces'][$interface]['ipaddr']);
6129
	}
6130

    
6131
	/*
6132
	 * Beaware that find_interface_ip() is our last option, it will
6133
	 * return the first IP it find on interface, not necessarily the
6134
	 * main IP address.
6135
	 */
6136
	$curip = find_interface_ip($realif);
6137
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6138
		return $curip;
6139
	} else {
6140
		return null;
6141
	}
6142
}
6143

    
6144
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6145
	global $config;
6146

    
6147
	if (substr($interface, 0, 4) == '_vip') {
6148
		return get_configured_vip_ipv6($interface);
6149
	} else if (substr($interface, 0, 5) == '_lloc') {
6150
		return get_interface_linklocal($interface);
6151
	}
6152

    
6153
	$realif = get_failover_interface($interface, 'inet6');
6154
	if (!$realif) {
6155
		return null;
6156
	}
6157

    
6158
	if (substr($realif, 0, 4) == '_vip') {
6159
		return get_configured_vip_ipv6($realif);
6160
	} else if (substr($realif, 0, 5) == '_lloc') {
6161
		return get_interface_linklocal($realif);
6162
	}
6163

    
6164
	if (is_array($config['interfaces'][$interface])) {
6165
		switch ($config['interfaces'][$interface]['ipaddr']) {
6166
			case 'pppoe':
6167
			case 'l2tp':
6168
			case 'pptp':
6169
			case 'ppp':
6170
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
6171
					$realif = get_real_interface($interface, 'inet6', false);
6172
				}
6173
				break;
6174
		}
6175
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6176
			return ($config['interfaces'][$interface]['ipaddrv6']);
6177
		}
6178
	}
6179

    
6180
	/*
6181
	 * Beaware that find_interface_ip() is our last option, it will
6182
	 * return the first IP it find on interface, not necessarily the
6183
	 * main IP address.
6184
	 */
6185
	$curip = find_interface_ipv6($realif, $flush);
6186
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6187
		return $curip;
6188
	} else {
6189
		/*
6190
		 * NOTE: On the case when only the prefix is requested,
6191
		 * the communication on WAN will be done over link-local.
6192
		 */
6193
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6194
			$curip = find_interface_ipv6_ll($realif, $flush);
6195
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6196
				return $curip;
6197
			}
6198
		}
6199
	}
6200
	return null;
6201
}
6202

    
6203
function get_interface_linklocal($interface = "wan") {
6204

    
6205
	$realif = get_failover_interface($interface, 'inet6');
6206
	if (!$realif) {
6207
		return null;
6208
	}
6209

    
6210
	if (substr($interface, 0, 4) == '_vip') {
6211
		$realif = get_real_interface($interface);
6212
	} else if (substr($interface, 0, 5) == '_lloc') {
6213
		$realif = get_real_interface(substr($interface, 5));
6214
	}
6215

    
6216
	$curip = find_interface_ipv6_ll($realif);
6217
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6218
		return $curip;
6219
	} else {
6220
		return null;
6221
	}
6222
}
6223

    
6224
function get_interface_subnet($interface = "wan") {
6225
	global $config;
6226

    
6227
	if (substr($interface, 0, 4) == '_vip') {
6228
		return (get_configured_vip_subnetv4($interface));
6229
	}
6230

    
6231
	if (is_array($config['interfaces'][$interface]) &&
6232
		!empty($config['interfaces'][$interface]['subnet'])) {
6233
		return ($config['interfaces'][$interface]['subnet']);
6234
	}
6235

    
6236
	$realif = get_real_interface($interface);
6237
	if (!$realif) {
6238
		return (NULL);
6239
	}
6240

    
6241
	$cursn = find_interface_subnet($realif);
6242
	if (!empty($cursn)) {
6243
		return ($cursn);
6244
	}
6245

    
6246
	return (NULL);
6247
}
6248

    
6249
function get_interface_subnetv6($interface = "wan") {
6250
	global $config;
6251

    
6252
	if (substr($interface, 0, 4) == '_vip') {
6253
		return (get_configured_vip_subnetv6($interface));
6254
	} else if (substr($interface, 0, 5) == '_lloc') {
6255
		$interface = substr($interface, 5);
6256
	}
6257

    
6258
	if (is_array($config['interfaces'][$interface]) &&
6259
		!empty($config['interfaces'][$interface]['subnetv6'])) {
6260
		return ($config['interfaces'][$interface]['subnetv6']);
6261
	}
6262

    
6263
	$realif = get_real_interface($interface, 'inet6');
6264
	if (!$realif) {
6265
		return (NULL);
6266
	}
6267

    
6268
	$cursn = find_interface_subnetv6($realif);
6269
	if (!empty($cursn)) {
6270
		return ($cursn);
6271
	}
6272

    
6273
	return (NULL);
6274
}
6275

    
6276
/* return outside interfaces with a gateway */
6277
function get_interfaces_with_gateway() {
6278
	global $config;
6279

    
6280
	$ints = array();
6281

    
6282
	/* loop interfaces, check config for outbound */
6283
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6284
		switch ($ifname['ipaddr']) {
6285
			case "dhcp":
6286
			case "pppoe":
6287
			case "pptp":
6288
			case "l2tp":
6289
			case "ppp":
6290
				$ints[$ifdescr] = $ifdescr;
6291
				break;
6292
			default:
6293
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6294
				    !empty($ifname['gateway'])) {
6295
					$ints[$ifdescr] = $ifdescr;
6296
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6297
				    !empty($ifname['gateway'])) {
6298
					$ints[$ifdescr] = $ifdescr;
6299
				}
6300

    
6301
				break;
6302
		}
6303
	}
6304
	return $ints;
6305
}
6306

    
6307
/* return true if interface has a gateway */
6308
function interface_has_gateway($friendly) {
6309
	global $config;
6310

    
6311
	if (!empty($config['interfaces'][$friendly])) {
6312
		$ifname = &$config['interfaces'][$friendly];
6313
		switch ($ifname['ipaddr']) {
6314
			case "dhcp":
6315
			case "pppoe":
6316
			case "pptp":
6317
			case "l2tp":
6318
			case "ppp":
6319
				return true;
6320
			break;
6321
			default:
6322
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6323
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6324
					return true;
6325
				}
6326
				$tunnelif = substr($ifname['if'], 0, 3);
6327
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6328
					if (find_interface_ip($ifname['if'])) {
6329
						return true;
6330
					}
6331
				}
6332
				if (!empty($ifname['gateway'])) {
6333
					return true;
6334
				}
6335
			break;
6336
		}
6337
	}
6338

    
6339
	return false;
6340
}
6341

    
6342
/* return true if interface has a gateway */
6343
function interface_has_gatewayv6($friendly) {
6344
	global $config;
6345

    
6346
	if (!empty($config['interfaces'][$friendly])) {
6347
		$ifname = &$config['interfaces'][$friendly];
6348
		switch ($ifname['ipaddrv6']) {
6349
			case "slaac":
6350
			case "dhcp6":
6351
			case "6to4":
6352
			case "6rd":
6353
				return true;
6354
				break;
6355
			default:
6356
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6357
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6358
					return true;
6359
				}
6360
				$tunnelif = substr($ifname['if'], 0, 3);
6361
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6362
					if (find_interface_ipv6($ifname['if'])) {
6363
						return true;
6364
					}
6365
				}
6366
				if (!empty($ifname['gatewayv6'])) {
6367
					return true;
6368
				}
6369
				break;
6370
		}
6371
	}
6372

    
6373
	return false;
6374
}
6375

    
6376
/****f* interfaces/is_altq_capable
6377
 * NAME
6378
 *   is_altq_capable - Test if interface is capable of using ALTQ
6379
 * INPUTS
6380
 *   $int            - string containing interface name
6381
 * RESULT
6382
 *   boolean         - true or false
6383
 ******/
6384

    
6385
function is_altq_capable($int) {
6386
	/* Per:
6387
	 * http://www.freebsd.org/cgi/man.cgi?query=altq&apropos=0&sektion=0&manpath=FreeBSD+11.0-RELEASE&arch=default&format=html
6388
	 * Only the following drivers have ALTQ support
6389
	 * 20150328 - removed wireless drivers - ath, awi, bwn, iwi, ipw, ral, rum, run, wi - for now. redmine #4406
6390
	 */
6391
	$capable = array("ae", "age", "alc", "ale", "an", "aue", "axe", "bce",
6392
			"bfe", "bge", "bridge", "cas", "cpsw", "cxl", "dc", "de",
6393
			"ed", "em", "ep", "epair", "et", "fxp", "gem", "hme", "hn",
6394
			"igb", "jme", "l2tp", "le", "lem", "msk", "mxge", "my",
6395
			"ndis", "nfe", "ng", "nge", "npe", "nve", "ovpnc", "ovpns",
6396
			"ppp", "pppoe", "pptp", "re", "rl", "sf", "sge", "sis", "sk",
6397
			"ste", "stge", "ti", "tun", "txp", "udav", "ural", "vge",
6398
			"vlan", "vmx", "vr", "vte", "vtnet", "xl");
6399

    
6400
	$int_family = remove_ifindex($int);
6401

    
6402
	if (in_array($int_family, $capable)) {
6403
		return true;
6404
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6405
		return true;
6406
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6407
		return true;
6408
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6409
		return true;
6410
	} else {
6411
		return false;
6412
	}
6413
}
6414

    
6415
/****f* interfaces/is_interface_wireless
6416
 * NAME
6417
 *   is_interface_wireless - Returns if an interface is wireless
6418
 * RESULT
6419
 *   $tmp       - Returns if an interface is wireless
6420
 ******/
6421
function is_interface_wireless($interface) {
6422
	global $config, $g;
6423

    
6424
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6425
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6426
		if (preg_match($g['wireless_regex'], $interface)) {
6427
			if (isset($config['interfaces'][$friendly])) {
6428
				$config['interfaces'][$friendly]['wireless'] = array();
6429
			}
6430
			return true;
6431
		}
6432
		return false;
6433
	} else {
6434
		return true;
6435
	}
6436
}
6437

    
6438
function get_wireless_modes($interface) {
6439
	/* return wireless modes and channels */
6440
	$wireless_modes = array();
6441

    
6442
	$cloned_interface = get_real_interface($interface);
6443

    
6444
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6445
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6446
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6447
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6448

    
6449
		$interface_channels = "";
6450
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6451
		$interface_channel_count = count($interface_channels);
6452

    
6453
		$c = 0;
6454
		while ($c < $interface_channel_count) {
6455
			$channel_line = explode(",", $interface_channels["$c"]);
6456
			$wireless_mode = trim($channel_line[0]);
6457
			$wireless_channel = trim($channel_line[1]);
6458
			if (trim($wireless_mode) != "") {
6459
				/* if we only have 11g also set 11b channels */
6460
				if ($wireless_mode == "11g") {
6461
					if (!isset($wireless_modes["11b"])) {
6462
						$wireless_modes["11b"] = array();
6463
					}
6464
				} else if ($wireless_mode == "11g ht") {
6465
					if (!isset($wireless_modes["11b"])) {
6466
						$wireless_modes["11b"] = array();
6467
					}
6468
					if (!isset($wireless_modes["11g"])) {
6469
						$wireless_modes["11g"] = array();
6470
					}
6471
					$wireless_mode = "11ng";
6472
				} else if ($wireless_mode == "11a ht") {
6473
					if (!isset($wireless_modes["11a"])) {
6474
						$wireless_modes["11a"] = array();
6475
					}
6476
					$wireless_mode = "11na";
6477
				}
6478
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6479
			}
6480
			$c++;
6481
		}
6482
	}
6483
	return($wireless_modes);
6484
}
6485

    
6486
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6487
function get_wireless_channel_info($interface) {
6488
	$wireless_channels = array();
6489

    
6490
	$cloned_interface = get_real_interface($interface);
6491

    
6492
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6493
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
6494
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6495
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
6496

    
6497
		$interface_channels = "";
6498
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6499

    
6500
		foreach ($interface_channels as $channel_line) {
6501
			$channel_line = explode(",", $channel_line);
6502
			if (!isset($wireless_channels[$channel_line[0]])) {
6503
				$wireless_channels[$channel_line[0]] = $channel_line;
6504
			}
6505
		}
6506
	}
6507
	return($wireless_channels);
6508
}
6509

    
6510
function set_interface_mtu($interface, $mtu) {
6511

    
6512
	/* LAGG interface must be destroyed and re-created to change MTU */
6513
	if (substr($interface, 0, 4) == 'lagg') {
6514
		if (isset($config['laggs']['lagg']) &&
6515
		    is_array($config['laggs']['lagg'])) {
6516
			foreach ($config['laggs']['lagg'] as $lagg) {
6517
				if ($lagg['laggif'] == $interface) {
6518
					interface_lagg_configure($lagg);
6519
					break;
6520
				}
6521
			}
6522
		}
6523
	} else {
6524
		pfSense_interface_mtu($interface, $mtu);
6525
	}
6526
}
6527

    
6528
/****f* interfaces/get_interface_mtu
6529
 * NAME
6530
 *   get_interface_mtu - Return the mtu of an interface
6531
 * RESULT
6532
 *   $tmp       - Returns the mtu of an interface
6533
 ******/
6534
function get_interface_mtu($interface) {
6535
	$mtu = pfSense_interface_getmtu($interface);
6536
	return $mtu['mtu'];
6537
}
6538

    
6539
function get_interface_mac($interface) {
6540
	$macinfo = pfSense_get_interface_addresses($interface);
6541
	return $macinfo["macaddr"];
6542
}
6543

    
6544
function get_interface_vendor_mac($interface) {
6545
	$macinfo = pfSense_get_interface_addresses($interface);
6546
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] != "00:00:00:00:00:00") {
6547
		return ($macinfo["hwaddr"]);
6548
	}
6549
	return (NULL);
6550
}
6551

    
6552
/****f* pfsense-utils/generate_random_mac_address
6553
 * NAME
6554
 *   generate_random_mac - generates a random mac address
6555
 * INPUTS
6556
 *   none
6557
 * RESULT
6558
 *   $mac - a random mac address
6559
 ******/
6560
function generate_random_mac_address() {
6561
	$mac = "02";
6562
	for ($x = 0; $x < 5; $x++) {
6563
		$mac .= ":" . dechex(rand(16, 255));
6564
	}
6565
	return $mac;
6566
}
6567

    
6568
/****f* interfaces/is_jumbo_capable
6569
 * NAME
6570
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
6571
 * INPUTS
6572
 *   $int             - string containing interface name
6573
 * RESULT
6574
 *   boolean          - true or false
6575
 ******/
6576
function is_jumbo_capable($iface) {
6577
	$iface = trim($iface);
6578
	$capable = pfSense_get_interface_addresses($iface);
6579

    
6580
	if (isset($capable['caps']['vlanmtu'])) {
6581
		return true;
6582
	}
6583

    
6584
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
6585
	if (substr($iface, 0, 4) == "lagg") {
6586
		return true;
6587
	}
6588

    
6589
	return false;
6590
}
6591

    
6592
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6593
	global $g;
6594

    
6595
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6596

    
6597
	if (!empty($iface) && !empty($pppif)) {
6598
		$cron_cmd = <<<EOD
6599
#!/bin/sh
6600
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
6601
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
6602

    
6603
EOD;
6604

    
6605
		@file_put_contents($cron_file, $cron_cmd);
6606
		chmod($cron_file, 0755);
6607
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
6608
	} else {
6609
		unlink_if_exists($cron_file);
6610
	}
6611
}
6612

    
6613
function get_interface_default_mtu($type = "ethernet") {
6614
	switch ($type) {
6615
		case "gre":
6616
			return 1476;
6617
			break;
6618
		case "gif":
6619
			return 1280;
6620
			break;
6621
		case "tun":
6622
		case "vlan":
6623
		case "tap":
6624
		case "ethernet":
6625
		default:
6626
			return 1500;
6627
			break;
6628
	}
6629

    
6630
	/* Never reached */
6631
	return 1500;
6632
}
6633

    
6634
function get_vip_descr($ipaddress) {
6635
	global $config;
6636

    
6637
	foreach ($config['virtualip']['vip'] as $vip) {
6638
		if ($vip['subnet'] == $ipaddress) {
6639
			return ($vip['descr']);
6640
		}
6641
	}
6642
	return "";
6643
}
6644

    
6645
function interfaces_staticarp_configure($if) {
6646
	global $config, $g;
6647
	if (isset($config['system']['developerspew'])) {
6648
		$mt = microtime();
6649
		echo "interfaces_staticarp_configure($if) being called $mt\n";
6650
	}
6651

    
6652
	$ifcfg = $config['interfaces'][$if];
6653

    
6654
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
6655
		return 0;
6656
	}
6657

    
6658
	/* Enable staticarp, if enabled */
6659
	if (isset($config['dhcpd'][$if]['staticarp'])) {
6660
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
6661
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6662
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
6663
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6664
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6665
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6666
				}
6667
			}
6668
		}
6669
	} else {
6670
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
6671
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6672
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
6673
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6674
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6675
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6676
				}
6677
			}
6678
		}
6679
	}
6680

    
6681
	return 0;
6682
}
6683

    
6684
function get_failover_interface($interface, $family = "all") {
6685
	global $config;
6686

    
6687
	/* shortcut to get_real_interface if we find it in the config */
6688
	if (is_array($config['interfaces'][$interface])) {
6689
		return get_real_interface($interface, $family);
6690
	}
6691

    
6692
	/* compare against gateway groups */
6693
	$a_groups = return_gateway_groups_array(true);
6694
	if (is_array($a_groups[$interface])) {
6695
		/* we found a gateway group, fetch the interface or vip */
6696
		if (!empty($a_groups[$interface][0]['vip'])) {
6697
			return $a_groups[$interface][0]['vip'];
6698
		} else {
6699
			return $a_groups[$interface][0]['int'];
6700
		}
6701
	}
6702
	/* fall through to get_real_interface */
6703
	/* XXX: Really needed? */
6704
	return get_real_interface($interface, $family);
6705
}
6706

    
6707
/****f* interfaces/interface_has_dhcp
6708
 * NAME
6709
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6710
 * INPUTS
6711
 *   interface or gateway group name
6712
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6713
 * RESULT
6714
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6715
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6716
 ******/
6717
function interface_has_dhcp($interface, $family = 4) {
6718
	global $config;
6719

    
6720
	if ($config['interfaces'][$interface]) {
6721
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6722
			return true;
6723
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6724
			return true;
6725
		} else {
6726
			return false;
6727
		}
6728
	}
6729

    
6730
	if (!is_array($config['gateways']['gateway_group'])) {
6731
		return false;
6732
	}
6733

    
6734
	if ($family == 6) {
6735
		$dhcp_string = "_DHCP6";
6736
	} else {
6737
		$dhcp_string = "_DHCP";
6738
	}
6739

    
6740
	foreach ($config['gateways']['gateway_group'] as $group) {
6741
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6742
			continue;
6743
		}
6744
		foreach ($group['item'] as $item) {
6745
			$item_data = explode("|", $item);
6746
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6747
				return true;
6748
			}
6749
		}
6750
	}
6751

    
6752
	return false;
6753
}
6754

    
6755
function remove_ifindex($ifname) {
6756
	return preg_replace("/[0-9]+$/", "", $ifname);
6757
}
6758

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

    
6762
	$viplist = get_configured_vip_list($family, $type);
6763
	foreach ($viplist as $vip => $address) {
6764
		$interfaces[$vip] = $address;
6765
		if ($type = VIP_CARP) {
6766
			$vip = get_configured_vip($vipid);
6767
			if (isset($vip) && is_array($vip) ) {
6768
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
6769
			}
6770
		}
6771
		if (get_vip_descr($address)) {
6772
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
6773
		}
6774
	}
6775
	return $interfaces;
6776
}
6777

    
6778
function return_gateway_groups_array_with_descr() {
6779
	$interfaces = array();
6780
	$grouplist = return_gateway_groups_array();
6781
	foreach ($grouplist as $name => $group) {
6782
		if ($group[0]['vip'] != "") {
6783
			$vipif = $group[0]['vip'];
6784
		} else {
6785
			$vipif = $group[0]['int'];
6786
		}
6787

    
6788
		$interfaces[$name] = "GW Group {$name}";
6789
	}
6790
	return $interfaces;
6791
}
6792

    
6793
function get_serial_ports() {
6794
	$linklist = array();
6795
	if (!is_dir("/var/spool/lock")) {
6796
		mwexec("/bin/mkdir -p /var/spool/lock");
6797
	}
6798
	$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);
6799
	foreach ($serialports as $port) {
6800
		$linklist[$port] = trim($port);
6801
	}
6802
	return $linklist;
6803
}
6804

    
6805
function get_interface_ports() {
6806
	global $config;
6807
	$linklist = array();
6808
	$portlist = get_interface_list();
6809
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
6810
		foreach ($config['vlans']['vlan'] as $vlan) {
6811
			$portlist[$vlan['vlanif']] = $vlan;
6812
		}
6813
	}
6814

    
6815
	foreach ($portlist as $ifn => $ifinfo) {
6816
		$string = "";
6817
		if (is_array($ifinfo)) {
6818
			$string .= $ifn;
6819
			if ($ifinfo['mac']) {
6820
				$string .= " ({$ifinfo['mac']})";
6821
			}
6822
			if ($ifinfo['friendly']) {
6823
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
6824
			} elseif ($ifinfo['descr']) {
6825
				$string .= " - {$ifinfo['descr']}";
6826
			}
6827
		} else {
6828
			$string .= $ifinfo;
6829
		}
6830

    
6831
		$linklist[$ifn] = $string;
6832
	}
6833
	return $linklist;
6834
}
6835

    
6836
function build_ppps_link_list() {
6837
	global $pconfig;
6838

    
6839
	$linklist = array('list' => array(), 'selected' => array());
6840

    
6841
	if ($pconfig['type'] == 'ppp') {
6842
		$linklist['list'] = get_serial_ports();
6843
	} else {
6844
		$iflist = get_interface_ports();
6845

    
6846
		$viplist = get_configured_vip_list_with_descr('all', VIP_CARP);
6847

    
6848
		$linklist['list'] = array_merge($iflist, $viplist);
6849

    
6850
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
6851
		$lagglist = get_lagg_interface_list();
6852
		foreach ($lagglist as $laggif => $lagg) {
6853
			/* LAGG members cannot be assigned */
6854
			$laggmembers = explode(',', $lagg['members']);
6855
			foreach ($laggmembers as $lagm) {
6856
				if (isset($linklist['list'][$lagm])) {
6857
					unset($linklist['list'][$lagm]);
6858
				}
6859
			}
6860
		}
6861
	}
6862

    
6863
	$selected_ports = array();
6864
	if (is_array($pconfig['interfaces'])) {
6865
		$selected_ports = $pconfig['interfaces'];
6866
	} elseif (!empty($pconfig['interfaces'])) {
6867
		$selected_ports = explode(',', $pconfig['interfaces']);
6868
	}
6869
	foreach ($selected_ports as $port) {
6870
		if (isset($linklist['list'][$port])) {
6871
			array_push($linklist['selected'], $port);
6872
		}
6873
	}
6874
	return($linklist);
6875
}
6876

    
6877
function create_interface_list() {
6878
	global $config;
6879

    
6880
	$iflist = array();
6881

    
6882
	// add group interfaces
6883
	if (is_array($config['ifgroups']['ifgroupentry'])) {
6884
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
6885
			if (have_ruleint_access($ifgen['ifname'])) {
6886
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
6887
			}
6888
		}
6889
	}
6890

    
6891
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
6892
		if (have_ruleint_access($ifent)) {
6893
			$iflist[$ifent] = $ifdesc;
6894
		}
6895
	}
6896

    
6897
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
6898
		$iflist['l2tp'] = gettext('L2TP VPN');
6899
	}
6900

    
6901
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
6902
		$iflist['pppoe'] = gettext("PPPoE Server");
6903
	}
6904

    
6905
	// add ipsec interfaces
6906
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
6907
		$iflist["enc0"] = gettext("IPsec");
6908
	}
6909

    
6910
	// add openvpn/tun interfaces
6911
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
6912
		$iflist["openvpn"] = gettext("OpenVPN");
6913
	}
6914

    
6915
	return($iflist);
6916
}
6917

    
6918
?>
(22-22/60)