Project

General

Profile

Download (206 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * interfaces.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2019 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 interface_is_lagg($if = NULL) {
272
	global $config;
273

    
274
	if (!isset($config['laggs']['lagg']) || !is_array($config['laggs']['lagg'])) {
275
		return (NULL);
276
	}
277

    
278
	foreach ($config['laggs']['lagg'] as $lagg) {
279
		if ($lagg['laggif'] == $if) {
280
			return ($lagg);
281
		}
282
	}
283
	return (NULL);
284
}
285

    
286
function vlan_inuse($vlan) {
287
	global $config;
288

    
289
	if ($vlan == NULL || !is_array($vlan)) {
290
		return (false);
291
	}
292

    
293
	$iflist = get_configured_interface_list(true);
294
	foreach ($iflist as $if) {
295
		if ($config['interfaces'][$if]['if'] == $vlan['vlanif']) {
296
			return (true);
297
		}
298
	}
299

    
300
	return (false);
301
}
302

    
303
function interface_is_vlan($if = NULL) {
304
	global $config;
305

    
306
	if ($if == NULL || empty($if) || is_array($if)) {
307
		return (NULL);
308
	}
309

    
310
	/* Check basic format. */
311
	list($vlanif, $vlantag) = explode(".", $if);
312
	if (empty($vlanif) || empty($vlantag) || !vlan_valid_tag($vlantag)) {
313
		return (NULL);
314
	}
315

    
316
	/* Find the VLAN interface. */
317
	if (isset($config['vlans']['vlan']) && is_array($config['vlans']['vlan'])) {
318
		foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
319
			if ($if == $vlan['vlanif']) {
320
				return ($vlan);
321
			}
322
		}
323
	}
324

    
325
	/* Check for the first level tag in QinQ interfaces. */
326
	if (isset($config['qinqs']['qinqentry']) && is_array($config['qinqs']['qinqentry'])) {
327
		foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
328
			if ($if == $qinq['vlanif']) {
329
				return ($qinq);
330
			}
331
		}
332
	}
333

    
334
	return (NULL);
335
}
336

    
337
function vlan_interface($vlan = NULL) {
338
	if ($vlan == NULL || !is_array($vlan) || !isset($vlan['if']) ||
339
	    !isset($vlan['tag']) || !vlan_valid_tag($vlan['tag'])) {
340
		return (NULL);
341
	}
342
	return ("{$vlan['if']}.{$vlan['tag']}");
343
}
344

    
345
function interface_set_macaddr($interface, $mac_addr) {
346
	if (empty($mac_addr) || !is_macaddr($mac_addr)) {
347
		return;
348
	}
349

    
350
	$current_mac = get_interface_mac($interface);
351

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

    
364
function interface_is_parent($if, $parent_check) {
365

    
366
	$parent_array = get_parent_interface($if);
367
	if (count($parent_array) > 1) {
368
		$parent = $parent_array;
369
	} else {
370
		$parent = $parent_array[0];
371
	}
372
	if (is_array($parent)) {
373
		foreach ($parent as $parentif) {
374
			if (strcasecmp($parent_check, $parentif) == 0) {
375
				return (TRUE);
376
			}
377
		}
378
	} else {
379
		$realif = get_real_interface($parent);
380
		if (strcasecmp($parent_check, $realif) == 0) {
381
			return (TRUE);
382
		}
383
	}
384
	return (FALSE);
385
}
386

    
387
function interface_has_clones($if) {
388
	global $config;
389

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

    
421
	return (FALSE);
422
}
423

    
424
function interfaces_vlan_configure($realif = "") {
425
	global $config, $g;
426
	if (platform_booting()) {
427
		echo gettext("Configuring VLAN interfaces...");
428
	}
429
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
430
		foreach ($config['vlans']['vlan'] as $vlan) {
431
			if (empty($vlan['vlanif'])) {
432
				$vlan['vlanif'] = vlan_interface($vlan);
433
			}
434
			if (!empty($realif) && $realif != $vlan['vlanif']) {
435
				continue;
436
			}
437

    
438
			/* XXX: Maybe we should report any errors?! */
439
			interface_vlan_configure($vlan);
440
		}
441
	}
442
	if (platform_booting()) {
443
		echo gettext("done.") . "\n";
444
	}
445
}
446

    
447
function interface_vlan_configure(&$vlan) {
448
	global $config, $g;
449

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

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

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

    
473
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
474
		pfSense_interface_destroy($vlanif);
475
	}
476

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

    
481
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
482

    
483
	interfaces_bring_up($vlanif);
484

    
485
	/* invalidate interface cache */
486
	get_interface_arr(true);
487

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

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

    
499
	return $vlanif;
500
}
501

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

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

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

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

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

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

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

    
553
	/* invalidate interface cache */
554
	get_interface_arr(true);
555

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

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

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

    
588
	return $vlanif;
589
}
590

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

    
607
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr) {
608
	global $config, $g;
609

    
610
	if (!is_array($qinq)) {
611
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
612
		return;
613
	}
614

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

    
629
	exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1");
630
	$cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n";
631
	$cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n";
632
	$cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n";
633
	$cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n";
634
	$cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n";
635

    
636
	/* invalidate interface cache */
637
	get_interface_arr(true);
638

    
639
	return $vlanif;
640
}
641

    
642
function interfaces_create_wireless_clones() {
643
	global $config, $g;
644

    
645
	if (platform_booting()) {
646
		echo gettext("Creating wireless clone interfaces...");
647
	}
648

    
649
	$iflist = get_configured_interface_list();
650

    
651
	foreach ($iflist as $if) {
652
		$realif = $config['interfaces'][$if]['if'];
653
		if (is_interface_wireless($realif)) {
654
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
655
		}
656
	}
657

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

    
674
}
675

    
676
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
677
	global $config;
678

    
679
	$i = 0;
680
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
681
		foreach ($config['bridges']['bridged'] as $bridge) {
682
			if (empty($bridge['bridgeif'])) {
683
				$bridge['bridgeif'] = "bridge{$i}";
684
			}
685
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
686
				continue;
687
			}
688

    
689
			if ($checkmember == 1) {
690
				/* XXX: It should not be possible no? */
691
				if (strstr($bridge['if'], '_vip')) {
692
					continue;
693
				}
694
				$members = explode(',', $bridge['members']);
695
				foreach ($members as $member) {
696
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6") {
697
						continue 2;
698
					}
699
				}
700
			}
701
			else if ($checkmember == 2) {
702
				$members = explode(',', $bridge['members']);
703
				foreach ($members as $member) {
704
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6") {
705
						continue 2;
706
					}
707
				}
708
			}
709
			/* XXX: Maybe we should report any errors?! */
710
			interface_bridge_configure($bridge, $checkmember);
711
			$i++;
712
		}
713
	}
714
}
715

    
716
function interface_bridge_configure(&$bridge, $checkmember = 0) {
717
	global $config, $g;
718

    
719
	if (!is_array($bridge)) {
720
		return;
721
	}
722

    
723
	if (empty($bridge['members'])) {
724
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
725
		return;
726
	}
727

    
728
	$members = explode(',', $bridge['members']);
729
	if (!count($members)) {
730
		return;
731
	}
732

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

    
758
	/* Just in case anything is not working well */
759
	if ($smallermtu == 0) {
760
		$smallermtu = 1500;
761
	}
762

    
763
	if (!empty($bridge['bridgeif'])) {
764
		pfSense_interface_destroy($bridge['bridgeif']);
765
		pfSense_interface_create($bridge['bridgeif']);
766
		$bridgeif = escapeshellarg($bridge['bridgeif']);
767
	} else {
768
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
769
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
770
		$bridgeif = pfSense_interface_create("bridge");
771
		$bridge['bridgeif'] = $bridgeif;
772
	}
773

    
774
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
775
	if ($bridgemtu > $smallermtu) {
776
		$smallermtu = $bridgemtu;
777
	}
778

    
779
	$checklist = get_configured_interface_list();
780

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

    
798
	if (isset($bridge['enablestp'])) {
799
		interface_bridge_configure_stp($bridge);
800
	}
801

    
802
	interface_bridge_configure_advanced($bridge);
803

    
804
	interface_bridge_configure_ip6linklocal($bridge);
805

    
806
	if ($bridge['bridgeif']) {
807
		interfaces_bring_up($bridge['bridgeif']);
808
	} else {
809
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
810
	}
811
}
812

    
813
function interface_bridge_configure_stp($bridge) {
814
	if (isset($bridge['enablestp'])) {
815
		$bridgeif = trim($bridge['bridgeif']);
816
		/* configure spanning tree proto */
817
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
818

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

    
872
function interface_bridge_configure_advanced($bridge) {
873
	$bridgeif = trim($bridge['bridgeif']);
874

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

    
932
function interface_bridge_configure_ip6linklocal($bridge) {
933
	$bridgeif = trim($bridge['bridgeif']);
934

    
935
	$members = explode(',', $bridge['members']);
936
	if (!count($members)) {
937
		return;
938
	}
939

    
940
	$auto_linklocal = isset($bridge['ip6linklocal']);
941
	$bridgeop = $auto_linklocal ? '' : '-';
942
	$memberop = $auto_linklocal ? '-' : '';
943

    
944
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
945
	foreach ($members as $member) {
946
		$realif = get_real_interface($member);
947
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
948
	}
949
}
950

    
951
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
952
	global $config;
953

    
954
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
955
		return;
956
	}
957

    
958
	if ($flagsapplied == false) {
959
		$mtu = get_interface_mtu($bridgeif);
960
		$mtum = get_interface_mtu($interface);
961
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
962
			pfSense_interface_mtu($interface, $mtu);
963
		}
964

    
965
		hardware_offloading_applyflags($interface);
966
		interfaces_bring_up($interface);
967
	}
968

    
969
	pfSense_bridge_add_member($bridgeif, $interface);
970
	if (is_array($config['bridges']['bridged'])) {
971
		foreach ($config['bridges']['bridged'] as $bridge) {
972
			if ($bridgeif == $bridge['bridgeif']) {
973
				interface_bridge_configure_stp($bridge);
974
				interface_bridge_configure_advanced($bridge);
975
			}
976
		}
977
	}
978
}
979

    
980
function interfaces_lagg_configure($realif = "") {
981
	global $config, $g;
982
	if (platform_booting()) {
983
		echo gettext("Configuring LAGG interfaces...");
984
	}
985
	$i = 0;
986
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
987
		foreach ($config['laggs']['lagg'] as $lagg) {
988
			if (empty($lagg['laggif'])) {
989
				$lagg['laggif'] = "lagg{$i}";
990
			}
991
			if (!empty($realif) && $realif != $lagg['laggif']) {
992
				continue;
993
			}
994
			/* XXX: Maybe we should report any errors?! */
995
			interface_lagg_configure($lagg);
996
			$i++;
997
		}
998
	}
999
	if (platform_booting()) {
1000
		echo gettext("done.") . "\n";
1001
	}
1002
}
1003

    
1004
function interface_lagg_configure($lagg) {
1005
	global $config, $g;
1006

    
1007
	if (!is_array($lagg)) {
1008
		return -1;
1009
	}
1010

    
1011
	$members = explode(',', $lagg['members']);
1012
	if (!count($members)) {
1013
		return -1;
1014
	}
1015

    
1016
	if (platform_booting() || !(empty($lagg['laggif']))) {
1017
		pfSense_interface_destroy($lagg['laggif']);
1018
		pfSense_interface_create($lagg['laggif']);
1019
		$laggif = $lagg['laggif'];
1020
	} else {
1021
		$laggif = pfSense_interface_create("lagg");
1022
	}
1023

    
1024
	/* Check if MTU was defined for this lagg interface */
1025
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
1026
	if ($lagg_mtu == 0 &&
1027
	    is_array($config['interfaces'])) {
1028
		foreach ($config['interfaces'] as $tmpinterface) {
1029
			if ($tmpinterface['if'] == $lagg['laggif'] &&
1030
			    !empty($tmpinterface['mtu'])) {
1031
				$lagg_mtu = $tmpinterface['mtu'];
1032
				break;
1033
			}
1034
		}
1035
	}
1036

    
1037
	/* Just in case anything is not working well */
1038
	if ($lagg_mtu == 0) {
1039
		$lagg_mtu = 1500;
1040
	}
1041

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

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

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

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

    
1060
	interfaces_bring_up($laggif);
1061

    
1062
	return $laggif;
1063
}
1064

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

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

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

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

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

    
1107
	$realif = get_real_interface($gre['if']);
1108
	$realifip = get_interface_ip($gre['if']);
1109
	$realifip6 = get_interface_ipv6($gre['if']);
1110

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

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

    
1122
	/* Do not change the order here for more see gre(4) NOTES section. */
1123
	if (is_ipaddrv6($gre['remote-addr'])) {
1124
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1125
	} else {
1126
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1127
	}
1128
	if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
1129
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1130
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
1131
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
1132
	} else {
1133
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1134
	}
1135

    
1136
	if ($greif) {
1137
		interfaces_bring_up($greif);
1138
	} else {
1139
		log_error(gettext("Could not bring greif up -- variable not defined."));
1140
	}
1141

    
1142
	if (isset($gre['link1']) && $gre['link1']) {
1143
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1144
	}
1145
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
1146
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1147
	}
1148
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
1149
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
1150
	}
1151

    
1152
	interfaces_bring_up($greif);
1153

    
1154
	return $greif;
1155
}
1156

    
1157
function interfaces_gif_configure($checkparent = 0, $realif = "") {
1158
	global $config;
1159

    
1160
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
1161
		foreach ($config['gifs']['gif'] as $i => $gif) {
1162
			if (empty($gif['gifif'])) {
1163
				$gre['gifif'] = "gif{$i}";
1164
			}
1165
			if (!empty($realif) && $realif != $gif['gifif']) {
1166
				continue;
1167
			}
1168

    
1169
			if ($checkparent == 1) {
1170
				if (substr($gif['if'], 0, 4) == '_vip') {
1171
					continue;
1172
				}
1173
				if (substr($gif['if'], 0, 5) == '_lloc') {
1174
					continue;
1175
				}
1176
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
1177
					continue;
1178
				}
1179
			}
1180
			else if ($checkparent == 2) {
1181
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
1182
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
1183
					continue;
1184
				}
1185
			}
1186
			/* XXX: Maybe we should report any errors?! */
1187
			interface_gif_configure($gif);
1188
		}
1189
	}
1190
}
1191

    
1192
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1193
function interface_gif_configure(&$gif, $gifkey = "") {
1194
	global $config, $g;
1195

    
1196
	if (!is_array($gif)) {
1197
		return -1;
1198
	}
1199

    
1200
	$realif = get_real_interface($gif['if']);
1201
	$ipaddr = get_interface_ip($gif['if']);
1202

    
1203
	if (is_ipaddrv4($gif['remote-addr'])) {
1204
		if (is_ipaddrv4($ipaddr)) {
1205
			$realifip = $ipaddr;
1206
		} else {
1207
			$realifip = get_interface_ip($gif['if']);
1208
		}
1209
		$realifgw = get_interface_gateway($gif['if']);
1210
	} else if (is_ipaddrv6($gif['remote-addr'])) {
1211
		if (is_ipaddrv6($ipaddr)) {
1212
			$realifip = $ipaddr;
1213
		} else {
1214
			$realifip = get_interface_ipv6($gif['if']);
1215
		}
1216
		$realifgw = get_interface_gateway_v6($gif['if']);
1217
	}
1218
	/* make sure the parent interface is up */
1219
	if ($realif) {
1220
		interfaces_bring_up($realif);
1221
	} else {
1222
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
1223
	}
1224

    
1225
	if (platform_booting() || !(empty($gif['gifif']))) {
1226
		pfSense_interface_destroy($gif['gifif']);
1227
		pfSense_interface_create($gif['gifif']);
1228
		$gifif = $gif['gifif'];
1229
	} else {
1230
		$gifif = pfSense_interface_create("gif");
1231
	}
1232

    
1233
	/* Do not change the order here for more see gif(4) NOTES section. */
1234
	if (is_ipaddrv6($gif['remote-addr'])) {
1235
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1236
	} else {
1237
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1238
	}
1239
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1240
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1241
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1242
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1243
	} else {
1244
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1245
	}
1246
	if (isset($gif['link1'])) {
1247
		pfSense_interface_flags($gifif, IFF_LINK1);
1248
	}
1249
	if (isset($gif['link2'])) {
1250
		pfSense_interface_flags($gifif, IFF_LINK2);
1251
	}
1252
	if ($gifif) {
1253
		interfaces_bring_up($gifif);
1254
		$gifmtu = "";
1255
		$currentgifmtu = get_interface_mtu($gifif);
1256
		foreach ($config['interfaces'] as $tmpinterface) {
1257
			if ($tmpinterface['if'] == $gifif) {
1258
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1259
					$gifmtu = $tmpinterface['mtu'];
1260
				}
1261
			}
1262
		}
1263
		if (is_numericint($gifmtu)) {
1264
			if ($gifmtu != $currentgifmtu) {
1265
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1266
			}
1267
		}
1268
	} else {
1269
		log_error(gettext("could not bring gifif up -- variable not defined"));
1270
	}
1271

    
1272
	if (!platform_booting()) {
1273
		$iflist = get_configured_interface_list();
1274
		foreach ($iflist as $ifname) {
1275
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1276
				if (get_interface_gateway($ifname)) {
1277
					system_routing_configure($ifname);
1278
					break;
1279
				}
1280
				if (get_interface_gateway_v6($ifname)) {
1281
					system_routing_configure($ifname);
1282
					break;
1283
				}
1284
			}
1285
		}
1286
	}
1287

    
1288

    
1289
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1290
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1291
	}
1292
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1293
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1294
	}
1295

    
1296
	if (is_ipaddrv4($realifgw)) {
1297
		route_add_or_change("-host {$gif['remote-addr']} {$realifgw}");
1298
	}
1299
	if (is_ipaddrv6($realifgw)) {
1300
		route_add_or_change("-host -inet6 {$gif['remote-addr']} {$realifgw}");
1301
	}
1302

    
1303
	interfaces_bring_up($gifif);
1304

    
1305
	return $gifif;
1306
}
1307

    
1308
/* Build a list of IPsec interfaces */
1309
function interface_ipsec_vti_list_p1($ph1ent) {
1310
	global $config;
1311
	$iface_list = array();
1312

    
1313
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1314
		return $iface_list;
1315
	}
1316

    
1317
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1318
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1319
		return $iface_list;
1320
	}
1321

    
1322
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1323
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1324
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1325
			$iface_list["ipsec{$ph1ent['ikeid']}00{$idx}"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1326
		}
1327
	} else {
1328
		/* For IKEv2, only create one interface with additional addresses as aliases */
1329
		$iface_list["ipsec{$ph1ent['ikeid']}000"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1330
	}
1331
	return $iface_list;
1332
}
1333
function interface_ipsec_vti_list_all() {
1334
	global $config;
1335
	$iface_list = array();
1336
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1337
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1338
			if ($ph1ent['disabled']) {
1339
				continue;
1340
			}
1341
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1342
		}
1343
	}
1344
	return $iface_list;
1345
}
1346

    
1347
function is_interface_ipsec_vti_assigned($phase2) {
1348
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1349
	$vti_interface = null;
1350
	$vtisubnet_spec = ipsec_vti($phase1, true);
1351
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1352
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1353
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1354
			foreach ($vtisubnet_spec as $idx => $vtisub) {
1355
				/* Is this for this P2? */
1356
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1357
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1358
					$vti_interface = "ipsec{$phase1['ikeid']}00{$idx}";
1359
				}
1360
			}
1361
		} else {
1362
			$vti_interface = "ipsec{$phase1['ikeid']}000";
1363
		}
1364
	}
1365
	/* Check if this interface is assigned */
1366
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1367
}
1368
function interface_ipsec_vti_configure($ph1ent) {
1369
	global $config;
1370

    
1371
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1372
		return false;
1373
	}
1374

    
1375
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1376
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1377
		return false;
1378
	}
1379

    
1380
	$left_spec = ipsec_get_phase1_src($ph1ent);
1381
	$right_spec = $ph1ent['remote-gateway'];
1382

    
1383
	$iface_addrs = array();
1384

    
1385
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1386
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1387
		/* Form a single interface for each P2 entry */
1388
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1389
			$ipsecifnum = "{$ph1ent['ikeid']}00{$idx}";
1390
			if (!is_array($iface_addrs[$ipsecifnum])) {
1391
				$iface_addrs[$ipsecifnum] = array();
1392
			}
1393
			$vtisub['alias'] = "";
1394
			$iface_addrs[$ipsecifnum][] = $vtisub;
1395
		}
1396
	} else {
1397
		/* For IKEv2, only create one interface with additional addresses as aliases */
1398
		$ipsecifnum = "{$ph1ent['ikeid']}000";
1399
		if (!is_array($iface_addrs[$ipsecifnum])) {
1400
			$iface_addrs[$ipsecifnum] = array();
1401
		}
1402
		$have_v4 = false;
1403
		$have_v6 = false;
1404
		foreach ($vtisubnet_spec as $vtisub) {
1405
			// Alias stuff
1406
			$vtisub['alias'] = "";
1407
			if (is_ipaddrv6($vtisub['left'])) {
1408
				if ($have_v6) {
1409
					$vtisub['alias'] = " alias";
1410
				}
1411
				$have_v6 = true;
1412
			} else {
1413
				if ($have_v4) {
1414
					$vtisub['alias'] = " alias";
1415
				}
1416
				$have_v4 = true;
1417
			}
1418
			$iface_addrs[$ipsecifnum][] = $vtisub;
1419
		}
1420
	}
1421

    
1422
	foreach ($iface_addrs as $ipsecifnum => $addrs) {
1423
		$ipsecif = "ipsec{$ipsecifnum}";
1424
		if (!is_array($addrs)) {
1425
			continue;
1426
		}
1427
		// Create IPsec interface
1428
		if (platform_booting() || !does_interface_exist($ipsecif)) {
1429
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy", false);
1430
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1431
		} else {
1432
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1433
		}
1434

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

    
1439
		/* Loop through all of the addresses for this interface and apply them as needed */
1440
		foreach ($addrs as $addr) {
1441
			// apply interface addresses
1442
			if (is_ipaddrv6($addr['left'])) {
1443
				$inet = "inet6";
1444
				$gwtype = "v6";
1445
			} else {
1446
				$inet = "inet";
1447
				$gwtype = "";
1448
			}
1449

    
1450
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . escapeshellarg($addr['right']) . $addr['alias'], false);
1451
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1452
			if (empty($addr['alias'])) {
1453
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1454
			}
1455
		}
1456
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1457
	}
1458
}
1459

    
1460
function interfaces_ipsec_vti_configure() {
1461
	global $config;
1462
	if (platform_booting()) {
1463
		echo gettext("Configuring IPsec VTI interfaces...");
1464
	}
1465
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1466
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1467
			if ($ph1ent['disabled']) {
1468
				continue;
1469
			}
1470
			interface_ipsec_vti_configure($ph1ent);
1471
		}
1472
	}
1473
	if (platform_booting()) {
1474
		echo gettext("done.") . "\n";
1475
	}
1476
}
1477

    
1478
function interfaces_configure() {
1479
	global $config, $g;
1480

    
1481
	/* Set up our loopback interface */
1482
	interfaces_loopback_configure();
1483

    
1484
	/* create the unconfigured wireless clones */
1485
	interfaces_create_wireless_clones();
1486

    
1487
	/* set up LAGG virtual interfaces */
1488
	interfaces_lagg_configure();
1489

    
1490
	/* set up VLAN virtual interfaces */
1491
	interfaces_vlan_configure();
1492

    
1493
	interfaces_qinq_configure();
1494

    
1495
	/* set up IPsec VTI interfaces */
1496
	interfaces_ipsec_vti_configure();
1497

    
1498
	$iflist = get_configured_interface_with_descr();
1499
	$delayed_list = array();
1500
	$bridge_list = array();
1501
	$track6_list = array();
1502

    
1503
	/* This is needed to speedup interfaces on bootup. */
1504
	$reload = false;
1505
	if (!platform_booting()) {
1506
		$reload = true;
1507
	}
1508

    
1509
	foreach ($iflist as $if => $ifname) {
1510
		$realif = $config['interfaces'][$if]['if'];
1511
		if (strstr($realif, "bridge")) {
1512
			$bridge_list[$if] = $ifname;
1513
		} else if (strstr($realif, "gre")) {
1514
			$delayed_list[$if] = $ifname;
1515
		} else if (strstr($realif, "gif")) {
1516
			$delayed_list[$if] = $ifname;
1517
		} else if (strstr($realif, "ovpn")) {
1518
			//echo "Delaying OpenVPN interface configuration...done.\n";
1519
			continue;
1520
		} else if (strstr($realif, "ipsec")) {
1521
			continue;
1522
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1523
			$track6_list[$if] = $ifname;
1524
		} else {
1525
			if (platform_booting()) {
1526
				printf(gettext("Configuring %s interface..."), $ifname);
1527
			}
1528

    
1529
			if ($g['debug']) {
1530
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1531
			}
1532
			interface_configure($if, $reload);
1533
			if (platform_booting()) {
1534
				echo gettext("done.") . "\n";
1535
			}
1536
		}
1537
	}
1538

    
1539
	/*
1540
	 * NOTE: The following function parameter consists of
1541
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1542
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1543
	 */
1544

    
1545
	/* set up GRE virtual interfaces */
1546
	interfaces_gre_configure(1);
1547

    
1548
	/* set up GIF virtual interfaces */
1549
	interfaces_gif_configure(1);
1550

    
1551
	/* set up BRIDGe virtual interfaces */
1552
	interfaces_bridge_configure(1);
1553

    
1554
	foreach ($track6_list as $if => $ifname) {
1555
		if (platform_booting()) {
1556
			printf(gettext("Configuring %s interface..."), $ifname);
1557
		}
1558
		if ($g['debug']) {
1559
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1560
		}
1561

    
1562
		interface_configure($if, $reload);
1563

    
1564
		if (platform_booting()) {
1565
			echo gettext("done.") . "\n";
1566
		}
1567
	}
1568

    
1569
	/* bring up vip interfaces */
1570
	interfaces_vips_configure();
1571

    
1572
	/* set up GRE virtual interfaces */
1573
	interfaces_gre_configure(2);
1574

    
1575
	/* set up GIF virtual interfaces */
1576
	interfaces_gif_configure(2);
1577

    
1578
	foreach ($delayed_list as $if => $ifname) {
1579
		if (platform_booting()) {
1580
			printf(gettext("Configuring %s interface..."), $ifname);
1581
		}
1582
		if ($g['debug']) {
1583
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1584
		}
1585

    
1586
		interface_configure($if, $reload);
1587

    
1588
		if (platform_booting()) {
1589
			echo gettext("done.") . "\n";
1590
		}
1591
	}
1592

    
1593
	/* set up BRIDGe virtual interfaces */
1594
	interfaces_bridge_configure(2);
1595

    
1596
	foreach ($bridge_list as $if => $ifname) {
1597
		if (platform_booting()) {
1598
			printf(gettext("Configuring %s interface..."), $ifname);
1599
		}
1600
		if ($g['debug']) {
1601
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1602
		}
1603

    
1604
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1605
		// redmine #3997
1606
		interface_reconfigure($if, $reload);
1607
		interfaces_vips_configure($if);
1608

    
1609
		if (platform_booting()) {
1610
			echo gettext("done.") . "\n";
1611
		}
1612
	}
1613

    
1614
	/* configure interface groups */
1615
	interfaces_group_setup();
1616

    
1617
	if (!platform_booting()) {
1618
		/* reconfigure static routes (kernel may have deleted them) */
1619
		system_routing_configure();
1620

    
1621
		/* reload IPsec tunnels */
1622
		vpn_ipsec_configure();
1623

    
1624
		/* restart dns servers (defering dhcpd reload) */
1625
		if (isset($config['dnsmasq']['enable'])) {
1626
			services_dnsmasq_configure(false);
1627
		}
1628
		if (isset($config['unbound']['enable'])) {
1629
			services_unbound_configure(false);
1630
		}
1631

    
1632
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1633
		services_dhcpd_configure();
1634
	}
1635

    
1636
	return 0;
1637
}
1638

    
1639
function interface_reconfigure($interface = "wan", $reloadall = false) {
1640
	interface_bring_down($interface);
1641
	interface_configure($interface, $reloadall);
1642
}
1643

    
1644
function interface_vip_bring_down($vip) {
1645
	global $g;
1646

    
1647
	$vipif = get_real_interface($vip['interface']);
1648
	switch ($vip['mode']) {
1649
		case "proxyarp":
1650
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1651
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1652
			}
1653
			break;
1654
		case "ipalias":
1655
			if (does_interface_exist($vipif)) {
1656
				if (is_ipaddrv6($vip['subnet'])) {
1657
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1658
				} else {
1659
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1660
				}
1661
			}
1662
			break;
1663
		case "carp":
1664
			/* XXX: Is enough to delete ip address? */
1665
			if (does_interface_exist($vipif)) {
1666
				if (is_ipaddrv6($vip['subnet'])) {
1667
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1668
				} else {
1669
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1670
				}
1671
			}
1672
			break;
1673
	}
1674
}
1675

    
1676
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1677
	global $config, $g;
1678

    
1679
	if (!isset($config['interfaces'][$interface])) {
1680
		return;
1681
	}
1682

    
1683
	if ($g['debug']) {
1684
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1685
	}
1686

    
1687
	/*
1688
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1689
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1690
	 * Keep this in mind while doing changes here!
1691
	 */
1692
	if ($ifacecfg === false) {
1693
		$ifcfg = $config['interfaces'][$interface];
1694
		$ppps = $config['ppps']['ppp'];
1695
		$realif = get_real_interface($interface);
1696
		$realifv6 = get_real_interface($interface, "inet6", true);
1697
	} elseif (!is_array($ifacecfg)) {
1698
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1699
		$ifcfg = $config['interfaces'][$interface];
1700
		$ppps = $config['ppps']['ppp'];
1701
		$realif = get_real_interface($interface);
1702
		$realifv6 = get_real_interface($interface, "inet6", true);
1703
	} else {
1704
		$ifcfg = $ifacecfg['ifcfg'];
1705
		$ppps = $ifacecfg['ppps'];
1706
		if (isset($ifacecfg['ifcfg']['realif'])) {
1707
			$realif = $ifacecfg['ifcfg']['realif'];
1708
			/* XXX: Any better way? */
1709
			$realifv6 = $realif;
1710
		} else {
1711
			$realif = get_real_interface($interface);
1712
			$realifv6 = get_real_interface($interface, "inet6", true);
1713
		}
1714
	}
1715

    
1716
	switch ($ifcfg['ipaddr']) {
1717
		case "ppp":
1718
		case "pppoe":
1719
		case "pptp":
1720
		case "l2tp":
1721
			if (is_array($ppps) && count($ppps)) {
1722
				foreach ($ppps as $pppid => $ppp) {
1723
					if ($realif == $ppp['if']) {
1724
						if (isset($ppp['ondemand']) && !$destroy) {
1725
							send_event("interface reconfigure {$interface}");
1726
							break;
1727
						}
1728
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1729
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1730
							sleep(2);
1731
						}
1732
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1733
						break;
1734
					}
1735
				}
1736
			}
1737
			break;
1738
		case "dhcp":
1739
			kill_dhclient_process($realif);
1740
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1741
			if (does_interface_exist("$realif")) {
1742
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1743
				interface_vip_cleanup($interface, "inet4");
1744
				if ($destroy == true) {
1745
					pfSense_interface_flags($realif, -IFF_UP);
1746
				}
1747
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1748
			}
1749
			break;
1750
		default:
1751
			if (does_interface_exist("$realif")) {
1752
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1753
				interface_vip_cleanup($interface, "inet4");
1754
				if ($destroy == true) {
1755
					pfSense_interface_flags($realif, -IFF_UP);
1756
				}
1757
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1758
			}
1759
			break;
1760
	}
1761

    
1762
	$track6 = array();
1763
	switch ($ifcfg['ipaddrv6']) {
1764
		case "slaac":
1765
		case "dhcp6":
1766
			kill_dhcp6client_process($realif, $destroy, false);
1767
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1768
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1769
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1770
			if (does_interface_exist($realifv6)) {
1771
				$ip6 = find_interface_ipv6($realifv6);
1772
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1773
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1774
				}
1775
				interface_vip_cleanup($interface, "inet6");
1776
				if ($destroy == true) {
1777
					pfSense_interface_flags($realif, -IFF_UP);
1778
				}
1779
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1780
			}
1781
			$track6 = link_interface_to_track6($interface);
1782
			break;
1783
		case "6rd":
1784
		case "6to4":
1785
			$realif = "{$interface}_stf";
1786
			if (does_interface_exist("$realif")) {
1787
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1788
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1789
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1790
					$destroy = true;
1791
				} else {
1792
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1793
					$ip6 = get_interface_ipv6($interface);
1794
					if (is_ipaddrv6($ip6)) {
1795
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1796
					}
1797
				}
1798
				interface_vip_cleanup($interface, "inet6");
1799
				if ($destroy == true) {
1800
					pfSense_interface_flags($realif, -IFF_UP);
1801
				}
1802
			}
1803
			$track6 = link_interface_to_track6($interface);
1804
			break;
1805
		default:
1806
			if (does_interface_exist("$realif")) {
1807
				$ip6 = get_interface_ipv6($interface);
1808
				if (is_ipaddrv6($ip6)) {
1809
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1810
				}
1811
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1812
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1813
				}
1814
				interface_vip_cleanup($interface, "inet6");
1815
				if ($destroy == true) {
1816
					pfSense_interface_flags($realif, -IFF_UP);
1817
				}
1818
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1819
			}
1820
			$track6 = link_interface_to_track6($interface);
1821
			break;
1822
	}
1823

    
1824
	if (!empty($track6) && is_array($track6)) {
1825
		if (!function_exists('services_dhcpd_configure')) {
1826
			require_once('services.inc');
1827
		}
1828
		/* Bring down radvd and dhcp6 on these interfaces */
1829
		services_dhcpd_configure('inet6', $track6);
1830
	}
1831

    
1832
	$old_router = '';
1833
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1834
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1835
	}
1836

    
1837
	/* remove interface up file if it exists */
1838
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1839
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1840
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1841
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1842
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1843
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1844
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1845

    
1846
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1847
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1848
	if (is_array($ifcfg['wireless'])) {
1849
		kill_hostapd($realif);
1850
		mwexec(kill_wpasupplicant($realif));
1851
	}
1852

    
1853
	if ($destroy == true) {
1854
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^ipsec|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1855
			pfSense_interface_destroy($realif);
1856
		}
1857
	}
1858

    
1859
	return;
1860
}
1861

    
1862
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1863
	global $config;
1864
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1865
		unset($config["virtualip_carp_maintenancemode"]);
1866
		write_config("Leave CARP maintenance mode");
1867
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1868
		$config["virtualip_carp_maintenancemode"] = true;
1869
		write_config(gettext("Enter CARP maintenance mode"));
1870
	}
1871
	init_config_arr(array('virtualip', 'vip'));
1872
	$viparr = &$config['virtualip']['vip'];
1873

    
1874
	if (is_array($viparr)) {
1875
		foreach ($viparr as $vip) {
1876
			if ($vip['mode'] == "carp") {
1877
				interface_carp_configure($vip, true);
1878
			}
1879
		}
1880
	}
1881
}
1882

    
1883
function interface_wait_tentative($interface, $timeout = 10) {
1884
	if (!does_interface_exist($interface)) {
1885
		return false;
1886
	}
1887

    
1888
	$time = 0;
1889
	while ($time <= $timeout) {
1890
		$if = pfSense_get_interface_addresses($interface);
1891
		if (!isset($if['tentative'])) {
1892
			return true;
1893
		}
1894
		sleep(1);
1895
		$time++;
1896
	}
1897

    
1898
	return false;
1899
}
1900

    
1901
function interface_isppp_type($interface) {
1902
	global $config;
1903

    
1904
	if (!is_array($config['interfaces'][$interface])) {
1905
		return false;
1906
	}
1907

    
1908
	switch ($config['interfaces'][$interface]['ipaddr']) {
1909
		case 'pptp':
1910
		case 'l2tp':
1911
		case 'pppoe':
1912
		case 'ppp':
1913
			return true;
1914
			break;
1915
		default:
1916
			return false;
1917
			break;
1918
	}
1919
}
1920

    
1921
function interfaces_ptpid_used($ptpid) {
1922
	global $config;
1923

    
1924
	if (is_array($config['ppps']['ppp'])) {
1925
		foreach ($config['ppps']['ppp'] as & $settings) {
1926
			if ($ptpid == $settings['ptpid']) {
1927
				return true;
1928
			}
1929
		}
1930
	}
1931

    
1932
	return false;
1933
}
1934

    
1935
function interfaces_ptpid_next() {
1936

    
1937
	$ptpid = 0;
1938
	while (interfaces_ptpid_used($ptpid)) {
1939
		$ptpid++;
1940
	}
1941

    
1942
	return $ptpid;
1943
}
1944

    
1945
function getMPDCRONSettings($pppif) {
1946
	global $config;
1947

    
1948
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1949
	if (is_array($config['cron']['item'])) {
1950
		foreach ($config['cron']['item'] as $i => $item) {
1951
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1952
				return array("ID" => $i, "ITEM" => $item);
1953
			}
1954
		}
1955
	}
1956

    
1957
	return NULL;
1958
}
1959

    
1960
function handle_pppoe_reset($post_array) {
1961
	global $config, $g;
1962

    
1963
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1964
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1965

    
1966
	if (!is_array($config['cron']['item'])) {
1967
		$config['cron']['item'] = array();
1968
	}
1969

    
1970
	$itemhash = getMPDCRONSettings($pppif);
1971

    
1972
	// reset cron items if necessary and return
1973
	if (empty($post_array['pppoe-reset-type'])) {
1974
		if (isset($itemhash)) {
1975
			unset($config['cron']['item'][$itemhash['ID']]);
1976
		}
1977
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1978
		return;
1979
	}
1980

    
1981
	if (empty($itemhash)) {
1982
		$itemhash = array();
1983
	}
1984
	$item = array();
1985
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1986
		$item['minute'] = $post_array['pppoe_resetminute'];
1987
		$item['hour'] = $post_array['pppoe_resethour'];
1988
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1989
			$date = explode("/", $post_array['pppoe_resetdate']);
1990
			$item['mday'] = $date[1];
1991
			$item['month'] = $date[0];
1992
		} else {
1993
			$item['mday'] = "*";
1994
			$item['month'] = "*";
1995
		}
1996
		$item['wday'] = "*";
1997
		$item['who'] = "root";
1998
		$item['command'] = $cron_cmd_file;
1999
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2000
		switch ($post_array['pppoe_pr_preset_val']) {
2001
			case "monthly":
2002
				$item['minute'] = "0";
2003
				$item['hour'] = "0";
2004
				$item['mday'] = "1";
2005
				$item['month'] = "*";
2006
				$item['wday'] = "*";
2007
				break;
2008
			case "weekly":
2009
				$item['minute'] = "0";
2010
				$item['hour'] = "0";
2011
				$item['mday'] = "*";
2012
				$item['month'] = "*";
2013
				$item['wday'] = "0";
2014
				break;
2015
			case "daily":
2016
				$item['minute'] = "0";
2017
				$item['hour'] = "0";
2018
				$item['mday'] = "*";
2019
				$item['month'] = "*";
2020
				$item['wday'] = "*";
2021
				break;
2022
			case "hourly":
2023
				$item['minute'] = "0";
2024
				$item['hour'] = "*";
2025
				$item['mday'] = "*";
2026
				$item['month'] = "*";
2027
				$item['wday'] = "*";
2028
				break;
2029
		} // end switch
2030
		$item['who'] = "root";
2031
		$item['command'] = $cron_cmd_file;
2032
	}
2033
	if (empty($item)) {
2034
		return;
2035
	}
2036
	if (isset($itemhash['ID'])) {
2037
		$config['cron']['item'][$itemhash['ID']] = $item;
2038
	} else {
2039
		$config['cron']['item'][] = $item;
2040
	}
2041
}
2042

    
2043
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2044
	global $config;
2045
	$ppp_list = array();
2046
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2047
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2048
			$ports = explode(",", $ppp['ports']);
2049
			foreach($ports as $port) {
2050
				foreach($triggerinterfaces as $vip) {
2051
					if ($port == "_vip{$vip['uniqid']}") {
2052
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2053
						$ppp_list[$if] = 1;
2054
					}
2055
				}
2056
			}
2057
		}
2058
	}
2059
	foreach($ppp_list as $pppif => $dummy) {
2060
		interface_ppps_configure($pppif);
2061
	}
2062
}
2063

    
2064
/*
2065
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2066
 * It writes the mpd config file to /var/etc every time the link is opened.
2067
 */
2068
function interface_ppps_configure($interface) {
2069
	global $config, $g;
2070

    
2071
	/* Return for unassigned interfaces. This is a minimum requirement. */
2072
	if (empty($config['interfaces'][$interface])) {
2073
		return 0;
2074
	}
2075
	$ifcfg = $config['interfaces'][$interface];
2076
	if (!isset($ifcfg['enable'])) {
2077
		return 0;
2078
	}
2079

    
2080
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2081
	if (!is_dir("/var/spool/lock")) {
2082
		mkdir("/var/spool/lock", 0777, true);
2083
	}
2084
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2085
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2086
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2087
	}
2088

    
2089
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2090
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2091
			if ($ifcfg['if'] == $ppp['if']) {
2092
				break;
2093
			}
2094
		}
2095
	}
2096
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2097
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2098
		return 0;
2099
	}
2100
	$pppif = $ifcfg['if'];
2101
	if ($ppp['type'] == "ppp") {
2102
		$type = "modem";
2103
	} else {
2104
		$type = $ppp['type'];
2105
	}
2106
	$upper_type = strtoupper($ppp['type']);
2107

    
2108
	/* XXX: This does not make sense and may create trouble
2109
	 * comment it for now to be removed later on.
2110
	if (platform_booting()) {
2111
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
2112
		echo "starting {$pppif} link...";
2113
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
2114
			return 0;
2115
	}
2116
	*/
2117
	$confports = explode(',', $ppp['ports']);
2118
	if ($type == "modem") {
2119
		$ports = $confports;
2120
	} else {
2121
		$ports = array();
2122
		foreach ($confports as $pid => $port) {
2123
			if (strstr($port, "_vip")) {
2124
				if (get_carp_interface_status($port) != "MASTER") {
2125
					continue;
2126
				}
2127
			}
2128
			$ports[$pid] = get_real_interface($port);
2129
			if (empty($ports[$pid])) {
2130
				return 0;
2131
			}
2132
		}
2133
	}
2134
	$localips = explode(',', $ppp['localip']);
2135
	$gateways = explode(',', $ppp['gateway']);
2136
	$subnets = explode(',', $ppp['subnet']);
2137

    
2138
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2139
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2140
	 */
2141
	foreach ($ports as $pid => $port) {
2142
		switch ($ppp['type']) {
2143
			case "pppoe":
2144
				/* Bring the parent interface up */
2145
				interfaces_bring_up($port);
2146
				pfSense_ngctl_attach(".", $port);
2147
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2148
				$ngif = str_replace(".", "_", $port);
2149
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2150
				break;
2151
			case "pptp":
2152
			case "l2tp":
2153
				/* configure interface */
2154
				if (is_ipaddr($localips[$pid])) {
2155
					// Manually configure interface IP/subnet
2156
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2157
					interfaces_bring_up($port);
2158
				} else if (empty($localips[$pid])) {
2159
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2160
				}
2161

    
2162
				if (!is_ipaddr($localips[$pid])) {
2163
					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));
2164
					$localips[$pid] = "0.0.0.0";
2165
				}
2166
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2167
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2168
				}
2169
				if (!is_ipaddr($gateways[$pid])) {
2170
					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));
2171
					return 0;
2172
				}
2173
				pfSense_ngctl_attach(".", $port);
2174
				break;
2175
			case "ppp":
2176
				if (!file_exists("{$port}")) {
2177
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2178
					return 0;
2179
				}
2180
				break;
2181
			default:
2182
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2183
				break;
2184
		}
2185
	}
2186

    
2187
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2188
	    (is_array($ports) && count($ports) > 1)) {
2189
		$multilink = "enable";
2190
	} else {
2191
		$multilink = "disable";
2192
	}
2193

    
2194
	if ($type == "modem") {
2195
		if (is_ipaddr($ppp['localip'])) {
2196
			$localip = $ppp['localip'];
2197
		} else {
2198
			$localip = '0.0.0.0';
2199
		}
2200

    
2201
		if (is_ipaddr($ppp['gateway'])) {
2202
			$gateway = $ppp['gateway'];
2203
		} else {
2204
			$gateway = "10.64.64.{$pppid}";
2205
		}
2206
		$ranges = "{$localip}/0 {$gateway}/0";
2207

    
2208
		if (empty($ppp['apnum'])) {
2209
			$ppp['apnum'] = 1;
2210
		}
2211
	} else {
2212
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2213
	}
2214

    
2215
	if (isset($ppp['ondemand'])) {
2216
		$ondemand = "enable";
2217
	} else {
2218
		$ondemand = "disable";
2219
	}
2220
	if (!isset($ppp['idletimeout'])) {
2221
		$ppp['idletimeout'] = 0;
2222
	}
2223

    
2224
	if (empty($ppp['username']) && $type == "modem") {
2225
		$ppp['username'] = "user";
2226
		$ppp['password'] = "none";
2227
	}
2228
	if (empty($ppp['password']) && $type == "modem") {
2229
		$passwd = "none";
2230
	} else {
2231
		$passwd = base64_decode($ppp['password']);
2232
	}
2233

    
2234
	$bandwidths = explode(',', $ppp['bandwidth']);
2235
	$defaultmtu = "1492";
2236
	if (!empty($ifcfg['mtu'])) {
2237
		$defaultmtu = intval($ifcfg['mtu']);
2238
	}
2239
	if (isset($ppp['mtu'])) {
2240
		$mtus = explode(',', $ppp['mtu']);
2241
	}
2242
	if (isset($ppp['mru'])) {
2243
		$mrus = explode(',', $ppp['mru']);
2244
	}
2245
	if (isset($ppp['mrru'])) {
2246
		$mrrus = explode(',', $ppp['mrru']);
2247
	}
2248

    
2249
	// Construct the mpd.conf file
2250
	$mpdconf = <<<EOD
2251
startup:
2252
	# configure the console
2253
	set console close
2254
	# configure the web server
2255
	set web close
2256

    
2257
default:
2258
{$ppp['type']}client:
2259
	create bundle static {$interface}
2260
	set bundle enable ipv6cp
2261
	set iface name {$pppif}
2262

    
2263
EOD;
2264
	$setdefaultgw = false;
2265
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2266
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2267
	if ($defgw4['interface'] == $interface) {
2268
		$setdefaultgw = true;
2269
	}
2270

    
2271
/* Omit this, we maintain the default route by other means, and it causes problems with
2272
 * default gateway switching. See redmine #1837 for original issue
2273
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2274
 * edge case. redmine #6495 open to address.
2275
 */
2276
	if ($setdefaultgw == true) {
2277
		$mpdconf .= <<<EOD
2278
	set iface route default
2279

    
2280
EOD;
2281
	}
2282

    
2283
	$mpdconf .= <<<EOD
2284
	set iface {$ondemand} on-demand
2285
	set iface idle {$ppp['idletimeout']}
2286

    
2287
EOD;
2288

    
2289
	if (isset($ppp['ondemand'])) {
2290
		$mpdconf .= <<<EOD
2291
	set iface addrs 10.10.1.1 10.10.1.2
2292

    
2293
EOD;
2294
	}
2295

    
2296
	if (isset($ppp['mtu-override']) &&
2297
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2298
		/* Find the smaller MTU set on ports */
2299
		$mtu = $defaultmtu;
2300
		foreach ($ports as $pid => $port) {
2301
			if (empty($mtus[$pid])) {
2302
				$mtus[$pid] = $defaultmtu;
2303
			}
2304
			if ($type == "pppoe") {
2305
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2306
					$mtus[$pid] = get_interface_mtu($port) - 8;
2307
				}
2308
			}
2309
			if ($mtu > $mtus[$pid]) {
2310
				$mtu = $mtus[$pid];
2311
			}
2312
		}
2313
		$mpdconf .= <<<EOD
2314
	set iface mtu {$mtu} override
2315

    
2316
EOD;
2317
	}
2318

    
2319
	if (isset($ppp['tcpmssfix'])) {
2320
		$tcpmss = "disable";
2321
	} else {
2322
		$tcpmss = "enable";
2323
	}
2324
	$mpdconf .= <<<EOD
2325
	set iface {$tcpmss} tcpmssfix
2326

    
2327
EOD;
2328

    
2329
	$mpdconf .= <<<EOD
2330
	set iface up-script /usr/local/sbin/ppp-linkup
2331
	set iface down-script /usr/local/sbin/ppp-linkdown
2332
	set ipcp ranges {$ranges}
2333

    
2334
EOD;
2335
	if (isset($ppp['vjcomp'])) {
2336
		$mpdconf .= <<<EOD
2337
	set ipcp no vjcomp
2338

    
2339
EOD;
2340
	}
2341

    
2342
	if (isset($config['system']['dnsallowoverride'])) {
2343
		$mpdconf .= <<<EOD
2344
	set ipcp enable req-pri-dns
2345
	set ipcp enable req-sec-dns
2346

    
2347
EOD;
2348
	}
2349

    
2350
	if (!isset($ppp['verbose_log'])) {
2351
		$mpdconf .= <<<EOD
2352
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2353

    
2354
EOD;
2355
	}
2356

    
2357
	foreach ($ports as $pid => $port) {
2358
		$port = get_real_interface($port);
2359
		$mpdconf .= <<<EOD
2360

    
2361
	create link static {$interface}_link{$pid} {$type}
2362
	set link action bundle {$interface}
2363
	set link {$multilink} multilink
2364
	set link keep-alive 10 60
2365
	set link max-redial 0
2366

    
2367
EOD;
2368
		if (isset($ppp['shortseq'])) {
2369
			$mpdconf .= <<<EOD
2370
	set link no shortseq
2371

    
2372
EOD;
2373
		}
2374

    
2375
		if (isset($ppp['acfcomp'])) {
2376
			$mpdconf .= <<<EOD
2377
	set link no acfcomp
2378

    
2379
EOD;
2380
		}
2381

    
2382
		if (isset($ppp['protocomp'])) {
2383
			$mpdconf .= <<<EOD
2384
	set link no protocomp
2385

    
2386
EOD;
2387
		}
2388

    
2389
		$mpdconf .= <<<EOD
2390
	set link disable chap pap
2391
	set link accept chap pap eap
2392
	set link disable incoming
2393

    
2394
EOD;
2395

    
2396

    
2397
		if (!empty($bandwidths[$pid])) {
2398
			$mpdconf .= <<<EOD
2399
	set link bandwidth {$bandwidths[$pid]}
2400

    
2401
EOD;
2402
		}
2403

    
2404
		if (empty($mtus[$pid])) {
2405
			$mtus[$pid] = $defaultmtu;
2406
		}
2407
		if ($type == "pppoe") {
2408
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2409
				$mtus[$pid] = get_interface_mtu($port) - 8;
2410
			}
2411
		}
2412
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2413
		    !isset($ppp['mtu-override']) &&
2414
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2415
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2416
			$mpdconf .= <<<EOD
2417
	set link mtu {$mtus[$pid]}
2418

    
2419
EOD;
2420
		}
2421

    
2422
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2423
		    !isset($ppp['mtu-override']) &&
2424
		    !empty($mrus[$pid])) {
2425
			$mpdconf .= <<<EOD
2426
	set link mru {$mrus[$pid]}
2427

    
2428
EOD;
2429
		}
2430

    
2431
		if (!empty($mrrus[$pid])) {
2432
			$mpdconf .= <<<EOD
2433
	set link mrru {$mrrus[$pid]}
2434

    
2435
EOD;
2436
		}
2437

    
2438
		$mpdconf .= <<<EOD
2439
	set auth authname "{$ppp['username']}"
2440
	set auth password {$passwd}
2441

    
2442
EOD;
2443
		if ($type == "modem") {
2444
			$mpdconf .= <<<EOD
2445
	set modem device {$ppp['ports']}
2446
	set modem script DialPeer
2447
	set modem idle-script Ringback
2448
	set modem watch -cd
2449
	set modem var \$DialPrefix "DT"
2450
	set modem var \$Telephone "{$ppp['phone']}"
2451

    
2452
EOD;
2453
		}
2454
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2455
			$mpdconf .= <<<EOD
2456
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2457

    
2458
EOD;
2459
		}
2460
		if (isset($ppp['initstr']) && $type == "modem") {
2461
			$initstr = base64_decode($ppp['initstr']);
2462
			$mpdconf .= <<<EOD
2463
	set modem var \$InitString "{$initstr}"
2464

    
2465
EOD;
2466
		}
2467
		if (isset($ppp['simpin']) && $type == "modem") {
2468
			if ($ppp['pin-wait'] == "") {
2469
				$ppp['pin-wait'] = 0;
2470
			}
2471
			$mpdconf .= <<<EOD
2472
	set modem var \$SimPin "{$ppp['simpin']}"
2473
	set modem var \$PinWait "{$ppp['pin-wait']}"
2474

    
2475
EOD;
2476
		}
2477
		if (isset($ppp['apn']) && $type == "modem") {
2478
			$mpdconf .= <<<EOD
2479
	set modem var \$APN "{$ppp['apn']}"
2480
	set modem var \$APNum "{$ppp['apnum']}"
2481

    
2482
EOD;
2483
		}
2484
		if ($type == "pppoe") {
2485
			// Send a null service name if none is set.
2486
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2487
			$mpdconf .= <<<EOD
2488
	set pppoe service "{$provider}"
2489

    
2490
EOD;
2491
		}
2492
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
2493
			$mpdconf .= <<<EOD
2494
	set pppoe max-payload {$mtus[$pid]}
2495

    
2496
EOD;
2497
		}
2498
		if ($type == "pppoe") {
2499
			$mpdconf .= <<<EOD
2500
	set pppoe iface {$port}
2501

    
2502
EOD;
2503
		}
2504

    
2505
		if ($type == "pptp" || $type == "l2tp") {
2506
			$mpdconf .= <<<EOD
2507
	set {$type} self {$localips[$pid]}
2508
	set {$type} peer {$gateways[$pid]}
2509

    
2510
EOD;
2511
		}
2512

    
2513
		$mpdconf .= "\topen\n";
2514
	} //end foreach ($port)
2515

    
2516

    
2517
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2518
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2519
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2520
	} else {
2521
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2522
		if (!$fd) {
2523
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2524
			return 0;
2525
		}
2526
		// Write out mpd_ppp.conf
2527
		fwrite($fd, $mpdconf);
2528
		fclose($fd);
2529
		unset($mpdconf);
2530
	}
2531

    
2532
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2533
	if (isset($ppp['uptime'])) {
2534
		if (!file_exists("/conf/{$pppif}.log")) {
2535
			file_put_contents("/conf/{$pppif}.log", '');
2536
		}
2537
	} else {
2538
		if (file_exists("/conf/{$pppif}.log")) {
2539
			@unlink("/conf/{$pppif}.log");
2540
		}
2541
	}
2542

    
2543
	/* clean up old lock files */
2544
	foreach ($ports as $port) {
2545
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2546
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2547
		}
2548
	}
2549

    
2550
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2551
	/* random IPv6 interface identifier during boot. More details at */
2552
	/* https://forum.pfsense.org/index.php?topic=101967.msg570519#msg570519 */
2553
	if (platform_booting() && is_array($config['interfaces'])) {
2554
		$count = 0;
2555
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2556
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2557
				$tempaddr[$count]['if'] = $tempiface['if'];
2558
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2559
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2560
				$count++;
2561
			}
2562
			// Maximum /31 is is x.y.z.254/31
2563
			if ($count > 122) {
2564
				break;
2565
			}
2566
		}
2567
		unset($count);
2568
	}
2569

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

    
2575
	// Check for PPPoE periodic reset request
2576
	if ($type == "pppoe") {
2577
		if (!empty($ppp['pppoe-reset-type'])) {
2578
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2579
		} else {
2580
			interface_setup_pppoe_reset_file($ppp['if']);
2581
		}
2582
	}
2583
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2584
	$i = 0;
2585
	while ($i < 10) {
2586
		if (does_interface_exist($ppp['if'], true)) {
2587
			break;
2588
		}
2589
		sleep(3);
2590
		$i++;
2591
	}
2592

    
2593
	/* Remove all temporary bogon IPv4 addresses */
2594
	if (is_array($tempaddr)) {
2595
		foreach ($tempaddr as $tempiface) {
2596
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2597
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2598
			}
2599
		}
2600
		unset ($tempaddr);
2601
	}
2602

    
2603
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2604
	/* We should be able to launch the right version for each modem */
2605
	/* We can also guess the mondev from the manufacturer */
2606
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2607
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2608
	foreach ($ports as $port) {
2609
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2610
			$mondev = substr(basename($port), 0, -1);
2611
			$devlist = glob("/dev/{$mondev}?");
2612
			$mondev = basename(end($devlist));
2613
		}
2614
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2615
			$mondev = substr(basename($port), 0, -1) . "1";
2616
		}
2617
		if ($mondev != '') {
2618
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2619
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2620
		}
2621
	}
2622

    
2623
	return 1;
2624
}
2625

    
2626
function interfaces_sync_setup() {
2627
	global $g, $config;
2628

    
2629
	if (isset($config['system']['developerspew'])) {
2630
		$mt = microtime();
2631
		echo "interfaces_sync_setup() being called $mt\n";
2632
	}
2633

    
2634
	if (platform_booting()) {
2635
		echo gettext("Configuring CARP settings...");
2636
		mute_kernel_msgs();
2637
	}
2638

    
2639
	/* suck in configuration items */
2640
	if ($config['hasync']) {
2641
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2642
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2643
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2644
	} else {
2645
		unset($pfsyncinterface);
2646
		unset($pfsyncenabled);
2647
	}
2648

    
2649
	set_sysctl(array(
2650
		"net.inet.carp.preempt" => "1",
2651
		"net.inet.carp.log" => "1")
2652
	);
2653

    
2654
	if (!empty($pfsyncinterface)) {
2655
		$carp_sync_int = get_real_interface($pfsyncinterface);
2656
	} else {
2657
		unset($carp_sync_int);
2658
	}
2659

    
2660
	/* setup pfsync interface */
2661
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2662
		if (is_ipaddr($pfsyncpeerip)) {
2663
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2664
		} else {
2665
			$syncpeer = "-syncpeer";
2666
		}
2667

    
2668
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2669
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2670

    
2671
		sleep(1);
2672

    
2673
		/* 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
2674
		 * for existing sessions.
2675
		 */
2676
		log_error(gettext("waiting for pfsync..."));
2677
		$i = 0;
2678
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2679
			$i++;
2680
			sleep(1);
2681
		}
2682
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2683
		log_error(gettext("Configuring CARP settings finalize..."));
2684
	} else {
2685
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2686
	}
2687

    
2688
	$carplist = get_configured_vip_list('all', VIP_CARP);
2689
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2690
		set_single_sysctl("net.inet.carp.allow", "1");
2691
	} else {
2692
		set_single_sysctl("net.inet.carp.allow", "0");
2693
	}
2694

    
2695
	if (platform_booting()) {
2696
		unmute_kernel_msgs();
2697
		echo gettext("done.") . "\n";
2698
	}
2699
}
2700

    
2701
function interface_proxyarp_configure($interface = "") {
2702
	global $config, $g;
2703
	if (isset($config['system']['developerspew'])) {
2704
		$mt = microtime();
2705
		echo "interface_proxyarp_configure() being called $mt\n";
2706
	}
2707

    
2708
	/* kill any running choparp */
2709
	if (empty($interface)) {
2710
		killbyname("choparp");
2711
	} else {
2712
		$vipif = get_real_interface($interface);
2713
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2714
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2715
		}
2716
	}
2717

    
2718
	$paa = array();
2719
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2720

    
2721
		/* group by interface */
2722
		foreach ($config['virtualip']['vip'] as $vipent) {
2723
			if ($vipent['mode'] === "proxyarp") {
2724
				if ($vipent['interface']) {
2725
					$proxyif = $vipent['interface'];
2726
				} else {
2727
					$proxyif = "wan";
2728
				}
2729

    
2730
				if (!empty($interface) && $interface != $proxyif) {
2731
					continue;
2732
				}
2733

    
2734
				if (!is_array($paa[$proxyif])) {
2735
					$paa[$proxyif] = array();
2736
				}
2737

    
2738
				$paa[$proxyif][] = $vipent;
2739
			}
2740
		}
2741
	}
2742

    
2743
	if (!empty($interface)) {
2744
		if (is_array($paa[$interface])) {
2745
			$paaifip = get_interface_ip($interface);
2746
			if (!is_ipaddr($paaifip)) {
2747
				return;
2748
			}
2749
			$vipif = get_real_interface($interface);
2750
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2751
			$args .= $vipif . " auto";
2752
			foreach ($paa[$interface] as $paent) {
2753
				if (isset($paent['subnet'])) {
2754
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2755
				} else if (isset($paent['range'])) {
2756
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2757
				}
2758
			}
2759
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2760
		}
2761
	} else if (count($paa) > 0) {
2762
		foreach ($paa as $paif => $paents) {
2763
			$paaifip = get_interface_ip($paif);
2764
			if (!is_ipaddr($paaifip)) {
2765
				continue;
2766
			}
2767
			$vipif = get_real_interface($paif);
2768
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2769
			$args .= $vipif . " auto";
2770
			foreach ($paents as $paent) {
2771
				if (isset($paent['subnet'])) {
2772
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2773
				} else if (isset($paent['range'])) {
2774
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2775
				}
2776
			}
2777
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2778
		}
2779
	}
2780
}
2781

    
2782
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2783
	global $g, $config;
2784

    
2785
	if (is_array($config['virtualip']['vip'])) {
2786
		foreach ($config['virtualip']['vip'] as $vip) {
2787

    
2788
			$iface = $vip['interface'];
2789
			if (substr($iface, 0, 4) == "_vip")
2790
				$iface = get_configured_vip_interface($vip['interface']);
2791
			if ($iface != $interface)
2792
				continue;
2793
			if ($type == VIP_CARP) {
2794
				if ($vip['mode'] != "carp")
2795
					continue;
2796
			} elseif ($type == VIP_IPALIAS) {
2797
				if ($vip['mode'] != "ipalias")
2798
					continue;
2799
			} else {
2800
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2801
					continue;
2802
			}
2803

    
2804
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2805
				interface_vip_bring_down($vip);
2806
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2807
				interface_vip_bring_down($vip);
2808
			else if ($inet == "all")
2809
				interface_vip_bring_down($vip);
2810
		}
2811
	}
2812
}
2813

    
2814
function interfaces_vips_configure($interface = "") {
2815
	global $g, $config;
2816
	if (isset($config['system']['developerspew'])) {
2817
		$mt = microtime();
2818
		echo "interfaces_vips_configure() being called $mt\n";
2819
	}
2820
	$paa = array();
2821
	if (is_array($config['virtualip']['vip'])) {
2822
		$carp_setuped = false;
2823
		$anyproxyarp = false;
2824
		foreach ($config['virtualip']['vip'] as $vip) {
2825
			if ($interface <> "" && get_root_interface($vip['interface']) <> $interface) {
2826
				continue;
2827
			}
2828
			switch ($vip['mode']) {
2829
				case "proxyarp":
2830
					/* nothing it is handled on interface_proxyarp_configure() */
2831
					$anyproxyarp = true;
2832
					break;
2833
				case "ipalias":
2834
					interface_ipalias_configure($vip);
2835
					break;
2836
				case "carp":
2837
					if ($carp_setuped == false) {
2838
						$carp_setuped = true;
2839
					}
2840
					interface_carp_configure($vip);
2841
					break;
2842
			}
2843
		}
2844
		if ($carp_setuped == true) {
2845
			interfaces_sync_setup();
2846
		}
2847
		if ($anyproxyarp == true) {
2848
			interface_proxyarp_configure();
2849
		}
2850
	}
2851
}
2852

    
2853
function interface_ipalias_configure(&$vip) {
2854
	global $config;
2855

    
2856
	if ($vip['mode'] != 'ipalias') {
2857
		return;
2858
	}
2859

    
2860
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2861
	if ($realif != "lo0") {
2862
		$if = convert_real_interface_to_friendly_interface_name($realif);
2863
		if (!isset($config['interfaces'][$if]) ||
2864
		    !isset($config['interfaces'][$if]['enable'])) {
2865
			return;
2866
		}
2867
	}
2868

    
2869
	$af = 'inet';
2870
	if (is_ipaddrv6($vip['subnet'])) {
2871
		$af = 'inet6';
2872
	}
2873
	$iface = $vip['interface'];
2874
	$vhid = '';
2875
	if (substr($vip['interface'], 0, 4) == "_vip") {
2876
		$carpvip = get_configured_vip($vip['interface']);
2877
		$iface = $carpvip['interface'];
2878
		$vhid = "vhid {$carpvip['vhid']}";
2879
	}
2880
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2881
	unset($iface, $af, $realif, $carpvip, $vhid);
2882
}
2883

    
2884
function interface_carp_configure(&$vip, $maintenancemode_only = false) {
2885
	global $config, $g;
2886
	if (isset($config['system']['developerspew'])) {
2887
		$mt = microtime();
2888
		echo "interface_carp_configure() being called $mt\n";
2889
	}
2890

    
2891
	if ($vip['mode'] != "carp") {
2892
		return;
2893
	}
2894

    
2895
	$realif = get_real_interface($vip['interface']);
2896
	if (!does_interface_exist($realif)) {
2897
		file_notice("CARP", sprintf(gettext(
2898
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
2899
		    $vip['subnet']), "Firewall: Virtual IP", "");
2900
		return;
2901
	}
2902
	if ($realif != "lo0") {
2903
		if (!isset($config['interfaces'][$vip['interface']]) ||
2904
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
2905
			return;
2906
		}
2907
	}
2908

    
2909
	$vip_password = $vip['password'];
2910
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
2911
	    $vip_password)));
2912
	if ($vip['password'] != "") {
2913
		$password = " pass {$vip_password}";
2914
	}
2915

    
2916
	$advbase = "";
2917
	if (!empty($vip['advbase'])) {
2918
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2919
	}
2920

    
2921
	$carp_maintenancemode = isset(
2922
	    $config["virtualip_carp_maintenancemode"]);
2923
	if ($carp_maintenancemode) {
2924
		$advskew = "advskew 254";
2925
	} else {
2926
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2927
	}
2928

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

    
2932
	if (!$maintenancemode_only) {
2933
		if (is_ipaddrv4($vip['subnet'])) {
2934
			mwexec("/sbin/ifconfig {$realif} " .
2935
			    escapeshellarg($vip['subnet']) . "/" .
2936
			    escapeshellarg($vip['subnet_bits']) .
2937
			    " alias vhid " . escapeshellarg($vip['vhid']));
2938
		} else if (is_ipaddrv6($vip['subnet'])) {
2939
			mwexec("/sbin/ifconfig {$realif} inet6 " .
2940
			    escapeshellarg($vip['subnet']) . " prefixlen " .
2941
			    escapeshellarg($vip['subnet_bits']) .
2942
			    " alias vhid " . escapeshellarg($vip['vhid']));
2943
		}
2944
	}
2945

    
2946
	return $realif;
2947
}
2948

    
2949
function interface_wireless_clone($realif, $wlcfg) {
2950
	global $config, $g;
2951
	/*   Check to see if interface has been cloned as of yet.
2952
	 *   If it has not been cloned then go ahead and clone it.
2953
	 */
2954
	$needs_clone = false;
2955
	if (is_array($wlcfg['wireless'])) {
2956
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2957
	} else {
2958
		$wlcfg_mode = $wlcfg['mode'];
2959
	}
2960
	switch ($wlcfg_mode) {
2961
		case "hostap":
2962
			$mode = "wlanmode hostap";
2963
			break;
2964
		case "adhoc":
2965
			$mode = "wlanmode adhoc";
2966
			break;
2967
		default:
2968
			$mode = "";
2969
			break;
2970
	}
2971
	$baseif = interface_get_wireless_base($wlcfg['if']);
2972
	if (does_interface_exist($realif)) {
2973
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2974
		$ifconfig_str = implode($output);
2975
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2976
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2977
			$needs_clone = true;
2978
		}
2979
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2980
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2981
			$needs_clone = true;
2982
		}
2983
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2984
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2985
			$needs_clone = true;
2986
		}
2987
	} else {
2988
		$needs_clone = true;
2989
	}
2990

    
2991
	if ($needs_clone == true) {
2992
		/* remove previous instance if it exists */
2993
		if (does_interface_exist($realif)) {
2994
			pfSense_interface_destroy($realif);
2995
		}
2996

    
2997
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2998
		// Create the new wlan interface. FreeBSD returns the new interface name.
2999
		// example:  wlan2
3000
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3001
		if ($ret <> 0) {
3002
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3003
			return false;
3004
		}
3005
		$newif = trim($out[0]);
3006
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3007
		pfSense_interface_rename($newif, $realif);
3008
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3009
	}
3010
	return true;
3011
}
3012

    
3013
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3014
	global $config, $g;
3015

    
3016
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3017
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3018
				 'regdomain', 'regcountry', 'reglocation');
3019

    
3020
	if (!is_interface_wireless($ifcfg['if'])) {
3021
		return;
3022
	}
3023

    
3024
	$baseif = interface_get_wireless_base($ifcfg['if']);
3025

    
3026
	// Sync shared settings for assigned clones
3027
	$iflist = get_configured_interface_list(true);
3028
	foreach ($iflist as $if) {
3029
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
3030
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
3031
				foreach ($shared_settings as $setting) {
3032
					if ($sync_changes) {
3033
						if (isset($ifcfg['wireless'][$setting])) {
3034
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
3035
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3036
							unset($config['interfaces'][$if]['wireless'][$setting]);
3037
						}
3038
					} else {
3039
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3040
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
3041
						} else if (isset($ifcfg['wireless'][$setting])) {
3042
							unset($ifcfg['wireless'][$setting]);
3043
						}
3044
					}
3045
				}
3046
				if (!$sync_changes) {
3047
					break;
3048
				}
3049
			}
3050
		}
3051
	}
3052

    
3053
	// Read or write settings at shared area
3054
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3055
		foreach ($shared_settings as $setting) {
3056
			if ($sync_changes) {
3057
				if (isset($ifcfg['wireless'][$setting])) {
3058
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3059
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3060
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3061
				}
3062
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3063
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3064
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3065
				} else if (isset($ifcfg['wireless'][$setting])) {
3066
					unset($ifcfg['wireless'][$setting]);
3067
				}
3068
			}
3069
		}
3070
	}
3071

    
3072
	// Sync the mode on the clone creation page with the configured mode on the interface
3073
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3074
		foreach ($config['wireless']['clone'] as &$clone) {
3075
			if ($clone['cloneif'] == $ifcfg['if']) {
3076
				if ($sync_changes) {
3077
					$clone['mode'] = $ifcfg['wireless']['mode'];
3078
				} else {
3079
					$ifcfg['wireless']['mode'] = $clone['mode'];
3080
				}
3081
				break;
3082
			}
3083
		}
3084
		unset($clone);
3085
	}
3086
}
3087

    
3088
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3089
	global $config, $g;
3090

    
3091
	/*    open up a shell script that will be used to output the commands.
3092
	 *    since wireless is changing a lot, these series of commands are fragile
3093
	 *    and will sometimes need to be verified by a operator by executing the command
3094
	 *    and returning the output of the command to the developers for inspection.  please
3095
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3096
	 */
3097

    
3098
	// Remove script file
3099
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3100

    
3101
	// Clone wireless nic if needed.
3102
	interface_wireless_clone($if, $wl);
3103

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

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

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

    
3113
	/* set values for /path/program */
3114
	if (file_exists("/usr/local/sbin/hostapd")) {
3115
		$hostapd = "/usr/local/sbin/hostapd";
3116
	} else {
3117
		$hostapd = "/usr/sbin/hostapd";
3118
	}
3119
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3120
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3121
	} else {
3122
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3123
	}
3124
	$ifconfig = "/sbin/ifconfig";
3125
	$sysctl = "/sbin/sysctl";
3126
	$sysctl_args = "-q";
3127
	$killall = "/usr/bin/killall";
3128

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

    
3131
	$wlcmd = array();
3132
	$wl_sysctl = array();
3133
	/* Set a/b/g standard */
3134
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3135
	/* skip mode entirely for "auto" */
3136
	if ($wlcfg['standard'] != "auto") {
3137
		$wlcmd[] = "mode " . escapeshellarg($standard);
3138
	}
3139

    
3140
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3141
	 * to prevent massive packet loss under certain conditions. */
3142
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3143
		$wlcmd[] = "-ampdu";
3144
	}
3145

    
3146
	/* Set ssid */
3147
	if ($wlcfg['ssid']) {
3148
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3149
	}
3150

    
3151
	/* Set 802.11g protection mode */
3152
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3153

    
3154
	/* set wireless channel value */
3155
	if (isset($wlcfg['channel'])) {
3156
		if ($wlcfg['channel'] == "0") {
3157
			$wlcmd[] = "channel any";
3158
		} else {
3159
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
3160
		}
3161
	}
3162

    
3163
	/* Set antenna diversity value */
3164
	if (isset($wlcfg['diversity'])) {
3165
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3166
	}
3167

    
3168
	/* Set txantenna value */
3169
	if (isset($wlcfg['txantenna'])) {
3170
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3171
	}
3172

    
3173
	/* Set rxantenna value */
3174
	if (isset($wlcfg['rxantenna'])) {
3175
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3176
	}
3177

    
3178
	/* set Distance value */
3179
	if ($wlcfg['distance']) {
3180
		$distance = escapeshellarg($wlcfg['distance']);
3181
	}
3182

    
3183
	/* Set wireless hostap mode */
3184
	if ($wlcfg['mode'] == "hostap") {
3185
		$wlcmd[] = "mediaopt hostap";
3186
	} else {
3187
		$wlcmd[] = "-mediaopt hostap";
3188
	}
3189

    
3190
	/* Set wireless adhoc mode */
3191
	if ($wlcfg['mode'] == "adhoc") {
3192
		$wlcmd[] = "mediaopt adhoc";
3193
	} else {
3194
		$wlcmd[] = "-mediaopt adhoc";
3195
	}
3196

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

    
3199
	/* handle hide ssid option */
3200
	if (isset($wlcfg['hidessid']['enable'])) {
3201
		$wlcmd[] = "hidessid";
3202
	} else {
3203
		$wlcmd[] = "-hidessid";
3204
	}
3205

    
3206
	/* handle pureg (802.11g) only option */
3207
	if (isset($wlcfg['pureg']['enable'])) {
3208
		$wlcmd[] = "mode 11g pureg";
3209
	} else {
3210
		$wlcmd[] = "-pureg";
3211
	}
3212

    
3213
	/* handle puren (802.11n) only option */
3214
	if (isset($wlcfg['puren']['enable'])) {
3215
		$wlcmd[] = "puren";
3216
	} else {
3217
		$wlcmd[] = "-puren";
3218
	}
3219

    
3220
	/* enable apbridge option */
3221
	if (isset($wlcfg['apbridge']['enable'])) {
3222
		$wlcmd[] = "apbridge";
3223
	} else {
3224
		$wlcmd[] = "-apbridge";
3225
	}
3226

    
3227
	/* handle turbo option */
3228
	if (isset($wlcfg['turbo']['enable'])) {
3229
		$wlcmd[] = "mediaopt turbo";
3230
	} else {
3231
		$wlcmd[] = "-mediaopt turbo";
3232
	}
3233

    
3234
	/* handle txpower setting */
3235
	// or don't. this has issues at the moment.
3236
	/*
3237
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3238
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3239
	}*/
3240

    
3241
	/* handle wme option */
3242
	if (isset($wlcfg['wme']['enable'])) {
3243
		$wlcmd[] = "wme";
3244
	} else {
3245
		$wlcmd[] = "-wme";
3246
	}
3247

    
3248
	/* Enable wpa if it's configured. No WEP support anymore. */
3249
	if (isset($wlcfg['wpa']['enable'])) {
3250
		$wlcmd[] = "authmode wpa wepmode off ";
3251
	} else {
3252
		$wlcmd[] = "authmode open wepmode off ";
3253
	}
3254

    
3255
	kill_hostapd($if);
3256
	mwexec(kill_wpasupplicant("{$if}"));
3257

    
3258
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3259

    
3260
	switch ($wlcfg['mode']) {
3261
		case 'bss':
3262
			if (isset($wlcfg['wpa']['enable'])) {
3263
				$wpa .= <<<EOD
3264
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3265
ctrl_interface_group=0
3266
ap_scan=1
3267
#fast_reauth=1
3268
network={
3269
ssid="{$wlcfg['ssid']}"
3270
scan_ssid=1
3271
priority=5
3272
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3273
psk="{$wlcfg['wpa']['passphrase']}"
3274
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3275
group={$wlcfg['wpa']['wpa_pairwise']}
3276
}
3277
EOD;
3278

    
3279
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
3280
				unset($wpa);
3281
			}
3282
			break;
3283
		case 'hostap':
3284
			if (!empty($wlcfg['wpa']['passphrase'])) {
3285
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3286
			} else {
3287
				$wpa_passphrase = "";
3288
			}
3289
			if (isset($wlcfg['wpa']['enable'])) {
3290
				$wpa .= <<<EOD
3291
interface={$if}
3292
driver=bsd
3293
logger_syslog=-1
3294
logger_syslog_level=0
3295
logger_stdout=-1
3296
logger_stdout_level=0
3297
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3298
ctrl_interface={$g['varrun_path']}/hostapd
3299
ctrl_interface_group=wheel
3300
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3301
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3302
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3303
ssid={$wlcfg['ssid']}
3304
debug={$wlcfg['wpa']['debug_mode']}
3305
wpa={$wlcfg['wpa']['wpa_mode']}
3306
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3307
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3308
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3309
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3310
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3311
{$wpa_passphrase}
3312

    
3313
EOD;
3314

    
3315
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3316
					$wpa .= <<<EOD
3317
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3318
rsn_preauth=1
3319
rsn_preauth_interfaces={$if}
3320

    
3321
EOD;
3322
				}
3323
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3324
					$wpa .= "ieee8021x=1\n";
3325

    
3326
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3327
						$auth_server_port = "1812";
3328
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3329
							$auth_server_port = intval($wlcfg['auth_server_port']);
3330
						}
3331
						$wpa .= <<<EOD
3332

    
3333
auth_server_addr={$wlcfg['auth_server_addr']}
3334
auth_server_port={$auth_server_port}
3335
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3336

    
3337
EOD;
3338
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3339
							$auth_server_port2 = "1812";
3340
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3341
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3342
							}
3343

    
3344
							$wpa .= <<<EOD
3345
auth_server_addr={$wlcfg['auth_server_addr2']}
3346
auth_server_port={$auth_server_port2}
3347
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3348

    
3349
EOD;
3350
						}
3351
					}
3352
				}
3353

    
3354
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3355
				unset($wpa);
3356
			}
3357
			break;
3358
	}
3359

    
3360
	/*
3361
	 *    all variables are set, lets start up everything
3362
	 */
3363

    
3364
	$baseif = interface_get_wireless_base($if);
3365
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3366
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3367

    
3368
	/* set sysctls for the wireless interface */
3369
	if (!empty($wl_sysctl)) {
3370
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3371
		foreach ($wl_sysctl as $wl_sysctl_line) {
3372
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3373
		}
3374
	}
3375

    
3376
	/* set ack timers according to users preference (if he/she has any) */
3377
	if ($distance) {
3378
		fwrite($fd_set, "# Enable ATH distance settings\n");
3379
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3380
	}
3381

    
3382
	if (isset($wlcfg['wpa']['enable'])) {
3383
		if ($wlcfg['mode'] == "bss") {
3384
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3385
		}
3386
		if ($wlcfg['mode'] == "hostap") {
3387
			/* add line to script to restore old mac to make hostapd happy */
3388
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3389
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3390
				$if_curmac = get_interface_mac($if);
3391
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3392
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3393
						" link " . escapeshellarg($if_oldmac) . "\n");
3394
				}
3395
			}
3396

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

    
3399
			/* add line to script to restore spoofed mac after running hostapd */
3400
			if ($wl['spoofmac']) {
3401
				$if_curmac = get_interface_mac($if);
3402
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3403
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3404
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3405
				}
3406
			}
3407
		}
3408
	}
3409

    
3410
	fclose($fd_set);
3411

    
3412
	/* Making sure regulatory settings have actually changed
3413
	 * before applying, because changing them requires bringing
3414
	 * down all wireless networks on the interface. */
3415
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3416
	$ifconfig_str = implode($output);
3417
	unset($output);
3418
	$reg_changing = false;
3419

    
3420
	/* special case for the debug country code */
3421
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3422
		$reg_changing = true;
3423
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3424
		$reg_changing = true;
3425
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3426
		$reg_changing = true;
3427
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3428
		$reg_changing = true;
3429
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3430
		$reg_changing = true;
3431
	}
3432

    
3433
	if ($reg_changing) {
3434
		/* set regulatory domain */
3435
		if ($wlcfg['regdomain']) {
3436
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3437
		}
3438

    
3439
		/* set country */
3440
		if ($wlcfg['regcountry']) {
3441
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3442
		}
3443

    
3444
		/* set location */
3445
		if ($wlcfg['reglocation']) {
3446
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3447
		}
3448

    
3449
		$wlregcmd_args = implode(" ", $wlregcmd);
3450

    
3451
		/* build a complete list of the wireless clones for this interface */
3452
		$clone_list = array();
3453
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3454
			$clone_list[] = interface_get_wireless_clone($baseif);
3455
		}
3456
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3457
			foreach ($config['wireless']['clone'] as $clone) {
3458
				if ($clone['if'] == $baseif) {
3459
					$clone_list[] = $clone['cloneif'];
3460
				}
3461
			}
3462
		}
3463

    
3464
		/* find which clones are up and bring them down */
3465
		$clones_up = array();
3466
		foreach ($clone_list as $clone_if) {
3467
			$clone_status = pfSense_get_interface_addresses($clone_if);
3468
			if ($clone_status['status'] == 'up') {
3469
				$clones_up[] = $clone_if;
3470
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3471
			}
3472
		}
3473

    
3474
		/* apply the regulatory settings */
3475
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3476
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3477

    
3478
		/* bring the clones back up that were previously up */
3479
		foreach ($clones_up as $clone_if) {
3480
			interfaces_bring_up($clone_if);
3481

    
3482
			/*
3483
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3484
			 * is in infrastructure mode, and WPA is enabled.
3485
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3486
			 */
3487
			if ($clone_if != $if) {
3488
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3489
				if ((!empty($friendly_if)) &&
3490
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3491
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3492
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3493
				}
3494
			}
3495
		}
3496
	}
3497

    
3498
	/* The mode must be specified in a separate command before ifconfig
3499
	 * will allow the mode and channel at the same time in the next.
3500
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3501
	 */
3502
	if ($wlcfg['mode'] == "hostap") {
3503
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3504
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3505
	}
3506

    
3507
	/* configure wireless */
3508
	$wlcmd_args = implode(" ", $wlcmd);
3509
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3510
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3511
	/* Bring the interface up only after setting up all the other parameters. */
3512
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3513
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3514
	fclose($wlan_setup_log);
3515

    
3516
	unset($wlcmd_args, $wlcmd);
3517

    
3518

    
3519
	sleep(1);
3520
	/* execute hostapd and wpa_supplicant if required in shell */
3521
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3522

    
3523
	return 0;
3524

    
3525
}
3526

    
3527
function kill_hostapd($interface) {
3528
	global $g;
3529

    
3530
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3531
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3532
	}
3533
}
3534

    
3535
function kill_wpasupplicant($interface) {
3536
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3537
}
3538

    
3539
function find_dhclient_process($interface) {
3540
	if ($interface) {
3541
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3542
	} else {
3543
		$pid = 0;
3544
	}
3545

    
3546
	return intval($pid);
3547
}
3548

    
3549
function kill_dhclient_process($interface) {
3550
	if (empty($interface) || !does_interface_exist($interface)) {
3551
		return;
3552
	}
3553

    
3554
	$i = 0;
3555
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3556
		/* 3rd time make it die for sure */
3557
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3558
		posix_kill($pid, $sig);
3559
		sleep(1);
3560
		$i++;
3561
	}
3562
	unset($i);
3563
}
3564

    
3565
function find_dhcp6c_process($interface) {
3566
	global $g;
3567

    
3568
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3569
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3570
	} else {
3571
		return(false);
3572
	}
3573

    
3574
	return intval($pid);
3575
}
3576

    
3577
function kill_dhcp6client_process($interface, $force, $release = false) {
3578
	global $g;
3579

    
3580
	$i = 0;
3581

    
3582
	/*
3583
	Beware of the following: Reason, the interface may be down, but
3584
	dhcp6c may still be running, it just complains it cannot send
3585
	and carries on. Commented out as will stop the call to kill.
3586

    
3587
	if (empty($interface) || !does_interface_exist($interface)) {
3588
		return;
3589
	}
3590
	*/
3591

    
3592
	/*********** Notes on signals for dhcp6c and this function *************
3593

    
3594
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3595
	a release and waiting for the response that never comes.
3596
	So we need to tell it that the interface is down and to just die quickly
3597
	otherwise a new client may launch and we have duplicate proceses.
3598
	In this case use SIGUSR1.
3599

    
3600
	If we want to exit normally obeying the no release flag then use SIGTERM.
3601
	If we want to exit with a release overiding the no release flag then
3602
	use SIGUSR2.
3603

    
3604
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3605
	exit quickly without sending release signals.
3606

    
3607
	If $Force is set to false and $release is also set to false dhcp6c will
3608
	follow the no-release flag.
3609

    
3610
	If $Force is set to false and $release is true then dhcp6c will send a
3611
	release regardless of the no-release flag.
3612
	***********************************************************************/
3613

    
3614
	if ($force == true) {
3615
		$psig=SIGUSR1;
3616
	} else if ($release == false) {
3617
		$psig=SIGTERM;
3618
	} else {
3619
		$psig=SIGUSR2;
3620
	}
3621

    
3622
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3623
		/* 3rd time make it die for sure */
3624
		$sig = ($i == 2 ? SIGKILL : $psig);
3625
		posix_kill($pid, $sig);
3626
		sleep(1);
3627
		$i++;
3628
	}
3629
	/* Clear the RTSOLD script created lock & tidy up */
3630
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3631
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
3632
}
3633
function reset_dhcp6client_process($interface) {
3634

    
3635
	$pid = find_dhcp6c_process($interface);
3636

    
3637
	if($pid != 0) {
3638
		posix_kill($pid, SIGHUP);
3639
	}
3640
}
3641

    
3642
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3643
	global $g;
3644

    
3645
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3646
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3647

    
3648
	/*
3649
	 * Only run this if the lock does not exist. In theory the lock being
3650
	 * there in this mode means the user has selected dhcp6withoutRA while
3651
	 * a session is active in the other mode.
3652
	 *
3653
	 * It should not happen as the process should have been killed and the
3654
	 * lock deleted.
3655
	 */
3656

    
3657
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
3658
		kill_dhcp6client_process($interface, true);
3659
		/* Lock it to avoid multiple runs */
3660
		touch("/tmp/dhcp6c_{$interface}_lock");
3661
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3662
		    "{$noreleaseOption} " .
3663
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
3664
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
3665
		    $interface);
3666
		log_error(sprintf(gettext(
3667
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
3668
		    $interface));
3669
	}
3670
}
3671

    
3672
function interface_virtual_create($interface) {
3673
	global $config;
3674

    
3675
	if (interface_is_vlan($interface) != NULL) {
3676
		interfaces_vlan_configure($interface);
3677
	} else if (substr($interface, 0, 3) == "gre") {
3678
		interfaces_gre_configure(0, $interface);
3679
	} else if (substr($interface, 0, 3) == "gif") {
3680
		interfaces_gif_configure(0, $interface);
3681
	} else if (substr($interface, 0, 5) == "ovpns") {
3682
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3683
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3684
				if ($interface == "ovpns{$server['vpnid']}") {
3685
					if (!function_exists('openvpn_resync')) {
3686
						require_once('openvpn.inc');
3687
					}
3688
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3689
					openvpn_resync('server', $server);
3690
				}
3691
			}
3692
			unset($server);
3693
		}
3694
	} else if (substr($interface, 0, 5) == "ovpnc") {
3695
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3696
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3697
				if ($interface == "ovpnc{$client['vpnid']}") {
3698
					if (!function_exists('openvpn_resync')) {
3699
						require_once('openvpn.inc');
3700
					}
3701
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3702
					openvpn_resync('client', $client);
3703
				}
3704
			}
3705
			unset($client);
3706
		}
3707
	} else if (substr($interface, 0, 5) == "ipsec") {
3708
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
3709
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
3710
				if ($ph1ent['disabled']) {
3711
					continue;
3712
				}
3713
				if ($interface == "ipsec{$ph1ent['ikeid']}") {
3714
					interface_ipsec_vti_configure($ph1ent);
3715
				}
3716
			}
3717
		}
3718
	} else if (substr($interface, 0, 4) == "lagg") {
3719
		interfaces_lagg_configure($interface);
3720
	} else if (substr($interface, 0, 6) == "bridge") {
3721
		interfaces_bridge_configure(0, $interface);
3722
	}
3723
}
3724

    
3725
function interface_vlan_mtu_configured($iface) {
3726
	global $config;
3727

    
3728
	$mtu = 0;
3729
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3730
		foreach ($config['vlans']['vlan'] as $vlan) {
3731

    
3732
			if ($vlan['vlanif'] != $iface)
3733
				continue;
3734

    
3735
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3736
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3737
				/* VLAN MTU */
3738
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3739
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3740
				/* Parent MTU */
3741
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3742
			}
3743
		}
3744
	}
3745

    
3746
	return $mtu;
3747
}
3748

    
3749
function interface_mtu_wanted_for_pppoe($realif) {
3750
	global $config;
3751

    
3752
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3753
		return 0;
3754

    
3755
	$mtu = 0;
3756
	foreach ($config['ppps']['ppp'] as $ppp) {
3757
		if ($ppp['type'] != "pppoe") {
3758
			continue;
3759
		}
3760

    
3761
		$mtus = array();
3762
		if (!empty($ppp['mtu'])) {
3763
			$mtus = explode(',', $ppp['mtu']);
3764
		}
3765
		$ports = explode(',', $ppp['ports']);
3766

    
3767
		foreach ($ports as $pid => $port) {
3768
			$parentifa = get_parent_interface($port);
3769
			$parentif = $parentifa[0];
3770
			if ($parentif != $realif)
3771
				continue;
3772

    
3773
			// there is an MTU configured on the port in question
3774
			if (!empty($mtus[$pid])) {
3775
				$mtu = intval($mtus[$pid]) + 8;
3776
			// or use the MTU configured on the interface ...
3777
			} elseif (is_array($config['interfaces'])) {
3778
				foreach ($config['interfaces'] as $interface) {
3779
					if ($interface['if'] == $ppp['if'] &&
3780
					    !empty($interface['mtu'])) {
3781
						$mtu = intval($interface['mtu']) + 8;
3782
						break;
3783
					}
3784
				}
3785
			}
3786
		}
3787
	}
3788

    
3789
	return $mtu;
3790
}
3791

    
3792
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3793
	global $config, $g;
3794
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3795
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3796

    
3797
	$wancfg = $config['interfaces'][$interface];
3798

    
3799
	if (!isset($wancfg['enable'])) {
3800
		return;
3801
	}
3802

    
3803
	$realif = get_real_interface($interface);
3804
	$realhwif_array = get_parent_interface($interface);
3805
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3806
	$realhwif = $realhwif_array[0];
3807

    
3808
	$mac_if_cfg = $wancfg;
3809
	if (interface_is_vlan($realif)) {
3810
		$mac_if = convert_real_interface_to_friendly_interface_name(
3811
		    $realhwif);
3812
		if (is_array($config['interfaces'][$mac_if])) {
3813
			$mac_if_cfg = $config['interfaces'][$mac_if];
3814
		} else {
3815
			$mac_if = $interface;
3816
		}
3817
	}
3818

    
3819
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn") && !(substr($realif, 0, 5) == "ipsec")) {
3820
		/* remove all IPv4 and IPv6 addresses */
3821
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3822
		if (is_array($tmpifaces)) {
3823
			foreach ($tmpifaces as $tmpiface) {
3824
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3825
					if (!is_linklocal($tmpiface)) {
3826
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3827
					}
3828
				} else {
3829
					if (is_subnetv4($tmpiface)) {
3830
						$tmpip = explode('/', $tmpiface);
3831
						$tmpip = $tmpip[0];
3832
					} else {
3833
						$tmpip = $tmpiface;
3834
					}
3835
					pfSense_interface_deladdress($realif, $tmpip);
3836
				}
3837
			}
3838
		}
3839

    
3840
		/* only bring down the interface when both v4 and v6 are set to NONE */
3841
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3842
			interface_bring_down($interface);
3843
		}
3844
	}
3845

    
3846
	$interface_to_check = $realif;
3847
	if (interface_isppp_type($interface)) {
3848
		$interface_to_check = $realhwif;
3849
	}
3850

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

    
3856
	/* Disable Accepting router advertisements unless specifically requested */
3857
	if ($g['debug']) {
3858
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3859
	}
3860
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
3861
	{
3862
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3863
	}
3864
	/* wireless configuration? */
3865
	if (is_array($wancfg['wireless']) && !$linkupevent) {
3866
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3867
	}
3868

    
3869
	$current_mac = get_interface_mac($realhwif);
3870
	$vendor_mac = get_interface_vendor_mac($realhwif);
3871

    
3872
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
3873
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
3874

    
3875
		interface_set_macaddr($realhwif, $mac_addr);
3876
	} else {
3877
		/*
3878
		 * this is not a valid mac address.  generate a
3879
		 * temporary mac address so the machine can get online.
3880
		 */
3881
		echo gettext("Generating new MAC address.");
3882
		$random_mac = generate_random_mac_address();
3883
		interface_set_macaddr($realhwif, $random_mac);
3884
		$config['interfaces'][$mac_if]['spoofmac'] = $random_mac;
3885
		write_config(sprintf(gettext('The invalid MAC address ' .
3886
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
3887
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
3888
		file_notice("MAC Address altered", sprintf(gettext('The ' .
3889
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
3890
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
3891
		    $random_mac), "Interfaces");
3892
	}
3893

    
3894
	/* media */
3895
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3896
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3897
		if ($wancfg['media']) {
3898
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3899
		}
3900
		if ($wancfg['mediaopt']) {
3901
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3902
		}
3903
		mwexec($cmd);
3904
	}
3905

    
3906
	/* Apply hw offloading policies as configured */
3907
	enable_hardware_offloading($interface);
3908

    
3909
	/* invalidate interface/ip/sn cache */
3910
	get_interface_arr(true);
3911
	unset($interface_ip_arr_cache[$realif]);
3912
	unset($interface_sn_arr_cache[$realif]);
3913
	unset($interface_ipv6_arr_cache[$realif]);
3914
	unset($interface_snv6_arr_cache[$realif]);
3915

    
3916
	$tunnelif = substr($realif, 0, 3);
3917

    
3918
	$mtuif = $realif;
3919
	$mtuhwif = $realhwif;
3920

    
3921
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3922
	if (interface_isppp_type($interface)) {
3923
		$mtuif = $realhwif;
3924
		$mtuhwif_array = get_parent_interface($mtuif);
3925
		$mtuhwif = $mtuhwif_array[0];
3926
	}
3927

    
3928
	$wantedmtu = 0;
3929
	if (is_array($config['interfaces'])) {
3930
		foreach ($config['interfaces'] as $tmpinterface) {
3931
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3932
				$wantedmtu = $tmpinterface['mtu'];
3933
				break;
3934
			}
3935
		}
3936
	}
3937

    
3938
	/* MTU is not specified for interface, try the pppoe settings. */
3939
	if ($wantedmtu == 0) {
3940
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3941
	}
3942
	if ($wantedmtu == 0 && interface_is_vlan($mtuif) != NULL && interface_isppp_type($interface)) {
3943
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3944
	}
3945

    
3946
	/* Set the MTU to 1500 if no explicit MTU configured. */
3947
	if ($wantedmtu == 0) {
3948
		$wantedmtu = 1500; /* Default */
3949
	}
3950

    
3951
	if (interface_is_vlan($mtuif) != NULL) {
3952
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3953
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3954
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3955
			if ($wancfg['mtu'] > $parentmtu) {
3956
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3957
			}
3958
		}
3959

    
3960
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3961

    
3962
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3963
			$configuredmtu = $parentmtu;
3964
		if ($configuredmtu != 0)
3965
			$mtu = $configuredmtu;
3966
		else
3967
			$mtu = $wantedmtu;
3968

    
3969
		/* Set the parent MTU. */
3970
		if (get_interface_mtu($mtuhwif) < $mtu)
3971
			set_interface_mtu($mtuhwif, $mtu);
3972
		/* Set the VLAN MTU. */
3973
		if (get_interface_mtu($mtuif) != $mtu)
3974
			set_interface_mtu($mtuif, $mtu);
3975
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3976
		/* LAGG interface must be destroyed and re-created to change MTU */
3977
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3978
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3979
				foreach ($config['laggs']['lagg'] as $lagg) {
3980
					if ($lagg['laggif'] == $mtuif) {
3981
						interface_lagg_configure($lagg);
3982
						break;
3983
					}
3984
				}
3985
			}
3986
		}
3987
	} else {
3988
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3989
			pfSense_interface_mtu($mtuif, $wantedmtu);
3990
		}
3991
	}
3992
	/* XXX: What about gre/gif/.. ? */
3993

    
3994
	if (does_interface_exist($wancfg['if'])) {
3995
		interfaces_bring_up($wancfg['if']);
3996
	}
3997

    
3998
	switch ($wancfg['ipaddr']) {
3999
		case 'dhcp':
4000
			interface_dhcp_configure($interface);
4001
			break;
4002
		case 'pppoe':
4003
		case 'l2tp':
4004
		case 'pptp':
4005
		case 'ppp':
4006
			interface_ppps_configure($interface);
4007
			break;
4008
		default:
4009
			/* XXX: Kludge for now related to #3280 */
4010
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4011
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4012
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4013
				}
4014
			}
4015
			break;
4016
	}
4017

    
4018
	switch ($wancfg['ipaddrv6']) {
4019
		case 'slaac':
4020
		case 'dhcp6':
4021
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4022
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4023
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4024
			/* Remove the check file. Should not be there but just in case */
4025
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
4026
			log_error(gettext("calling interface_dhcpv6_configure."));
4027
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
4028
				interface_dhcpv6_configure($interface, $wancfg);
4029
			}
4030
			break;
4031
		case '6rd':
4032
			interface_6rd_configure($interface, $wancfg);
4033
			break;
4034
		case '6to4':
4035
			interface_6to4_configure($interface, $wancfg);
4036
			break;
4037
		case 'track6':
4038
			interface_track6_configure($interface, $wancfg, $linkupevent);
4039
			break;
4040
		default:
4041
			/* XXX: Kludge for now related to #3280 */
4042
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4043
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4044
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4045
					// FIXME: Add IPv6 Support to the pfSense module
4046
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4047
				}
4048
			}
4049
			break;
4050
	}
4051

    
4052
	interface_netgraph_needed($interface);
4053

    
4054
	if (!platform_booting()) {
4055
		link_interface_to_vips($interface, "update");
4056

    
4057
		if ($tunnelif != 'gre') {
4058
			unset($gre);
4059
			$gre = link_interface_to_gre($interface);
4060
			if (!empty($gre)) {
4061
				array_walk($gre, 'interface_gre_configure');
4062
			}
4063
		}
4064

    
4065
		if ($tunnelif != 'gif') {
4066
			unset($gif);
4067
			$gif = link_interface_to_gif ($interface);
4068
			if (!empty($gif)) {
4069
				array_walk($gif, 'interface_gif_configure');
4070
			}
4071
		}
4072

    
4073
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4074
			unset($bridgetmp);
4075
			$bridgetmp = link_interface_to_bridge($interface);
4076
			if (!empty($bridgetmp)) {
4077
				interface_bridge_add_member($bridgetmp, $realif);
4078
			}
4079
		}
4080

    
4081
		$grouptmp = link_interface_to_group($interface);
4082
		if (!empty($grouptmp)) {
4083
			array_walk($grouptmp, 'interface_group_add_member');
4084
		}
4085

    
4086
		if ($interface == "lan") {
4087
			/* make new hosts file */
4088
			system_hosts_generate();
4089
		}
4090

    
4091
		if ($reloadall == true) {
4092

    
4093
			/* reconfigure static routes (kernel may have deleted them) */
4094
			system_routing_configure($interface);
4095

    
4096
			/* reload ipsec tunnels */
4097
			send_event("service reload ipsecdns");
4098

    
4099
			if (isset($config['dnsmasq']['enable'])) {
4100
				services_dnsmasq_configure();
4101
			}
4102

    
4103
			if (isset($config['unbound']['enable'])) {
4104
				services_unbound_configure();
4105
			}
4106

    
4107
			/* update dyndns */
4108
			send_event("service reload dyndns {$interface}");
4109

    
4110
			/* reload captive portal */
4111
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4112
				require_once('captiveportal.inc');
4113
			}
4114
			captiveportal_init_rules_byinterface($interface);
4115
		}
4116
	}
4117

    
4118
	interfaces_staticarp_configure($interface);
4119
	return 0;
4120
}
4121

    
4122
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4123
	global $config, $g;
4124

    
4125
	if (!is_array($wancfg)) {
4126
		return;
4127
	}
4128

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

    
4133
	/* If the interface is not configured via another, exit */
4134
	if (empty($wancfg['track6-interface'])) {
4135
		return;
4136
	}
4137

    
4138
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4139
	$realif = get_real_interface($interface);
4140
	$linklocal = find_interface_ipv6_ll($realif, true);
4141
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4142
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
4143
	}
4144
	/* XXX: This might break for good on a carp installation using link-local as network ips */
4145
	/* XXX: Probably should remove? */
4146
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
4147

    
4148
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4149
	if (!isset($trackcfg['enable'])) {
4150
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4151
		return;
4152
	}
4153

    
4154
	switch ($trackcfg['ipaddrv6']) {
4155
		case "6to4":
4156
			if ($g['debug']) {
4157
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4158
			}
4159
			interface_track6_6to4_configure($interface, $wancfg);
4160
			break;
4161
		case "6rd":
4162
			if ($g['debug']) {
4163
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4164
			}
4165
			interface_track6_6rd_configure($interface, $wancfg);
4166
			break;
4167
		case "dhcp6":
4168
			if ($linkupevent == true) {
4169
				/*
4170
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4171
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4172
				 *
4173
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4174
				 */
4175
				$parentrealif = get_real_interface($wancfg['track6-interface']);
4176
				$pidv6 = find_dhcp6c_process($parentrealif);
4177
				if ($pidv6) {
4178
					posix_kill($pidv6, SIGHUP);
4179
				}
4180
			}
4181
			break;
4182
	}
4183

    
4184
	if ($linkupevent == false && !platform_booting()) {
4185
		if (!function_exists('services_dhcpd_configure')) {
4186
			require_once("services.inc");
4187
		}
4188

    
4189
		/* restart dns servers (defering dhcpd reload) */
4190
		if (isset($config['unbound']['enable'])) {
4191
			services_unbound_configure(false);
4192
		}
4193
		if (isset($config['dnsmasq']['enable'])) {
4194
			services_dnsmasq_configure(false);
4195
		}
4196

    
4197
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4198
		services_dhcpd_configure("inet6");
4199
	}
4200

    
4201
	return 0;
4202
}
4203

    
4204
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4205
	global $config, $g;
4206
	global $interface_ipv6_arr_cache;
4207
	global $interface_snv6_arr_cache;
4208

    
4209
	if (!is_array($lancfg)) {
4210
		return;
4211
	}
4212

    
4213
	/* If the interface is not configured via another, exit */
4214
	if (empty($lancfg['track6-interface'])) {
4215
		return;
4216
	}
4217

    
4218
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4219
	if (empty($wancfg)) {
4220
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4221
		return;
4222
	}
4223

    
4224
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4225
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4226
		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']));
4227
		return;
4228
	}
4229
	$hexwanv4 = return_hex_ipv4($ip4address);
4230

    
4231
	/* create the long prefix notation for math, save the prefix length */
4232
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4233
	$rd6prefixlen = $rd6prefix[1];
4234
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4235

    
4236
	/* binary presentation of the prefix for all 128 bits. */
4237
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4238

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

    
4244
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4245
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4246
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4247
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4248
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4249
	/* fill the rest out with zeros */
4250
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4251

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

    
4255
	$lanif = get_real_interface($interface);
4256
	$oip = find_interface_ipv6($lanif);
4257
	if (is_ipaddrv6($oip)) {
4258
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4259
	}
4260
	unset($interface_ipv6_arr_cache[$lanif]);
4261
	unset($interface_snv6_arr_cache[$lanif]);
4262
	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));
4263
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4264

    
4265
	return 0;
4266
}
4267

    
4268
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4269
	global $config, $g;
4270
	global $interface_ipv6_arr_cache;
4271
	global $interface_snv6_arr_cache;
4272

    
4273
	if (!is_array($lancfg)) {
4274
		return;
4275
	}
4276

    
4277
	/* If the interface is not configured via another, exit */
4278
	if (empty($lancfg['track6-interface'])) {
4279
		return;
4280
	}
4281

    
4282
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4283
	if (empty($wancfg)) {
4284
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4285
		return;
4286
	}
4287

    
4288
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4289
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4290
		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']));
4291
		return;
4292
	}
4293
	$hexwanv4 = return_hex_ipv4($ip4address);
4294

    
4295
	/* create the long prefix notation for math, save the prefix length */
4296
	$sixto4prefix = "2002::";
4297
	$sixto4prefixlen = 16;
4298
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4299

    
4300
	/* binary presentation of the prefix for all 128 bits. */
4301
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4302

    
4303
	/* just save the left prefix length bits */
4304
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4305
	/* add the v4 address */
4306
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4307
	/* add the custom prefix id */
4308
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4309
	/* fill the rest out with zeros */
4310
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4311

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

    
4315
	$lanif = get_real_interface($interface);
4316
	$oip = find_interface_ipv6($lanif);
4317
	if (is_ipaddrv6($oip)) {
4318
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4319
	}
4320
	unset($interface_ipv6_arr_cache[$lanif]);
4321
	unset($interface_snv6_arr_cache[$lanif]);
4322
	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));
4323
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4324

    
4325
	return 0;
4326
}
4327

    
4328
function interface_6rd_configure($interface = "wan", $wancfg) {
4329
	global $config, $g;
4330

    
4331
	/* because this is a tunnel interface we can only function
4332
	 *	with a public IPv4 address on the interface */
4333

    
4334
	if (!is_array($wancfg)) {
4335
		return;
4336
	}
4337

    
4338
	if (!is_module_loaded('if_stf.ko')) {
4339
		mwexec('/sbin/kldload if_stf.ko');
4340
	}
4341

    
4342
	$wanif = get_real_interface($interface);
4343
	$ip4address = find_interface_ip($wanif);
4344
	if (!is_ipaddrv4($ip4address)) {
4345
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4346
		return false;
4347
	}
4348
	$hexwanv4 = return_hex_ipv4($ip4address);
4349

    
4350
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4351
		$wancfg['prefix-6rd-v4plen'] = 0;
4352
	}
4353

    
4354
	/* create the long prefix notation for math, save the prefix length */
4355
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4356
	$rd6prefixlen = $rd6prefix[1];
4357
	$brgw = explode('.', $wancfg['gateway-6rd']);
4358
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4359
	$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);
4360
	if (strlen($rd6brgw) < 128) {
4361
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4362
	}
4363
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4364
	unset($brgw);
4365
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4366

    
4367
	/* binary presentation of the prefix for all 128 bits. */
4368
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4369

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

    
4377
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4378
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4379

    
4380

    
4381
	/* XXX: need to extend to support variable prefix size for v4 */
4382
	$stfiface = "{$interface}_stf";
4383
	if (does_interface_exist($stfiface)) {
4384
		pfSense_interface_destroy($stfiface);
4385
	}
4386
	$tmpstfiface = pfSense_interface_create("stf");
4387
	pfSense_interface_rename($tmpstfiface, $stfiface);
4388
	pfSense_interface_flags($stfiface, IFF_LINK2);
4389
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4390
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4391
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4392
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4393
	}
4394
	if ($g['debug']) {
4395
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4396
	}
4397

    
4398
	/* write out a default router file */
4399
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4400
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4401

    
4402
	$ip4gateway = get_interface_gateway($interface);
4403
	if (is_ipaddrv4($ip4gateway)) {
4404
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
4405
	}
4406

    
4407
	/* configure dependent interfaces */
4408
	if (!platform_booting()) {
4409
		link_interface_to_track6($interface, "update");
4410
	}
4411

    
4412
	return 0;
4413
}
4414

    
4415
function interface_6to4_configure($interface = "wan", $wancfg) {
4416
	global $config, $g;
4417

    
4418
	/* because this is a tunnel interface we can only function
4419
	 *	with a public IPv4 address on the interface */
4420

    
4421
	if (!is_array($wancfg)) {
4422
		return;
4423
	}
4424

    
4425
	$wanif = get_real_interface($interface);
4426
	$ip4address = find_interface_ip($wanif);
4427
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4428
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4429
		return false;
4430
	}
4431

    
4432
	/* create the long prefix notation for math, save the prefix length */
4433
	$stfprefixlen = 16;
4434
	$stfprefix = Net_IPv6::uncompress("2002::");
4435
	$stfarr = explode(":", $stfprefix);
4436
	$v4prefixlen = "0";
4437

    
4438
	/* we need the hex form of the interface IPv4 address */
4439
	$ip4arr = explode(".", $ip4address);
4440
	$hexwanv4 = "";
4441
	foreach ($ip4arr as $octet) {
4442
		$hexwanv4 .= sprintf("%02x", $octet);
4443
	}
4444

    
4445
	/* we need the hex form of the broker IPv4 address */
4446
	$ip4arr = explode(".", "192.88.99.1");
4447
	$hexbrv4 = "";
4448
	foreach ($ip4arr as $octet) {
4449
		$hexbrv4 .= sprintf("%02x", $octet);
4450
	}
4451

    
4452
	/* binary presentation of the prefix for all 128 bits. */
4453
	$stfprefixbin = "";
4454
	foreach ($stfarr as $element) {
4455
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4456
	}
4457
	/* just save the left prefix length bits */
4458
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4459

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

    
4464
	/* for the local subnet too. */
4465
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4466
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4467

    
4468
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4469
	$stfbrarr = array();
4470
	$stfbrbinarr = array();
4471
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4472
	foreach ($stfbrbinarr as $bin) {
4473
		$stfbrarr[] = dechex(bindec($bin));
4474
	}
4475
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4476

    
4477
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4478
	$stflanarr = array();
4479
	$stflanbinarr = array();
4480
	$stflanbinarr = str_split($stflanbin, 16);
4481
	foreach ($stflanbinarr as $bin) {
4482
		$stflanarr[] = dechex(bindec($bin));
4483
	}
4484
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4485
	$stflanarr[7] = 1;
4486
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4487

    
4488
	/* setup the stf interface */
4489
	if (!is_module_loaded("if_stf")) {
4490
		mwexec("/sbin/kldload if_stf.ko");
4491
	}
4492
	$stfiface = "{$interface}_stf";
4493
	if (does_interface_exist($stfiface)) {
4494
		pfSense_interface_destroy($stfiface);
4495
	}
4496
	$tmpstfiface = pfSense_interface_create("stf");
4497
	pfSense_interface_rename($tmpstfiface, $stfiface);
4498
	pfSense_interface_flags($stfiface, IFF_LINK2);
4499
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4500

    
4501
	if ($g['debug']) {
4502
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4503
	}
4504

    
4505
	/* write out a default router file */
4506
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4507
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4508

    
4509
	$ip4gateway = get_interface_gateway($interface);
4510
	if (is_ipaddrv4($ip4gateway)) {
4511
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
4512
	}
4513

    
4514
	if (!platform_booting()) {
4515
		link_interface_to_track6($interface, "update");
4516
	}
4517

    
4518
	return 0;
4519
}
4520

    
4521
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4522
	global $config, $g;
4523

    
4524
	if (!is_array($wancfg)) {
4525
		return;
4526
	}
4527

    
4528
	$wanif = get_real_interface($interface, "inet6");
4529
	$dhcp6cconf = "";
4530

    
4531
	if (!empty($config['system']['global-v6duid'])) {
4532
		// Write the DUID file
4533
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4534
		    log_error(gettext("Failed to write user DUID file!"));
4535
		}
4536
	}
4537

    
4538
	/* accept router advertisements for this interface                 */
4539
	/* Moved to early in the function as sometimes interface not ready */
4540
	/* RTSOLD fails as interface does not accept .....                 */
4541

    
4542
	log_error("Accept router advertisements on interface {$wanif} ");
4543
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4544

    
4545
	if ($wancfg['adv_dhcp6_config_file_override']) {
4546
		// DHCP6 Config File Override
4547
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4548
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4549
		// DHCP6 Config File Advanced
4550
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4551
	} else {
4552
		// DHCP6 Config File Basic
4553
		$dhcp6cconf .= "interface {$wanif} {\n";
4554

    
4555
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4556
		if ($wancfg['ipaddrv6'] == "slaac") {
4557
			$dhcp6cconf .= "\tinformation-only;\n";
4558
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4559
			$dhcp6cconf .= "\trequest domain-name;\n";
4560
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4561
			$dhcp6cconf .= "};\n";
4562
		} else {
4563
			$trackiflist = array();
4564
			$iflist = link_interface_to_track6($interface);
4565
			foreach ($iflist as $ifname => $ifcfg) {
4566
				if (is_numeric($ifcfg['track6-prefix-id'])) {
4567
					$trackiflist[$ifname] = $ifcfg;
4568
				}
4569
			}
4570

    
4571
			/* skip address request if this is set */
4572
			if (!isset($wancfg['dhcp6prefixonly'])) {
4573
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4574
			}
4575
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4576
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4577
			}
4578

    
4579
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4580
			$dhcp6cconf .= "\trequest domain-name;\n";
4581

    
4582
			/*
4583
			 * dhcp6c will run different scripts depending on
4584
			 * whether dhcpwithoutra is set or unset.
4585
			 */
4586
			if (isset($wancfg['dhcp6withoutra'])) {
4587
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4588
			} else {
4589
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4590
			}
4591
			$dhcp6cconf .= "};\n";
4592

    
4593
			if (!isset($wancfg['dhcp6prefixonly'])) {
4594
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4595
			}
4596

    
4597
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4598
				/* Setup the prefix delegation */
4599
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4600
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4601
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4602
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4603
				}
4604
				foreach ($trackiflist as $friendly => $ifcfg) {
4605
					if ($g['debug']) {
4606
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4607
					}
4608
					$realif = get_real_interface($friendly);
4609
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4610
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4611
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4612
					$dhcp6cconf .= "\t};\n";
4613
				}
4614
				unset($preflen, $iflist, $ifcfg, $ifname);
4615
				$dhcp6cconf .= "};\n";
4616
			}
4617
			unset($trackiflist);
4618
		}
4619
	}
4620

    
4621
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4622
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4623

    
4624
	/* wide-dhcp6c works for now. */
4625
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4626
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4627
		unset($dhcp6cconf);
4628
		return 1;
4629
	}
4630
	unset($dhcp6cconf);
4631

    
4632
	/*************** Script Debug Logging ***************************
4633
	Both dhcp6 scripts now have a logging message built in.
4634
	These logging messages ONLY appear if dhcp6c debug logging is set.
4635
	The logging messages appear in the dhcp section of the logs,
4636
	not in system.
4637

    
4638
	These scripts now also take advantage of the REASON= env vars
4639
	supplied by dhcp6c.
4640
	****************************************************************/
4641

    
4642
	/* Script create for dhcp6withoutRA mode */
4643
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4644
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4645
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4646
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4647
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4648
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4649
	// Need to pass params to  the final script
4650
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4651
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4652
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4653
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4654
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
4655
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
4656
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4657
	if ($debugOption == '-D') {
4658
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4659
	}
4660
	$dhcp6cscriptwithoutra .= ";;\n";
4661
	$dhcp6cscriptwithoutra .= "REBIND)\n";
4662
	if ($debugOption == '-D') {
4663
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4664
	}
4665
	$dhcp6cscriptwithoutra .= ";;\n";
4666
	if (isset($wancfg['dhcp6norelease'])) {
4667
		$dhcp6cscriptwithoutra .= "EXIT)\n";
4668
	} else {
4669
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
4670
	}
4671
	if ($debugOption == '-D') {
4672
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4673
	}
4674
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4675
	$dhcp6cscriptwithoutra .= ";;\n";
4676
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
4677
	if ($debugOption == '-D') {
4678
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4679
	}
4680
	$dhcp6cscriptwithoutra .= "esac\n";
4681
	if (!@file_put_contents(
4682
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4683
	    $dhcp6cscriptwithoutra)) {
4684
		printf("Error: cannot open " .
4685
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4686
		    "interface_dhcpv6_configure() for writing.\n");
4687
		unset($dhcp6cscriptwithoutra);
4688
		return 1;
4689
	}
4690

    
4691
	unset($dhcp6cscriptwithoutra);
4692
	@chmod(
4693
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4694
	    0755);
4695

    
4696
	/*
4697
	 * Dual mode wan_dhcp6c script with variations depending on node
4698
	 * dhcp6 will run the wan ipv6 configure
4699
	 */
4700
	$dhcp6cscript  = "#!/bin/sh\n";
4701
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4702
	if (!isset($wancfg['dhcp6withoutra'])) {
4703
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4704
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4705
		$dhcp6cscript .= "case \$REASON in\n";
4706
		$dhcp6cscript .= "REQUEST)\n";
4707
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4708
		if ($debugOption == '-D') {
4709
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4710
		}
4711
		$dhcp6cscript .= ";;\n";
4712
		$dhcp6cscript .= "REBIND)\n";
4713
		if ($debugOption == '-D') {
4714
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4715
		}
4716
		$dhcp6cscript .= ";;\n";
4717
		if (isset($wancfg['dhcp6norelease'])) {
4718
			$dhcp6cscript .= "EXIT)\n";
4719
		} else {
4720
			$dhcp6cscript .= "RELEASE)\n";
4721
		}
4722
		if ($debugOption == '-D') {
4723
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4724
		}
4725
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4726
		$dhcp6cscript .= ";;\n";
4727
		$dhcp6cscript .= "RENEW|INFO)\n";
4728
		if ($debugOption == '-D') {
4729
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4730
		}
4731
		$dhcp6cscript .= "esac\n";
4732
	} else {
4733
		// Need to get the parameters from the dhcp6cwithoutRA run
4734
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
4735
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
4736
		$dhcp6cscript .= "/bin/sleep 1\n";
4737
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4738
	}
4739

    
4740
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4741
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4742
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4743
		unset($dhcp6cscript);
4744
		return 1;
4745
	}
4746
	unset($dhcp6cscript);
4747
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4748

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

    
4755
	/* non ipoe Process */
4756
	if (!isset($wancfg['dhcp6withoutra'])) {
4757
		/*
4758
		 * We only want this script to run once, and if it runs twice
4759
		 * then do not launch dhcp6c again, this only happens if
4760
		 * dhcpwithoutra is not set.
4761
		 *
4762
		 * Check for a lock file, trying to prevent multiple instances
4763
		 * of dhcp6c being launched
4764
		 */
4765
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
4766
		/*
4767
		 * Create the lock file, trying to prevent multiple instances
4768
		 * of dhcp6c being launched
4769
		 */
4770
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
4771
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
4772
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4773
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4774
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
4775
		$rtsoldscript .= "\tfi\n";
4776
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
4777
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
4778
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4779
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4780
		$rtsoldscript .= "else\n";
4781
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
4782
		$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c_{$wanif}.pid\")\n";
4783
		$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
4784
		$rtsoldscript .= "fi\n";
4785
	} else {
4786
		/*
4787
		 * The script needs to run in dhcp6withoutra mode as RA may
4788
		 * not have been received, or there can be a delay with
4789
		 * certain ISPs
4790
		 */
4791
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
4792
		$rtsoldscript .= "/bin/sleep 1\n";
4793
	}
4794
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4795
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4796
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4797
		unset($rtsoldscript);
4798
		return 1;
4799
	}
4800
	unset($rtsoldscript);
4801
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4802

    
4803
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4804
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4805
		log_error("Killing running rtsold process");
4806
		sleep(2);
4807
	}
4808

    
4809
	if (isset($wancfg['dhcp6withoutra'])) {
4810
		/*
4811
		 * Start dhcp6c here if we don't want to wait for ra - calls
4812
		 * seperate function
4813
		 *
4814
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
4815
		 * will then run the configure on receipt of the RA.
4816
		 *
4817
		 * Already started. interface_dhcpv6_configure() appears to get
4818
		 * called multiple times.
4819
		 *
4820
		 * Taking the interface down or releasing will kill the client.
4821
		 */
4822
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
4823
		{
4824
			/*
4825
			 * If the interface is being brought up, wait for the
4826
			 * interface to configure accept RA before launching.
4827
			 * Otherwise it is not ready to accept and will fail.
4828
			 */
4829
			sleep(3);
4830
			run_dhcp6client_process($wanif,$interface,$wancfg);
4831
		}
4832
	} else {
4833
		/*
4834
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
4835
		 * ( it does not background, it exits! ) It will launch dhcp6c
4836
		 * if dhcpwihtoutra is not set
4837
		 */
4838
		log_error("Starting rtsold process");
4839
		sleep(2);
4840
		mwexec("/usr/sbin/rtsold -1 " .
4841
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
4842
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
4843
		    $wanif);
4844
	}
4845
	/*
4846
	 * NOTE: will be called from rtsold invoked script
4847
	 * link_interface_to_track6($interface, "update");
4848
	 */
4849

    
4850
	return 0;
4851
}
4852

    
4853
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4854
	global $g;
4855

    
4856
	$send_options = "";
4857
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4858
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4859
		foreach ($options as $option) {
4860
			$send_options .= "\tsend " . trim($option) . ";\n";
4861
		}
4862
	}
4863

    
4864
	$request_options = "";
4865
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4866
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4867
		foreach ($options as $option) {
4868
			$request_options .= "\trequest " . trim($option) . ";\n";
4869
		}
4870
	}
4871

    
4872
	$information_only = "";
4873
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4874
		$information_only = "\tinformation-only;\n";
4875
	}
4876

    
4877
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4878
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4879
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4880
	}
4881

    
4882
	$interface_statement  = "interface";
4883
	$interface_statement .= " {$wanif}";
4884
	$interface_statement .= " {\n";
4885
	$interface_statement .= "$send_options";
4886
	$interface_statement .= "$request_options";
4887
	$interface_statement .= "$information_only";
4888
	$interface_statement .= "$script";
4889
	$interface_statement .= "};\n";
4890

    
4891
	$id_assoc_statement_address = "";
4892
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4893
		$id_assoc_statement_address .= "id-assoc";
4894
		$id_assoc_statement_address .= " na";
4895
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4896
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4897
		}
4898
		$id_assoc_statement_address .= " { ";
4899

    
4900
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4901
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4902
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4903
			$id_assoc_statement_address .= "\n\taddress";
4904
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4905
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4906
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4907
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4908
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4909
			}
4910
			$id_assoc_statement_address .= ";\n";
4911
		}
4912

    
4913
		$id_assoc_statement_address .= "};\n";
4914
	}
4915

    
4916
	$id_assoc_statement_prefix = "";
4917
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4918
		$id_assoc_statement_prefix .= "id-assoc";
4919
		$id_assoc_statement_prefix .= " pd";
4920
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4921
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4922
		}
4923
		$id_assoc_statement_prefix .= " { ";
4924

    
4925
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4926
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4927
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4928
			$id_assoc_statement_prefix .= "\n\tprefix";
4929
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4930
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4931
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4932
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4933
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4934
			}
4935
			$id_assoc_statement_prefix .= ";";
4936
		}
4937

    
4938
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
4939
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4940
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4941
			$id_assoc_statement_prefix .= " {$realif}";
4942
			$id_assoc_statement_prefix .= " {\n";
4943
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4944
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4945
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4946
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4947
			}
4948
			$id_assoc_statement_prefix .= "\t};";
4949
		}
4950

    
4951
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4952
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4953
			$id_assoc_statement_prefix .= "\n";
4954
		}
4955

    
4956
		$id_assoc_statement_prefix .= "};\n";
4957
	}
4958

    
4959
	$authentication_statement = "";
4960
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4961
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4962
		$authentication_statement .= "authentication";
4963
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4964
		$authentication_statement .= " {\n";
4965
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4966
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4967
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4968
		}
4969
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4970
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4971
		}
4972
		$authentication_statement .= "};\n";
4973
	}
4974

    
4975
	$key_info_statement = "";
4976
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4977
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4978
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4979
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4980
		$key_info_statement .= "keyinfo";
4981
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4982
		$key_info_statement .= " {\n";
4983
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4984
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4985
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4986
		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'])) {
4987
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4988
		}
4989
		$key_info_statement .= "};\n";
4990
	}
4991

    
4992
	$dhcp6cconf  = $interface_statement;
4993
	$dhcp6cconf .= $id_assoc_statement_address;
4994
	$dhcp6cconf .= $id_assoc_statement_prefix;
4995
	$dhcp6cconf .= $authentication_statement;
4996
	$dhcp6cconf .= $key_info_statement;
4997

    
4998
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4999

    
5000
	return $dhcp6cconf;
5001
}
5002

    
5003

    
5004
function DHCP6_Config_File_Override($wancfg, $wanif) {
5005

    
5006
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5007

    
5008
	if ($dhcp6cconf === false) {
5009
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5010
		return '';
5011
	} else {
5012
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5013
	}
5014
}
5015

    
5016

    
5017
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5018

    
5019
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5020

    
5021
	return $dhcp6cconf;
5022
}
5023

    
5024

    
5025
function interface_dhcp_configure($interface = "wan") {
5026
	global $config, $g, $vlanprio_values;
5027

    
5028
	$ifcfg = $config['interfaces'][$interface];
5029
	if (empty($ifcfg)) {
5030
		$ifcfg = array();
5031
	}
5032

    
5033
	$dhclientconf_vlantag = "";
5034
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5035
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5036
	}
5037

    
5038
	/* generate dhclient_wan.conf */
5039
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5040
	if (!$fd) {
5041
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5042
		return 1;
5043
	}
5044

    
5045
	if ($ifcfg['dhcphostname']) {
5046
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5047
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5048
	} else {
5049
		$dhclientconf_hostname = "";
5050
	}
5051

    
5052
	$realif = get_real_interface($interface);
5053
	if (empty($realif)) {
5054
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5055
		return 0;
5056
	}
5057
	$dhclientconf = "";
5058

    
5059
	$dhclientconf .= <<<EOD
5060
interface "{$realif}" {
5061
	supersede interface-mtu 0;
5062
	timeout 60;
5063
	retry 15;
5064
	select-timeout 0;
5065
	initial-interval 1;
5066
	{$dhclientconf_vlantag}
5067
	{$dhclientconf_hostname}
5068
	script "/usr/local/sbin/pfSense-dhclient-script";
5069
EOD;
5070

    
5071
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5072
		$dhclientconf .= <<<EOD
5073

    
5074
	reject {$ifcfg['dhcprejectfrom']};
5075
EOD;
5076
	}
5077
	$dhclientconf .= <<<EOD
5078

    
5079
}
5080

    
5081
EOD;
5082

    
5083
	// DHCP Config File Advanced
5084
	if ($ifcfg['adv_dhcp_config_advanced']) {
5085
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5086
	}
5087

    
5088
	if (is_ipaddr($ifcfg['alias-address'])) {
5089
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5090
		$dhclientconf .= <<<EOD
5091
alias {
5092
	interface "{$realif}";
5093
	fixed-address {$ifcfg['alias-address']};
5094
	option subnet-mask {$subnetmask};
5095
}
5096

    
5097
EOD;
5098
	}
5099

    
5100
	// DHCP Config File Override
5101
	if ($ifcfg['adv_dhcp_config_file_override']) {
5102
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5103
	}
5104

    
5105
	fwrite($fd, $dhclientconf);
5106
	fclose($fd);
5107

    
5108
	/* bring wan interface up before starting dhclient */
5109
	if ($realif) {
5110
		interfaces_bring_up($realif);
5111
	}
5112

    
5113
	/* Make sure dhclient is not running */
5114
	kill_dhclient_process($realif);
5115

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

    
5119
	return 0;
5120
}
5121

    
5122
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5123

    
5124
	$hostname = "";
5125
	if ($ifcfg['dhcphostname'] != '') {
5126
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5127
	}
5128

    
5129
	/* DHCP Protocol Timings */
5130
	$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");
5131
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5132
		$pt_variable = "{$Protocol_Timing}";
5133
		${$pt_variable} = "";
5134
		if ($ifcfg[$Protocol_Timing] != "") {
5135
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5136
		}
5137
	}
5138

    
5139
	$send_options = "";
5140
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5141
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5142
		foreach ($options as $option) {
5143
			$send_options .= "\tsend " . trim($option) . ";\n";
5144
		}
5145
	}
5146

    
5147
	$request_options = "";
5148
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5149
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5150
	}
5151

    
5152
	$required_options = "";
5153
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5154
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5155
	}
5156

    
5157
	$option_modifiers = "";
5158
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5159
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5160
		foreach ($modifiers as $modifier) {
5161
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5162
		}
5163
	}
5164

    
5165
	$dhclientconf  = "interface \"{$realif}\" {\n";
5166
	$dhclientconf .= "\n";
5167
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5168
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5169
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5170
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5171
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5172
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5173
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5174
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5175
	$dhclientconf .= "\n";
5176
	$dhclientconf .= "# DHCP Protocol Options\n";
5177
	$dhclientconf .= "{$hostname}";
5178
	$dhclientconf .= "{$send_options}";
5179
	$dhclientconf .= "{$request_options}";
5180
	$dhclientconf .= "{$required_options}";
5181
	$dhclientconf .= "{$option_modifiers}";
5182
	$dhclientconf .= "\n";
5183
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5184
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5185
	}
5186
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5187
	$dhclientconf .= "}\n";
5188

    
5189
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5190

    
5191
	return $dhclientconf;
5192
}
5193

    
5194
function DHCP_Config_Option_Split($option_string) {
5195
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5196
	return $matches ? $matches[0] : [];
5197
}
5198

    
5199
function DHCP_Config_File_Override($ifcfg, $realif) {
5200

    
5201
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5202

    
5203
	if ($dhclientconf === false) {
5204
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5205
		return '';
5206
	} else {
5207
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5208
	}
5209
}
5210

    
5211

    
5212
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5213

    
5214
	/* Apply Interface Substitutions */
5215
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5216

    
5217
	/* Apply Hostname Substitutions */
5218
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5219

    
5220
	/* Arrays of MAC Address Types, Cases, Delimiters */
5221
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5222
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5223
	$various_mac_cases      = array("U", "L");
5224
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5225

    
5226
	/* Apply MAC Address Substitutions */
5227
	foreach ($various_mac_types as $various_mac_type) {
5228
		foreach ($various_mac_cases as $various_mac_case) {
5229
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5230

    
5231
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5232
				if ($res !== false) {
5233

    
5234
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5235
					if ("$various_mac_case" == "U") {
5236
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5237
					}
5238
					if ("$various_mac_case" == "L") {
5239
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5240
					}
5241

    
5242
					if ("$various_mac_type" == "mac_addr_hex") {
5243
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5244
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5245
						$dhcpclientconf_mac_hex = "";
5246
						$delimiter = "";
5247
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5248
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5249
							$delimiter = ":";
5250
						}
5251
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5252
					}
5253

    
5254
					/* MAC Address Delimiter Substitutions */
5255
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5256

    
5257
					/* Apply MAC Address Substitutions */
5258
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5259
				}
5260
			}
5261
		}
5262
	}
5263

    
5264
	return $dhclientconf;
5265
}
5266

    
5267
function interfaces_group_setup() {
5268
	global $config;
5269

    
5270
	if (!isset($config['ifgroups']['ifgroupentry']) || !is_array($config['ifgroups']['ifgroupentry'])) {
5271
		return;
5272
	}
5273

    
5274
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5275
		interface_group_setup($groupar);
5276
	}
5277

    
5278
	return;
5279
}
5280

    
5281
function interface_group_setup(&$groupname /* The parameter is an array */) {
5282
	global $config;
5283

    
5284
	if (!is_array($groupname)) {
5285
		return;
5286
	}
5287
	$members = explode(" ", $groupname['members']);
5288
	foreach ($members as $ifs) {
5289
		$realif = get_real_interface($ifs);
5290
		if ($realif && does_interface_exist($realif)) {
5291
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5292
		}
5293
	}
5294

    
5295
	return;
5296
}
5297

    
5298
function is_interface_group($if) {
5299
	global $config;
5300

    
5301
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5302
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5303
			if ($groupentry['ifname'] === $if) {
5304
				return true;
5305
			}
5306
		}
5307
	}
5308

    
5309
	return false;
5310
}
5311

    
5312
function interface_group_add_member($interface, $groupname) {
5313
	$interface = get_real_interface($interface);
5314
	if (does_interface_exist($interface)) {
5315
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5316
	}
5317
}
5318

    
5319
/* COMPAT Function */
5320
function convert_friendly_interface_to_real_interface_name($interface) {
5321
	return get_real_interface($interface);
5322
}
5323

    
5324
/* COMPAT Function */
5325
function get_real_wan_interface($interface = "wan") {
5326
	return get_real_interface($interface);
5327
}
5328

    
5329
/* COMPAT Function */
5330
function get_current_wan_address($interface = "wan") {
5331
	return get_interface_ip($interface);
5332
}
5333

    
5334
/*
5335
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5336
 */
5337
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5338
	global $config;
5339

    
5340
	/* XXX: For speed reasons reference directly the interface array */
5341
	init_config_arr(array('interfaces'));
5342
	$ifdescrs = &$config['interfaces'];
5343
	//$ifdescrs = get_configured_interface_list(true);
5344

    
5345
	foreach ($ifdescrs as $if => $ifname) {
5346
		if ($if == $interface || $ifname['if'] == $interface) {
5347
			return $if;
5348
		}
5349

    
5350
		if (get_real_interface($if) == $interface) {
5351
			return $if;
5352
		}
5353

    
5354
		if ($checkparent == false) {
5355
			continue;
5356
		}
5357

    
5358
		$int = get_parent_interface($if, true);
5359
		if (is_array($int)) {
5360
			foreach ($int as $iface) {
5361
				if ($iface == $interface) {
5362
					return $if;
5363
				}
5364
			}
5365
		}
5366
	}
5367

    
5368
	if ($interface == "enc0") {
5369
		return 'IPsec';
5370
	}
5371
}
5372

    
5373
/* attempt to resolve interface to friendly descr */
5374
function convert_friendly_interface_to_friendly_descr($interface) {
5375
	global $config;
5376

    
5377
	switch ($interface) {
5378
		case "l2tp":
5379
			$ifdesc = "L2TP";
5380
			break;
5381
		case "pptp":
5382
			$ifdesc = "PPTP";
5383
			break;
5384
		case "pppoe":
5385
			$ifdesc = "PPPoE";
5386
			break;
5387
		case "openvpn":
5388
			$ifdesc = "OpenVPN";
5389
			break;
5390
		case "lo0":
5391
			$ifdesc = "Loopback";
5392
			break;
5393
		case "enc0":
5394
		case "ipsec":
5395
		case "IPsec":
5396
			$ifdesc = "IPsec";
5397
			break;
5398
		default:
5399
			if (isset($config['interfaces'][$interface])) {
5400
				if (empty($config['interfaces'][$interface]['descr'])) {
5401
					$ifdesc = strtoupper($interface);
5402
				} else {
5403
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5404
				}
5405
				break;
5406
			} else if (substr($interface, 0, 4) == '_vip') {
5407
				if (is_array($config['virtualip']['vip'])) {
5408
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5409
						if ($vip['mode'] == "carp") {
5410
							if ($interface == "_vip{$vip['uniqid']}") {
5411
								$descr = $vip['subnet'];
5412
								$descr .= " (vhid {$vip['vhid']})";
5413
								if (!empty($vip['descr'])) {
5414
									$descr .= " - " .$vip['descr'];
5415
								}
5416
								return $descr;
5417
							}
5418
						}
5419
					}
5420
				}
5421
			} else if (substr($interface, 0, 5) == '_lloc') {
5422
				return get_interface_linklocal($interface);
5423
			} else {
5424
				if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5425
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5426
						if ($ifgen['ifname'] === $interface) {
5427
							return $ifgen['ifname'];
5428
						}
5429
					}
5430
				}
5431

    
5432
				/* if list */
5433
				$ifdescrs = get_configured_interface_with_descr(true);
5434
				foreach ($ifdescrs as $if => $ifname) {
5435
					if ($if == $interface || $ifname == $interface) {
5436
						return $ifname;
5437
					}
5438
				}
5439
			}
5440
			break;
5441
	}
5442

    
5443
	return $ifdesc;
5444
}
5445

    
5446
function convert_real_interface_to_friendly_descr($interface) {
5447

    
5448
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5449

    
5450
	if (!empty($ifdesc)) {
5451
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5452
	}
5453

    
5454
	return $interface;
5455
}
5456

    
5457
/*
5458
 *  get_parent_interface($interface):
5459
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5460
 *				or virtual interface (i.e. vlan)
5461
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5462
 *			-- returns $interface passed in if $interface parent is not found
5463
 *			-- returns empty array if an invalid interface is passed
5464
 *	(Only handles ppps and vlans now.)
5465
 */
5466
function get_parent_interface($interface, $avoidrecurse = false) {
5467
	global $config;
5468

    
5469
	$parents = array();
5470
	//Check that we got a valid interface passed
5471
	$realif = get_real_interface($interface);
5472
	if ($realif == NULL) {
5473
		return $parents;
5474
	}
5475

    
5476
	// If we got a real interface, find it's friendly assigned name
5477
	if ($interface == $realif && $avoidrecurse == false) {
5478
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5479
	}
5480

    
5481
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5482
		$ifcfg = $config['interfaces'][$interface];
5483
		switch ($ifcfg['ipaddr']) {
5484
			case "ppp":
5485
			case "pppoe":
5486
			case "pptp":
5487
			case "l2tp":
5488
				if (empty($parents)) {
5489
					if (is_array($config['ppps']['ppp'])) {
5490
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5491
							if ($ifcfg['if'] == $ppp['if']) {
5492
								$ports = explode(',', $ppp['ports']);
5493
								foreach ($ports as $pid => $parent_if) {
5494
									$parents[$pid] = get_real_interface($parent_if);
5495
								}
5496
								break;
5497
							}
5498
						}
5499
					}
5500
				}
5501
				break;
5502
			case "dhcp":
5503
			case "static":
5504
			default:
5505
				// Handle _vlans
5506
				$vlan = interface_is_vlan($ifcfg['if']);
5507
				if ($vlan != NULL) {
5508
					$parents[0] = $vlan['if'];
5509
				}
5510
				break;
5511
		}
5512
	}
5513

    
5514
	if (empty($parents)) {
5515
		// Handle _vlans not assigned to an interface
5516
		$vlan = interface_is_vlan($realif);
5517
		if ($vlan != NULL) {
5518
			$parents[0] = $vlan['if'];
5519
		}
5520
	}
5521

    
5522
	if (empty($parents)) {
5523
		/* Handle LAGGs. */
5524
		$lagg = interface_is_lagg($realif);
5525
		if ($lagg != NULL && isset($lagg['members'])) {
5526
			$parents = explode(",", $lagg['members']);
5527
		}
5528
	}
5529

    
5530
	if (empty($parents)) {
5531
		$parents[0] = $realif;
5532
	}
5533

    
5534
	return $parents;
5535
}
5536

    
5537
/*
5538
 *  get_parent_physical_interface($interface):
5539
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5540
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5541
 */
5542
function get_parent_physical_interface($interface) {
5543
	global $config;
5544

    
5545
	$realif = get_parent_interface($interface);
5546

    
5547
	if (substr($realif[0], 0, 4) == "lagg") {
5548
		foreach ($config['laggs']['lagg'] as $lagg) {
5549
			if ($realif[0] == $lagg['laggif']) {
5550
				return explode(",", $lagg['members']);
5551
			}
5552
		}
5553
	} else {
5554
		return $realif;
5555
	}
5556
}
5557

    
5558
function interface_is_wireless_clone($wlif) {
5559
	if (!stristr($wlif, "_wlan")) {
5560
		return false;
5561
	} else {
5562
		return true;
5563
	}
5564
}
5565

    
5566
function interface_get_wireless_base($wlif) {
5567
	if (!stristr($wlif, "_wlan")) {
5568
		return $wlif;
5569
	} else {
5570
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5571
	}
5572
}
5573

    
5574
function interface_get_wireless_clone($wlif) {
5575
	if (!stristr($wlif, "_wlan")) {
5576
		return $wlif . "_wlan0";
5577
	} else {
5578
		return $wlif;
5579
	}
5580
}
5581

    
5582
function interface_list_wireless() {
5583
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5584

    
5585
	$result = array();
5586
	foreach ($portlist as $port) {
5587
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5588
			continue;
5589
		}
5590

    
5591
		$desc = $port . " ( " . get_single_sysctl(
5592
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5593

    
5594
		$result[] = array(
5595
		    "if" => $port,
5596
		    "descr" => $desc
5597
		);
5598
	}
5599

    
5600
	return $result;
5601
}
5602

    
5603
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
5604
	global $config, $g;
5605

    
5606
	$wanif = NULL;
5607

    
5608
	switch ($interface) {
5609
		case "l2tp":
5610
			$wanif = "l2tp";
5611
			break;
5612
		case "pptp":
5613
			$wanif = "pptp";
5614
			break;
5615
		case "pppoe":
5616
			$wanif = "pppoe";
5617
			break;
5618
		case "openvpn":
5619
			$wanif = "openvpn";
5620
			break;
5621
		case "IPsec":
5622
		case "ipsec":
5623
		case "enc0":
5624
			$wanif = "enc0";
5625
			break;
5626
		case "ppp":
5627
			$wanif = "ppp";
5628
			break;
5629
		default:
5630
			if (substr($interface, 0, 4) == '_vip') {
5631
				$wanif = get_configured_vip_interface($interface);
5632
				if (!empty($wanif)) {
5633
					$wanif = get_real_interface($wanif);
5634
				}
5635
				break;
5636
			} else if (substr($interface, 0, 5) == '_lloc') {
5637
				$interface = substr($interface, 5);
5638
			} else if (interface_is_vlan($interface) != NULL ||
5639
			    does_interface_exist($interface, $flush)) {
5640
				/*
5641
				 * If a real interface was already passed simply
5642
				 * pass the real interface back.  This encourages
5643
				 * the usage of this function in more cases so that
5644
				 * we can combine logic for more flexibility.
5645
				 */
5646
				$wanif = $interface;
5647
				break;
5648
			}
5649

    
5650
			if (empty($config['interfaces'][$interface])) {
5651
				break;
5652
			}
5653

    
5654
			$cfg = &$config['interfaces'][$interface];
5655

    
5656
			if ($family == "inet6") {
5657
				switch ($cfg['ipaddrv6']) {
5658
					case "6rd":
5659
					case "6to4":
5660
						$wanif = "{$interface}_stf";
5661
						break;
5662
					case 'pppoe':
5663
					case 'ppp':
5664
					case 'l2tp':
5665
					case 'pptp':
5666
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5667
							$wanif = interface_get_wireless_clone($cfg['if']);
5668
						} else {
5669
							$wanif = $cfg['if'];
5670
						}
5671
						break;
5672
					default:
5673
						switch ($cfg['ipaddr']) {
5674
							case 'pppoe':
5675
							case 'ppp':
5676
							case 'l2tp':
5677
							case 'pptp':
5678
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
5679
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) || isset($cfg['ipv6usev4iface'])) {
5680
									$wanif = $cfg['if'];
5681
								} else {
5682
									$parents = get_parent_interface($interface);
5683
									if (!empty($parents[0])) {
5684
										$wanif = $parents[0];
5685
									} else {
5686
										$wanif = $cfg['if'];
5687
									}
5688
								}
5689
								break;
5690
							default:
5691
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5692
									$wanif = interface_get_wireless_clone($cfg['if']);
5693
								} else {
5694
									$wanif = $cfg['if'];
5695
								}
5696
								break;
5697
						}
5698
						break;
5699
				}
5700
			} else {
5701
				// Wireless cloned NIC support (FreeBSD 8+)
5702
				// interface name format: $parentnic_wlanparentnic#
5703
				// example: ath0_wlan0
5704
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5705
					$wanif = interface_get_wireless_clone($cfg['if']);
5706
				} else {
5707
					$wanif = $cfg['if'];
5708
				}
5709
			}
5710
			break;
5711
	}
5712

    
5713
	return $wanif;
5714
}
5715

    
5716
/* Guess the physical interface by providing a IP address */
5717
function guess_interface_from_ip($ipaddress) {
5718

    
5719
	$family = '';
5720
	if (is_ipaddrv4($ipaddress)) {
5721
		$family = 'inet';
5722
	}
5723
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5724
		$family = 'inet6';
5725
	}
5726

    
5727
	if (empty($family)) {
5728
		return false;
5729
	}
5730

    
5731
	/* create a route table we can search */
5732
	$output = '';
5733
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
5734
	$output[0] = trim($output[0], " \n");
5735
	if (!empty($output[0])) {
5736
		return $output[0];
5737
	}
5738

    
5739
	return false;
5740
}
5741

    
5742
/*
5743
 * find_ip_interface($ip): return the interface where an ip is defined
5744
 *   (or if $bits is specified, where an IP within the subnet is defined)
5745
 */
5746
function find_ip_interface($ip, $bits = null) {
5747
	if (!is_ipaddr($ip)) {
5748
		return false;
5749
	}
5750

    
5751
	$isv6ip = is_ipaddrv6($ip);
5752

    
5753
	/* if list */
5754
	$ifdescrs = get_configured_interface_list();
5755

    
5756
	foreach ($ifdescrs as $ifdescr => $ifname) {
5757
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
5758
		if (is_null($ifip)) {
5759
			continue;
5760
		}
5761
		if (is_null($bits)) {
5762
			if ($ip == $ifip) {
5763
				$int = get_real_interface($ifname);
5764
				return $int;
5765
			}
5766
		} else {
5767
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
5768
				$int = get_real_interface($ifname);
5769
				return $int;
5770
			}
5771
		}
5772
	}
5773

    
5774
	return false;
5775
}
5776

    
5777
/*
5778
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5779
 *   (or if $bits is specified, where an IP within the subnet is found)
5780
 */
5781
function find_virtual_ip_alias($ip, $bits = null) {
5782
	global $config;
5783

    
5784
	if (!is_array($config['virtualip']['vip'])) {
5785
		return false;
5786
	}
5787
	if (!is_ipaddr($ip)) {
5788
		return false;
5789
	}
5790

    
5791
	$isv6ip = is_ipaddrv6($ip);
5792

    
5793
	foreach ($config['virtualip']['vip'] as $vip) {
5794
		if ($vip['mode'] === "ipalias") {
5795
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
5796
				continue;
5797
			}
5798
			if (is_null($bits)) {
5799
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
5800
					return $vip;
5801
				}
5802
			} else {
5803
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5804
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5805
					return $vip;
5806
				}
5807
			}
5808
		}
5809
	}
5810
	return false;
5811
}
5812

    
5813
function link_interface_to_track6($int, $action = "") {
5814
	global $config;
5815

    
5816
	if (empty($int)) {
5817
		return;
5818
	}
5819

    
5820
	if (is_array($config['interfaces'])) {
5821
		$list = array();
5822
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5823
			if (!isset($ifcfg['enable'])) {
5824
				continue;
5825
			}
5826
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5827
				if ($action == "update") {
5828
					interface_track6_configure($ifname, $ifcfg);
5829
				} else if ($action == "") {
5830
					$list[$ifname] = $ifcfg;
5831
				}
5832
			}
5833
		}
5834
		return $list;
5835
	}
5836
}
5837

    
5838
function interface_find_child_cfgmtu($realiface) {
5839
	global $config;
5840

    
5841
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5842
	$vlans = link_interface_to_vlans($realiface);
5843
	$qinqs = link_interface_to_qinqs($realiface);
5844
	$bridge = link_interface_to_bridge($realiface);
5845
	if (!empty($interface)) {
5846
		$gifs = link_interface_to_gif($interface);
5847
		$gres = link_interface_to_gre($interface);
5848
	} else {
5849
		$gifs = array();
5850
		$gres = array();
5851
	}
5852

    
5853
	$mtu = 0;
5854
	if (is_array($vlans)) {
5855
		foreach ($vlans as $vlan) {
5856
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5857
			if (empty($ifass)) {
5858
				continue;
5859
			}
5860
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5861
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5862
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5863
				}
5864
			}
5865
		}
5866
	}
5867
	if (is_array($qinqs)) {
5868
		foreach ($qinqs as $qinq) {
5869
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5870
			if (empty($ifass)) {
5871
				continue;
5872
			}
5873
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5874
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5875
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5876
				}
5877
			}
5878
		}
5879
	}
5880
	if (is_array($gifs)) {
5881
		foreach ($gifs as $gif) {
5882
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5883
			if (empty($ifass)) {
5884
				continue;
5885
			}
5886
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5887
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5888
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5889
				}
5890
			}
5891
		}
5892
	}
5893
	if (is_array($gres)) {
5894
		foreach ($gres as $gre) {
5895
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5896
			if (empty($ifass)) {
5897
				continue;
5898
			}
5899
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5900
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5901
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5902
				}
5903
			}
5904
		}
5905
	}
5906
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5907
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5908
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5909
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5910
		}
5911
	}
5912
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5913

    
5914
	return $mtu;
5915
}
5916

    
5917
function link_interface_to_vlans($int, $action = "") {
5918
	global $config;
5919

    
5920
	if (empty($int)) {
5921
		return;
5922
	}
5923

    
5924
	if (is_array($config['vlans']['vlan'])) {
5925
		$ifaces = array();
5926
		foreach ($config['vlans']['vlan'] as $vlan) {
5927
			if ($int == $vlan['if']) {
5928
				if ($action == "update") {
5929
					interfaces_bring_up($int);
5930
				} else {
5931
					$ifaces[$vlan['tag']] = $vlan;
5932
				}
5933
			}
5934
		}
5935
		if (!empty($ifaces)) {
5936
			return $ifaces;
5937
		}
5938
	}
5939
}
5940

    
5941
function link_interface_to_qinqs($int, $action = "") {
5942
	global $config;
5943

    
5944
	if (empty($int)) {
5945
		return;
5946
	}
5947

    
5948
	if (is_array($config['qinqs']['qinqentry'])) {
5949
		$ifaces = array();
5950
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5951
			if ($int == $qinq['if']) {
5952
				if ($action == "update") {
5953
					interfaces_bring_up($int);
5954
				} else {
5955
					$ifaces[$qinq['tag']] = $qinq;
5956
				}
5957
			}
5958
		}
5959
		if (!empty($ifaces)) {
5960
			return $ifaces;
5961
		}
5962
	}
5963
}
5964

    
5965
function link_interface_to_vips($int, $action = "", $vhid = '') {
5966
	global $config;
5967

    
5968
	$updatevips = false;
5969
	if (is_array($config['virtualip']['vip'])) {
5970
		$result = array();
5971
		foreach ($config['virtualip']['vip'] as $vip) {
5972
			if (substr($vip['interface'], 0, 4) == "_vip") {
5973
				$iface = get_configured_vip_interface($vip['interface']);
5974
			} else {
5975
				$iface = $vip['interface'];
5976
			}
5977
			if ($int != $iface) {
5978
				continue;
5979
			}
5980
			if ($action == "update") {
5981
				$updatevips = true;
5982
			} else {
5983
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5984
				    substr($vip['interface'], 0, 4) == "_vip") {
5985
					$result[] = $vip;
5986
				}
5987
			}
5988
		}
5989
		if ($updatevips === true) {
5990
			interfaces_vips_configure($int);
5991
		}
5992
		return $result;
5993
	}
5994

    
5995
	return NULL;
5996
}
5997

    
5998
/****f* interfaces/link_interface_to_bridge
5999
 * NAME
6000
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6001
 * INPUTS
6002
 *   $ip
6003
 * RESULT
6004
 *   bridge[0-99]
6005
 ******/
6006
function link_interface_to_bridge($int) {
6007
	global $config;
6008

    
6009
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6010
		foreach ($config['bridges']['bridged'] as $bridge) {
6011
			if (in_array($int, explode(',', $bridge['members']))) {
6012
				return "{$bridge['bridgeif']}";
6013
			}
6014
		}
6015
	}
6016
}
6017

    
6018
function link_interface_to_group($int) {
6019
	global $config;
6020

    
6021
	$result = array();
6022

    
6023
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6024
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6025
			if (in_array($int, explode(" ", $group['members']))) {
6026
				$result[$group['ifname']] = $int;
6027
			}
6028
		}
6029
	}
6030

    
6031
	return $result;
6032
}
6033

    
6034
function link_interface_to_gre($interface) {
6035
	global $config;
6036

    
6037
	$result = array();
6038

    
6039
	if (is_array($config['gres']['gre'])) {
6040
		foreach ($config['gres']['gre'] as $gre) {
6041
			if ($gre['if'] == $interface) {
6042
				$result[] = $gre;
6043
			}
6044
		}
6045
	}
6046

    
6047
	return $result;
6048
}
6049

    
6050
function link_interface_to_gif($interface) {
6051
	global $config;
6052

    
6053
	$result = array();
6054

    
6055
	if (is_array($config['gifs']['gif'])) {
6056
		foreach ($config['gifs']['gif'] as $gif) {
6057
			if ($gif['if'] == $interface) {
6058
				$result[] = $gif;
6059
			}
6060
		}
6061
	}
6062

    
6063
	return $result;
6064
}
6065

    
6066
/*
6067
 * find_interface_ip($interface): return the interface ip (first found)
6068
 */
6069
function find_interface_ip($interface, $flush = false) {
6070
	global $interface_ip_arr_cache;
6071
	global $interface_sn_arr_cache;
6072

    
6073
	$interface = str_replace("\n", "", $interface);
6074

    
6075
	if (!does_interface_exist($interface)) {
6076
		return;
6077
	}
6078

    
6079
	/* Setup IP cache */
6080
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6081
		if (file_exists("/var/db/${interface}_ip")) {
6082
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6083
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6084
			foreach ($ifaddrs as $ifaddr) {
6085
				list($ip, $mask) = explode("/", $ifaddr);
6086
				if ($ip == $ifip) {
6087
					$interface_ip_arr_cache[$interface] = $ip;
6088
					$interface_sn_arr_cache[$interface] = $mask;
6089
					break;
6090
				}
6091
			}
6092
		}
6093
		if (!isset($interface_ip_arr_cache[$interface])) {
6094
			$ifinfo = pfSense_get_interface_addresses($interface);
6095
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6096
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6097
		}
6098
	}
6099

    
6100
	return $interface_ip_arr_cache[$interface];
6101
}
6102

    
6103
/*
6104
 * find_interface_ipv6($interface): return the interface ip (first found)
6105
 */
6106
function find_interface_ipv6($interface, $flush = false) {
6107
	global $interface_ipv6_arr_cache;
6108
	global $interface_snv6_arr_cache;
6109
	global $config;
6110

    
6111
	$interface = trim($interface);
6112
	$interface = get_real_interface($interface);
6113

    
6114
	if (!does_interface_exist($interface)) {
6115
		return;
6116
	}
6117

    
6118
	/* Setup IP cache */
6119
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6120
		$ifinfo = pfSense_get_interface_addresses($interface);
6121
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6122
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6123
	}
6124

    
6125
	return $interface_ipv6_arr_cache[$interface];
6126
}
6127

    
6128
/*
6129
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6130
 */
6131
function find_interface_ipv6_ll($interface, $flush = false) {
6132
	global $interface_llv6_arr_cache;
6133
	global $config;
6134

    
6135
	$interface = str_replace("\n", "", $interface);
6136

    
6137
	if (!does_interface_exist($interface)) {
6138
		return;
6139
	}
6140

    
6141
	/* Setup IP cache */
6142
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6143
		$ifinfo = pfSense_getall_interface_addresses($interface);
6144
		foreach ($ifinfo as $line) {
6145
			if (strstr($line, ":")) {
6146
				$parts = explode("/", $line);
6147
				if (is_linklocal($parts[0])) {
6148
					$ifinfo['linklocal'] = $parts[0];
6149
				}
6150
			}
6151
		}
6152
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6153
	}
6154
	return $interface_llv6_arr_cache[$interface];
6155
}
6156

    
6157
function find_interface_subnet($interface, $flush = false) {
6158
	global $interface_sn_arr_cache;
6159
	global $interface_ip_arr_cache;
6160

    
6161
	$interface = str_replace("\n", "", $interface);
6162
	if (does_interface_exist($interface) == false) {
6163
		return;
6164
	}
6165

    
6166
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6167
		$ifinfo = pfSense_get_interface_addresses($interface);
6168
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6169
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6170
	}
6171

    
6172
	return $interface_sn_arr_cache[$interface];
6173
}
6174

    
6175
function find_interface_subnetv6($interface, $flush = false) {
6176
	global $interface_snv6_arr_cache;
6177
	global $interface_ipv6_arr_cache;
6178

    
6179
	$interface = str_replace("\n", "", $interface);
6180
	if (does_interface_exist($interface) == false) {
6181
		return;
6182
	}
6183

    
6184
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6185
		$ifinfo = pfSense_get_interface_addresses($interface);
6186
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6187
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6188
	}
6189

    
6190
	return $interface_snv6_arr_cache[$interface];
6191
}
6192

    
6193
function ip_in_interface_alias_subnet($interface, $ipalias) {
6194
	global $config;
6195

    
6196
	if (empty($interface) || !is_ipaddr($ipalias)) {
6197
		return false;
6198
	}
6199
	if (is_array($config['virtualip']['vip'])) {
6200
		foreach ($config['virtualip']['vip'] as $vip) {
6201
			switch ($vip['mode']) {
6202
				case "ipalias":
6203
					if ($vip['interface'] <> $interface) {
6204
						break;
6205
					}
6206
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6207
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6208
						return true;
6209
					}
6210
					break;
6211
			}
6212
		}
6213
	}
6214

    
6215
	return false;
6216
}
6217

    
6218
function get_possible_listen_ips($include_ipv6_link_local=false) {
6219

    
6220
	$interfaces = get_configured_interface_with_descr();
6221
	foreach ($interfaces as $iface => $ifacename) {
6222
		if ($include_ipv6_link_local) {
6223
			/* This is to avoid going though added ll below */
6224
			if (substr($iface, 0, 5) == '_lloc') {
6225
				continue;
6226
			}
6227
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6228
			if (!empty($llip)) {
6229
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6230
			}
6231
		}
6232
	}
6233
	$viplist = get_configured_vip_list();
6234
	foreach ($viplist as $vip => $address) {
6235
		$interfaces[$vip] = $address;
6236
		if (get_vip_descr($address)) {
6237
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6238
		}
6239
	}
6240

    
6241
	$interfaces['lo0'] = 'Localhost';
6242

    
6243
	return $interfaces;
6244
}
6245

    
6246
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6247
	global $config;
6248

    
6249
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6250
	foreach (array('server', 'client') as $mode) {
6251
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6252
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6253
				if (!isset($setting['disable'])) {
6254
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6255
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6256
				}
6257
			}
6258
		}
6259
	}
6260
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
6261
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
6262
			if ($ph1ent['disabled']) {
6263
				continue;
6264
			}
6265
			if (ipsec_vti($ph1ent)) {
6266
				$sourceips_key = "ipsec{$ph1ent['ikeid']}";
6267
				$sourceips[$sourceips_key] = gettext("IPsec VTI") . ": " . htmlspecialchars($ph1ent['descr']);
6268
			}
6269
		}
6270
	}
6271
	return $sourceips;
6272
}
6273

    
6274
function get_interface_ip($interface = "wan") {
6275
	global $config;
6276

    
6277
	if (substr($interface, 0, 4) == '_vip') {
6278
		return get_configured_vip_ipv4($interface);
6279
	} else if (substr($interface, 0, 5) == '_lloc') {
6280
		/* No link-local address for v4. */
6281
		return null;
6282
	}
6283

    
6284
	$realif = get_failover_interface($interface, 'inet');
6285
	if (!$realif) {
6286
		return null;
6287
	}
6288

    
6289
	if (substr($realif, 0, 4) == '_vip') {
6290
		return get_configured_vip_ipv4($realif);
6291
	} else if (substr($realif, 0, 5) == '_lloc') {
6292
		/* No link-local address for v4. */
6293
		return null;
6294
	}
6295

    
6296
	if (is_array($config['interfaces'][$interface]) &&
6297
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6298
		return ($config['interfaces'][$interface]['ipaddr']);
6299
	}
6300

    
6301
	/*
6302
	 * Beaware that find_interface_ip() is our last option, it will
6303
	 * return the first IP it find on interface, not necessarily the
6304
	 * main IP address.
6305
	 */
6306
	$curip = find_interface_ip($realif);
6307
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6308
		return $curip;
6309
	} else {
6310
		return null;
6311
	}
6312
}
6313

    
6314
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6315
	global $config;
6316

    
6317
	if (substr($interface, 0, 4) == '_vip') {
6318
		return get_configured_vip_ipv6($interface);
6319
	} else if (substr($interface, 0, 5) == '_lloc') {
6320
		return get_interface_linklocal($interface);
6321
	}
6322

    
6323
	$realif = get_failover_interface($interface, 'inet6');
6324
	if (!$realif) {
6325
		return null;
6326
	}
6327

    
6328
	if (substr($realif, 0, 4) == '_vip') {
6329
		return get_configured_vip_ipv6($realif);
6330
	} else if (substr($realif, 0, 5) == '_lloc') {
6331
		return get_interface_linklocal($realif);
6332
	}
6333

    
6334
	if (is_array($config['interfaces'][$interface])) {
6335
		switch ($config['interfaces'][$interface]['ipaddr']) {
6336
			case 'pppoe':
6337
			case 'l2tp':
6338
			case 'pptp':
6339
			case 'ppp':
6340
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
6341
					$realif = get_real_interface($interface, 'inet6', false);
6342
				}
6343
				break;
6344
		}
6345
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6346
			return ($config['interfaces'][$interface]['ipaddrv6']);
6347
		}
6348
	}
6349

    
6350
	/*
6351
	 * Beaware that find_interface_ip() is our last option, it will
6352
	 * return the first IP it find on interface, not necessarily the
6353
	 * main IP address.
6354
	 */
6355
	$curip = find_interface_ipv6($realif, $flush);
6356
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6357
		return $curip;
6358
	} else {
6359
		/*
6360
		 * NOTE: On the case when only the prefix is requested,
6361
		 * the communication on WAN will be done over link-local.
6362
		 */
6363
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6364
			$curip = find_interface_ipv6_ll($realif, $flush);
6365
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6366
				return $curip;
6367
			}
6368
		}
6369
	}
6370
	return null;
6371
}
6372

    
6373
function get_interface_linklocal($interface = "wan") {
6374

    
6375
	$realif = get_failover_interface($interface, 'inet6');
6376
	if (!$realif) {
6377
		return null;
6378
	}
6379

    
6380
	if (substr($interface, 0, 4) == '_vip') {
6381
		$realif = get_real_interface($interface);
6382
	} else if (substr($interface, 0, 5) == '_lloc') {
6383
		$realif = get_real_interface(substr($interface, 5));
6384
	}
6385

    
6386
	$curip = find_interface_ipv6_ll($realif);
6387
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6388
		return $curip;
6389
	} else {
6390
		return null;
6391
	}
6392
}
6393

    
6394
function get_interface_subnet($interface = "wan") {
6395
	global $config;
6396

    
6397
	if (substr($interface, 0, 4) == '_vip') {
6398
		return (get_configured_vip_subnetv4($interface));
6399
	}
6400

    
6401
	if (is_array($config['interfaces'][$interface]) &&
6402
		!empty($config['interfaces'][$interface]['subnet'])) {
6403
		return ($config['interfaces'][$interface]['subnet']);
6404
	}
6405

    
6406
	$realif = get_real_interface($interface);
6407
	if (!$realif) {
6408
		return (NULL);
6409
	}
6410

    
6411
	$cursn = find_interface_subnet($realif);
6412
	if (!empty($cursn)) {
6413
		return ($cursn);
6414
	}
6415

    
6416
	return (NULL);
6417
}
6418

    
6419
function get_interface_subnetv6($interface = "wan") {
6420
	global $config;
6421

    
6422
	if (substr($interface, 0, 4) == '_vip') {
6423
		return (get_configured_vip_subnetv6($interface));
6424
	} else if (substr($interface, 0, 5) == '_lloc') {
6425
		$interface = substr($interface, 5);
6426
	}
6427

    
6428
	if (is_array($config['interfaces'][$interface]) &&
6429
		!empty($config['interfaces'][$interface]['subnetv6'])) {
6430
		return ($config['interfaces'][$interface]['subnetv6']);
6431
	}
6432

    
6433
	$realif = get_real_interface($interface, 'inet6');
6434
	if (!$realif) {
6435
		return (NULL);
6436
	}
6437

    
6438
	$cursn = find_interface_subnetv6($realif);
6439
	if (!empty($cursn)) {
6440
		return ($cursn);
6441
	}
6442

    
6443
	return (NULL);
6444
}
6445

    
6446
/* return outside interfaces with a gateway */
6447
function get_interfaces_with_gateway() {
6448
	global $config;
6449

    
6450
	$ints = array();
6451

    
6452
	/* loop interfaces, check config for outbound */
6453
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6454
		switch ($ifname['ipaddr']) {
6455
			case "dhcp":
6456
			case "pppoe":
6457
			case "pptp":
6458
			case "l2tp":
6459
			case "ppp":
6460
				$ints[$ifdescr] = $ifdescr;
6461
				break;
6462
			default:
6463
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6464
				    !empty($ifname['gateway'])) {
6465
					$ints[$ifdescr] = $ifdescr;
6466
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6467
				    !empty($ifname['gateway'])) {
6468
					$ints[$ifdescr] = $ifdescr;
6469
				}
6470

    
6471
				break;
6472
		}
6473
	}
6474
	return $ints;
6475
}
6476

    
6477
/* return true if interface has a gateway */
6478
function interface_has_gateway($friendly) {
6479
	global $config;
6480

    
6481
	if (!empty($config['interfaces'][$friendly])) {
6482
		$ifname = &$config['interfaces'][$friendly];
6483
		switch ($ifname['ipaddr']) {
6484
			case "dhcp":
6485
			case "pppoe":
6486
			case "pptp":
6487
			case "l2tp":
6488
			case "ppp":
6489
				return true;
6490
			break;
6491
			default:
6492
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6493
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6494
					return true;
6495
				}
6496
				$tunnelif = substr($ifname['if'], 0, 3);
6497
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6498
					if (find_interface_ip($ifname['if'])) {
6499
						return true;
6500
					}
6501
				}
6502
				if (!empty($ifname['gateway'])) {
6503
					return true;
6504
				}
6505
			break;
6506
		}
6507
	}
6508

    
6509
	return false;
6510
}
6511

    
6512
/* return true if interface has a gateway */
6513
function interface_has_gatewayv6($friendly) {
6514
	global $config;
6515

    
6516
	if (!empty($config['interfaces'][$friendly])) {
6517
		$ifname = &$config['interfaces'][$friendly];
6518
		switch ($ifname['ipaddrv6']) {
6519
			case "slaac":
6520
			case "dhcp6":
6521
			case "6to4":
6522
			case "6rd":
6523
				return true;
6524
				break;
6525
			default:
6526
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6527
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6528
					return true;
6529
				}
6530
				$tunnelif = substr($ifname['if'], 0, 3);
6531
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6532
					if (find_interface_ipv6($ifname['if'])) {
6533
						return true;
6534
					}
6535
				}
6536
				if (!empty($ifname['gatewayv6'])) {
6537
					return true;
6538
				}
6539
				break;
6540
		}
6541
	}
6542

    
6543
	return false;
6544
}
6545

    
6546
/****f* interfaces/is_altq_capable
6547
 * NAME
6548
 *   is_altq_capable - Test if interface is capable of using ALTQ
6549
 * INPUTS
6550
 *   $int            - string containing interface name
6551
 * RESULT
6552
 *   boolean         - true or false
6553
 ******/
6554

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

    
6570
	$int_family = remove_ifindex($int);
6571

    
6572
	if (in_array($int_family, $capable)) {
6573
		return true;
6574
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6575
		return true;
6576
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6577
		return true;
6578
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6579
		return true;
6580
	} else {
6581
		return false;
6582
	}
6583
}
6584

    
6585
/****f* interfaces/is_interface_wireless
6586
 * NAME
6587
 *   is_interface_wireless - Returns if an interface is wireless
6588
 * RESULT
6589
 *   $tmp       - Returns if an interface is wireless
6590
 ******/
6591
function is_interface_wireless($interface) {
6592
	global $config, $g;
6593

    
6594
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6595
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6596
		if (preg_match($g['wireless_regex'], $interface)) {
6597
			if (isset($config['interfaces'][$friendly])) {
6598
				$config['interfaces'][$friendly]['wireless'] = array();
6599
			}
6600
			return true;
6601
		}
6602
		return false;
6603
	} else {
6604
		return true;
6605
	}
6606
}
6607

    
6608
function get_wireless_modes($interface) {
6609
	/* return wireless modes and channels */
6610
	$wireless_modes = array();
6611

    
6612
	$cloned_interface = get_real_interface($interface);
6613

    
6614
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6615
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6616
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6617
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6618

    
6619
		$interface_channels = "";
6620
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6621
		$interface_channel_count = count($interface_channels);
6622

    
6623
		$c = 0;
6624
		while ($c < $interface_channel_count) {
6625
			$channel_line = explode(",", $interface_channels["$c"]);
6626
			$wireless_mode = trim($channel_line[0]);
6627
			$wireless_channel = trim($channel_line[1]);
6628
			if (trim($wireless_mode) != "") {
6629
				/* if we only have 11g also set 11b channels */
6630
				if ($wireless_mode == "11g") {
6631
					if (!isset($wireless_modes["11b"])) {
6632
						$wireless_modes["11b"] = array();
6633
					}
6634
				} else if ($wireless_mode == "11g ht") {
6635
					if (!isset($wireless_modes["11b"])) {
6636
						$wireless_modes["11b"] = array();
6637
					}
6638
					if (!isset($wireless_modes["11g"])) {
6639
						$wireless_modes["11g"] = array();
6640
					}
6641
					$wireless_mode = "11ng";
6642
				} else if ($wireless_mode == "11a ht") {
6643
					if (!isset($wireless_modes["11a"])) {
6644
						$wireless_modes["11a"] = array();
6645
					}
6646
					$wireless_mode = "11na";
6647
				}
6648
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6649
			}
6650
			$c++;
6651
		}
6652
	}
6653
	return($wireless_modes);
6654
}
6655

    
6656
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6657
function get_wireless_channel_info($interface) {
6658
	$wireless_channels = array();
6659

    
6660
	$cloned_interface = get_real_interface($interface);
6661

    
6662
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6663
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
6664
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6665
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
6666

    
6667
		$interface_channels = "";
6668
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6669

    
6670
		foreach ($interface_channels as $channel_line) {
6671
			$channel_line = explode(",", $channel_line);
6672
			if (!isset($wireless_channels[$channel_line[0]])) {
6673
				$wireless_channels[$channel_line[0]] = $channel_line;
6674
			}
6675
		}
6676
	}
6677
	return($wireless_channels);
6678
}
6679

    
6680
function set_interface_mtu($interface, $mtu) {
6681

    
6682
	/* LAGG interface must be destroyed and re-created to change MTU */
6683
	if (substr($interface, 0, 4) == 'lagg') {
6684
		if (isset($config['laggs']['lagg']) &&
6685
		    is_array($config['laggs']['lagg'])) {
6686
			foreach ($config['laggs']['lagg'] as $lagg) {
6687
				if ($lagg['laggif'] == $interface) {
6688
					interface_lagg_configure($lagg);
6689
					break;
6690
				}
6691
			}
6692
		}
6693
	} else {
6694
		pfSense_interface_mtu($interface, $mtu);
6695
	}
6696
}
6697

    
6698
/****f* interfaces/get_interface_mtu
6699
 * NAME
6700
 *   get_interface_mtu - Return the mtu of an interface
6701
 * RESULT
6702
 *   $tmp       - Returns the mtu of an interface
6703
 ******/
6704
function get_interface_mtu($interface) {
6705
	$mtu = pfSense_interface_getmtu($interface);
6706
	return $mtu['mtu'];
6707
}
6708

    
6709
function get_interface_mac($interface) {
6710
	$macinfo = pfSense_get_interface_addresses($interface);
6711
	return $macinfo["macaddr"];
6712
}
6713

    
6714
function get_interface_vendor_mac($interface) {
6715
	global $config, $g;
6716

    
6717
	$macinfo = pfSense_get_interface_addresses($interface);
6718
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
6719
	    "00:00:00:00:00:00") {
6720
		return ($macinfo["hwaddr"]);
6721
	}
6722

    
6723
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
6724
	if (file_exists($hwaddr_file)) {
6725
		$macaddr = trim(file_get_contents($hwaddr_file));
6726
		if (is_macaddr($macaddr)) {
6727
			return ($macaddr);
6728
		}
6729
	} elseif (is_macaddr($macinfo['macaddr'])) {
6730
		/* Save original macaddress to be restored when necessary */
6731
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
6732
	}
6733

    
6734
	return (NULL);
6735
}
6736

    
6737
/****f* pfsense-utils/generate_random_mac_address
6738
 * NAME
6739
 *   generate_random_mac - generates a random mac address
6740
 * INPUTS
6741
 *   none
6742
 * RESULT
6743
 *   $mac - a random mac address
6744
 ******/
6745
function generate_random_mac_address() {
6746
	$mac = "02";
6747
	for ($x = 0; $x < 5; $x++) {
6748
		$mac .= ":" . dechex(rand(16, 255));
6749
	}
6750
	return $mac;
6751
}
6752

    
6753
/****f* interfaces/is_jumbo_capable
6754
 * NAME
6755
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
6756
 * INPUTS
6757
 *   $int             - string containing interface name
6758
 * RESULT
6759
 *   boolean          - true or false
6760
 ******/
6761
function is_jumbo_capable($iface) {
6762
	$iface = trim($iface);
6763
	$capable = pfSense_get_interface_addresses($iface);
6764

    
6765
	if (isset($capable['caps']['vlanmtu'])) {
6766
		return true;
6767
	}
6768

    
6769
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
6770
	if (substr($iface, 0, 4) == "lagg") {
6771
		return true;
6772
	}
6773

    
6774
	return false;
6775
}
6776

    
6777
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6778
	global $g;
6779

    
6780
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6781

    
6782
	if (!empty($iface) && !empty($pppif)) {
6783
		$cron_cmd = <<<EOD
6784
#!/bin/sh
6785
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
6786
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
6787

    
6788
EOD;
6789

    
6790
		@file_put_contents($cron_file, $cron_cmd);
6791
		chmod($cron_file, 0755);
6792
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
6793
	} else {
6794
		unlink_if_exists($cron_file);
6795
	}
6796
}
6797

    
6798
function get_interface_default_mtu($type = "ethernet") {
6799
	switch ($type) {
6800
		case "gre":
6801
			return 1476;
6802
			break;
6803
		case "gif":
6804
			return 1280;
6805
			break;
6806
		case "tun":
6807
		case "vlan":
6808
		case "tap":
6809
		case "ethernet":
6810
		default:
6811
			return 1500;
6812
			break;
6813
	}
6814

    
6815
	/* Never reached */
6816
	return 1500;
6817
}
6818

    
6819
function get_vip_descr($ipaddress) {
6820
	global $config;
6821

    
6822
	foreach ($config['virtualip']['vip'] as $vip) {
6823
		if ($vip['subnet'] == $ipaddress) {
6824
			return ($vip['descr']);
6825
		}
6826
	}
6827
	return "";
6828
}
6829

    
6830
function interfaces_staticarp_configure($if) {
6831
	global $config, $g;
6832
	if (isset($config['system']['developerspew'])) {
6833
		$mt = microtime();
6834
		echo "interfaces_staticarp_configure($if) being called $mt\n";
6835
	}
6836

    
6837
	$ifcfg = $config['interfaces'][$if];
6838

    
6839
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
6840
		return 0;
6841
	}
6842

    
6843
	/* Enable staticarp, if enabled */
6844
	if (isset($config['dhcpd'][$if]['staticarp'])) {
6845
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
6846
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6847
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
6848
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6849
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6850
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6851
				}
6852
			}
6853
		}
6854
	} else {
6855
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
6856
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6857
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
6858
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6859
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6860
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6861
				}
6862
			}
6863
		}
6864
	}
6865

    
6866
	return 0;
6867
}
6868

    
6869
function get_failover_interface($interface, $family = "all") {
6870
	global $config;
6871

    
6872
	/* shortcut to get_real_interface if we find it in the config */
6873
	if (is_array($config['interfaces'][$interface])) {
6874
		return get_real_interface($interface, $family);
6875
	}
6876

    
6877
	/* compare against gateway groups */
6878
	$a_groups = return_gateway_groups_array(true);
6879
	if (is_array($a_groups[$interface])) {
6880
		/* we found a gateway group, fetch the interface or vip */
6881
		if (!empty($a_groups[$interface][0]['vip'])) {
6882
			return $a_groups[$interface][0]['vip'];
6883
		} else {
6884
			return $a_groups[$interface][0]['int'];
6885
		}
6886
	}
6887
	/* fall through to get_real_interface */
6888
	/* XXX: Really needed? */
6889
	return get_real_interface($interface, $family);
6890
}
6891

    
6892
/****f* interfaces/interface_has_dhcp
6893
 * NAME
6894
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6895
 * INPUTS
6896
 *   interface or gateway group name
6897
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6898
 * RESULT
6899
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6900
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6901
 ******/
6902
function interface_has_dhcp($interface, $family = 4) {
6903
	global $config;
6904

    
6905
	if ($config['interfaces'][$interface]) {
6906
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6907
			return true;
6908
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6909
			return true;
6910
		} else {
6911
			return false;
6912
		}
6913
	}
6914

    
6915
	if (!is_array($config['gateways']['gateway_group'])) {
6916
		return false;
6917
	}
6918

    
6919
	if ($family == 6) {
6920
		$dhcp_string = "_DHCP6";
6921
	} else {
6922
		$dhcp_string = "_DHCP";
6923
	}
6924

    
6925
	foreach ($config['gateways']['gateway_group'] as $group) {
6926
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6927
			continue;
6928
		}
6929
		foreach ($group['item'] as $item) {
6930
			$item_data = explode("|", $item);
6931
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6932
				return true;
6933
			}
6934
		}
6935
	}
6936

    
6937
	return false;
6938
}
6939

    
6940
function remove_ifindex($ifname) {
6941
	return preg_replace("/[0-9]+$/", "", $ifname);
6942
}
6943

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

    
6947
	$viplist = get_configured_vip_list($family, $type);
6948
	foreach ($viplist as $vip => $address) {
6949
		$interfaces[$vip] = $address;
6950
		if ($type = VIP_CARP) {
6951
			$vip = get_configured_vip($vipid);
6952
			if (isset($vip) && is_array($vip) ) {
6953
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
6954
			}
6955
		}
6956
		if (get_vip_descr($address)) {
6957
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
6958
		}
6959
	}
6960
	return $interfaces;
6961
}
6962

    
6963
function return_gateway_groups_array_with_descr() {
6964
	$interfaces = array();
6965
	$grouplist = return_gateway_groups_array();
6966
	foreach ($grouplist as $name => $group) {
6967
		if ($group[0]['vip'] != "") {
6968
			$vipif = $group[0]['vip'];
6969
		} else {
6970
			$vipif = $group[0]['int'];
6971
		}
6972

    
6973
		$interfaces[$name] = "GW Group {$name}";
6974
	}
6975
	return $interfaces;
6976
}
6977

    
6978
function get_serial_ports() {
6979
	$linklist = array();
6980
	if (!is_dir("/var/spool/lock")) {
6981
		mwexec("/bin/mkdir -p /var/spool/lock");
6982
	}
6983
	$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);
6984
	foreach ($serialports as $port) {
6985
		$linklist[$port] = trim($port);
6986
	}
6987
	return $linklist;
6988
}
6989

    
6990
function get_interface_ports() {
6991
	global $config;
6992
	$linklist = array();
6993
	$portlist = get_interface_list();
6994
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
6995
		foreach ($config['vlans']['vlan'] as $vlan) {
6996
			$portlist[$vlan['vlanif']] = $vlan;
6997
		}
6998
	}
6999

    
7000
	foreach ($portlist as $ifn => $ifinfo) {
7001
		$string = "";
7002
		if (is_array($ifinfo)) {
7003
			$string .= $ifn;
7004
			if ($ifinfo['mac']) {
7005
				$string .= " ({$ifinfo['mac']})";
7006
			}
7007
			if ($ifinfo['friendly']) {
7008
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7009
			} elseif ($ifinfo['descr']) {
7010
				$string .= " - {$ifinfo['descr']}";
7011
			}
7012
		} else {
7013
			$string .= $ifinfo;
7014
		}
7015

    
7016
		$linklist[$ifn] = $string;
7017
	}
7018
	return $linklist;
7019
}
7020

    
7021
function build_ppps_link_list() {
7022
	global $pconfig;
7023

    
7024
	$linklist = array('list' => array(), 'selected' => array());
7025

    
7026
	if ($pconfig['type'] == 'ppp') {
7027
		$linklist['list'] = get_serial_ports();
7028
	} else {
7029
		$iflist = get_interface_ports();
7030

    
7031
		$viplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7032

    
7033
		$linklist['list'] = array_merge($iflist, $viplist);
7034

    
7035
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7036
		$lagglist = get_lagg_interface_list();
7037
		foreach ($lagglist as $laggif => $lagg) {
7038
			/* LAGG members cannot be assigned */
7039
			$laggmembers = explode(',', $lagg['members']);
7040
			foreach ($laggmembers as $lagm) {
7041
				if (isset($linklist['list'][$lagm])) {
7042
					unset($linklist['list'][$lagm]);
7043
				}
7044
			}
7045
		}
7046
	}
7047

    
7048
	$selected_ports = array();
7049
	if (is_array($pconfig['interfaces'])) {
7050
		$selected_ports = $pconfig['interfaces'];
7051
	} elseif (!empty($pconfig['interfaces'])) {
7052
		$selected_ports = explode(',', $pconfig['interfaces']);
7053
	}
7054
	foreach ($selected_ports as $port) {
7055
		if (isset($linklist['list'][$port])) {
7056
			array_push($linklist['selected'], $port);
7057
		}
7058
	}
7059
	return($linklist);
7060
}
7061

    
7062
function create_interface_list() {
7063
	global $config;
7064

    
7065
	$iflist = array();
7066

    
7067
	// add group interfaces
7068
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7069
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7070
			if (have_ruleint_access($ifgen['ifname'])) {
7071
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7072
			}
7073
		}
7074
	}
7075

    
7076
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7077
		if (have_ruleint_access($ifent)) {
7078
			$iflist[$ifent] = $ifdesc;
7079
		}
7080
	}
7081

    
7082
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
7083
		$iflist['l2tp'] = gettext('L2TP VPN');
7084
	}
7085

    
7086
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
7087
		$iflist['pppoe'] = gettext("PPPoE Server");
7088
	}
7089

    
7090
	// add ipsec interfaces
7091
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
7092
		$iflist["enc0"] = gettext("IPsec");
7093
	}
7094

    
7095
	// add openvpn/tun interfaces
7096
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7097
		$iflist["openvpn"] = gettext("OpenVPN");
7098
	}
7099

    
7100
	return($iflist);
7101
}
7102

    
7103
?>
(23-23/59)