Project

General

Profile

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

    
28
/* include all configuration functions */
29
require_once("globals.inc");
30
require_once("util.inc");
31
require_once("gwlb.inc");
32
require_once("ipsec.inc");
33

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

    
43
/*
44
 * Validate comma-separated list of IPv4 addresses
45
 */
46
function validate_ipv4_list($value) {
47
	$value = trim($value);
48

    
49
	if (empty($value)) {
50
		return false;
51
	}
52

    
53
	$list = explode(',', $value);
54

    
55
	foreach ($list as $ip) {
56
		if (!is_ipaddrv4($ip)) {
57
			return false;
58
		}
59
	}
60

    
61
	return true;
62
}
63

    
64
/*
65
 * Return the interface array
66
 */
67
function get_interface_arr($flush = false) {
68
	global $interface_arr_cache;
69

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

    
75
	return $interface_arr_cache;
76
}
77

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

    
85
	if (!$interface) {
86
		return false;
87
	}
88

    
89
	$ints = get_interface_arr($flush);
90
	if (in_array($interface, $ints)) {
91
		return true;
92
	} else {
93
		return false;
94
	}
95
}
96

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

    
104
	if (!$vip) {
105
		return false;
106
	}
107

    
108

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

    
124
	$ifacedata = pfSense_getall_interface_addresses($realif);
125

    
126
	if (is_subnetv6("{$vip['subnet']}/{$vip['subnet_bits']}")) {	
127
		$comparevip = text_to_compressed_ip6("{$vip['subnet']}/{$vip['subnet_bits']}");
128
	} else {
129
		$comparevip = "{$vip['subnet']}/{$vip['subnet_bits']}";
130
	}
131

    
132
	foreach ($ifacedata as $vipips) {
133
		if ($vipips == $comparevip) {
134
			return true;
135
		}
136
	}
137

    
138
	return false;
139
}
140

    
141
function interface_netgraph_needed($interface = "wan") {
142
	global $config;
143

    
144
	$found = false;
145
	if (!empty($config['l2tp']) &&
146
	    $config['l2tp']['mode'] == "server") {
147
		$found = true;
148
	}
149
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
150
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
151
			if ($pppoe['mode'] != "server") {
152
				continue;
153
			}
154
			if ($pppoe['interface'] == $interface) {
155
				$found = true;
156
				break;
157
			}
158
		}
159
	}
160
	if ($found == false) {
161
		$found = interface_isppp_type($interface);
162
	}
163

    
164
	if ($found == false) {
165
		$realif = get_real_interface($interface);
166
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
167
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
168
				$ports = explode(',', $ppp['ports']);
169
				foreach ($ports as $pid => $port) {
170
					$port = get_real_interface($port);
171
					if ($realif == $port) {
172
						$found = true;
173
						break;
174
					}
175
					/* Find the parent interfaces of the vlans in the MLPPP configs
176
					* there should be only one element in the array here
177
					* -- this could be better . . . */
178
					$parent_if = get_parent_interface($port);
179
					if ($realif == $parent_if[0]) {
180
						$found = true;
181
						break;
182
					}
183
				}
184
			}
185
		}
186
	}
187

    
188
	if ($found == false) {
189
		$realif = get_real_interface($interface);
190
		pfSense_ngctl_detach("{$realif}:", $realif);
191
	}
192
	/* NOTE: We make sure for this on interface_ppps_configure()
193
	 *	no need to do it here again.
194
	 *	else
195
	 *		pfSense_ngctl_attach(".", $realif);
196
	 */
197
}
198

    
199
function interfaces_loopback_configure() {
200
	global $g;
201

    
202
	if (platform_booting()) {
203
		echo gettext("Configuring loopback interface...");
204
	}
205
	pfSense_interface_setaddress("lo0", "127.0.0.1");
206
	interfaces_bring_up("lo0");
207
	if (platform_booting()) {
208
		echo gettext("done.") . "\n";
209
	}
210
	return 0;
211
}
212

    
213
function vlan_valid_tag($tag = NULL) {
214

    
215
	if ($tag == NULL || empty($tag) ||
216
	    !is_numericint($tag) || intval($tag) < 1 || intval($tag) > 4094) {
217
		return (false);
218
	}
219
	return (true);
220
}
221

    
222
function qinq_inuse($qinq = NULL, $inqtag = NULL) {
223
        global $config;
224

    
225
	if ($qinq == NULL || $inqtag == NULL ||
226
	    !is_array($qinq) || !vlan_valid_tag($inqtag)) {
227
		return (false);
228
	}
229

    
230
        $iflist = get_configured_interface_list(true);
231
        foreach ($iflist as $if) {
232
                if ($config['interfaces'][$if]['if'] == qinq_interface($qinq, $inqtag)) {
233
                        return (true);
234
                }
235
        }
236

    
237
        return (false);
238
}
239

    
240
function qinq_interface($qinq = NULL, $inqtag = NULL) {
241

    
242
	if ($qinq == NULL || $inqtag == NULL || !is_array($qinq) ||
243
	    !isset($qinq['if']) || !isset($qinq['tag']) ||
244
	    !vlan_valid_tag($qinq['tag']) || !vlan_valid_tag($inqtag)) {
245
		return (NULL);
246
	}
247
	return ("{$qinq['if']}.{$qinq['tag']}.{$inqtag}");
248
}
249

    
250
function interface_is_qinq($if = NULL) {
251
	global $config;
252

    
253
	if ($if == NULL || empty($if) || !is_array($config['qinqs']['qinqentry'])) {
254
		return (NULL);
255
	}
256

    
257
	/* Check basic format. */
258
	list($qinqif, $vlantag, $inqtag) = explode(".", $if);
259
	if (empty($qinqif) || empty($vlantag) || empty($inqtag) ||
260
	    !vlan_valid_tag($vlantag) || !vlan_valid_tag($inqtag)) {
261
		return (NULL);
262
	}
263

    
264
	foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
265
		if ("{$qinqif}.{$vlantag}" != $qinq['vlanif']) {
266
			continue;
267
		}
268
		if (empty($qinq['members'])) {
269
			continue;
270
		}
271
		foreach (explode(" ", $qinq['members']) as $tag) {
272
			if ($if == qinq_interface($qinq, $tag)) {
273
				return ($qinq);
274
			}
275
		}
276
	}
277

    
278
	return (NULL);
279
}
280

    
281
function vlan_inuse($vlan) {
282
	global $config;
283

    
284
	if ($vlan == NULL || !is_array($vlan)) {
285
		return (false);
286
	}
287

    
288
	$iflist = get_configured_interface_list(true);
289
	foreach ($iflist as $if) {
290
		if ($config['interfaces'][$if]['if'] == $vlan['vlanif']) {
291
			return (true);
292
		}
293
	}
294

    
295
	return (false);
296
}
297

    
298
function interface_is_vlan($if = NULL) {
299
	global $config;
300

    
301
	if ($if == NULL || empty($if) || is_array($if)) {
302
		return (NULL);
303
	}
304

    
305
	/* Check basic format. */
306
	list($vlanif, $vlantag) = explode(".", $if);
307
	if (empty($vlanif) || empty($vlantag) || !vlan_valid_tag($vlantag)) {
308
		return (NULL);
309
	}
310

    
311
	/* Find the VLAN interface. */
312
	if (isset($config['vlans']['vlan']) && is_array($config['vlans']['vlan'])) {
313
		foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
314
			if ($if == $vlan['vlanif']) {
315
				return ($vlan);
316
			}
317
		}
318
	}
319

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

    
329
	return (NULL);
330
}
331

    
332
function vlan_interface($vlan = NULL) {
333
	if ($vlan == NULL || !is_array($vlan) || !isset($vlan['if']) ||
334
	    !isset($vlan['tag']) || !vlan_valid_tag($vlan['tag'])) {
335
		return (NULL);
336
	}
337
	return ("{$vlan['if']}.{$vlan['tag']}");
338
}
339

    
340
function interface_set_macaddr($interface, $mac_addr) {
341
	if (empty($mac_addr) || !is_macaddr($mac_addr)) {
342
		return;
343
	}
344

    
345
	$current_mac = get_interface_mac($interface);
346

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

    
359
function interface_is_parent($if, $parent_check) {
360

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

    
382
function interface_has_clones($if) {
383
	global $config;
384

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

    
416
	return (FALSE);
417
}
418

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

    
433
			/* XXX: Maybe we should report any errors?! */
434
			interface_vlan_configure($vlan);
435
		}
436
	}
437
	if (platform_booting()) {
438
		echo gettext("done.") . "\n";
439
	}
440
}
441

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

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

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

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

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

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

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

    
478
	interfaces_bring_up($vlanif);
479

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

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

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

    
494
	return $vlanif;
495
}
496

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

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

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

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

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

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

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

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

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

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

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

    
583
	return $vlanif;
584
}
585

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

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

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

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

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

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

    
634
	return $vlanif;
635
}
636

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

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

    
644
	$iflist = get_configured_interface_list();
645

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

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

    
669
}
670

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

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

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

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

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

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

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

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

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

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

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

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

    
768
	$checklist = get_configured_interface_list();
769

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

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

    
791
	interface_bridge_configure_advanced($bridge);
792

    
793
	interface_bridge_configure_ip6linklocal($bridge);
794

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1063
	interfaces_bring_up($laggif);
1064

    
1065
	return $laggif;
1066
}
1067

    
1068
function interfaces_gre_configure($checkparent = 0, $realif = "") {
1069
	global $config;
1070

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

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

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

    
1106
	if (!is_array($gre)) {
1107
		return -1;
1108
	}
1109

    
1110
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1111
	if (!interface_is_vlan($realif)) {
1112
		$realif = get_real_interface($gre['if']);
1113
	}
1114
	$realifip = get_interface_ip($gre['if']);
1115
	$realifip6 = get_interface_ipv6($gre['if']);
1116

    
1117
	/* make sure the parent interface is up */
1118
	interfaces_bring_up($realif);
1119

    
1120
	if (platform_booting() || !(empty($gre['greif']))) {
1121
		pfSense_interface_destroy($gre['greif']);
1122
		pfSense_interface_create($gre['greif']);
1123
		$greif = $gre['greif'];
1124
	} else {
1125
		$greif = pfSense_interface_create("gre");
1126
	}
1127

    
1128
	$tunnel_type = '';
1129
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1130
		$tunnel_type = 'v4';
1131
	}
1132
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1133
		$tunnel_type .= 'v6';
1134
	}
1135

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

    
1150
	$parentif = get_real_interface($gre['if']);
1151
	if ($parentif) {
1152
		interfaces_bring_up($parentif);
1153
	} else {
1154
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1155
	}
1156

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

    
1172
	interfaces_bring_up($greif);
1173

    
1174
	return $greif;
1175
}
1176

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

    
1199
	if (!isset($config[$list][$entry]) || !is_array($config[$list][$entry])) {
1200
		return (NULL);
1201
	}
1202

    
1203
	foreach ($config[$list][$entry] as $ent) {
1204
		if ($ent[$entif] == $if) {
1205
			return ($ent);
1206
		}
1207
	}
1208
	return (NULL);
1209
}
1210

    
1211
function is_greipsec($if) {
1212
	global $config;
1213

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

    
1233
function interfaces_gif_configure($checkparent = 0, $realif = "") {
1234
	global $config;
1235

    
1236
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
1237
		foreach ($config['gifs']['gif'] as $i => $gif) {
1238
			if (empty($gif['gifif'])) {
1239
				$gre['gifif'] = "gif{$i}";
1240
			}
1241
			if (!empty($realif) && $realif != $gif['gifif']) {
1242
				continue;
1243
			}
1244

    
1245
			if ($checkparent == 1) {
1246
				if (substr($gif['if'], 0, 4) == '_vip') {
1247
					continue;
1248
				}
1249
				if (substr($gif['if'], 0, 5) == '_lloc') {
1250
					continue;
1251
				}
1252
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
1253
					continue;
1254
				}
1255
			}
1256
			else if ($checkparent == 2) {
1257
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
1258
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
1259
					continue;
1260
				}
1261
			}
1262
			/* XXX: Maybe we should report any errors?! */
1263
			interface_gif_configure($gif);
1264
		}
1265
	}
1266
}
1267

    
1268
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1269
function interface_gif_configure(&$gif, $gifkey = "") {
1270
	global $config, $g;
1271

    
1272
	if (!is_array($gif)) {
1273
		return -1;
1274
	}
1275

    
1276
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1277
	if (!interface_is_vlan($realif)) {
1278
		$realif = get_real_interface($gif['if']);
1279
	}
1280
	$ipaddr = get_interface_ip($gif['if']);
1281

    
1282
	if (is_ipaddrv4($gif['remote-addr'])) {
1283
		if (is_ipaddrv4($ipaddr)) {
1284
			$realifip = $ipaddr;
1285
		} else {
1286
			$realifip = get_interface_ip($gif['if']);
1287
		}
1288
		$realifgw = get_interface_gateway($gif['if']);
1289
	} else if (is_ipaddrv6($gif['remote-addr'])) {
1290
		if (is_ipaddrv6($ipaddr)) {
1291
			$realifip = $ipaddr;
1292
		} else {
1293
			$realifip = get_interface_ipv6($gif['if']);
1294
		}
1295
		$realifgw = get_interface_gateway_v6($gif['if']);
1296
	}
1297
	/* make sure the parent interface is up */
1298
	$parentif = get_real_interface($gif['if']);
1299
	if ($parentif) {
1300
		interfaces_bring_up($parentif);
1301
	} else {
1302
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gif_configure()"));
1303
	}
1304

    
1305
	if (platform_booting() || !(empty($gif['gifif']))) {
1306
		pfSense_interface_destroy($gif['gifif']);
1307
		pfSense_interface_create($gif['gifif']);
1308
		$gifif = $gif['gifif'];
1309
	} else {
1310
		$gifif = pfSense_interface_create("gif");
1311
	}
1312

    
1313
	/* Do not change the order here for more see gif(4) NOTES section. */
1314
	if (is_ipaddrv6($gif['remote-addr'])) {
1315
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1316
	} else {
1317
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1318
	}
1319
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1320
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1321
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1322
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1323
	} else {
1324
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1325
	}
1326
	if (isset($gif['link1'])) {
1327
		pfSense_interface_flags($gifif, IFF_LINK1);
1328
	}
1329
	if (isset($gif['link2'])) {
1330
		pfSense_interface_flags($gifif, IFF_LINK2);
1331
	}
1332
	if ($gifif) {
1333
		interfaces_bring_up($gifif);
1334
		$gifmtu = "";
1335
		$currentgifmtu = get_interface_mtu($gifif);
1336
		foreach ($config['interfaces'] as $tmpinterface) {
1337
			if ($tmpinterface['if'] == $gifif) {
1338
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1339
					$gifmtu = $tmpinterface['mtu'];
1340
				}
1341
			}
1342
		}
1343
		if (is_numericint($gifmtu)) {
1344
			if ($gifmtu != $currentgifmtu) {
1345
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1346
			}
1347
		}
1348
	} else {
1349
		log_error(gettext("could not bring gifif up -- variable not defined"));
1350
	}
1351

    
1352
	if (!platform_booting()) {
1353
		$iflist = get_configured_interface_list();
1354
		foreach ($iflist as $ifname) {
1355
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1356
				if (get_interface_gateway($ifname)) {
1357
					system_routing_configure($ifname);
1358
					break;
1359
				}
1360
				if (get_interface_gateway_v6($ifname)) {
1361
					system_routing_configure($ifname);
1362
					break;
1363
				}
1364
			}
1365
		}
1366
	}
1367

    
1368

    
1369
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1370
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1371
	}
1372
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1373
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1374
	}
1375

    
1376
	if (is_ipaddrv4($realifgw)) {
1377
		route_add_or_change("-host {$gif['remote-addr']} {$realifgw}");
1378
	}
1379
	if (is_ipaddrv6($realifgw)) {
1380
		route_add_or_change("-host -inet6 {$gif['remote-addr']} {$realifgw}");
1381
	}
1382

    
1383
	interfaces_bring_up($gifif);
1384

    
1385
	return $gifif;
1386
}
1387

    
1388
/* Build a list of IPsec interfaces */
1389
function interface_ipsec_vti_list_p1($ph1ent) {
1390
	global $config;
1391
	$iface_list = array();
1392

    
1393
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1394
		return $iface_list;
1395
	}
1396

    
1397
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1398
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1399
		return $iface_list;
1400
	}
1401

    
1402
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1403
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1404
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1405
			$iface_list["ipsec{$ph1ent['ikeid']}00{$idx}"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1406
		}
1407
	} else {
1408
		/* For IKEv2, only create one interface with additional addresses as aliases */
1409
		$iface_list["ipsec{$ph1ent['ikeid']}000"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1410
	}
1411
	return $iface_list;
1412
}
1413
function interface_ipsec_vti_list_all() {
1414
	global $config;
1415
	$iface_list = array();
1416
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1417
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1418
			if ($ph1ent['disabled']) {
1419
				continue;
1420
			}
1421
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1422
		}
1423
	}
1424
	return $iface_list;
1425
}
1426

    
1427
function is_interface_ipsec_vti_assigned($phase2) {
1428
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1429
	$vti_interface = null;
1430
	$vtisubnet_spec = ipsec_vti($phase1, true);
1431
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1432
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1433
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1434
			foreach ($vtisubnet_spec as $idx => $vtisub) {
1435
				/* Is this for this P2? */
1436
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1437
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1438
					$vti_interface = "ipsec{$phase1['ikeid']}00{$idx}";
1439
				}
1440
			}
1441
		} else {
1442
			$vti_interface = "ipsec{$phase1['ikeid']}000";
1443
		}
1444
	}
1445
	/* Check if this interface is assigned */
1446
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1447
}
1448
function interface_ipsec_vti_configure($ph1ent) {
1449
	global $config;
1450

    
1451
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1452
		return false;
1453
	}
1454

    
1455
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1456
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1457
		return false;
1458
	}
1459

    
1460
	$left_spec = ipsec_get_phase1_src($ph1ent);
1461
	$right_spec = $ph1ent['remote-gateway'];
1462

    
1463
	$iface_addrs = array();
1464

    
1465
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1466
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1467
		/* Form a single interface for each P2 entry */
1468
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1469
			$ipsecifnum = "{$ph1ent['ikeid']}00{$idx}";
1470
			if (!is_array($iface_addrs[$ipsecifnum])) {
1471
				$iface_addrs[$ipsecifnum] = array();
1472
			}
1473
			$vtisub['alias'] = "";
1474
			$iface_addrs[$ipsecifnum][] = $vtisub;
1475
		}
1476
	} else {
1477
		/* For IKEv2, only create one interface with additional addresses as aliases */
1478
		$ipsecifnum = "{$ph1ent['ikeid']}000";
1479
		if (!is_array($iface_addrs[$ipsecifnum])) {
1480
			$iface_addrs[$ipsecifnum] = array();
1481
		}
1482
		$have_v4 = false;
1483
		$have_v6 = false;
1484
		foreach ($vtisubnet_spec as $vtisub) {
1485
			// Alias stuff
1486
			$vtisub['alias'] = "";
1487
			if (is_ipaddrv6($vtisub['left'])) {
1488
				if ($have_v6) {
1489
					$vtisub['alias'] = " alias";
1490
				}
1491
				$have_v6 = true;
1492
			} else {
1493
				if ($have_v4) {
1494
					$vtisub['alias'] = " alias";
1495
				}
1496
				$have_v4 = true;
1497
			}
1498
			$iface_addrs[$ipsecifnum][] = $vtisub;
1499
		}
1500
	}
1501

    
1502
	foreach ($iface_addrs as $ipsecifnum => $addrs) {
1503
		$ipsecif = "ipsec{$ipsecifnum}";
1504
		if (!is_array($addrs)) {
1505
			continue;
1506
		}
1507
		// Create IPsec interface
1508
		if (does_interface_exist($ipsecif)) {
1509
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy", false);
1510
		}
1511
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1512

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

    
1517
		/* Loop through all of the addresses for this interface and apply them as needed */
1518
		foreach ($addrs as $addr) {
1519
			// apply interface addresses
1520
			if (is_v6($addr['left'])) {
1521
				$inet = "inet6";
1522
				$gwtype = "v6";
1523
				$right = '';
1524
			} else {
1525
				$inet = "inet";
1526
				$gwtype = "";
1527
				$right = escapeshellarg($addr['right']);
1528
			}
1529

    
1530
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias'], false);
1531
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1532
			if (empty($addr['alias'])) {
1533
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1534
			}
1535
		}
1536
		/* Check/set the MTU if the user configured a custom value.
1537
		 * https://redmine.pfsense.org/issues/9111 */
1538
		$currentvtimtu = get_interface_mtu($ipsecif);
1539
		foreach ($config['interfaces'] as $tmpinterface) {
1540
			if ($tmpinterface['if'] == $ipsecif) {
1541
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1542
					$vtimtu = $tmpinterface['mtu'];
1543
				}
1544
			}
1545
		}
1546
		if (is_numericint($vtimtu)) {
1547
			if ($vtimtu != $currentvtimtu) {
1548
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1549
			}
1550
		}
1551
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1552
	}
1553
}
1554

    
1555
function interfaces_ipsec_vti_configure() {
1556
	global $config;
1557
	if (platform_booting()) {
1558
		echo gettext("Configuring IPsec VTI interfaces...");
1559
	}
1560
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1561
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1562
			if ($ph1ent['disabled']) {
1563
				continue;
1564
			}
1565
			interface_ipsec_vti_configure($ph1ent);
1566
		}
1567
	}
1568
	if (platform_booting()) {
1569
		echo gettext("done.") . "\n";
1570
	}
1571
}
1572

    
1573
function interfaces_configure() {
1574
	global $config, $g;
1575

    
1576
	/* Set up our loopback interface */
1577
	interfaces_loopback_configure();
1578

    
1579
	/* create the unconfigured wireless clones */
1580
	interfaces_create_wireless_clones();
1581

    
1582
	/* set up LAGG virtual interfaces */
1583
	interfaces_lagg_configure();
1584

    
1585
	/* set up VLAN virtual interfaces */
1586
	interfaces_vlan_configure();
1587

    
1588
	interfaces_qinq_configure();
1589

    
1590
	/* set up IPsec VTI interfaces */
1591
	interfaces_ipsec_vti_configure();
1592

    
1593
	$iflist = get_configured_interface_with_descr();
1594
	$delayed_list = array();
1595
	$bridge_list = array();
1596
	$track6_list = array();
1597

    
1598
	/* This is needed to speedup interfaces on bootup. */
1599
	$reload = false;
1600
	if (!platform_booting()) {
1601
		$reload = true;
1602
	}
1603

    
1604
	foreach ($iflist as $if => $ifname) {
1605
		$realif = $config['interfaces'][$if]['if'];
1606
		if (strstr($realif, "bridge")) {
1607
			$bridge_list[$if] = $ifname;
1608
		} else if (strstr($realif, "gre")) {
1609
			$delayed_list[$if] = $ifname;
1610
		} else if (strstr($realif, "gif")) {
1611
			$delayed_list[$if] = $ifname;
1612
		} else if (strstr($realif, "ovpn")) {
1613
			//echo "Delaying OpenVPN interface configuration...done.\n";
1614
			continue;
1615
		} else if (strstr($realif, "ipsec")) {
1616
			continue;
1617
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1618
			$track6_list[$if] = $ifname;
1619
		} else {
1620
			if (platform_booting()) {
1621
				printf(gettext("Configuring %s interface..."), $ifname);
1622
			}
1623

    
1624
			if ($g['debug']) {
1625
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1626
			}
1627
			interface_configure($if, $reload);
1628
			if (platform_booting()) {
1629
				echo gettext("done.") . "\n";
1630
			}
1631
		}
1632
	}
1633

    
1634
	/*
1635
	 * NOTE: The following function parameter consists of
1636
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1637
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1638
	 */
1639

    
1640
	/* set up GRE virtual interfaces */
1641
	interfaces_gre_configure(1);
1642

    
1643
	/* set up GIF virtual interfaces */
1644
	interfaces_gif_configure(1);
1645

    
1646
	/* set up BRIDGe virtual interfaces */
1647
	interfaces_bridge_configure(1);
1648

    
1649
	foreach ($track6_list as $if => $ifname) {
1650
		if (platform_booting()) {
1651
			printf(gettext("Configuring %s interface..."), $ifname);
1652
		}
1653
		if ($g['debug']) {
1654
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1655
		}
1656

    
1657
		interface_configure($if, $reload);
1658

    
1659
		if (platform_booting()) {
1660
			echo gettext("done.") . "\n";
1661
		}
1662
	}
1663

    
1664
	/* bring up vip interfaces */
1665
	interfaces_vips_configure();
1666

    
1667
	/* set up GRE virtual interfaces */
1668
	interfaces_gre_configure(2);
1669

    
1670
	/* set up GIF virtual interfaces */
1671
	interfaces_gif_configure(2);
1672

    
1673
	foreach ($delayed_list as $if => $ifname) {
1674
		if (platform_booting()) {
1675
			printf(gettext("Configuring %s interface..."), $ifname);
1676
		}
1677
		if ($g['debug']) {
1678
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1679
		}
1680

    
1681
		interface_configure($if, $reload);
1682

    
1683
		if (platform_booting()) {
1684
			echo gettext("done.") . "\n";
1685
		}
1686
	}
1687

    
1688
	/* set up BRIDGe virtual interfaces */
1689
	interfaces_bridge_configure(2);
1690

    
1691
	foreach ($bridge_list as $if => $ifname) {
1692
		if (platform_booting()) {
1693
			printf(gettext("Configuring %s interface..."), $ifname);
1694
		}
1695
		if ($g['debug']) {
1696
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1697
		}
1698

    
1699
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1700
		// redmine #3997
1701
		interface_reconfigure($if, $reload);
1702
		interfaces_vips_configure($if);
1703

    
1704
		if (platform_booting()) {
1705
			echo gettext("done.") . "\n";
1706
		}
1707
	}
1708

    
1709
	/* configure interface groups */
1710
	interfaces_group_setup();
1711

    
1712
	if (!platform_booting()) {
1713
		/* reconfigure static routes (kernel may have deleted them) */
1714
		system_routing_configure();
1715

    
1716
		/* reload IPsec tunnels */
1717
		ipsec_configure();
1718

    
1719
		/* restart dns servers (defering dhcpd reload) */
1720
		if (isset($config['dnsmasq']['enable'])) {
1721
			services_dnsmasq_configure(false);
1722
		}
1723
		if (isset($config['unbound']['enable'])) {
1724
			services_unbound_configure(false);
1725
		}
1726

    
1727
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1728
		services_dhcpd_configure();
1729
	}
1730

    
1731
	return 0;
1732
}
1733

    
1734
function interface_reconfigure($interface = "wan", $reloadall = false) {
1735
	interface_bring_down($interface);
1736
	interface_configure($interface, $reloadall);
1737
}
1738

    
1739
function interface_vip_bring_down($vip) {
1740
	global $g;
1741

    
1742
	$vipif = get_real_interface($vip['interface']);
1743
	switch ($vip['mode']) {
1744
		case "proxyarp":
1745
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1746
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1747
			}
1748
			break;
1749
		case "ipalias":
1750
			if (does_interface_exist($vipif)) {
1751
				if (is_ipaddrv6($vip['subnet'])) {
1752
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1753
				} else {
1754
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1755
				}
1756
			}
1757
			break;
1758
		case "carp":
1759
			/* XXX: Is enough to delete ip address? */
1760
			if (does_interface_exist($vipif)) {
1761
				if (is_ipaddrv6($vip['subnet'])) {
1762
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1763
				} else {
1764
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1765
				}
1766
			}
1767
			break;
1768
	}
1769
}
1770

    
1771
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1772
	global $config, $g;
1773

    
1774
	if (!isset($config['interfaces'][$interface])) {
1775
		return;
1776
	}
1777

    
1778
	if ($g['debug']) {
1779
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1780
	}
1781

    
1782
	/*
1783
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1784
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1785
	 * Keep this in mind while doing changes here!
1786
	 */
1787
	if ($ifacecfg === false) {
1788
		$ifcfg = $config['interfaces'][$interface];
1789
		$ppps = $config['ppps']['ppp'];
1790
		$realif = get_real_interface($interface);
1791
		$realifv6 = get_real_interface($interface, "inet6", true);
1792
	} elseif (!is_array($ifacecfg)) {
1793
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1794
		$ifcfg = $config['interfaces'][$interface];
1795
		$ppps = $config['ppps']['ppp'];
1796
		$realif = get_real_interface($interface);
1797
		$realifv6 = get_real_interface($interface, "inet6", true);
1798
	} else {
1799
		$ifcfg = $ifacecfg['ifcfg'];
1800
		$ppps = $ifacecfg['ppps'];
1801
		if (isset($ifacecfg['ifcfg']['realif'])) {
1802
			$realif = $ifacecfg['ifcfg']['realif'];
1803
			/* XXX: Any better way? */
1804
			$realifv6 = $realif;
1805
		} else {
1806
			$realif = get_real_interface($interface);
1807
			$realifv6 = get_real_interface($interface, "inet6", true);
1808
		}
1809
	}
1810

    
1811
	switch ($ifcfg['ipaddr']) {
1812
		case "ppp":
1813
		case "pppoe":
1814
		case "pptp":
1815
		case "l2tp":
1816
			if (is_array($ppps) && count($ppps)) {
1817
				foreach ($ppps as $pppid => $ppp) {
1818
					if ($realif == $ppp['if']) {
1819
						if (isset($ppp['ondemand']) && !$destroy) {
1820
							send_event("interface reconfigure {$interface}");
1821
							break;
1822
						}
1823
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1824
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1825
							sleep(2);
1826
						}
1827
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1828
						break;
1829
					}
1830
				}
1831
			}
1832
			break;
1833
		case "dhcp":
1834
			kill_dhclient_process($realif);
1835
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1836
			if (does_interface_exist("$realif")) {
1837
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1838
				interface_vip_cleanup($interface, "inet4");
1839
				if ($destroy == true) {
1840
					pfSense_interface_flags($realif, -IFF_UP);
1841
				}
1842
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1843
			}
1844
			break;
1845
		default:
1846
			if (does_interface_exist("$realif")) {
1847
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1848
				interface_vip_cleanup($interface, "inet4");
1849
				if ($destroy == true) {
1850
					pfSense_interface_flags($realif, -IFF_UP);
1851
				}
1852
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1853
			}
1854
			break;
1855
	}
1856

    
1857
	$track6 = array();
1858
	switch ($ifcfg['ipaddrv6']) {
1859
		case "slaac":
1860
		case "dhcp6":
1861
			kill_dhcp6client_process($realif, $destroy, false);
1862
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1863
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1864
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1865
			if (does_interface_exist($realifv6)) {
1866
				$ip6 = find_interface_ipv6($realifv6);
1867
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1868
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1869
				}
1870
				interface_vip_cleanup($interface, "inet6");
1871
				if ($destroy == true) {
1872
					pfSense_interface_flags($realif, -IFF_UP);
1873
				}
1874
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1875
			}
1876
			$track6 = link_interface_to_track6($interface);
1877
			break;
1878
		case "6rd":
1879
		case "6to4":
1880
			$realif = "{$interface}_stf";
1881
			if (does_interface_exist("$realif")) {
1882
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1883
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1884
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1885
					$destroy = true;
1886
				} else {
1887
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1888
					$ip6 = get_interface_ipv6($interface);
1889
					if (is_ipaddrv6($ip6)) {
1890
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1891
					}
1892
				}
1893
				interface_vip_cleanup($interface, "inet6");
1894
				if ($destroy == true) {
1895
					pfSense_interface_flags($realif, -IFF_UP);
1896
				}
1897
			}
1898
			$track6 = link_interface_to_track6($interface);
1899
			break;
1900
		default:
1901
			if (does_interface_exist("$realif")) {
1902
				$ip6 = get_interface_ipv6($interface);
1903
				if (is_ipaddrv6($ip6)) {
1904
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1905
				}
1906
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1907
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1908
				}
1909
				interface_vip_cleanup($interface, "inet6");
1910
				if ($destroy == true) {
1911
					pfSense_interface_flags($realif, -IFF_UP);
1912
				}
1913
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1914
			}
1915
			$track6 = link_interface_to_track6($interface);
1916
			break;
1917
	}
1918

    
1919
	if (!empty($track6) && is_array($track6)) {
1920
		if (!function_exists('services_dhcpd_configure')) {
1921
			require_once('services.inc');
1922
		}
1923
		/* Bring down radvd and dhcp6 on these interfaces */
1924
		services_dhcpd_configure('inet6', $track6);
1925
	}
1926

    
1927
	$old_router = '';
1928
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1929
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1930
	}
1931

    
1932
	/* remove interface up file if it exists */
1933
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1934
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1935
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1936
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1937
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1938
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1939
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1940

    
1941
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1942
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1943
	if (is_array($ifcfg['wireless'])) {
1944
		kill_hostapd($realif);
1945
		mwexec(kill_wpasupplicant($realif));
1946
	}
1947

    
1948
	if ($destroy == true) {
1949
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^ipsec|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1950
			pfSense_interface_destroy($realif);
1951
		}
1952
	}
1953

    
1954
	return;
1955
}
1956

    
1957
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1958
	global $config;
1959
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1960
		unset($config["virtualip_carp_maintenancemode"]);
1961
		write_config("Leave CARP maintenance mode");
1962
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1963
		$config["virtualip_carp_maintenancemode"] = true;
1964
		write_config(gettext("Enter CARP maintenance mode"));
1965
	}
1966
	init_config_arr(array('virtualip', 'vip'));
1967
	$viparr = &$config['virtualip']['vip'];
1968

    
1969
	if (is_array($viparr)) {
1970
		foreach ($viparr as $vip) {
1971
			if ($vip['mode'] == "carp") {
1972
				interface_carp_configure($vip, true);
1973
			}
1974
		}
1975
	}
1976
}
1977

    
1978
function interface_wait_tentative($interface, $timeout = 10) {
1979
	if (!does_interface_exist($interface)) {
1980
		return false;
1981
	}
1982

    
1983
	$time = 0;
1984
	while ($time <= $timeout) {
1985
		$if = pfSense_get_interface_addresses($interface);
1986
		if (!isset($if['tentative'])) {
1987
			return true;
1988
		}
1989
		sleep(1);
1990
		$time++;
1991
	}
1992

    
1993
	return false;
1994
}
1995

    
1996
function interface_isppp_type($interface) {
1997
	global $config;
1998

    
1999
	if (!is_array($config['interfaces'][$interface])) {
2000
		return false;
2001
	}
2002

    
2003
	switch ($config['interfaces'][$interface]['ipaddr']) {
2004
		case 'pptp':
2005
		case 'l2tp':
2006
		case 'pppoe':
2007
		case 'ppp':
2008
			return true;
2009
			break;
2010
		default:
2011
			return false;
2012
			break;
2013
	}
2014
}
2015

    
2016
function interfaces_ptpid_used($ptpid) {
2017
	global $config;
2018

    
2019
	if (is_array($config['ppps']['ppp'])) {
2020
		foreach ($config['ppps']['ppp'] as & $settings) {
2021
			if ($ptpid == $settings['ptpid']) {
2022
				return true;
2023
			}
2024
		}
2025
	}
2026

    
2027
	return false;
2028
}
2029

    
2030
function interfaces_ptpid_next() {
2031

    
2032
	$ptpid = 0;
2033
	while (interfaces_ptpid_used($ptpid)) {
2034
		$ptpid++;
2035
	}
2036

    
2037
	return $ptpid;
2038
}
2039

    
2040
function getMPDCRONSettings($pppif) {
2041
	global $config;
2042

    
2043
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2044
	if (is_array($config['cron']['item'])) {
2045
		foreach ($config['cron']['item'] as $i => $item) {
2046
			if (stripos($item['command'], $cron_cmd_file) !== false) {
2047
				return array("ID" => $i, "ITEM" => $item);
2048
			}
2049
		}
2050
	}
2051

    
2052
	return NULL;
2053
}
2054

    
2055
function handle_pppoe_reset($post_array) {
2056
	global $config, $g;
2057

    
2058
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2059
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2060

    
2061
	if (!is_array($config['cron']['item'])) {
2062
		$config['cron']['item'] = array();
2063
	}
2064

    
2065
	$itemhash = getMPDCRONSettings($pppif);
2066

    
2067
	// reset cron items if necessary and return
2068
	if (empty($post_array['pppoe-reset-type'])) {
2069
		if (isset($itemhash)) {
2070
			unset($config['cron']['item'][$itemhash['ID']]);
2071
		}
2072
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2073
		return;
2074
	}
2075

    
2076
	if (empty($itemhash)) {
2077
		$itemhash = array();
2078
	}
2079
	$item = array();
2080
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2081
		$item['minute'] = $post_array['pppoe_resetminute'];
2082
		$item['hour'] = $post_array['pppoe_resethour'];
2083
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2084
			$date = explode("/", $post_array['pppoe_resetdate']);
2085
			$item['mday'] = $date[1];
2086
			$item['month'] = $date[0];
2087
		} else {
2088
			$item['mday'] = "*";
2089
			$item['month'] = "*";
2090
		}
2091
		$item['wday'] = "*";
2092
		$item['who'] = "root";
2093
		$item['command'] = $cron_cmd_file;
2094
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2095
		switch ($post_array['pppoe_pr_preset_val']) {
2096
			case "monthly":
2097
				$item['minute'] = "0";
2098
				$item['hour'] = "0";
2099
				$item['mday'] = "1";
2100
				$item['month'] = "*";
2101
				$item['wday'] = "*";
2102
				break;
2103
			case "weekly":
2104
				$item['minute'] = "0";
2105
				$item['hour'] = "0";
2106
				$item['mday'] = "*";
2107
				$item['month'] = "*";
2108
				$item['wday'] = "0";
2109
				break;
2110
			case "daily":
2111
				$item['minute'] = "0";
2112
				$item['hour'] = "0";
2113
				$item['mday'] = "*";
2114
				$item['month'] = "*";
2115
				$item['wday'] = "*";
2116
				break;
2117
			case "hourly":
2118
				$item['minute'] = "0";
2119
				$item['hour'] = "*";
2120
				$item['mday'] = "*";
2121
				$item['month'] = "*";
2122
				$item['wday'] = "*";
2123
				break;
2124
		} // end switch
2125
		$item['who'] = "root";
2126
		$item['command'] = $cron_cmd_file;
2127
	}
2128
	if (empty($item)) {
2129
		return;
2130
	}
2131
	if (isset($itemhash['ID'])) {
2132
		$config['cron']['item'][$itemhash['ID']] = $item;
2133
	} else {
2134
		$config['cron']['item'][] = $item;
2135
	}
2136
}
2137

    
2138
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2139
	global $config;
2140
	$ppp_list = array();
2141
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2142
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2143
			$ports = explode(",", $ppp['ports']);
2144
			foreach($ports as $port) {
2145
				foreach($triggerinterfaces as $vip) {
2146
					if ($port == "_vip{$vip['uniqid']}") {
2147
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2148
						$ppp_list[$if] = 1;
2149
					}
2150
				}
2151
			}
2152
		}
2153
	}
2154
	foreach($ppp_list as $pppif => $dummy) {
2155
		interface_ppps_configure($pppif);
2156
	}
2157
}
2158

    
2159
/*
2160
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2161
 * It writes the mpd config file to /var/etc every time the link is opened.
2162
 */
2163
function interface_ppps_configure($interface) {
2164
	global $config, $g;
2165

    
2166
	/* Return for unassigned interfaces. This is a minimum requirement. */
2167
	if (empty($config['interfaces'][$interface])) {
2168
		return 0;
2169
	}
2170
	$ifcfg = $config['interfaces'][$interface];
2171
	if (!isset($ifcfg['enable'])) {
2172
		return 0;
2173
	}
2174

    
2175
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2176
	if (!is_dir("/var/spool/lock")) {
2177
		mkdir("/var/spool/lock", 0777, true);
2178
	}
2179
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2180
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2181
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2182
	}
2183

    
2184
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2185
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2186
			if ($ifcfg['if'] == $ppp['if']) {
2187
				break;
2188
			}
2189
		}
2190
	}
2191
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2192
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2193
		return 0;
2194
	}
2195
	$pppif = $ifcfg['if'];
2196
	if ($ppp['type'] == "ppp") {
2197
		$type = "modem";
2198
	} else {
2199
		$type = $ppp['type'];
2200
	}
2201
	$upper_type = strtoupper($ppp['type']);
2202

    
2203
	$confports = explode(',', $ppp['ports']);
2204
	if ($type == "modem") {
2205
		$ports = $confports;
2206
	} else {
2207
		$ports = array();
2208
		foreach ($confports as $pid => $port) {
2209
			if (strstr($port, "_vip")) {
2210
				if (get_carp_interface_status($port) != "MASTER") {
2211
					continue;
2212
				}
2213
			}
2214
			$ports[$pid] = get_real_interface($port);
2215
			if (empty($ports[$pid])) {
2216
				return 0;
2217
			}
2218
		}
2219
	}
2220
	$localips = explode(',', $ppp['localip']);
2221
	$gateways = explode(',', $ppp['gateway']);
2222
	$subnets = explode(',', $ppp['subnet']);
2223

    
2224
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2225
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2226
	 */
2227
	foreach ($ports as $pid => $port) {
2228
		switch ($ppp['type']) {
2229
			case "pppoe":
2230
				/* Bring the parent interface up */
2231
				interfaces_bring_up($port);
2232
				pfSense_ngctl_attach(".", $port);
2233
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2234
				$ngif = str_replace(".", "_", $port);
2235
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2236
				break;
2237
			case "pptp":
2238
			case "l2tp":
2239
				/* configure interface */
2240
				if (is_ipaddr($localips[$pid])) {
2241
					// Manually configure interface IP/subnet
2242
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2243
					interfaces_bring_up($port);
2244
				} else if (empty($localips[$pid])) {
2245
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2246
				}
2247

    
2248
				if (!is_ipaddr($localips[$pid])) {
2249
					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));
2250
					$localips[$pid] = "0.0.0.0";
2251
				}
2252
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2253
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2254
				}
2255
				if (!is_ipaddr($gateways[$pid])) {
2256
					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));
2257
					return 0;
2258
				}
2259
				pfSense_ngctl_attach(".", $port);
2260
				break;
2261
			case "ppp":
2262
				if (!file_exists("{$port}")) {
2263
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2264
					return 0;
2265
				}
2266
				break;
2267
			default:
2268
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2269
				break;
2270
		}
2271
	}
2272

    
2273
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2274
	    (is_array($ports) && count($ports) > 1)) {
2275
		$multilink = "enable";
2276
	} else {
2277
		$multilink = "disable";
2278
	}
2279

    
2280
	if ($type == "modem") {
2281
		if (is_ipaddr($ppp['localip'])) {
2282
			$localip = $ppp['localip'];
2283
		} else {
2284
			$localip = '0.0.0.0';
2285
		}
2286

    
2287
		if (is_ipaddr($ppp['gateway'])) {
2288
			$gateway = $ppp['gateway'];
2289
		} else {
2290
			$gateway = "10.64.64.{$pppid}";
2291
		}
2292
		$ranges = "{$localip}/0 {$gateway}/0";
2293

    
2294
		if (empty($ppp['apnum'])) {
2295
			$ppp['apnum'] = 1;
2296
		}
2297
	} else {
2298
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2299
	}
2300

    
2301
	if (isset($ppp['ondemand'])) {
2302
		$ondemand = "enable";
2303
	} else {
2304
		$ondemand = "disable";
2305
	}
2306
	if (!isset($ppp['idletimeout'])) {
2307
		$ppp['idletimeout'] = 0;
2308
	}
2309

    
2310
	if (empty($ppp['username']) && $type == "modem") {
2311
		$ppp['username'] = "user";
2312
		$ppp['password'] = "none";
2313
	}
2314
	if (empty($ppp['password']) && $type == "modem") {
2315
		$passwd = "none";
2316
	} else {
2317
		$passwd = base64_decode($ppp['password']);
2318
	}
2319

    
2320
	$bandwidths = explode(',', $ppp['bandwidth']);
2321
	$defaultmtu = "1492";
2322
	if (!empty($ifcfg['mtu'])) {
2323
		$defaultmtu = intval($ifcfg['mtu']);
2324
	}
2325
	if (isset($ppp['mtu'])) {
2326
		$mtus = explode(',', $ppp['mtu']);
2327
	}
2328
	if (isset($ppp['mru'])) {
2329
		$mrus = explode(',', $ppp['mru']);
2330
	}
2331
	if (isset($ppp['mrru'])) {
2332
		$mrrus = explode(',', $ppp['mrru']);
2333
	}
2334
	if (!empty($ifcfg['ipaddrv6'])) {
2335
		$ipv6cp = "set bundle enable ipv6cp";
2336
	}
2337

    
2338
	// Construct the mpd.conf file
2339
	$mpdconf = <<<EOD
2340
startup:
2341
	# configure the console
2342
	set console close
2343
	# configure the web server
2344
	set web close
2345

    
2346
default:
2347
{$ppp['type']}client:
2348
	create bundle static {$interface}
2349
	{$ipv6cp}
2350
	set iface name {$pppif}
2351

    
2352
EOD;
2353
	$setdefaultgw = false;
2354
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2355
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2356
	if ($defgw4['interface'] == $interface) {
2357
		$setdefaultgw = true;
2358
	}
2359

    
2360
/* Omit this, we maintain the default route by other means, and it causes problems with
2361
 * default gateway switching. See redmine #1837 for original issue
2362
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2363
 * edge case. redmine #6495 open to address.
2364
 */
2365
	if ($setdefaultgw == true) {
2366
		$mpdconf .= <<<EOD
2367
	set iface route default
2368

    
2369
EOD;
2370
	}
2371

    
2372
	$mpdconf .= <<<EOD
2373
	set iface {$ondemand} on-demand
2374
	set iface idle {$ppp['idletimeout']}
2375

    
2376
EOD;
2377

    
2378
	if (isset($ppp['ondemand'])) {
2379
		$mpdconf .= <<<EOD
2380
	set iface addrs 10.10.1.1 10.10.1.2
2381

    
2382
EOD;
2383
	}
2384

    
2385
	if (isset($ppp['mtu-override']) &&
2386
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2387
		/* Find the smaller MTU set on ports */
2388
		$mtu = $defaultmtu;
2389
		foreach ($ports as $pid => $port) {
2390
			if (empty($mtus[$pid])) {
2391
				$mtus[$pid] = $defaultmtu;
2392
			}
2393
			if ($type == "pppoe") {
2394
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2395
					$mtus[$pid] = get_interface_mtu($port) - 8;
2396
				}
2397
			}
2398
			if ($mtu > $mtus[$pid]) {
2399
				$mtu = $mtus[$pid];
2400
			}
2401
		}
2402
		$mpdconf .= <<<EOD
2403
	set iface mtu {$mtu} override
2404

    
2405
EOD;
2406
	}
2407

    
2408
	if (isset($ppp['tcpmssfix'])) {
2409
		$tcpmss = "disable";
2410
	} else {
2411
		$tcpmss = "enable";
2412
	}
2413
	$mpdconf .= <<<EOD
2414
	set iface {$tcpmss} tcpmssfix
2415

    
2416
EOD;
2417

    
2418
	$mpdconf .= <<<EOD
2419
	set iface up-script /usr/local/sbin/ppp-linkup
2420
	set iface down-script /usr/local/sbin/ppp-linkdown
2421
	set ipcp ranges {$ranges}
2422

    
2423
EOD;
2424
	if (isset($ppp['vjcomp'])) {
2425
		$mpdconf .= <<<EOD
2426
	set ipcp no vjcomp
2427

    
2428
EOD;
2429
	}
2430

    
2431
	if (isset($config['system']['dnsallowoverride'])) {
2432
		$mpdconf .= <<<EOD
2433
	set ipcp enable req-pri-dns
2434
	set ipcp enable req-sec-dns
2435

    
2436
EOD;
2437
	}
2438

    
2439
	if (!isset($ppp['verbose_log'])) {
2440
		$mpdconf .= <<<EOD
2441
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2442

    
2443
EOD;
2444
	}
2445

    
2446
	foreach ($ports as $pid => $port) {
2447
		$port = get_real_interface($port);
2448
		$mpdconf .= <<<EOD
2449

    
2450
	create link static {$interface}_link{$pid} {$type}
2451
	set link action bundle {$interface}
2452
	set link {$multilink} multilink
2453
	set link keep-alive 10 60
2454
	set link max-redial 0
2455

    
2456
EOD;
2457
		if (isset($ppp['shortseq'])) {
2458
			$mpdconf .= <<<EOD
2459
	set link no shortseq
2460

    
2461
EOD;
2462
		}
2463

    
2464
		if (isset($ppp['acfcomp'])) {
2465
			$mpdconf .= <<<EOD
2466
	set link no acfcomp
2467

    
2468
EOD;
2469
		}
2470

    
2471
		if (isset($ppp['protocomp'])) {
2472
			$mpdconf .= <<<EOD
2473
	set link no protocomp
2474

    
2475
EOD;
2476
		}
2477

    
2478
		$mpdconf .= <<<EOD
2479
	set link disable chap pap
2480
	set link accept chap pap eap
2481
	set link disable incoming
2482

    
2483
EOD;
2484

    
2485

    
2486
		if (!empty($bandwidths[$pid])) {
2487
			$mpdconf .= <<<EOD
2488
	set link bandwidth {$bandwidths[$pid]}
2489

    
2490
EOD;
2491
		}
2492

    
2493
		if (empty($mtus[$pid])) {
2494
			$mtus[$pid] = $defaultmtu;
2495
		}
2496
		if ($type == "pppoe") {
2497
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2498
				$mtus[$pid] = get_interface_mtu($port) - 8;
2499
			}
2500
		}
2501
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2502
		    !isset($ppp['mtu-override']) &&
2503
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2504
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2505
			$mpdconf .= <<<EOD
2506
	set link mtu {$mtus[$pid]}
2507

    
2508
EOD;
2509
		}
2510

    
2511
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2512
		    !isset($ppp['mtu-override']) &&
2513
		    !empty($mrus[$pid])) {
2514
			$mpdconf .= <<<EOD
2515
	set link mru {$mrus[$pid]}
2516

    
2517
EOD;
2518
		}
2519

    
2520
		if (!empty($mrrus[$pid])) {
2521
			$mpdconf .= <<<EOD
2522
	set link mrru {$mrrus[$pid]}
2523

    
2524
EOD;
2525
		}
2526

    
2527
		$mpdconf .= <<<EOD
2528
	set auth authname "{$ppp['username']}"
2529
	set auth password {$passwd}
2530

    
2531
EOD;
2532
		if ($type == "modem") {
2533
			$mpdconf .= <<<EOD
2534
	set modem device {$ppp['ports']}
2535
	set modem script DialPeer
2536
	set modem idle-script Ringback
2537
	set modem watch -cd
2538
	set modem var \$DialPrefix "DT"
2539
	set modem var \$Telephone "{$ppp['phone']}"
2540

    
2541
EOD;
2542
		}
2543
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2544
			$mpdconf .= <<<EOD
2545
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2546

    
2547
EOD;
2548
		}
2549
		if (isset($ppp['initstr']) && $type == "modem") {
2550
			$initstr = base64_decode($ppp['initstr']);
2551
			$mpdconf .= <<<EOD
2552
	set modem var \$InitString "{$initstr}"
2553

    
2554
EOD;
2555
		}
2556
		if (isset($ppp['simpin']) && $type == "modem") {
2557
			if ($ppp['pin-wait'] == "") {
2558
				$ppp['pin-wait'] = 0;
2559
			}
2560
			$mpdconf .= <<<EOD
2561
	set modem var \$SimPin "{$ppp['simpin']}"
2562
	set modem var \$PinWait "{$ppp['pin-wait']}"
2563

    
2564
EOD;
2565
		}
2566
		if (isset($ppp['apn']) && $type == "modem") {
2567
			$mpdconf .= <<<EOD
2568
	set modem var \$APN "{$ppp['apn']}"
2569
	set modem var \$APNum "{$ppp['apnum']}"
2570

    
2571
EOD;
2572
		}
2573
		if ($type == "pppoe") {
2574
			$hostuniq = '';
2575
			if (!empty($ppp['hostuniq'])) {
2576
				if (preg_match('/^0x[a-fA-F0-9]+$/', $ppp['hostuniq'])) {
2577
					$hostuniq = strtolower($ppp['hostuniq']) .'|';
2578
				} elseif (preg_match('/^[a-zA-Z0-9]+$/i', $ppp['hostuniq'])) {
2579
					$hostuniq = '0x' . bin2hex($ppp['hostuniq']) . '|';
2580
				}
2581
			}
2582
			// Send a null service name if none is set.
2583
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2584
			$mpdconf .= <<<EOD
2585
	set pppoe service "{$hostuniq}{$provider}"
2586

    
2587
EOD;
2588
		}
2589
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2590
			$mpdconf .= <<<EOD
2591
	set pppoe max-payload {$mtus[$pid]}
2592

    
2593
EOD;
2594
		}
2595
		if ($type == "pppoe") {
2596
			$mpdconf .= <<<EOD
2597
	set pppoe iface {$port}
2598

    
2599
EOD;
2600
		}
2601

    
2602
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2603
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2604
			$mpdconf .= <<<EOD
2605
	set l2tp secret "{$secret}"
2606

    
2607
EOD;
2608
		}
2609

    
2610
		if (($type == "pptp") || ($type == "l2tp")) {
2611
			$mpdconf .= <<<EOD
2612
	set {$type} self {$localips[$pid]}
2613
	set {$type} peer {$gateways[$pid]}
2614

    
2615
EOD;
2616
		}
2617

    
2618
		$mpdconf .= "\topen\n";
2619
	} //end foreach ($port)
2620

    
2621

    
2622
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2623
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2624
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2625
	} else {
2626
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2627
		if (!$fd) {
2628
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2629
			return 0;
2630
		}
2631
		// Write out mpd_ppp.conf
2632
		fwrite($fd, $mpdconf);
2633
		fclose($fd);
2634
		unset($mpdconf);
2635
	}
2636

    
2637
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2638
	if (isset($ppp['uptime'])) {
2639
		if (!file_exists("/conf/{$pppif}.log")) {
2640
			file_put_contents("/conf/{$pppif}.log", '');
2641
		}
2642
	} else {
2643
		if (file_exists("/conf/{$pppif}.log")) {
2644
			@unlink("/conf/{$pppif}.log");
2645
		}
2646
	}
2647

    
2648
	/* clean up old lock files */
2649
	foreach ($ports as $port) {
2650
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2651
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2652
		}
2653
	}
2654

    
2655
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2656
	/* random IPv6 interface identifier during boot. More details at */
2657
	/* https://forum.netgate.com/post/592474 */
2658
	if (platform_booting() && is_array($config['interfaces'])) {
2659
		$count = 0;
2660
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2661
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2662
				$tempaddr[$count]['if'] = $tempiface['if'];
2663
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2664
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2665
				$count++;
2666
			}
2667
			// Maximum /31 is is x.y.z.254/31
2668
			if ($count > 122) {
2669
				break;
2670
			}
2671
		}
2672
		unset($count);
2673
	}
2674

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

    
2680
	// Check for PPPoE periodic reset request
2681
	if ($type == "pppoe") {
2682
		if (!empty($ppp['pppoe-reset-type'])) {
2683
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2684
		} else {
2685
			interface_setup_pppoe_reset_file($ppp['if']);
2686
		}
2687
	}
2688
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2689
	$i = 0;
2690
	while ($i < 10) {
2691
		if (does_interface_exist($ppp['if'], true)) {
2692
			break;
2693
		}
2694
		sleep(3);
2695
		$i++;
2696
	}
2697

    
2698
	/* Remove all temporary bogon IPv4 addresses */
2699
	if (is_array($tempaddr)) {
2700
		foreach ($tempaddr as $tempiface) {
2701
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2702
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2703
			}
2704
		}
2705
		unset ($tempaddr);
2706
	}
2707

    
2708
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2709
	/* We should be able to launch the right version for each modem */
2710
	/* We can also guess the mondev from the manufacturer */
2711
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2712
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2713
	foreach ($ports as $port) {
2714
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2715
			$mondev = substr(basename($port), 0, -1);
2716
			$devlist = glob("/dev/{$mondev}?");
2717
			$mondev = basename(end($devlist));
2718
		}
2719
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2720
			$mondev = substr(basename($port), 0, -1) . "1";
2721
		}
2722
		if ($mondev != '') {
2723
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2724
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2725
		}
2726
	}
2727

    
2728
	return 1;
2729
}
2730

    
2731
function interfaces_sync_setup() {
2732
	global $g, $config;
2733

    
2734
	if (isset($config['system']['developerspew'])) {
2735
		$mt = microtime();
2736
		echo "interfaces_sync_setup() being called $mt\n";
2737
	}
2738

    
2739
	if (platform_booting()) {
2740
		echo gettext("Configuring CARP settings...");
2741
		mute_kernel_msgs();
2742
	}
2743

    
2744
	/* suck in configuration items */
2745
	if ($config['hasync']) {
2746
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2747
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2748
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2749
	} else {
2750
		unset($pfsyncinterface);
2751
		unset($pfsyncenabled);
2752
	}
2753

    
2754
	set_sysctl(array(
2755
		"net.inet.carp.preempt" => "1",
2756
		"net.inet.carp.log" => "1")
2757
	);
2758

    
2759
	if (!empty($pfsyncinterface)) {
2760
		$carp_sync_int = get_real_interface($pfsyncinterface);
2761
	} else {
2762
		unset($carp_sync_int);
2763
	}
2764

    
2765
	/* setup pfsync interface */
2766
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2767
		if (is_ipaddr($pfsyncpeerip)) {
2768
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2769
		} else {
2770
			$syncpeer = "-syncpeer";
2771
		}
2772

    
2773
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2774
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2775

    
2776
		sleep(1);
2777

    
2778
		/* 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
2779
		 * for existing sessions.
2780
		 */
2781
		log_error(gettext("waiting for pfsync..."));
2782
		$i = 0;
2783
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2784
			$i++;
2785
			sleep(1);
2786
		}
2787
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2788
		log_error(gettext("Configuring CARP settings finalize..."));
2789
	} else {
2790
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2791
	}
2792

    
2793
	$carplist = get_configured_vip_list('all', VIP_CARP);
2794
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2795
		set_single_sysctl("net.inet.carp.allow", "1");
2796
	} else {
2797
		set_single_sysctl("net.inet.carp.allow", "0");
2798
	}
2799

    
2800
	if (platform_booting()) {
2801
		unmute_kernel_msgs();
2802
		echo gettext("done.") . "\n";
2803
	}
2804
}
2805

    
2806
function interface_proxyarp_configure($interface = "") {
2807
	global $config, $g;
2808
	if (isset($config['system']['developerspew'])) {
2809
		$mt = microtime();
2810
		echo "interface_proxyarp_configure() being called $mt\n";
2811
	}
2812

    
2813
	/* kill any running choparp */
2814
	if (empty($interface)) {
2815
		killbyname("choparp");
2816
	} else {
2817
		$vipif = get_real_interface($interface);
2818
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2819
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2820
		}
2821
	}
2822

    
2823
	$paa = array();
2824
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2825

    
2826
		/* group by interface */
2827
		foreach ($config['virtualip']['vip'] as $vipent) {
2828
			if ($vipent['mode'] === "proxyarp") {
2829
				if ($vipent['interface']) {
2830
					$proxyif = $vipent['interface'];
2831
				} else {
2832
					$proxyif = "wan";
2833
				}
2834

    
2835
				if (!empty($interface) && $interface != $proxyif) {
2836
					continue;
2837
				}
2838

    
2839
				if (!is_array($paa[$proxyif])) {
2840
					$paa[$proxyif] = array();
2841
				}
2842

    
2843
				$paa[$proxyif][] = $vipent;
2844
			}
2845
		}
2846
	}
2847

    
2848
	if (!empty($interface)) {
2849
		if (is_array($paa[$interface])) {
2850
			$paaifip = get_interface_ip($interface);
2851
			if (!is_ipaddr($paaifip)) {
2852
				return;
2853
			}
2854
			$vipif = get_real_interface($interface);
2855
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2856
			$args .= $vipif . " auto";
2857
			foreach ($paa[$interface] as $paent) {
2858
				if (isset($paent['subnet'])) {
2859
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2860
				} else if (isset($paent['range'])) {
2861
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2862
				}
2863
			}
2864
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2865
		}
2866
	} else if (count($paa) > 0) {
2867
		foreach ($paa as $paif => $paents) {
2868
			$paaifip = get_interface_ip($paif);
2869
			if (!is_ipaddr($paaifip)) {
2870
				continue;
2871
			}
2872
			$vipif = get_real_interface($paif);
2873
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2874
			$args .= $vipif . " auto";
2875
			foreach ($paents as $paent) {
2876
				if (isset($paent['subnet'])) {
2877
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2878
				} else if (isset($paent['range'])) {
2879
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2880
				}
2881
			}
2882
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2883
		}
2884
	}
2885
}
2886

    
2887
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2888
	global $g, $config;
2889

    
2890
	if (is_array($config['virtualip']['vip'])) {
2891
		foreach ($config['virtualip']['vip'] as $vip) {
2892

    
2893
			$iface = $vip['interface'];
2894
			if (substr($iface, 0, 4) == "_vip")
2895
				$iface = get_configured_vip_interface($vip['interface']);
2896
			if ($iface != $interface)
2897
				continue;
2898
			if ($type == VIP_CARP) {
2899
				if ($vip['mode'] != "carp")
2900
					continue;
2901
			} elseif ($type == VIP_IPALIAS) {
2902
				if ($vip['mode'] != "ipalias")
2903
					continue;
2904
			} else {
2905
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2906
					continue;
2907
			}
2908

    
2909
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2910
				interface_vip_bring_down($vip);
2911
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2912
				interface_vip_bring_down($vip);
2913
			else if ($inet == "all")
2914
				interface_vip_bring_down($vip);
2915
		}
2916
	}
2917
}
2918

    
2919
function interfaces_vips_configure($interface = "") {
2920
	global $g, $config;
2921
	if (isset($config['system']['developerspew'])) {
2922
		$mt = microtime();
2923
		echo "interfaces_vips_configure() being called $mt\n";
2924
	}
2925
	$paa = array();
2926
	if (is_array($config['virtualip']['vip'])) {
2927
		$carp_setuped = false;
2928
		$anyproxyarp = false;
2929
		foreach ($config['virtualip']['vip'] as $vip) {
2930
			if ($interface <> "" && get_root_interface($vip['interface']) <> $interface) {
2931
				continue;
2932
			}
2933
			switch ($vip['mode']) {
2934
				case "proxyarp":
2935
					/* nothing it is handled on interface_proxyarp_configure() */
2936
					$anyproxyarp = true;
2937
					break;
2938
				case "ipalias":
2939
					interface_ipalias_configure($vip);
2940
					break;
2941
				case "carp":
2942
					if ($carp_setuped == false) {
2943
						$carp_setuped = true;
2944
					}
2945
					interface_carp_configure($vip);
2946
					break;
2947
			}
2948
		}
2949
		if ($carp_setuped == true) {
2950
			interfaces_sync_setup();
2951
		}
2952
		if ($anyproxyarp == true) {
2953
			interface_proxyarp_configure();
2954
		}
2955
	}
2956
}
2957

    
2958
function interface_ipalias_configure(&$vip) {
2959
	global $config;
2960

    
2961
	if ($vip['mode'] != 'ipalias') {
2962
		return;
2963
	}
2964

    
2965
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2966
	if ($realif != "lo0") {
2967
		$if = convert_real_interface_to_friendly_interface_name($realif);
2968
		if (!isset($config['interfaces'][$if]) ||
2969
		    !isset($config['interfaces'][$if]['enable'])) {
2970
			return;
2971
		}
2972
	}
2973

    
2974
	$af = 'inet';
2975
	if (is_ipaddrv6($vip['subnet'])) {
2976
		$af = 'inet6';
2977
	}
2978
	$iface = $vip['interface'];
2979
	$vhid = '';
2980
	if (substr($vip['interface'], 0, 4) == "_vip") {
2981
		$carpvip = get_configured_vip($vip['interface']);
2982
		$iface = $carpvip['interface'];
2983
		$vhid = "vhid {$carpvip['vhid']}";
2984
	}
2985
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2986
	unset($iface, $af, $realif, $carpvip, $vhid);
2987
}
2988

    
2989
function interface_carp_configure(&$vip, $maintenancemode_only = false) {
2990
	global $config, $g;
2991
	if (isset($config['system']['developerspew'])) {
2992
		$mt = microtime();
2993
		echo "interface_carp_configure() being called $mt\n";
2994
	}
2995

    
2996
	if ($vip['mode'] != "carp") {
2997
		return;
2998
	}
2999

    
3000
	$realif = get_real_interface($vip['interface']);
3001
	if (!does_interface_exist($realif)) {
3002
		file_notice("CARP", sprintf(gettext(
3003
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
3004
		    $vip['subnet']), "Firewall: Virtual IP", "");
3005
		return;
3006
	}
3007
	if ($realif != "lo0") {
3008
		if (!isset($config['interfaces'][$vip['interface']]) ||
3009
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
3010
			return;
3011
		}
3012
	}
3013

    
3014
	$vip_password = $vip['password'];
3015
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3016
	    $vip_password)));
3017
	if ($vip['password'] != "") {
3018
		$password = " pass {$vip_password}";
3019
	}
3020

    
3021
	$advbase = "";
3022
	if (!empty($vip['advbase'])) {
3023
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3024
	}
3025

    
3026
	$carp_maintenancemode = isset(
3027
	    $config["virtualip_carp_maintenancemode"]);
3028
	if ($carp_maintenancemode) {
3029
		$advskew = "advskew 254";
3030
	} else {
3031
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3032
	}
3033

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

    
3037
	if (!$maintenancemode_only) {
3038
		if (is_ipaddrv4($vip['subnet'])) {
3039
			mwexec("/sbin/ifconfig {$realif} " .
3040
			    escapeshellarg($vip['subnet']) . "/" .
3041
			    escapeshellarg($vip['subnet_bits']) .
3042
			    " alias vhid " . escapeshellarg($vip['vhid']));
3043
		} else if (is_ipaddrv6($vip['subnet'])) {
3044
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3045
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3046
			    escapeshellarg($vip['subnet_bits']) .
3047
			    " alias vhid " . escapeshellarg($vip['vhid']));
3048
		}
3049
	}
3050

    
3051
	return $realif;
3052
}
3053

    
3054
function interface_wireless_clone($realif, $wlcfg) {
3055
	global $config, $g;
3056
	/*   Check to see if interface has been cloned as of yet.
3057
	 *   If it has not been cloned then go ahead and clone it.
3058
	 */
3059
	$needs_clone = false;
3060
	if (is_array($wlcfg['wireless'])) {
3061
		$wlcfg_mode = $wlcfg['wireless']['mode'];
3062
	} else {
3063
		$wlcfg_mode = $wlcfg['mode'];
3064
	}
3065
	switch ($wlcfg_mode) {
3066
		case "hostap":
3067
			$mode = "wlanmode hostap";
3068
			break;
3069
		case "adhoc":
3070
			$mode = "wlanmode adhoc";
3071
			break;
3072
		default:
3073
			$mode = "";
3074
			break;
3075
	}
3076
	$baseif = interface_get_wireless_base($wlcfg['if']);
3077
	if (does_interface_exist($realif)) {
3078
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
3079
		$ifconfig_str = implode($output);
3080
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
3081
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
3082
			$needs_clone = true;
3083
		}
3084
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
3085
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
3086
			$needs_clone = true;
3087
		}
3088
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3089
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3090
			$needs_clone = true;
3091
		}
3092
	} else {
3093
		$needs_clone = true;
3094
	}
3095

    
3096
	if ($needs_clone == true) {
3097
		/* remove previous instance if it exists */
3098
		if (does_interface_exist($realif)) {
3099
			pfSense_interface_destroy($realif);
3100
		}
3101

    
3102
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3103
		// Create the new wlan interface. FreeBSD returns the new interface name.
3104
		// example:  wlan2
3105
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3106
		if ($ret <> 0) {
3107
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3108
			return false;
3109
		}
3110
		$newif = trim($out[0]);
3111
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3112
		pfSense_interface_rename($newif, $realif);
3113
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3114
	}
3115
	return true;
3116
}
3117

    
3118
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3119
	global $config, $g;
3120

    
3121
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3122
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3123
				 'regdomain', 'regcountry', 'reglocation');
3124

    
3125
	if (!is_interface_wireless($ifcfg['if'])) {
3126
		return;
3127
	}
3128

    
3129
	$baseif = interface_get_wireless_base($ifcfg['if']);
3130

    
3131
	// Sync shared settings for assigned clones
3132
	$iflist = get_configured_interface_list(true);
3133
	foreach ($iflist as $if) {
3134
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
3135
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
3136
				foreach ($shared_settings as $setting) {
3137
					if ($sync_changes) {
3138
						if (isset($ifcfg['wireless'][$setting])) {
3139
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
3140
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3141
							unset($config['interfaces'][$if]['wireless'][$setting]);
3142
						}
3143
					} else {
3144
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3145
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
3146
						} else if (isset($ifcfg['wireless'][$setting])) {
3147
							unset($ifcfg['wireless'][$setting]);
3148
						}
3149
					}
3150
				}
3151
				if (!$sync_changes) {
3152
					break;
3153
				}
3154
			}
3155
		}
3156
	}
3157

    
3158
	// Read or write settings at shared area
3159
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3160
		foreach ($shared_settings as $setting) {
3161
			if ($sync_changes) {
3162
				if (isset($ifcfg['wireless'][$setting])) {
3163
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3164
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3165
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3166
				}
3167
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3168
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3169
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3170
				} else if (isset($ifcfg['wireless'][$setting])) {
3171
					unset($ifcfg['wireless'][$setting]);
3172
				}
3173
			}
3174
		}
3175
	}
3176

    
3177
	// Sync the mode on the clone creation page with the configured mode on the interface
3178
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3179
		foreach ($config['wireless']['clone'] as &$clone) {
3180
			if ($clone['cloneif'] == $ifcfg['if']) {
3181
				if ($sync_changes) {
3182
					$clone['mode'] = $ifcfg['wireless']['mode'];
3183
				} else {
3184
					$ifcfg['wireless']['mode'] = $clone['mode'];
3185
				}
3186
				break;
3187
			}
3188
		}
3189
		unset($clone);
3190
	}
3191
}
3192

    
3193
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3194
	global $config, $g;
3195

    
3196
	/*    open up a shell script that will be used to output the commands.
3197
	 *    since wireless is changing a lot, these series of commands are fragile
3198
	 *    and will sometimes need to be verified by a operator by executing the command
3199
	 *    and returning the output of the command to the developers for inspection.  please
3200
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3201
	 */
3202

    
3203
	// Remove script file
3204
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3205

    
3206
	// Clone wireless nic if needed.
3207
	interface_wireless_clone($if, $wl);
3208

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

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

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

    
3218
	/* set values for /path/program */
3219
	if (file_exists("/usr/local/sbin/hostapd")) {
3220
		$hostapd = "/usr/local/sbin/hostapd";
3221
	} else {
3222
		$hostapd = "/usr/sbin/hostapd";
3223
	}
3224
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3225
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3226
	} else {
3227
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3228
	}
3229
	$ifconfig = "/sbin/ifconfig";
3230
	$sysctl = "/sbin/sysctl";
3231
	$sysctl_args = "-q";
3232
	$killall = "/usr/bin/killall";
3233

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

    
3236
	$wlcmd = array();
3237
	$wl_sysctl = array();
3238
	/* Set a/b/g standard */
3239
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3240
	/* skip mode entirely for "auto" */
3241
	if ($wlcfg['standard'] != "auto") {
3242
		$wlcmd[] = "mode " . escapeshellarg($standard);
3243
	}
3244

    
3245
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3246
	 * to prevent massive packet loss under certain conditions. */
3247
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3248
		$wlcmd[] = "-ampdu";
3249
	}
3250

    
3251
	/* Set ssid */
3252
	if ($wlcfg['ssid']) {
3253
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3254
	}
3255

    
3256
	/* Set 802.11g protection mode */
3257
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3258

    
3259
	/* set wireless channel value */
3260
	if (isset($wlcfg['channel'])) {
3261
		if ($wlcfg['channel'] == "0") {
3262
			$wlcmd[] = "channel any";
3263
		} else {
3264
			if ($wlcfg['channel_width'] != "0") {
3265
				$channel_width = ":" . $wlcfg['channel_width'];
3266
			} else {
3267
				$channel_width = '';
3268
			}
3269
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3270
		}
3271
	}
3272

    
3273
	/* Set antenna diversity value */
3274
	if (isset($wlcfg['diversity'])) {
3275
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3276
	}
3277

    
3278
	/* Set txantenna value */
3279
	if (isset($wlcfg['txantenna'])) {
3280
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3281
	}
3282

    
3283
	/* Set rxantenna value */
3284
	if (isset($wlcfg['rxantenna'])) {
3285
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3286
	}
3287

    
3288
	/* set Distance value */
3289
	if ($wlcfg['distance']) {
3290
		$distance = escapeshellarg($wlcfg['distance']);
3291
	}
3292

    
3293
	/* Set wireless hostap mode */
3294
	if ($wlcfg['mode'] == "hostap") {
3295
		$wlcmd[] = "mediaopt hostap";
3296
	} else {
3297
		$wlcmd[] = "-mediaopt hostap";
3298
	}
3299

    
3300
	/* Set wireless adhoc mode */
3301
	if ($wlcfg['mode'] == "adhoc") {
3302
		$wlcmd[] = "mediaopt adhoc";
3303
	} else {
3304
		$wlcmd[] = "-mediaopt adhoc";
3305
	}
3306

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

    
3309
	/* handle hide ssid option */
3310
	if (isset($wlcfg['hidessid']['enable'])) {
3311
		$wlcmd[] = "hidessid";
3312
	} else {
3313
		$wlcmd[] = "-hidessid";
3314
	}
3315

    
3316
	/* handle pureg (802.11g) only option */
3317
	if (isset($wlcfg['pureg']['enable'])) {
3318
		$wlcmd[] = "mode 11g pureg";
3319
	} else {
3320
		$wlcmd[] = "-pureg";
3321
	}
3322

    
3323
	/* handle puren (802.11n) only option */
3324
	if (isset($wlcfg['puren']['enable'])) {
3325
		$wlcmd[] = "puren";
3326
	} else {
3327
		$wlcmd[] = "-puren";
3328
	}
3329

    
3330
	/* enable apbridge option */
3331
	if (isset($wlcfg['apbridge']['enable'])) {
3332
		$wlcmd[] = "apbridge";
3333
	} else {
3334
		$wlcmd[] = "-apbridge";
3335
	}
3336

    
3337
	/* handle turbo option */
3338
	if (isset($wlcfg['turbo']['enable'])) {
3339
		$wlcmd[] = "mediaopt turbo";
3340
	} else {
3341
		$wlcmd[] = "-mediaopt turbo";
3342
	}
3343

    
3344
	/* handle txpower setting */
3345
	// or don't. this has issues at the moment.
3346
	/*
3347
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3348
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3349
	}*/
3350

    
3351
	/* handle wme option */
3352
	if (isset($wlcfg['wme']['enable'])) {
3353
		$wlcmd[] = "wme";
3354
	} else {
3355
		$wlcmd[] = "-wme";
3356
	}
3357

    
3358
	/* Enable wpa if it's configured. No WEP support anymore. */
3359
	if (isset($wlcfg['wpa']['enable'])) {
3360
		$wlcmd[] = "authmode wpa wepmode off ";
3361
	} else {
3362
		$wlcmd[] = "authmode open wepmode off ";
3363
	}
3364

    
3365
	kill_hostapd($if);
3366
	mwexec(kill_wpasupplicant("{$if}"));
3367

    
3368
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3369

    
3370
	switch ($wlcfg['mode']) {
3371
		case 'bss':
3372
			if (isset($wlcfg['wpa']['enable'])) {
3373
				$wpa .= <<<EOD
3374
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3375
ctrl_interface_group=0
3376
ap_scan=1
3377
#fast_reauth=1
3378
network={
3379
ssid="{$wlcfg['ssid']}"
3380
scan_ssid=1
3381
priority=5
3382
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3383
psk="{$wlcfg['wpa']['passphrase']}"
3384
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3385
group={$wlcfg['wpa']['wpa_pairwise']}
3386
}
3387
EOD;
3388

    
3389
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
3390
				unset($wpa);
3391
			}
3392
			break;
3393
		case 'hostap':
3394
			if (!empty($wlcfg['wpa']['passphrase'])) {
3395
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3396
			} else {
3397
				$wpa_passphrase = "";
3398
			}
3399
			if (isset($wlcfg['wpa']['enable'])) {
3400
				$wpa .= <<<EOD
3401
interface={$if}
3402
driver=bsd
3403
logger_syslog=-1
3404
logger_syslog_level=0
3405
logger_stdout=-1
3406
logger_stdout_level=0
3407
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3408
ctrl_interface={$g['varrun_path']}/hostapd
3409
ctrl_interface_group=wheel
3410
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3411
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3412
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3413
ssid={$wlcfg['ssid']}
3414
debug={$wlcfg['wpa']['debug_mode']}
3415
wpa={$wlcfg['wpa']['wpa_mode']}
3416
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3417
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3418
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3419
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3420
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3421
{$wpa_passphrase}
3422

    
3423
EOD;
3424

    
3425
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3426
					$wpa .= <<<EOD
3427
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3428
rsn_preauth=1
3429
rsn_preauth_interfaces={$if}
3430

    
3431
EOD;
3432
				}
3433
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3434
					$wpa .= "ieee8021x=1\n";
3435

    
3436
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3437
						$auth_server_port = "1812";
3438
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3439
							$auth_server_port = intval($wlcfg['auth_server_port']);
3440
						}
3441
						$wpa .= <<<EOD
3442

    
3443
auth_server_addr={$wlcfg['auth_server_addr']}
3444
auth_server_port={$auth_server_port}
3445
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3446

    
3447
EOD;
3448
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3449
							$auth_server_port2 = "1812";
3450
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3451
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3452
							}
3453

    
3454
							$wpa .= <<<EOD
3455
auth_server_addr={$wlcfg['auth_server_addr2']}
3456
auth_server_port={$auth_server_port2}
3457
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3458

    
3459
EOD;
3460
						}
3461
					}
3462
				}
3463

    
3464
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3465
				unset($wpa);
3466
			}
3467
			break;
3468
	}
3469

    
3470
	/*
3471
	 *    all variables are set, lets start up everything
3472
	 */
3473

    
3474
	$baseif = interface_get_wireless_base($if);
3475
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3476
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3477

    
3478
	/* set sysctls for the wireless interface */
3479
	if (!empty($wl_sysctl)) {
3480
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3481
		foreach ($wl_sysctl as $wl_sysctl_line) {
3482
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3483
		}
3484
	}
3485

    
3486
	/* set ack timers according to users preference (if he/she has any) */
3487
	if ($distance) {
3488
		fwrite($fd_set, "# Enable ATH distance settings\n");
3489
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3490
	}
3491

    
3492
	if (isset($wlcfg['wpa']['enable'])) {
3493
		if ($wlcfg['mode'] == "bss") {
3494
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3495
		}
3496
		if ($wlcfg['mode'] == "hostap") {
3497
			/* add line to script to restore old mac to make hostapd happy */
3498
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3499
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3500
				$if_curmac = get_interface_mac($if);
3501
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3502
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3503
						" link " . escapeshellarg($if_oldmac) . "\n");
3504
				}
3505
			}
3506

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

    
3509
			/* add line to script to restore spoofed mac after running hostapd */
3510
			if ($wl['spoofmac']) {
3511
				$if_curmac = get_interface_mac($if);
3512
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3513
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3514
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3515
				}
3516
			}
3517
		}
3518
	}
3519

    
3520
	fclose($fd_set);
3521

    
3522
	/* Making sure regulatory settings have actually changed
3523
	 * before applying, because changing them requires bringing
3524
	 * down all wireless networks on the interface. */
3525
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3526
	$ifconfig_str = implode($output);
3527
	unset($output);
3528
	$reg_changing = false;
3529

    
3530
	/* special case for the debug country code */
3531
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3532
		$reg_changing = true;
3533
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3534
		$reg_changing = true;
3535
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3536
		$reg_changing = true;
3537
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3538
		$reg_changing = true;
3539
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3540
		$reg_changing = true;
3541
	}
3542

    
3543
	if ($reg_changing) {
3544
		/* set regulatory domain */
3545
		if ($wlcfg['regdomain']) {
3546
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3547
		}
3548

    
3549
		/* set country */
3550
		if ($wlcfg['regcountry']) {
3551
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3552
		}
3553

    
3554
		/* set location */
3555
		if ($wlcfg['reglocation']) {
3556
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3557
		}
3558

    
3559
		$wlregcmd_args = implode(" ", $wlregcmd);
3560

    
3561
		/* build a complete list of the wireless clones for this interface */
3562
		$clone_list = array();
3563
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3564
			$clone_list[] = interface_get_wireless_clone($baseif);
3565
		}
3566
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3567
			foreach ($config['wireless']['clone'] as $clone) {
3568
				if ($clone['if'] == $baseif) {
3569
					$clone_list[] = $clone['cloneif'];
3570
				}
3571
			}
3572
		}
3573

    
3574
		/* find which clones are up and bring them down */
3575
		$clones_up = array();
3576
		foreach ($clone_list as $clone_if) {
3577
			$clone_status = pfSense_get_interface_addresses($clone_if);
3578
			if ($clone_status['status'] == 'up') {
3579
				$clones_up[] = $clone_if;
3580
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3581
			}
3582
		}
3583

    
3584
		/* apply the regulatory settings */
3585
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3586
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3587

    
3588
		/* bring the clones back up that were previously up */
3589
		foreach ($clones_up as $clone_if) {
3590
			interfaces_bring_up($clone_if);
3591

    
3592
			/*
3593
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3594
			 * is in infrastructure mode, and WPA is enabled.
3595
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3596
			 */
3597
			if ($clone_if != $if) {
3598
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3599
				if ((!empty($friendly_if)) &&
3600
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3601
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3602
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3603
				}
3604
			}
3605
		}
3606
	}
3607

    
3608
	/* The mode must be specified in a separate command before ifconfig
3609
	 * will allow the mode and channel at the same time in the next.
3610
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3611
	 */
3612
	if ($wlcfg['mode'] == "hostap") {
3613
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3614
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3615
	}
3616

    
3617
	/* configure wireless */
3618
	$wlcmd_args = implode(" ", $wlcmd);
3619
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3620
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3621
	/* Bring the interface up only after setting up all the other parameters. */
3622
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3623
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3624
	fclose($wlan_setup_log);
3625

    
3626
	unset($wlcmd_args, $wlcmd);
3627

    
3628

    
3629
	sleep(1);
3630
	/* execute hostapd and wpa_supplicant if required in shell */
3631
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3632

    
3633
	return 0;
3634

    
3635
}
3636

    
3637
function kill_hostapd($interface) {
3638
	global $g;
3639

    
3640
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3641
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3642
	}
3643
}
3644

    
3645
function kill_wpasupplicant($interface) {
3646
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3647
}
3648

    
3649
function find_dhclient_process($interface) {
3650
	if ($interface) {
3651
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3652
	} else {
3653
		$pid = 0;
3654
	}
3655

    
3656
	return intval($pid);
3657
}
3658

    
3659
function kill_dhclient_process($interface) {
3660
	if (empty($interface) || !does_interface_exist($interface)) {
3661
		return;
3662
	}
3663

    
3664
	$i = 0;
3665
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3666
		/* 3rd time make it die for sure */
3667
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3668
		posix_kill($pid, $sig);
3669
		sleep(1);
3670
		$i++;
3671
	}
3672
	unset($i);
3673
}
3674

    
3675
function find_dhcp6c_process($interface) {
3676
	global $g;
3677

    
3678
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3679
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3680
	} else {
3681
		return(false);
3682
	}
3683

    
3684
	return intval($pid);
3685
}
3686

    
3687
function kill_dhcp6client_process($interface, $force, $release = false) {
3688
	global $g;
3689

    
3690
	$i = 0;
3691

    
3692
	/*
3693
	Beware of the following: Reason, the interface may be down, but
3694
	dhcp6c may still be running, it just complains it cannot send
3695
	and carries on. Commented out as will stop the call to kill.
3696

    
3697
	if (empty($interface) || !does_interface_exist($interface)) {
3698
		return;
3699
	}
3700
	*/
3701

    
3702
	/*********** Notes on signals for dhcp6c and this function *************
3703

    
3704
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3705
	a release and waiting for the response that never comes.
3706
	So we need to tell it that the interface is down and to just die quickly
3707
	otherwise a new client may launch and we have duplicate proceses.
3708
	In this case use SIGUSR1.
3709

    
3710
	If we want to exit normally obeying the no release flag then use SIGTERM.
3711
	If we want to exit with a release overiding the no release flag then
3712
	use SIGUSR2.
3713

    
3714
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3715
	exit quickly without sending release signals.
3716

    
3717
	If $Force is set to false and $release is also set to false dhcp6c will
3718
	follow the no-release flag.
3719

    
3720
	If $Force is set to false and $release is true then dhcp6c will send a
3721
	release regardless of the no-release flag.
3722
	***********************************************************************/
3723

    
3724
	if ($force == true) {
3725
		$psig=SIGUSR1;
3726
	} else if ($release == false) {
3727
		$psig=SIGTERM;
3728
	} else {
3729
		$psig=SIGUSR2;
3730
	}
3731

    
3732
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3733
		/* 3rd time make it die for sure */
3734
		$sig = ($i == 2 ? SIGKILL : $psig);
3735
		posix_kill($pid, $sig);
3736
		sleep(1);
3737
		$i++;
3738
	}
3739
	/* Clear the RTSOLD script created lock & tidy up */
3740
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3741
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
3742
}
3743
function reset_dhcp6client_process($interface) {
3744

    
3745
	$pid = find_dhcp6c_process($interface);
3746

    
3747
	if($pid != 0) {
3748
		posix_kill($pid, SIGHUP);
3749
	}
3750
}
3751

    
3752
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3753
	global $g;
3754

    
3755
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3756
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3757

    
3758
	/*
3759
	 * Only run this if the lock does not exist. In theory the lock being
3760
	 * there in this mode means the user has selected dhcp6withoutRA while
3761
	 * a session is active in the other mode.
3762
	 *
3763
	 * It should not happen as the process should have been killed and the
3764
	 * lock deleted.
3765
	 */
3766

    
3767
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
3768
		kill_dhcp6client_process($interface, true);
3769
		/* Lock it to avoid multiple runs */
3770
		touch("/tmp/dhcp6c_{$interface}_lock");
3771
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3772
		    "{$noreleaseOption} " .
3773
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
3774
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
3775
		    $interface);
3776
		log_error(sprintf(gettext(
3777
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
3778
		    $interface));
3779
	}
3780
}
3781

    
3782
function interface_virtual_create($interface) {
3783
	global $config;
3784

    
3785
	if (interface_is_vlan($interface) != NULL) {
3786
		interfaces_vlan_configure($interface);
3787
	} else if (substr($interface, 0, 3) == "gre") {
3788
		interfaces_gre_configure(0, $interface);
3789
	} else if (substr($interface, 0, 3) == "gif") {
3790
		interfaces_gif_configure(0, $interface);
3791
	} else if (substr($interface, 0, 5) == "ovpns") {
3792
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3793
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3794
				if ($interface == "ovpns{$server['vpnid']}") {
3795
					if (!function_exists('openvpn_resync')) {
3796
						require_once('openvpn.inc');
3797
					}
3798
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3799
					openvpn_resync('server', $server);
3800
				}
3801
			}
3802
			unset($server);
3803
		}
3804
	} else if (substr($interface, 0, 5) == "ovpnc") {
3805
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3806
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3807
				if ($interface == "ovpnc{$client['vpnid']}") {
3808
					if (!function_exists('openvpn_resync')) {
3809
						require_once('openvpn.inc');
3810
					}
3811
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3812
					openvpn_resync('client', $client);
3813
				}
3814
			}
3815
			unset($client);
3816
		}
3817
	} else if (substr($interface, 0, 5) == "ipsec") {
3818
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
3819
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
3820
				if ($ph1ent['disabled']) {
3821
					continue;
3822
				}
3823
				if ($interface == "ipsec{$ph1ent['ikeid']}") {
3824
					interface_ipsec_vti_configure($ph1ent);
3825
				}
3826
			}
3827
		}
3828
	} else if (substr($interface, 0, 4) == "lagg") {
3829
		interfaces_lagg_configure($interface);
3830
	} else if (substr($interface, 0, 6) == "bridge") {
3831
		interfaces_bridge_configure(0, $interface);
3832
	}
3833
}
3834

    
3835
function interface_vlan_mtu_configured($iface) {
3836
	global $config;
3837

    
3838
	$mtu = 0;
3839
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3840
		foreach ($config['vlans']['vlan'] as $vlan) {
3841

    
3842
			if ($vlan['vlanif'] != $iface)
3843
				continue;
3844

    
3845
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3846
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3847
				/* VLAN MTU */
3848
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3849
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3850
				/* Parent MTU */
3851
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3852
			}
3853
		}
3854
	}
3855

    
3856
	return $mtu;
3857
}
3858

    
3859
function interface_mtu_wanted_for_pppoe($realif) {
3860
	global $config;
3861

    
3862
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3863
		return 0;
3864

    
3865
	$mtu = 0;
3866
	foreach ($config['ppps']['ppp'] as $ppp) {
3867
		if ($ppp['type'] != "pppoe") {
3868
			continue;
3869
		}
3870

    
3871
		$mtus = array();
3872
		if (!empty($ppp['mtu'])) {
3873
			$mtus = explode(',', $ppp['mtu']);
3874
		}
3875
		$ports = explode(',', $ppp['ports']);
3876

    
3877
		foreach ($ports as $pid => $port) {
3878
			$parentifa = get_parent_interface($port);
3879
			$parentif = $parentifa[0];
3880
			if ($parentif != $realif)
3881
				continue;
3882

    
3883
			// there is an MTU configured on the port in question
3884
			if (!empty($mtus[$pid])) {
3885
				$mtu = intval($mtus[$pid]) + 8;
3886
			// or use the MTU configured on the interface ...
3887
			} elseif (is_array($config['interfaces'])) {
3888
				foreach ($config['interfaces'] as $interface) {
3889
					if ($interface['if'] == $ppp['if'] &&
3890
					    !empty($interface['mtu'])) {
3891
						$mtu = intval($interface['mtu']) + 8;
3892
						break;
3893
					}
3894
				}
3895
			}
3896
		}
3897
	}
3898

    
3899
	return $mtu;
3900
}
3901

    
3902
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3903
	global $config, $g;
3904
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3905
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3906

    
3907
	$wancfg = $config['interfaces'][$interface];
3908

    
3909
	if (!isset($wancfg['enable'])) {
3910
		return;
3911
	}
3912

    
3913
	$realif = get_real_interface($interface);
3914
	$realhwif_array = get_parent_interface($interface);
3915
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3916
	$realhwif = $realhwif_array[0];
3917

    
3918
	$mac_if_cfg = $wancfg;
3919
	if (interface_is_vlan($realif)) {
3920
		$mac_if = convert_real_interface_to_friendly_interface_name(
3921
		    $realhwif);
3922
		if (is_array($config['interfaces'][$mac_if])) {
3923
			$mac_if_cfg = $config['interfaces'][$mac_if];
3924
		} else {
3925
			$mac_if = $interface;
3926
		}
3927
	}
3928

    
3929
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn") && !(substr($realif, 0, 5) == "ipsec")) {
3930
		/* remove all IPv4 and IPv6 addresses */
3931
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3932
		if (is_array($tmpifaces)) {
3933
			foreach ($tmpifaces as $tmpiface) {
3934
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3935
					if (!is_linklocal($tmpiface)) {
3936
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3937
					}
3938
				} elseif (strstr($tmpiface, "fe80::1:1")) {
3939
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 fe80::1:1 -alias");
3940
				} else {
3941
					if (is_subnetv4($tmpiface)) {
3942
						$tmpip = explode('/', $tmpiface);
3943
						$tmpip = $tmpip[0];
3944
					} else {
3945
						$tmpip = $tmpiface;
3946
					}
3947
					pfSense_interface_deladdress($realif, $tmpip);
3948
				}
3949
			}
3950
		}
3951

    
3952
		/* only bring down the interface when both v4 and v6 are set to NONE */
3953
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3954
			interface_bring_down($interface);
3955
		}
3956
	}
3957

    
3958
	$interface_to_check = $realif;
3959
	if (interface_isppp_type($interface)) {
3960
		$interface_to_check = $realhwif;
3961
	}
3962

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

    
3968
	/* Disable Accepting router advertisements unless specifically requested */
3969
	if ($g['debug']) {
3970
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3971
	}
3972
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
3973
	{
3974
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3975
	}
3976
	/* wireless configuration? */
3977
	if (is_array($wancfg['wireless']) && !$linkupevent) {
3978
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3979
	}
3980

    
3981
	$current_mac = get_interface_mac($realhwif);
3982
	$vendor_mac = get_interface_vendor_mac($realhwif);
3983

    
3984
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
3985
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
3986

    
3987
		interface_set_macaddr($realhwif, $mac_addr);
3988
	} else {
3989
		/*
3990
		 * this is not a valid mac address.  generate a
3991
		 * temporary mac address so the machine can get online.
3992
		 */
3993
		echo gettext("Generating new MAC address.");
3994
		$random_mac = generate_random_mac_address();
3995
		interface_set_macaddr($realhwif, $random_mac);
3996
		$config['interfaces'][$mac_if]['spoofmac'] = $random_mac;
3997
		write_config(sprintf(gettext('The invalid MAC address ' .
3998
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
3999
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
4000
		file_notice("MAC Address altered", sprintf(gettext('The ' .
4001
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
4002
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
4003
		    $random_mac), "Interfaces");
4004
	}
4005

    
4006
	/* media */
4007
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4008
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4009
		if ($wancfg['media']) {
4010
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4011
		}
4012
		if ($wancfg['mediaopt']) {
4013
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4014
		}
4015
		mwexec($cmd);
4016
	}
4017

    
4018
	/* Apply hw offloading policies as configured */
4019
	enable_hardware_offloading($interface);
4020

    
4021
	/* invalidate interface/ip/sn cache */
4022
	get_interface_arr(true);
4023
	unset($interface_ip_arr_cache[$realif]);
4024
	unset($interface_sn_arr_cache[$realif]);
4025
	unset($interface_ipv6_arr_cache[$realif]);
4026
	unset($interface_snv6_arr_cache[$realif]);
4027

    
4028
	$tunnelif = substr($realif, 0, 3);
4029

    
4030
	$mtuif = $realif;
4031
	$mtuhwif = $realhwif;
4032

    
4033
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4034
	if (interface_isppp_type($interface)) {
4035
		$mtuif = $realhwif;
4036
		$mtuhwif_array = get_parent_interface($mtuif);
4037
		$mtuhwif = $mtuhwif_array[0];
4038
	}
4039

    
4040
	$wantedmtu = 0;
4041
	if (is_array($config['interfaces'])) {
4042
		foreach ($config['interfaces'] as $tmpinterface) {
4043
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4044
				$wantedmtu = $tmpinterface['mtu'];
4045
				break;
4046
			}
4047
		}
4048
	}
4049

    
4050
	/* MTU is not specified for interface, try the pppoe settings. */
4051
	if ($wantedmtu == 0) {
4052
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4053
	}
4054
	if (($wantedmtu == 0) && (interface_is_vlan($mtuif) != NULL) && interface_isppp_type($interface)) {
4055
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4056
	}
4057
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4058
		/* set MTU to 1400 for GRE over IPsec */
4059
		if (is_greipsec($mtuif)) {
4060
			$wantedmtu = 1400;
4061
		} else {
4062
			$wantedmtu = 1476;
4063
		}
4064
	}
4065
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4066
		$wantedmtu = 1280;
4067
	}
4068

    
4069
	/* Set the MTU to 1500 if no explicit MTU configured. */
4070
	if ($wantedmtu == 0) {
4071
		$wantedmtu = 1500; /* Default */
4072
	}
4073

    
4074
	if (interface_is_vlan($mtuif) != NULL) {
4075
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4076
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
4077
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
4078
			if ($wancfg['mtu'] > $parentmtu) {
4079
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4080
			}
4081
		}
4082

    
4083
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4084

    
4085
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4086
			$configuredmtu = $parentmtu;
4087
		if ($configuredmtu != 0)
4088
			$mtu = $configuredmtu;
4089
		else
4090
			$mtu = $wantedmtu;
4091

    
4092
		/* Set the parent MTU. */
4093
		if (get_interface_mtu($mtuhwif) < $mtu)
4094
			set_interface_mtu($mtuhwif, $mtu);
4095
		/* Set the VLAN MTU. */
4096
		if (get_interface_mtu($mtuif) != $mtu)
4097
			set_interface_mtu($mtuif, $mtu);
4098
	} else if (substr($mtuif, 0, 4) == 'lagg') {
4099
		/* LAGG interface must be destroyed and re-created to change MTU */
4100
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4101
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
4102
				foreach ($config['laggs']['lagg'] as $lagg) {
4103
					if ($lagg['laggif'] == $mtuif) {
4104
						interface_lagg_configure($lagg);
4105
						break;
4106
					}
4107
				}
4108
			}
4109
		}
4110
	} else {
4111
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4112
			pfSense_interface_mtu($mtuif, $wantedmtu);
4113
			set_ipv6routes_mtu($mtuif, $wantedmtu);
4114
		}
4115
	}
4116
	/* XXX: What about gre/gif/.. ? */
4117

    
4118
	if (does_interface_exist($wancfg['if'])) {
4119
		interfaces_bring_up($wancfg['if']);
4120
	}
4121

    
4122
	switch ($wancfg['ipaddr']) {
4123
		case 'dhcp':
4124
			interface_dhcp_configure($interface);
4125
			break;
4126
		case 'pppoe':
4127
		case 'l2tp':
4128
		case 'pptp':
4129
		case 'ppp':
4130
			interface_ppps_configure($interface);
4131
			break;
4132
		default:
4133
			/* XXX: Kludge for now related to #3280 */
4134
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4135
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4136
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4137
				}
4138
			}
4139
			break;
4140
	}
4141

    
4142
	switch ($wancfg['ipaddrv6']) {
4143
		case 'slaac':
4144
		case 'dhcp6':
4145
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4146
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4147
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4148
			/* Remove the check file. Should not be there but just in case */
4149
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
4150
			log_error(gettext("calling interface_dhcpv6_configure."));
4151
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
4152
				interface_dhcpv6_configure($interface, $wancfg);
4153
			}
4154
			break;
4155
		case '6rd':
4156
			interface_6rd_configure($interface, $wancfg);
4157
			break;
4158
		case '6to4':
4159
			interface_6to4_configure($interface, $wancfg);
4160
			break;
4161
		case 'track6':
4162
			interface_track6_configure($interface, $wancfg, $linkupevent);
4163
			break;
4164
		default:
4165
			/* XXX: Kludge for now related to #3280 */
4166
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4167
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4168
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4169
					// FIXME: Add IPv6 Support to the pfSense module
4170
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4171
				}
4172
			}
4173
			break;
4174
	}
4175

    
4176
	interface_netgraph_needed($interface);
4177

    
4178
	if (!platform_booting()) {
4179
		link_interface_to_vips($interface, "update");
4180

    
4181
		if ($tunnelif != 'gre') {
4182
			unset($gre);
4183
			$gre = link_interface_to_gre($interface);
4184
			if (!empty($gre)) {
4185
				array_walk($gre, 'interface_gre_configure');
4186
			}
4187
		}
4188

    
4189
		if ($tunnelif != 'gif') {
4190
			unset($gif);
4191
			$gif = link_interface_to_gif ($interface);
4192
			if (!empty($gif)) {
4193
				array_walk($gif, 'interface_gif_configure');
4194
			}
4195
		}
4196

    
4197
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4198
			unset($bridgetmp);
4199
			$bridgetmp = link_interface_to_bridge($interface);
4200
			if (!empty($bridgetmp)) {
4201
				interface_bridge_add_member($bridgetmp, $realif);
4202
			}
4203
		}
4204

    
4205
		$grouptmp = link_interface_to_group($interface);
4206
		if (!empty($grouptmp)) {
4207
			array_walk($grouptmp, 'interface_group_add_member');
4208
		}
4209

    
4210
		if ($interface == "lan") {
4211
			/* make new hosts file */
4212
			system_hosts_generate();
4213
		}
4214

    
4215
		if ($reloadall == true) {
4216

    
4217
			/* reconfigure static routes (kernel may have deleted them) */
4218
			system_routing_configure($interface);
4219

    
4220
			/* reload ipsec tunnels */
4221
			send_event("service reload ipsecdns");
4222

    
4223
			if (isset($config['dnsmasq']['enable'])) {
4224
				services_dnsmasq_configure();
4225
			}
4226

    
4227
			if (isset($config['unbound']['enable'])) {
4228
				services_unbound_configure();
4229
			}
4230

    
4231
			/* update dyndns */
4232
			send_event("service reload dyndns {$interface}");
4233

    
4234
			/* reload captive portal */
4235
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4236
				require_once('captiveportal.inc');
4237
			}
4238
			captiveportal_init_rules_byinterface($interface);
4239
		}
4240
	}
4241

    
4242
	if (!empty($wancfg['descr'])) {
4243
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4244
	};
4245

    
4246
	interfaces_staticarp_configure($interface);
4247
	return 0;
4248
}
4249

    
4250
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4251
	global $config, $g;
4252

    
4253
	if (!is_array($wancfg)) {
4254
		return;
4255
	}
4256

    
4257
	if (!isset($wancfg['enable'])) {
4258
		return;
4259
	}
4260

    
4261
	/* If the interface is not configured via another, exit */
4262
	if (empty($wancfg['track6-interface'])) {
4263
		return;
4264
	}
4265

    
4266
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4267
	$realif = get_real_interface($interface);
4268
	$linklocal = find_interface_ipv6_ll($realif, true);
4269
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4270
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4271
	}
4272

    
4273
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4274
	if (!isset($trackcfg['enable'])) {
4275
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4276
		return;
4277
	}
4278

    
4279
	switch ($trackcfg['ipaddrv6']) {
4280
		case "6to4":
4281
			if ($g['debug']) {
4282
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4283
			}
4284
			interface_track6_6to4_configure($interface, $wancfg);
4285
			break;
4286
		case "6rd":
4287
			if ($g['debug']) {
4288
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4289
			}
4290
			interface_track6_6rd_configure($interface, $wancfg);
4291
			break;
4292
		case "dhcp6":
4293
			if ($linkupevent == true) {
4294
				/*
4295
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4296
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4297
				 *
4298
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4299
				 */
4300
				$parentrealif = get_real_interface($wancfg['track6-interface']);
4301
				$pidv6 = find_dhcp6c_process($parentrealif);
4302
				if ($pidv6) {
4303
					posix_kill($pidv6, SIGHUP);
4304
				}
4305
			}
4306
			break;
4307
	}
4308

    
4309
	if ($linkupevent == false && !platform_booting()) {
4310
		if (!function_exists('services_dhcpd_configure')) {
4311
			require_once("services.inc");
4312
		}
4313

    
4314
		/* restart dns servers (defering dhcpd reload) */
4315
		if (isset($config['unbound']['enable'])) {
4316
			services_unbound_configure(false);
4317
		}
4318
		if (isset($config['dnsmasq']['enable'])) {
4319
			services_dnsmasq_configure(false);
4320
		}
4321

    
4322
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4323
		services_dhcpd_configure("inet6");
4324
	}
4325

    
4326
	return 0;
4327
}
4328

    
4329
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4330
	global $config, $g;
4331
	global $interface_ipv6_arr_cache;
4332
	global $interface_snv6_arr_cache;
4333

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

    
4338
	/* If the interface is not configured via another, exit */
4339
	if (empty($lancfg['track6-interface'])) {
4340
		return;
4341
	}
4342

    
4343
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4344
	if (empty($wancfg)) {
4345
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4346
		return;
4347
	}
4348

    
4349
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4350
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4351
		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']));
4352
		return;
4353
	}
4354
	$hexwanv4 = return_hex_ipv4($ip4address);
4355

    
4356
	/* create the long prefix notation for math, save the prefix length */
4357
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4358
	$rd6prefixlen = $rd6prefix[1];
4359
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4360

    
4361
	/* binary presentation of the prefix for all 128 bits. */
4362
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4363

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

    
4369
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4370
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4371
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4372
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4373
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4374
	/* fill the rest out with zeros */
4375
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4376

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

    
4380
	$lanif = get_real_interface($interface);
4381
	$oip = find_interface_ipv6($lanif);
4382
	if (is_ipaddrv6($oip)) {
4383
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4384
	}
4385
	unset($interface_ipv6_arr_cache[$lanif]);
4386
	unset($interface_snv6_arr_cache[$lanif]);
4387
	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));
4388
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4389

    
4390
	return 0;
4391
}
4392

    
4393
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4394
	global $config, $g;
4395
	global $interface_ipv6_arr_cache;
4396
	global $interface_snv6_arr_cache;
4397

    
4398
	if (!is_array($lancfg)) {
4399
		return;
4400
	}
4401

    
4402
	/* If the interface is not configured via another, exit */
4403
	if (empty($lancfg['track6-interface'])) {
4404
		return;
4405
	}
4406

    
4407
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4408
	if (empty($wancfg)) {
4409
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4410
		return;
4411
	}
4412

    
4413
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4414
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4415
		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']));
4416
		return;
4417
	}
4418
	$hexwanv4 = return_hex_ipv4($ip4address);
4419

    
4420
	/* create the long prefix notation for math, save the prefix length */
4421
	$sixto4prefix = "2002::";
4422
	$sixto4prefixlen = 16;
4423
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4424

    
4425
	/* binary presentation of the prefix for all 128 bits. */
4426
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4427

    
4428
	/* just save the left prefix length bits */
4429
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4430
	/* add the v4 address */
4431
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4432
	/* add the custom prefix id */
4433
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4434
	/* fill the rest out with zeros */
4435
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4436

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

    
4440
	$lanif = get_real_interface($interface);
4441
	$oip = find_interface_ipv6($lanif);
4442
	if (is_ipaddrv6($oip)) {
4443
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4444
	}
4445
	unset($interface_ipv6_arr_cache[$lanif]);
4446
	unset($interface_snv6_arr_cache[$lanif]);
4447
	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));
4448
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4449

    
4450
	return 0;
4451
}
4452

    
4453
function interface_6rd_configure($interface = "wan", $wancfg) {
4454
	global $config, $g;
4455

    
4456
	/* because this is a tunnel interface we can only function
4457
	 *	with a public IPv4 address on the interface */
4458

    
4459
	if (!is_array($wancfg)) {
4460
		return;
4461
	}
4462

    
4463
	if (!is_module_loaded('if_stf.ko')) {
4464
		mwexec('/sbin/kldload if_stf.ko');
4465
	}
4466

    
4467
	$wanif = get_real_interface($interface);
4468
	$ip4address = find_interface_ip($wanif);
4469
	if (!is_ipaddrv4($ip4address)) {
4470
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4471
		return false;
4472
	}
4473
	$hexwanv4 = return_hex_ipv4($ip4address);
4474

    
4475
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4476
		$wancfg['prefix-6rd-v4plen'] = 0;
4477
	}
4478

    
4479
	/* create the long prefix notation for math, save the prefix length */
4480
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4481
	$rd6prefixlen = $rd6prefix[1];
4482
	$brgw = explode('.', $wancfg['gateway-6rd']);
4483
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4484
	$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);
4485
	if (strlen($rd6brgw) < 128) {
4486
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4487
	}
4488
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4489
	unset($brgw);
4490
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4491

    
4492
	/* binary presentation of the prefix for all 128 bits. */
4493
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4494

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

    
4502
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4503
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4504

    
4505

    
4506
	/* XXX: need to extend to support variable prefix size for v4 */
4507
	$stfiface = "{$interface}_stf";
4508
	if (does_interface_exist($stfiface)) {
4509
		pfSense_interface_destroy($stfiface);
4510
	}
4511
	$tmpstfiface = pfSense_interface_create("stf");
4512
	pfSense_interface_rename($tmpstfiface, $stfiface);
4513
	pfSense_interface_flags($stfiface, IFF_LINK2);
4514
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4515
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4516
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4517
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4518
	}
4519
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4520
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4521
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4522
	} elseif ($parentmtu > 1300) {
4523
		set_interface_mtu($stfiface, $parentmtu - 20);
4524
	}
4525
	if ($g['debug']) {
4526
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4527
	}
4528

    
4529
	/* write out a default router file */
4530
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4531
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4532

    
4533
	$ip4gateway = get_interface_gateway($interface);
4534
	if (is_ipaddrv4($ip4gateway)) {
4535
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
4536
	}
4537

    
4538
	/* configure dependent interfaces */
4539
	if (!platform_booting()) {
4540
		link_interface_to_track6($interface, "update");
4541
	}
4542

    
4543
	return 0;
4544
}
4545

    
4546
function interface_6to4_configure($interface = "wan", $wancfg) {
4547
	global $config, $g;
4548

    
4549
	/* because this is a tunnel interface we can only function
4550
	 *	with a public IPv4 address on the interface */
4551

    
4552
	if (!is_array($wancfg)) {
4553
		return;
4554
	}
4555

    
4556
	$wanif = get_real_interface($interface);
4557
	$ip4address = find_interface_ip($wanif);
4558
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4559
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4560
		return false;
4561
	}
4562

    
4563
	/* create the long prefix notation for math, save the prefix length */
4564
	$stfprefixlen = 16;
4565
	$stfprefix = Net_IPv6::uncompress("2002::");
4566
	$stfarr = explode(":", $stfprefix);
4567
	$v4prefixlen = "0";
4568

    
4569
	/* we need the hex form of the interface IPv4 address */
4570
	$ip4arr = explode(".", $ip4address);
4571
	$hexwanv4 = "";
4572
	foreach ($ip4arr as $octet) {
4573
		$hexwanv4 .= sprintf("%02x", $octet);
4574
	}
4575

    
4576
	/* we need the hex form of the broker IPv4 address */
4577
	$ip4arr = explode(".", "192.88.99.1");
4578
	$hexbrv4 = "";
4579
	foreach ($ip4arr as $octet) {
4580
		$hexbrv4 .= sprintf("%02x", $octet);
4581
	}
4582

    
4583
	/* binary presentation of the prefix for all 128 bits. */
4584
	$stfprefixbin = "";
4585
	foreach ($stfarr as $element) {
4586
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4587
	}
4588
	/* just save the left prefix length bits */
4589
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4590

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

    
4595
	/* for the local subnet too. */
4596
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4597
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4598

    
4599
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4600
	$stfbrarr = array();
4601
	$stfbrbinarr = array();
4602
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4603
	foreach ($stfbrbinarr as $bin) {
4604
		$stfbrarr[] = dechex(bindec($bin));
4605
	}
4606
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4607

    
4608
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4609
	$stflanarr = array();
4610
	$stflanbinarr = array();
4611
	$stflanbinarr = str_split($stflanbin, 16);
4612
	foreach ($stflanbinarr as $bin) {
4613
		$stflanarr[] = dechex(bindec($bin));
4614
	}
4615
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4616
	$stflanarr[7] = 1;
4617
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4618

    
4619
	/* setup the stf interface */
4620
	if (!is_module_loaded("if_stf")) {
4621
		mwexec("/sbin/kldload if_stf.ko");
4622
	}
4623
	$stfiface = "{$interface}_stf";
4624
	if (does_interface_exist($stfiface)) {
4625
		pfSense_interface_destroy($stfiface);
4626
	}
4627
	$tmpstfiface = pfSense_interface_create("stf");
4628
	pfSense_interface_rename($tmpstfiface, $stfiface);
4629
	pfSense_interface_flags($stfiface, IFF_LINK2);
4630
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4631

    
4632
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4633
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4634
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4635
	} elseif ($parentmtu > 1300) {
4636
		set_interface_mtu($stfiface, $parentmtu - 20);
4637
	}
4638
	if ($g['debug']) {
4639
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4640
	}
4641

    
4642
	/* write out a default router file */
4643
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4644
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4645

    
4646
	$ip4gateway = get_interface_gateway($interface);
4647
	if (is_ipaddrv4($ip4gateway)) {
4648
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
4649
	}
4650

    
4651
	if (!platform_booting()) {
4652
		link_interface_to_track6($interface, "update");
4653
	}
4654

    
4655
	return 0;
4656
}
4657

    
4658
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4659
	global $config, $g;
4660

    
4661
	if (!is_array($wancfg)) {
4662
		return;
4663
	}
4664

    
4665
	$wanif = get_real_interface($interface, "inet6");
4666
	$dhcp6cconf = "";
4667

    
4668
	if (!empty($config['system']['global-v6duid'])) {
4669
		// Write the DUID file
4670
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4671
		    log_error(gettext("Failed to write user DUID file!"));
4672
		}
4673
	}
4674

    
4675
	/* accept router advertisements for this interface                 */
4676
	/* Moved to early in the function as sometimes interface not ready */
4677
	/* RTSOLD fails as interface does not accept .....                 */
4678

    
4679
	log_error("Accept router advertisements on interface {$wanif} ");
4680
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4681

    
4682
	if ($wancfg['adv_dhcp6_config_file_override']) {
4683
		// DHCP6 Config File Override
4684
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4685
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4686
		// DHCP6 Config File Advanced
4687
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4688
	} else {
4689
		// DHCP6 Config File Basic
4690
		$dhcp6cconf .= "interface {$wanif} {\n";
4691

    
4692
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4693
		if ($wancfg['ipaddrv6'] == "slaac") {
4694
			$dhcp6cconf .= "\tinformation-only;\n";
4695
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4696
			$dhcp6cconf .= "\trequest domain-name;\n";
4697
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4698
			$dhcp6cconf .= "};\n";
4699
		} else {
4700
			$trackiflist = array();
4701
			$iflist = link_interface_to_track6($interface);
4702
			foreach ($iflist as $ifname => $ifcfg) {
4703
				if (is_numeric($ifcfg['track6-prefix-id'])) {
4704
					$trackiflist[$ifname] = $ifcfg;
4705
				}
4706
			}
4707

    
4708
			/* skip address request if this is set */
4709
			if (!isset($wancfg['dhcp6prefixonly'])) {
4710
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4711
			}
4712
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4713
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4714
			}
4715

    
4716
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4717
			$dhcp6cconf .= "\trequest domain-name;\n";
4718

    
4719
			/*
4720
			 * dhcp6c will run different scripts depending on
4721
			 * whether dhcpwithoutra is set or unset.
4722
			 */
4723
			if (isset($wancfg['dhcp6withoutra'])) {
4724
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4725
			} else {
4726
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4727
			}
4728
			$dhcp6cconf .= "};\n";
4729

    
4730
			if (!isset($wancfg['dhcp6prefixonly'])) {
4731
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4732
			}
4733

    
4734
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4735
				/* Setup the prefix delegation */
4736
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4737
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4738
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4739
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4740
				}
4741
				foreach ($trackiflist as $friendly => $ifcfg) {
4742
					if ($g['debug']) {
4743
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4744
					}
4745
					$realif = get_real_interface($friendly);
4746
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4747
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4748
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4749
					$dhcp6cconf .= "\t};\n";
4750
				}
4751
				unset($preflen, $iflist, $ifcfg, $ifname);
4752
				$dhcp6cconf .= "};\n";
4753
			}
4754
			unset($trackiflist);
4755
		}
4756
	}
4757

    
4758
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4759
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4760

    
4761
	/* wide-dhcp6c works for now. */
4762
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4763
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4764
		unset($dhcp6cconf);
4765
		return 1;
4766
	}
4767
	unset($dhcp6cconf);
4768

    
4769
	/*************** Script Debug Logging ***************************
4770
	Both dhcp6 scripts now have a logging message built in.
4771
	These logging messages ONLY appear if dhcp6c debug logging is set.
4772
	The logging messages appear in the dhcp section of the logs,
4773
	not in system.
4774

    
4775
	These scripts now also take advantage of the REASON= env vars
4776
	supplied by dhcp6c.
4777
	****************************************************************/
4778

    
4779
	/* Script create for dhcp6withoutRA mode */
4780
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4781
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4782
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4783
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4784
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4785
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4786
	// Need to pass params to  the final script
4787
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4788
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4789
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4790
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4791
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
4792
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
4793
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4794
	if ($debugOption == '-D') {
4795
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rtsold\"\n";
4796
	}
4797
	$dhcp6cscriptwithoutra .= ";;\n";
4798
	$dhcp6cscriptwithoutra .= "REBIND)\n";
4799
	if ($debugOption == '-D') {
4800
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4801
	}
4802
	$dhcp6cscriptwithoutra .= ";;\n";
4803
	if (isset($wancfg['dhcp6norelease'])) {
4804
		$dhcp6cscriptwithoutra .= "EXIT)\n";
4805
	} else {
4806
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
4807
	}
4808
	if ($debugOption == '-D') {
4809
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4810
	}
4811
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4812
	$dhcp6cscriptwithoutra .= ";;\n";
4813
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
4814
	if ($debugOption == '-D') {
4815
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4816
	}
4817
	$dhcp6cscriptwithoutra .= "esac\n";
4818
	if (!@file_put_contents(
4819
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4820
	    $dhcp6cscriptwithoutra)) {
4821
		printf("Error: cannot open " .
4822
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4823
		    "interface_dhcpv6_configure() for writing.\n");
4824
		unset($dhcp6cscriptwithoutra);
4825
		return 1;
4826
	}
4827

    
4828
	unset($dhcp6cscriptwithoutra);
4829
	@chmod(
4830
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4831
	    0755);
4832

    
4833
	/*
4834
	 * Dual mode wan_dhcp6c script with variations depending on node
4835
	 * dhcp6 will run the wan ipv6 configure
4836
	 */
4837
	$dhcp6cscript  = "#!/bin/sh\n";
4838
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4839
	if (!isset($wancfg['dhcp6withoutra'])) {
4840
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4841
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4842
		$dhcp6cscript .= "case \$REASON in\n";
4843
		$dhcp6cscript .= "REBIND)\n";
4844
		if ($debugOption == '-D') {
4845
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4846
		}
4847
		$dhcp6cscript .= ";;\n";
4848
		if (isset($wancfg['dhcp6norelease'])) {
4849
			$dhcp6cscript .= "EXIT)\n";
4850
		} else {
4851
			$dhcp6cscript .= "RELEASE)\n";
4852
		}
4853
		if ($debugOption == '-D') {
4854
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4855
		}
4856
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4857
		$dhcp6cscript .= ";;\n";
4858
		$dhcp6cscript .= "RENEW|REQUEST|INFO)\n";
4859
		if ($debugOption == '-D') {
4860
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4861
		}
4862
		$dhcp6cscript .= "esac\n";
4863
	} else {
4864
		// Need to get the parameters from the dhcp6cwithoutRA run
4865
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
4866
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
4867
		$dhcp6cscript .= "/bin/sleep 1\n";
4868
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4869
	}
4870

    
4871
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4872
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4873
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4874
		unset($dhcp6cscript);
4875
		return 1;
4876
	}
4877
	unset($dhcp6cscript);
4878
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4879

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

    
4886
	/* non ipoe Process */
4887
	if (!isset($wancfg['dhcp6withoutra'])) {
4888
		/*
4889
		 * We only want this script to run once, and if it runs twice
4890
		 * then do not launch dhcp6c again, this only happens if
4891
		 * dhcpwithoutra is not set.
4892
		 *
4893
		 * Check for a lock file, trying to prevent multiple instances
4894
		 * of dhcp6c being launched
4895
		 */
4896
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
4897
		/*
4898
		 * Create the lock file, trying to prevent multiple instances
4899
		 * of dhcp6c being launched
4900
		 */
4901
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
4902
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
4903
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4904
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4905
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
4906
		$rtsoldscript .= "\tfi\n";
4907
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
4908
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
4909
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4910
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4911
		$rtsoldscript .= "else\n";
4912
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
4913
		$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c_{$wanif}.pid\")\n";
4914
		$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
4915
		$rtsoldscript .= "fi\n";
4916
	} else {
4917
		/*
4918
		 * The script needs to run in dhcp6withoutra mode as RA may
4919
		 * not have been received, or there can be a delay with
4920
		 * certain ISPs
4921
		 */
4922
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
4923
		$rtsoldscript .= "/bin/sleep 1\n";
4924
	}
4925
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4926
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4927
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4928
		unset($rtsoldscript);
4929
		return 1;
4930
	}
4931
	unset($rtsoldscript);
4932
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4933

    
4934
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4935
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4936
		log_error("Killing running rtsold process");
4937
		sleep(2);
4938
	}
4939

    
4940
	if (isset($wancfg['dhcp6withoutra'])) {
4941
		/*
4942
		 * Start dhcp6c here if we don't want to wait for ra - calls
4943
		 * separate function
4944
		 *
4945
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
4946
		 * will then run the configure on receipt of the RA.
4947
		 *
4948
		 * Already started. interface_dhcpv6_configure() appears to get
4949
		 * called multiple times.
4950
		 *
4951
		 * Taking the interface down or releasing will kill the client.
4952
		 */
4953
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
4954
		{
4955
			/*
4956
			 * If the interface is being brought up, wait for the
4957
			 * interface to configure accept RA before launching.
4958
			 * Otherwise it is not ready to accept and will fail.
4959
			 */
4960
			sleep(3);
4961
			run_dhcp6client_process($wanif,$interface,$wancfg);
4962
		}
4963
	} else {
4964
		/*
4965
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
4966
		 * ( it does not background, it exits! ) It will launch dhcp6c
4967
		 * if dhcpwihtoutra is not set
4968
		 */
4969
		log_error("Starting rtsold process");
4970
		sleep(2);
4971
		mwexec("/usr/sbin/rtsold -1 " .
4972
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
4973
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
4974
		    $wanif);
4975
	}
4976
	/*
4977
	 * NOTE: will be called from rtsold invoked script
4978
	 * link_interface_to_track6($interface, "update");
4979
	 */
4980

    
4981
	return 0;
4982
}
4983

    
4984
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4985
	global $g;
4986

    
4987
	$send_options = "";
4988
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4989
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4990
		foreach ($options as $option) {
4991
			$send_options .= "\tsend " . trim($option) . ";\n";
4992
		}
4993
	}
4994

    
4995
	$request_options = "";
4996
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4997
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4998
		foreach ($options as $option) {
4999
			$request_options .= "\trequest " . trim($option) . ";\n";
5000
		}
5001
	}
5002

    
5003
	$information_only = "";
5004
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5005
		$information_only = "\tinformation-only;\n";
5006
	}
5007

    
5008
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5009
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5010
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5011
	}
5012

    
5013
	$interface_statement  = "interface";
5014
	$interface_statement .= " {$wanif}";
5015
	$interface_statement .= " {\n";
5016
	$interface_statement .= "$send_options";
5017
	$interface_statement .= "$request_options";
5018
	$interface_statement .= "$information_only";
5019
	$interface_statement .= "$script";
5020
	$interface_statement .= "};\n";
5021

    
5022
	$id_assoc_statement_address = "";
5023
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5024
		$id_assoc_statement_address .= "id-assoc";
5025
		$id_assoc_statement_address .= " na";
5026
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5027
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5028
		}
5029
		$id_assoc_statement_address .= " { ";
5030

    
5031
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5032
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5033
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5034
			$id_assoc_statement_address .= "\n\taddress";
5035
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5036
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5037
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5038
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5039
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5040
			}
5041
			$id_assoc_statement_address .= ";\n";
5042
		}
5043

    
5044
		$id_assoc_statement_address .= "};\n";
5045
	}
5046

    
5047
	$id_assoc_statement_prefix = "";
5048
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5049
		$id_assoc_statement_prefix .= "id-assoc";
5050
		$id_assoc_statement_prefix .= " pd";
5051
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5052
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5053
		}
5054
		$id_assoc_statement_prefix .= " { ";
5055

    
5056
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5057
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5058
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5059
			$id_assoc_statement_prefix .= "\n\tprefix";
5060
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5061
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5062
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5063
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5064
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5065
			}
5066
			$id_assoc_statement_prefix .= ";";
5067
		}
5068

    
5069
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5070
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5071
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5072
			$id_assoc_statement_prefix .= " {$realif}";
5073
			$id_assoc_statement_prefix .= " {\n";
5074
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5075
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5076
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5077
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5078
			}
5079
			$id_assoc_statement_prefix .= "\t};";
5080
		}
5081

    
5082
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5083
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5084
			$id_assoc_statement_prefix .= "\n";
5085
		}
5086

    
5087
		$id_assoc_statement_prefix .= "};\n";
5088
	}
5089

    
5090
	$authentication_statement = "";
5091
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5092
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5093
		$authentication_statement .= "authentication";
5094
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5095
		$authentication_statement .= " {\n";
5096
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5097
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5098
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5099
		}
5100
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5101
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5102
		}
5103
		$authentication_statement .= "};\n";
5104
	}
5105

    
5106
	$key_info_statement = "";
5107
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5108
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5109
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5110
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5111
		$key_info_statement .= "keyinfo";
5112
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5113
		$key_info_statement .= " {\n";
5114
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5115
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5116
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5117
		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'])) {
5118
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5119
		}
5120
		$key_info_statement .= "};\n";
5121
	}
5122

    
5123
	$dhcp6cconf  = $interface_statement;
5124
	$dhcp6cconf .= $id_assoc_statement_address;
5125
	$dhcp6cconf .= $id_assoc_statement_prefix;
5126
	$dhcp6cconf .= $authentication_statement;
5127
	$dhcp6cconf .= $key_info_statement;
5128

    
5129
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5130

    
5131
	return $dhcp6cconf;
5132
}
5133

    
5134

    
5135
function DHCP6_Config_File_Override($wancfg, $wanif) {
5136

    
5137
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5138

    
5139
	if ($dhcp6cconf === false) {
5140
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5141
		return '';
5142
	} else {
5143
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5144
	}
5145
}
5146

    
5147

    
5148
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5149

    
5150
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5151

    
5152
	return $dhcp6cconf;
5153
}
5154

    
5155

    
5156
function interface_dhcp_configure($interface = "wan") {
5157
	global $config, $g, $vlanprio_values;
5158

    
5159
	$ifcfg = $config['interfaces'][$interface];
5160
	if (empty($ifcfg)) {
5161
		$ifcfg = array();
5162
	}
5163

    
5164
	$dhclientconf_vlantag = "";
5165
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5166
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5167
	}
5168

    
5169
	/* generate dhclient_wan.conf */
5170
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5171
	if (!$fd) {
5172
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5173
		return 1;
5174
	}
5175

    
5176
	if ($ifcfg['dhcphostname']) {
5177
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5178
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5179
	} else {
5180
		$dhclientconf_hostname = "";
5181
	}
5182

    
5183
	$realif = get_real_interface($interface);
5184
	if (empty($realif)) {
5185
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5186
		return 0;
5187
	}
5188
	$dhclientconf = "";
5189

    
5190
	$dhclientconf .= <<<EOD
5191
interface "{$realif}" {
5192
	supersede interface-mtu 0;
5193
	timeout 60;
5194
	retry 15;
5195
	select-timeout 0;
5196
	initial-interval 1;
5197
	{$dhclientconf_vlantag}
5198
	{$dhclientconf_hostname}
5199
	script "/usr/local/sbin/pfSense-dhclient-script";
5200
EOD;
5201

    
5202
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5203
		$dhclientconf .= <<<EOD
5204

    
5205
	reject {$ifcfg['dhcprejectfrom']};
5206
EOD;
5207
	}
5208
	$dhclientconf .= <<<EOD
5209

    
5210
}
5211

    
5212
EOD;
5213

    
5214
	// DHCP Config File Advanced
5215
	if ($ifcfg['adv_dhcp_config_advanced']) {
5216
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5217
	}
5218

    
5219
	if (is_ipaddr($ifcfg['alias-address'])) {
5220
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5221
		$dhclientconf .= <<<EOD
5222
alias {
5223
	interface "{$realif}";
5224
	fixed-address {$ifcfg['alias-address']};
5225
	option subnet-mask {$subnetmask};
5226
}
5227

    
5228
EOD;
5229
	}
5230

    
5231
	// DHCP Config File Override
5232
	if ($ifcfg['adv_dhcp_config_file_override']) {
5233
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5234
	}
5235

    
5236
	fwrite($fd, $dhclientconf);
5237
	fclose($fd);
5238

    
5239
	/* bring wan interface up before starting dhclient */
5240
	if ($realif) {
5241
		interfaces_bring_up($realif);
5242
	}
5243

    
5244
	/* Make sure dhclient is not running */
5245
	kill_dhclient_process($realif);
5246

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

    
5250
	return 0;
5251
}
5252

    
5253
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5254

    
5255
	$hostname = "";
5256
	if ($ifcfg['dhcphostname'] != '') {
5257
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5258
	}
5259

    
5260
	/* DHCP Protocol Timings */
5261
	$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");
5262
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5263
		$pt_variable = "{$Protocol_Timing}";
5264
		${$pt_variable} = "";
5265
		if ($ifcfg[$Protocol_Timing] != "") {
5266
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5267
		}
5268
	}
5269

    
5270
	$send_options = "";
5271
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5272
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5273
		foreach ($options as $option) {
5274
			$send_options .= "\tsend " . trim($option) . ";\n";
5275
		}
5276
	}
5277

    
5278
	$request_options = "";
5279
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5280
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5281
	}
5282

    
5283
	$required_options = "";
5284
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5285
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5286
	}
5287

    
5288
	$option_modifiers = "";
5289
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5290
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5291
		foreach ($modifiers as $modifier) {
5292
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5293
		}
5294
	}
5295

    
5296
	$dhclientconf  = "interface \"{$realif}\" {\n";
5297
	$dhclientconf .= "\n";
5298
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5299
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5300
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5301
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5302
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5303
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5304
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5305
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5306
	$dhclientconf .= "\n";
5307
	$dhclientconf .= "# DHCP Protocol Options\n";
5308
	$dhclientconf .= "{$hostname}";
5309
	$dhclientconf .= "{$send_options}";
5310
	$dhclientconf .= "{$request_options}";
5311
	$dhclientconf .= "{$required_options}";
5312
	$dhclientconf .= "{$option_modifiers}";
5313
	$dhclientconf .= "\n";
5314
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5315
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5316
	}
5317
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5318
	$dhclientconf .= "}\n";
5319

    
5320
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5321

    
5322
	return $dhclientconf;
5323
}
5324

    
5325
function DHCP_Config_Option_Split($option_string) {
5326
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5327
	return $matches ? $matches[0] : [];
5328
}
5329

    
5330
function DHCP_Config_File_Override($ifcfg, $realif) {
5331

    
5332
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5333

    
5334
	if ($dhclientconf === false) {
5335
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5336
		return '';
5337
	} else {
5338
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5339
	}
5340
}
5341

    
5342

    
5343
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5344

    
5345
	/* Apply Interface Substitutions */
5346
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5347

    
5348
	/* Apply Hostname Substitutions */
5349
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5350

    
5351
	/* Arrays of MAC Address Types, Cases, Delimiters */
5352
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5353
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5354
	$various_mac_cases      = array("U", "L");
5355
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5356

    
5357
	/* Apply MAC Address Substitutions */
5358
	foreach ($various_mac_types as $various_mac_type) {
5359
		foreach ($various_mac_cases as $various_mac_case) {
5360
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5361

    
5362
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5363
				if ($res !== false) {
5364

    
5365
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5366
					if ("$various_mac_case" == "U") {
5367
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5368
					}
5369
					if ("$various_mac_case" == "L") {
5370
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5371
					}
5372

    
5373
					if ("$various_mac_type" == "mac_addr_hex") {
5374
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5375
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5376
						$dhcpclientconf_mac_hex = "";
5377
						$delimiter = "";
5378
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5379
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5380
							$delimiter = ":";
5381
						}
5382
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5383
					}
5384

    
5385
					/* MAC Address Delimiter Substitutions */
5386
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5387

    
5388
					/* Apply MAC Address Substitutions */
5389
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5390
				}
5391
			}
5392
		}
5393
	}
5394

    
5395
	return $dhclientconf;
5396
}
5397

    
5398
function interfaces_group_setup() {
5399
	global $config;
5400

    
5401
	if (!isset($config['ifgroups']['ifgroupentry']) || !is_array($config['ifgroups']['ifgroupentry'])) {
5402
		return;
5403
	}
5404

    
5405
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5406
		interface_group_setup($groupar);
5407
	}
5408

    
5409
	return;
5410
}
5411

    
5412
function interface_group_setup(&$groupname /* The parameter is an array */) {
5413
	global $config;
5414

    
5415
	if (!is_array($groupname)) {
5416
		return;
5417
	}
5418
	$members = explode(" ", $groupname['members']);
5419
	foreach ($members as $ifs) {
5420
		$realif = get_real_interface($ifs);
5421
		if ($realif && does_interface_exist($realif)) {
5422
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5423
		}
5424
	}
5425

    
5426
	return;
5427
}
5428

    
5429
function is_interface_group($if) {
5430
	global $config;
5431

    
5432
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5433
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5434
			if ($groupentry['ifname'] === $if) {
5435
				return true;
5436
			}
5437
		}
5438
	}
5439

    
5440
	return false;
5441
}
5442

    
5443
function interface_group_add_member($interface, $groupname) {
5444
	$interface = get_real_interface($interface);
5445
	if (does_interface_exist($interface)) {
5446
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5447
	}
5448
}
5449

    
5450
/* COMPAT Function */
5451
function convert_friendly_interface_to_real_interface_name($interface) {
5452
	return get_real_interface($interface);
5453
}
5454

    
5455
/* COMPAT Function */
5456
function get_real_wan_interface($interface = "wan") {
5457
	return get_real_interface($interface);
5458
}
5459

    
5460
/* COMPAT Function */
5461
function get_current_wan_address($interface = "wan") {
5462
	return get_interface_ip($interface);
5463
}
5464

    
5465
/*
5466
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5467
 */
5468
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5469
	global $config;
5470

    
5471
	/* XXX: For speed reasons reference directly the interface array */
5472
	init_config_arr(array('interfaces'));
5473
	$ifdescrs = &$config['interfaces'];
5474
	//$ifdescrs = get_configured_interface_list(true);
5475

    
5476
	foreach ($ifdescrs as $if => $ifname) {
5477
		if ($if == $interface || $ifname['if'] == $interface) {
5478
			return $if;
5479
		}
5480

    
5481
		if (get_real_interface($if) == $interface) {
5482
			return $if;
5483
		}
5484

    
5485
		if ($checkparent == false) {
5486
			continue;
5487
		}
5488

    
5489
		$int = get_parent_interface($if, true);
5490
		if (is_array($int)) {
5491
			foreach ($int as $iface) {
5492
				if ($iface == $interface) {
5493
					return $if;
5494
				}
5495
			}
5496
		}
5497
	}
5498

    
5499
	if ($interface == "enc0") {
5500
		return 'IPsec';
5501
	}
5502
}
5503

    
5504
/* attempt to resolve interface to friendly descr */
5505
function convert_friendly_interface_to_friendly_descr($interface) {
5506
	global $config;
5507

    
5508
	switch ($interface) {
5509
		case "l2tp":
5510
			$ifdesc = "L2TP";
5511
			break;
5512
		case "pptp":
5513
			$ifdesc = "PPTP";
5514
			break;
5515
		case "pppoe":
5516
			$ifdesc = "PPPoE";
5517
			break;
5518
		case "openvpn":
5519
			$ifdesc = "OpenVPN";
5520
			break;
5521
		case "lo0":
5522
			$ifdesc = "Loopback";
5523
			break;
5524
		case "enc0":
5525
		case "ipsec":
5526
		case "IPsec":
5527
			$ifdesc = "IPsec";
5528
			break;
5529
		default:
5530
			if (isset($config['interfaces'][$interface])) {
5531
				if (empty($config['interfaces'][$interface]['descr'])) {
5532
					$ifdesc = strtoupper($interface);
5533
				} else {
5534
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5535
				}
5536
				break;
5537
			} else if (substr($interface, 0, 4) == '_vip') {
5538
				if (is_array($config['virtualip']['vip'])) {
5539
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5540
						if ($vip['mode'] == "carp") {
5541
							if ($interface == "_vip{$vip['uniqid']}") {
5542
								$descr = $vip['subnet'];
5543
								$descr .= " (vhid {$vip['vhid']})";
5544
								if (!empty($vip['descr'])) {
5545
									$descr .= " - " .$vip['descr'];
5546
								}
5547
								return $descr;
5548
							}
5549
						}
5550
					}
5551
				}
5552
			} else if (substr($interface, 0, 5) == '_lloc') {
5553
				return get_interface_linklocal($interface);
5554
			} else {
5555
				if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5556
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5557
						if ($ifgen['ifname'] === $interface) {
5558
							return $ifgen['ifname'];
5559
						}
5560
					}
5561
				}
5562

    
5563
				/* if list */
5564
				$ifdescrs = get_configured_interface_with_descr(true);
5565
				foreach ($ifdescrs as $if => $ifname) {
5566
					if ($if == $interface || $ifname == $interface) {
5567
						return $ifname;
5568
					}
5569
				}
5570
			}
5571
			break;
5572
	}
5573

    
5574
	return $ifdesc;
5575
}
5576

    
5577
function convert_real_interface_to_friendly_descr($interface) {
5578

    
5579
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5580

    
5581
	if (!empty($ifdesc)) {
5582
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5583
	}
5584

    
5585
	return $interface;
5586
}
5587

    
5588
/*
5589
 *  get_parent_interface($interface):
5590
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5591
 *				or virtual interface (i.e. vlan)
5592
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5593
 *			-- returns $interface passed in if $interface parent is not found
5594
 *			-- returns empty array if an invalid interface is passed
5595
 *	(Only handles ppps and vlans now.)
5596
 */
5597
function get_parent_interface($interface, $avoidrecurse = false) {
5598
	global $config;
5599

    
5600
	$parents = array();
5601
	//Check that we got a valid interface passed
5602
	$realif = get_real_interface($interface);
5603
	if ($realif == NULL) {
5604
		return $parents;
5605
	}
5606

    
5607
	// If we got a real interface, find it's friendly assigned name
5608
	if ($interface == $realif && $avoidrecurse == false) {
5609
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5610
	}
5611

    
5612
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5613
		$ifcfg = $config['interfaces'][$interface];
5614
		switch ($ifcfg['ipaddr']) {
5615
			case "ppp":
5616
			case "pppoe":
5617
			case "pptp":
5618
			case "l2tp":
5619
				if (empty($parents)) {
5620
					if (is_array($config['ppps']['ppp'])) {
5621
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5622
							if ($ifcfg['if'] == $ppp['if']) {
5623
								$ports = explode(',', $ppp['ports']);
5624
								foreach ($ports as $pid => $parent_if) {
5625
									$parents[$pid] = get_real_interface($parent_if);
5626
								}
5627
								break;
5628
							}
5629
						}
5630
					}
5631
				}
5632
				break;
5633
			case "dhcp":
5634
			case "static":
5635
			default:
5636
				// Handle _vlans
5637
				$vlan = interface_is_vlan($ifcfg['if']);
5638
				if ($vlan != NULL) {
5639
					$parents[0] = $vlan['if'];
5640
				}
5641
				break;
5642
		}
5643
	}
5644

    
5645
	if (empty($parents)) {
5646
		// Handle _vlans not assigned to an interface
5647
		$vlan = interface_is_vlan($realif);
5648
		if ($vlan != NULL) {
5649
			$parents[0] = $vlan['if'];
5650
		}
5651
	}
5652

    
5653
	if (empty($parents)) {
5654
		/* Handle LAGGs. */
5655
		$lagg = interface_is_type($realif, 'lagg');
5656
		if ($lagg != NULL && isset($lagg['members'])) {
5657
			$parents = explode(",", $lagg['members']);
5658
		}
5659
	}
5660

    
5661
	if (empty($parents)) {
5662
		$parents[0] = $realif;
5663
	}
5664

    
5665
	return $parents;
5666
}
5667

    
5668
/*
5669
 *  get_parent_physical_interface($interface):
5670
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5671
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5672
 */
5673
function get_parent_physical_interface($interface) {
5674
	global $config;
5675

    
5676
	$realif = get_parent_interface($interface);
5677

    
5678
	if (substr($realif[0], 0, 4) == "lagg") {
5679
		foreach ($config['laggs']['lagg'] as $lagg) {
5680
			if ($realif[0] == $lagg['laggif']) {
5681
				return explode(",", $lagg['members']);
5682
			}
5683
		}
5684
	} else {
5685
		return $realif;
5686
	}
5687
}
5688

    
5689
function interface_is_wireless_clone($wlif) {
5690
	if (!stristr($wlif, "_wlan")) {
5691
		return false;
5692
	} else {
5693
		return true;
5694
	}
5695
}
5696

    
5697
function interface_get_wireless_base($wlif) {
5698
	if (!stristr($wlif, "_wlan")) {
5699
		return $wlif;
5700
	} else {
5701
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5702
	}
5703
}
5704

    
5705
function interface_get_wireless_clone($wlif) {
5706
	if (!stristr($wlif, "_wlan")) {
5707
		return $wlif . "_wlan0";
5708
	} else {
5709
		return $wlif;
5710
	}
5711
}
5712

    
5713
function interface_list_wireless() {
5714
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5715

    
5716
	$result = array();
5717
	foreach ($portlist as $port) {
5718
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5719
			continue;
5720
		}
5721

    
5722
		$desc = $port . " ( " . get_single_sysctl(
5723
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5724

    
5725
		$result[] = array(
5726
		    "if" => $port,
5727
		    "descr" => $desc
5728
		);
5729
	}
5730

    
5731
	return $result;
5732
}
5733

    
5734
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
5735
	global $config, $g;
5736

    
5737
	$wanif = NULL;
5738

    
5739
	switch ($interface) {
5740
		case "l2tp":
5741
			$wanif = "l2tp";
5742
			break;
5743
		case "pptp":
5744
			$wanif = "pptp";
5745
			break;
5746
		case "pppoe":
5747
			$wanif = "pppoe";
5748
			break;
5749
		case "openvpn":
5750
			$wanif = "openvpn";
5751
			break;
5752
		case "IPsec":
5753
		case "ipsec":
5754
		case "enc0":
5755
			$wanif = "enc0";
5756
			break;
5757
		case "ppp":
5758
			$wanif = "ppp";
5759
			break;
5760
		default:
5761
			if (substr($interface, 0, 4) == '_vip') {
5762
				$wanif = get_configured_vip_interface($interface);
5763
				if (!empty($wanif)) {
5764
					$wanif = get_real_interface($wanif);
5765
				}
5766
				break;
5767
			} else if (substr($interface, 0, 5) == '_lloc') {
5768
				$interface = substr($interface, 5);
5769
			} else if (interface_is_vlan($interface) != NULL ||
5770
			    does_interface_exist($interface, $flush)) {
5771
				/*
5772
				 * If a real interface was already passed simply
5773
				 * pass the real interface back.  This encourages
5774
				 * the usage of this function in more cases so that
5775
				 * we can combine logic for more flexibility.
5776
				 */
5777
				$wanif = $interface;
5778
				break;
5779
			}
5780

    
5781
			if (empty($config['interfaces'][$interface])) {
5782
				break;
5783
			}
5784

    
5785
			$cfg = &$config['interfaces'][$interface];
5786

    
5787
			if ($family == "inet6") {
5788
				switch ($cfg['ipaddrv6']) {
5789
					case "6rd":
5790
					case "6to4":
5791
						$wanif = "{$interface}_stf";
5792
						break;
5793
					case 'pppoe':
5794
					case 'ppp':
5795
					case 'l2tp':
5796
					case 'pptp':
5797
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5798
							$wanif = interface_get_wireless_clone($cfg['if']);
5799
						} else {
5800
							$wanif = $cfg['if'];
5801
						}
5802
						break;
5803
					default:
5804
						switch ($cfg['ipaddr']) {
5805
							case 'pppoe':
5806
							case 'ppp':
5807
							case 'l2tp':
5808
							case 'pptp':
5809
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
5810
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) || 
5811
								    isset($cfg['ipv6usev4iface']) || isset($cfg['slaacusev4iface'])) {
5812
									$wanif = $cfg['if'];
5813
								} else {
5814
									$parents = get_parent_interface($interface);
5815
									if (!empty($parents[0])) {
5816
										$wanif = $parents[0];
5817
									} else {
5818
										$wanif = $cfg['if'];
5819
									}
5820
								}
5821
								break;
5822
							default:
5823
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5824
									$wanif = interface_get_wireless_clone($cfg['if']);
5825
								} else {
5826
									$wanif = $cfg['if'];
5827
								}
5828
								break;
5829
						}
5830
						break;
5831
				}
5832
			} else {
5833
				// Wireless cloned NIC support (FreeBSD 8+)
5834
				// interface name format: $parentnic_wlanparentnic#
5835
				// example: ath0_wlan0
5836
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5837
					$wanif = interface_get_wireless_clone($cfg['if']);
5838
				} else {
5839
					$wanif = $cfg['if'];
5840
				}
5841
			}
5842
			break;
5843
	}
5844

    
5845
	return $wanif;
5846
}
5847

    
5848
/* Guess the physical interface by providing a IP address */
5849
function guess_interface_from_ip($ipaddress) {
5850

    
5851
	$family = '';
5852
	if (is_ipaddrv4($ipaddress)) {
5853
		$family = 'inet';
5854
	}
5855
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5856
		$family = 'inet6';
5857
	}
5858

    
5859
	if (empty($family)) {
5860
		return false;
5861
	}
5862

    
5863
	/* create a route table we can search */
5864
	$output = '';
5865
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
5866
	$output[0] = trim($output[0], " \n");
5867
	if (!empty($output[0])) {
5868
		return $output[0];
5869
	}
5870

    
5871
	return false;
5872
}
5873

    
5874
/*
5875
 * find_ip_interface($ip): return the interface where an ip is defined
5876
 *   (or if $bits is specified, where an IP within the subnet is defined)
5877
 */
5878
function find_ip_interface($ip, $bits = null) {
5879
	if (!is_ipaddr($ip)) {
5880
		return false;
5881
	}
5882

    
5883
	$isv6ip = is_ipaddrv6($ip);
5884

    
5885
	/* if list */
5886
	$ifdescrs = get_configured_interface_list();
5887

    
5888
	foreach ($ifdescrs as $ifdescr => $ifname) {
5889
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
5890
		if (is_null($ifip)) {
5891
			continue;
5892
		}
5893
		if (is_null($bits)) {
5894
			if ($ip == $ifip) {
5895
				$int = get_real_interface($ifname);
5896
				return $int;
5897
			}
5898
		} else {
5899
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
5900
				$int = get_real_interface($ifname);
5901
				return $int;
5902
			}
5903
		}
5904
	}
5905

    
5906
	return false;
5907
}
5908

    
5909
/*
5910
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5911
 *   (or if $bits is specified, where an IP within the subnet is found)
5912
 */
5913
function find_virtual_ip_alias($ip, $bits = null) {
5914
	global $config;
5915

    
5916
	if (!is_array($config['virtualip']['vip'])) {
5917
		return false;
5918
	}
5919
	if (!is_ipaddr($ip)) {
5920
		return false;
5921
	}
5922

    
5923
	$isv6ip = is_ipaddrv6($ip);
5924

    
5925
	foreach ($config['virtualip']['vip'] as $vip) {
5926
		if ($vip['mode'] === "ipalias") {
5927
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
5928
				continue;
5929
			}
5930
			if (is_null($bits)) {
5931
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
5932
					return $vip;
5933
				}
5934
			} else {
5935
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5936
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5937
					return $vip;
5938
				}
5939
			}
5940
		}
5941
	}
5942
	return false;
5943
}
5944

    
5945
function link_interface_to_track6($int, $action = "") {
5946
	global $config;
5947

    
5948
	if (empty($int)) {
5949
		return;
5950
	}
5951

    
5952
	if (is_array($config['interfaces'])) {
5953
		$list = array();
5954
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5955
			if (!isset($ifcfg['enable'])) {
5956
				continue;
5957
			}
5958
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5959
				if ($action == "update") {
5960
					interface_track6_configure($ifname, $ifcfg);
5961
				} else if ($action == "") {
5962
					$list[$ifname] = $ifcfg;
5963
				}
5964
			}
5965
		}
5966
		return $list;
5967
	}
5968
}
5969

    
5970
function interface_find_child_cfgmtu($realiface) {
5971
	global $config;
5972

    
5973
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5974
	$vlans = link_interface_to_vlans($realiface);
5975
	$qinqs = link_interface_to_qinqs($realiface);
5976
	$bridge = link_interface_to_bridge($realiface);
5977
	if (!empty($interface)) {
5978
		$gifs = link_interface_to_gif($interface);
5979
		$gres = link_interface_to_gre($interface);
5980
	} else {
5981
		$gifs = array();
5982
		$gres = array();
5983
	}
5984

    
5985
	$mtu = 0;
5986
	if (is_array($vlans)) {
5987
		foreach ($vlans as $vlan) {
5988
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5989
			if (empty($ifass)) {
5990
				continue;
5991
			}
5992
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5993
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5994
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5995
				}
5996
			}
5997
		}
5998
	}
5999
	if (is_array($qinqs)) {
6000
		foreach ($qinqs as $qinq) {
6001
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
6002
			if (empty($ifass)) {
6003
				continue;
6004
			}
6005
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6006
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6007
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6008
				}
6009
			}
6010
		}
6011
	}
6012
	if (is_array($gifs)) {
6013
		foreach ($gifs as $gif) {
6014
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
6015
			if (empty($ifass)) {
6016
				continue;
6017
			}
6018
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6019
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6020
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6021
				}
6022
			}
6023
		}
6024
	}
6025
	if (is_array($gres)) {
6026
		foreach ($gres as $gre) {
6027
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
6028
			if (empty($ifass)) {
6029
				continue;
6030
			}
6031
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6032
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6033
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6034
				}
6035
			}
6036
		}
6037
	}
6038
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
6039
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
6040
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6041
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
6042
		}
6043
	}
6044
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
6045

    
6046
	return $mtu;
6047
}
6048

    
6049
function link_interface_to_vlans($int, $action = "") {
6050
	global $config;
6051

    
6052
	if (empty($int)) {
6053
		return;
6054
	}
6055

    
6056
	if (is_array($config['vlans']['vlan'])) {
6057
		$ifaces = array();
6058
		foreach ($config['vlans']['vlan'] as $vlan) {
6059
			if ($int == $vlan['if']) {
6060
				if ($action == "update") {
6061
					interfaces_bring_up($int);
6062
				} else {
6063
					$ifaces[$vlan['tag']] = $vlan;
6064
				}
6065
			}
6066
		}
6067
		if (!empty($ifaces)) {
6068
			return $ifaces;
6069
		}
6070
	}
6071
}
6072

    
6073
function link_interface_to_qinqs($int, $action = "") {
6074
	global $config;
6075

    
6076
	if (empty($int)) {
6077
		return;
6078
	}
6079

    
6080
	if (is_array($config['qinqs']['qinqentry'])) {
6081
		$ifaces = array();
6082
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
6083
			if ($int == $qinq['if']) {
6084
				if ($action == "update") {
6085
					interfaces_bring_up($int);
6086
				} else {
6087
					$ifaces[$qinq['tag']] = $qinq;
6088
				}
6089
			}
6090
		}
6091
		if (!empty($ifaces)) {
6092
			return $ifaces;
6093
		}
6094
	}
6095
}
6096

    
6097
function link_interface_to_vips($int, $action = "", $vhid = '') {
6098
	global $config;
6099

    
6100
	$updatevips = false;
6101
	if (is_array($config['virtualip']['vip'])) {
6102
		$result = array();
6103
		foreach ($config['virtualip']['vip'] as $vip) {
6104
			if (substr($vip['interface'], 0, 4) == "_vip") {
6105
				$iface = get_configured_vip_interface($vip['interface']);
6106
			} else {
6107
				$iface = $vip['interface'];
6108
			}
6109
			if ($int != $iface) {
6110
				continue;
6111
			}
6112
			if ($action == "update") {
6113
				$updatevips = true;
6114
			} else {
6115
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
6116
				    substr($vip['interface'], 0, 4) == "_vip") {
6117
					$result[] = $vip;
6118
				}
6119
			}
6120
		}
6121
		if ($updatevips === true) {
6122
			interfaces_vips_configure($int);
6123
		}
6124
		return $result;
6125
	}
6126

    
6127
	return NULL;
6128
}
6129

    
6130
/****f* interfaces/link_interface_to_bridge
6131
 * NAME
6132
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6133
 * INPUTS
6134
 *   $ip
6135
 * RESULT
6136
 *   bridge[0-99]
6137
 ******/
6138
function link_interface_to_bridge($int) {
6139
	global $config;
6140

    
6141
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6142
		foreach ($config['bridges']['bridged'] as $bridge) {
6143
			if (in_array($int, explode(',', $bridge['members']))) {
6144
				return "{$bridge['bridgeif']}";
6145
			}
6146
		}
6147
	}
6148
}
6149

    
6150
function link_interface_to_lagg($int) {
6151
	global $config;
6152

    
6153
	if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
6154
		foreach ($config['laggs']['lagg'] as $lagg) {
6155
			if (in_array($int, explode(',', $lagg['members']))) {
6156
				return "{$lagg['laggif']}";
6157
			}
6158
		}
6159
	}
6160
}
6161

    
6162
function link_interface_to_group($int) {
6163
	global $config;
6164

    
6165
	$result = array();
6166

    
6167
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6168
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6169
			if (in_array($int, explode(" ", $group['members']))) {
6170
				$result[$group['ifname']] = $int;
6171
			}
6172
		}
6173
	}
6174

    
6175
	return $result;
6176
}
6177

    
6178
function link_interface_to_gre($interface) {
6179
	global $config;
6180

    
6181
	$result = array();
6182

    
6183
	if (is_array($config['gres']['gre'])) {
6184
		foreach ($config['gres']['gre'] as $gre) {
6185
			if ($gre['if'] == $interface) {
6186
				$result[] = $gre;
6187
			}
6188
		}
6189
	}
6190

    
6191
	return $result;
6192
}
6193

    
6194
function link_interface_to_gif($interface) {
6195
	global $config;
6196

    
6197
	$result = array();
6198

    
6199
	if (is_array($config['gifs']['gif'])) {
6200
		foreach ($config['gifs']['gif'] as $gif) {
6201
			if ($gif['if'] == $interface) {
6202
				$result[] = $gif;
6203
			}
6204
		}
6205
	}
6206

    
6207
	return $result;
6208
}
6209

    
6210
/*
6211
 * find_interface_ip($interface): return the interface ip (first found)
6212
 */
6213
function find_interface_ip($interface, $flush = false) {
6214
	global $interface_ip_arr_cache;
6215
	global $interface_sn_arr_cache;
6216

    
6217
	$interface = str_replace("\n", "", $interface);
6218

    
6219
	if (!does_interface_exist($interface)) {
6220
		return;
6221
	}
6222

    
6223
	/* Setup IP cache */
6224
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6225
		if (file_exists("/var/db/${interface}_ip")) {
6226
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6227
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6228
			foreach ($ifaddrs as $ifaddr) {
6229
				list($ip, $mask) = explode("/", $ifaddr);
6230
				if ($ip == $ifip) {
6231
					$interface_ip_arr_cache[$interface] = $ip;
6232
					$interface_sn_arr_cache[$interface] = $mask;
6233
					break;
6234
				}
6235
			}
6236
		}
6237
		if (!isset($interface_ip_arr_cache[$interface])) {
6238
			$ifinfo = pfSense_get_interface_addresses($interface);
6239
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6240
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6241
		}
6242
	}
6243

    
6244
	return $interface_ip_arr_cache[$interface];
6245
}
6246

    
6247
/*
6248
 * find_interface_ipv6($interface): return the interface ip (first found)
6249
 */
6250
function find_interface_ipv6($interface, $flush = false) {
6251
	global $interface_ipv6_arr_cache;
6252
	global $interface_snv6_arr_cache;
6253
	global $config;
6254

    
6255
	$interface = trim($interface);
6256
	$interface = get_real_interface($interface);
6257

    
6258
	if (!does_interface_exist($interface)) {
6259
		return;
6260
	}
6261

    
6262
	/* Setup IP cache */
6263
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6264
		$ifinfo = pfSense_get_interface_addresses($interface);
6265
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6266
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6267
	}
6268

    
6269
	return $interface_ipv6_arr_cache[$interface];
6270
}
6271

    
6272
/*
6273
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6274
 */
6275
function find_interface_ipv6_ll($interface, $flush = false) {
6276
	global $interface_llv6_arr_cache;
6277
	global $config;
6278

    
6279
	$interface = str_replace("\n", "", $interface);
6280

    
6281
	if (!does_interface_exist($interface)) {
6282
		return;
6283
	}
6284

    
6285
	/* Setup IP cache */
6286
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6287
		$ifinfo = pfSense_getall_interface_addresses($interface);
6288
		foreach ($ifinfo as $line) {
6289
			if (strstr($line, ":")) {
6290
				$parts = explode("/", $line);
6291
				if (is_linklocal($parts[0])) {
6292
					$ifinfo['linklocal'] = $parts[0];
6293
				}
6294
			}
6295
		}
6296
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6297
	}
6298
	return $interface_llv6_arr_cache[$interface];
6299
}
6300

    
6301
function find_interface_subnet($interface, $flush = false) {
6302
	global $interface_sn_arr_cache;
6303
	global $interface_ip_arr_cache;
6304

    
6305
	$interface = str_replace("\n", "", $interface);
6306
	if (does_interface_exist($interface) == false) {
6307
		return;
6308
	}
6309

    
6310
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6311
		$ifinfo = pfSense_get_interface_addresses($interface);
6312
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6313
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6314
	}
6315

    
6316
	return $interface_sn_arr_cache[$interface];
6317
}
6318

    
6319
function find_interface_subnetv6($interface, $flush = false) {
6320
	global $interface_snv6_arr_cache;
6321
	global $interface_ipv6_arr_cache;
6322

    
6323
	$interface = str_replace("\n", "", $interface);
6324
	if (does_interface_exist($interface) == false) {
6325
		return;
6326
	}
6327

    
6328
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6329
		$ifinfo = pfSense_get_interface_addresses($interface);
6330
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6331
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6332
	}
6333

    
6334
	return $interface_snv6_arr_cache[$interface];
6335
}
6336

    
6337
function ip_in_interface_alias_subnet($interface, $ipalias) {
6338
	global $config;
6339

    
6340
	if (empty($interface) || !is_ipaddr($ipalias)) {
6341
		return false;
6342
	}
6343
	if (is_array($config['virtualip']['vip'])) {
6344
		foreach ($config['virtualip']['vip'] as $vip) {
6345
			switch ($vip['mode']) {
6346
				case "ipalias":
6347
					if ($vip['interface'] <> $interface) {
6348
						break;
6349
					}
6350
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6351
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6352
						return true;
6353
					}
6354
					break;
6355
			}
6356
		}
6357
	}
6358

    
6359
	return false;
6360
}
6361

    
6362
function get_possible_listen_ips($include_ipv6_link_local=false) {
6363

    
6364
	$interfaces = get_configured_interface_with_descr();
6365
	foreach ($interfaces as $iface => $ifacename) {
6366
		if ($include_ipv6_link_local) {
6367
			/* This is to avoid going though added ll below */
6368
			if (substr($iface, 0, 5) == '_lloc') {
6369
				continue;
6370
			}
6371
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6372
			if (!empty($llip)) {
6373
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6374
			}
6375
		}
6376
	}
6377
	$viplist = get_configured_vip_list();
6378
	foreach ($viplist as $vip => $address) {
6379
		$interfaces[$vip] = $address;
6380
		if (get_vip_descr($address)) {
6381
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6382
		}
6383
	}
6384

    
6385
	$interfaces['lo0'] = 'Localhost';
6386

    
6387
	return $interfaces;
6388
}
6389

    
6390
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6391
	global $config;
6392

    
6393
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6394
	foreach (array('server', 'client') as $mode) {
6395
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6396
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6397
				if (!isset($setting['disable'])) {
6398
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6399
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6400
				}
6401
			}
6402
		}
6403
	}
6404
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
6405
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
6406
			if ($ph1ent['disabled']) {
6407
				continue;
6408
			}
6409
			if (ipsec_vti($ph1ent)) {
6410
				$sourceips_key = "ipsec{$ph1ent['ikeid']}";
6411
				$sourceips[$sourceips_key] = gettext("IPsec VTI") . ": " . htmlspecialchars($ph1ent['descr']);
6412
			}
6413
		}
6414
	}
6415
	return $sourceips;
6416
}
6417

    
6418
function get_interface_ip($interface = "wan") {
6419
	global $config;
6420

    
6421
	if (substr($interface, 0, 4) == '_vip') {
6422
		return get_configured_vip_ipv4($interface);
6423
	} else if (substr($interface, 0, 5) == '_lloc') {
6424
		/* No link-local address for v4. */
6425
		return null;
6426
	}
6427

    
6428
	$realif = get_failover_interface($interface, 'inet');
6429
	if (!$realif) {
6430
		return null;
6431
	}
6432

    
6433
	if (substr($realif, 0, 4) == '_vip') {
6434
		return get_configured_vip_ipv4($realif);
6435
	} else if (substr($realif, 0, 5) == '_lloc') {
6436
		/* No link-local address for v4. */
6437
		return null;
6438
	}
6439

    
6440
	if (is_array($config['interfaces'][$interface]) &&
6441
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6442
		return ($config['interfaces'][$interface]['ipaddr']);
6443
	}
6444

    
6445
	/*
6446
	 * Beaware that find_interface_ip() is our last option, it will
6447
	 * return the first IP it find on interface, not necessarily the
6448
	 * main IP address.
6449
	 */
6450
	$curip = find_interface_ip($realif);
6451
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6452
		return $curip;
6453
	} else {
6454
		return null;
6455
	}
6456
}
6457

    
6458
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6459
	global $config;
6460

    
6461
	if (substr($interface, 0, 4) == '_vip') {
6462
		return get_configured_vip_ipv6($interface);
6463
	} else if (substr($interface, 0, 5) == '_lloc') {
6464
		return get_interface_linklocal($interface);
6465
	}
6466

    
6467
	$realif = get_failover_interface($interface, 'inet6');
6468
	if (!$realif) {
6469
		return null;
6470
	}
6471

    
6472
	if (substr($realif, 0, 4) == '_vip') {
6473
		return get_configured_vip_ipv6($realif);
6474
	} else if (substr($realif, 0, 5) == '_lloc') {
6475
		return get_interface_linklocal($realif);
6476
	}
6477

    
6478
	if (is_array($config['interfaces'][$interface])) {
6479
		switch ($config['interfaces'][$interface]['ipaddr']) {
6480
			case 'pppoe':
6481
			case 'l2tp':
6482
			case 'pptp':
6483
			case 'ppp':
6484
				if (($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') ||
6485
				    ($config['interfaces'][$interface]['ipaddrv6'] == 'slaac')) {
6486
					$realif = get_real_interface($interface, 'inet6', false);
6487
				}
6488
				break;
6489
		}
6490
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6491
			return ($config['interfaces'][$interface]['ipaddrv6']);
6492
		}
6493
	}
6494

    
6495
	/*
6496
	 * Beaware that find_interface_ip() is our last option, it will
6497
	 * return the first IP it find on interface, not necessarily the
6498
	 * main IP address.
6499
	 */
6500
	$curip = find_interface_ipv6($realif, $flush);
6501
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6502
		return $curip;
6503
	} else {
6504
		/*
6505
		 * NOTE: On the case when only the prefix is requested,
6506
		 * the communication on WAN will be done over link-local.
6507
		 */
6508
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6509
			$curip = find_interface_ipv6_ll($realif, $flush);
6510
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6511
				return $curip;
6512
			}
6513
		}
6514
	}
6515
	return null;
6516
}
6517

    
6518
function get_interface_linklocal($interface = "wan") {
6519

    
6520
	$realif = get_failover_interface($interface, 'inet6');
6521
	if (!$realif) {
6522
		return null;
6523
	}
6524

    
6525
	if (substr($interface, 0, 4) == '_vip') {
6526
		$realif = get_real_interface($interface);
6527
	} else if (substr($interface, 0, 5) == '_lloc') {
6528
		$realif = get_real_interface(substr($interface, 5));
6529
	}
6530

    
6531
	$curip = find_interface_ipv6_ll($realif);
6532
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6533
		return $curip;
6534
	} else {
6535
		return null;
6536
	}
6537
}
6538

    
6539
function get_interface_subnet($interface = "wan") {
6540
	global $config;
6541

    
6542
	if (substr($interface, 0, 4) == '_vip') {
6543
		return (get_configured_vip_subnetv4($interface));
6544
	}
6545

    
6546
	if (is_array($config['interfaces'][$interface]) &&
6547
	    !empty($config['interfaces'][$interface]['subnet']) &&
6548
	    is_ipaddrv4($config['interfaces'][$interface]['ipaddr'])) {
6549
		return ($config['interfaces'][$interface]['subnet']);
6550
	}
6551

    
6552
	$realif = get_real_interface($interface);
6553
	if (!$realif) {
6554
		return (NULL);
6555
	}
6556

    
6557
	$cursn = find_interface_subnet($realif);
6558
	if (!empty($cursn)) {
6559
		return ($cursn);
6560
	}
6561

    
6562
	return (NULL);
6563
}
6564

    
6565
function get_interface_subnetv6($interface = "wan") {
6566
	global $config;
6567

    
6568
	if (substr($interface, 0, 4) == '_vip') {
6569
		return (get_configured_vip_subnetv6($interface));
6570
	} else if (substr($interface, 0, 5) == '_lloc') {
6571
		$interface = substr($interface, 5);
6572
	}
6573

    
6574
	if (is_array($config['interfaces'][$interface]) &&
6575
	    !empty($config['interfaces'][$interface]['subnetv6']) &&
6576
	    is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6577
		return ($config['interfaces'][$interface]['subnetv6']);
6578
	}
6579

    
6580
	$realif = get_real_interface($interface, 'inet6');
6581
	if (!$realif) {
6582
		return (NULL);
6583
	}
6584

    
6585
	$cursn = find_interface_subnetv6($realif);
6586
	if (!empty($cursn)) {
6587
		return ($cursn);
6588
	}
6589

    
6590
	return (NULL);
6591
}
6592

    
6593
/* return outside interfaces with a gateway */
6594
function get_interfaces_with_gateway() {
6595
	global $config;
6596

    
6597
	$ints = array();
6598

    
6599
	/* loop interfaces, check config for outbound */
6600
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6601
		switch ($ifname['ipaddr']) {
6602
			case "dhcp":
6603
			case "pppoe":
6604
			case "pptp":
6605
			case "l2tp":
6606
			case "ppp":
6607
				$ints[$ifdescr] = $ifdescr;
6608
				break;
6609
			default:
6610
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6611
				    !empty($ifname['gateway'])) {
6612
					$ints[$ifdescr] = $ifdescr;
6613
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6614
				    !empty($ifname['gateway'])) {
6615
					$ints[$ifdescr] = $ifdescr;
6616
				}
6617

    
6618
				break;
6619
		}
6620
	}
6621
	return $ints;
6622
}
6623

    
6624
/* return true if interface has a gateway */
6625
function interface_has_gateway($friendly) {
6626
	global $config;
6627

    
6628
	if (!empty($config['interfaces'][$friendly])) {
6629
		$ifname = &$config['interfaces'][$friendly];
6630
		switch ($ifname['ipaddr']) {
6631
			case "dhcp":
6632
			case "pppoe":
6633
			case "pptp":
6634
			case "l2tp":
6635
			case "ppp":
6636
				return true;
6637
			break;
6638
			default:
6639
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6640
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6641
					return true;
6642
				}
6643
				$tunnelif = substr($ifname['if'], 0, 3);
6644
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6645
					if (find_interface_ip($ifname['if'])) {
6646
						return true;
6647
					}
6648
				}
6649
				if (!empty($ifname['gateway'])) {
6650
					return true;
6651
				}
6652
			break;
6653
		}
6654
	}
6655

    
6656
	return false;
6657
}
6658

    
6659
/* return true if interface has a gateway */
6660
function interface_has_gatewayv6($friendly) {
6661
	global $config;
6662

    
6663
	if (!empty($config['interfaces'][$friendly])) {
6664
		$ifname = &$config['interfaces'][$friendly];
6665
		switch ($ifname['ipaddrv6']) {
6666
			case "slaac":
6667
			case "dhcp6":
6668
			case "6to4":
6669
			case "6rd":
6670
				return true;
6671
				break;
6672
			default:
6673
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6674
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6675
					return true;
6676
				}
6677
				$tunnelif = substr($ifname['if'], 0, 3);
6678
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6679
					if (find_interface_ipv6($ifname['if'])) {
6680
						return true;
6681
					}
6682
				}
6683
				if (!empty($ifname['gatewayv6'])) {
6684
					return true;
6685
				}
6686
				break;
6687
		}
6688
	}
6689

    
6690
	return false;
6691
}
6692

    
6693
/****f* interfaces/is_altq_capable
6694
 * NAME
6695
 *   is_altq_capable - Test if interface is capable of using ALTQ
6696
 * INPUTS
6697
 *   $int            - string containing interface name
6698
 * RESULT
6699
 *   boolean         - true or false
6700
 ******/
6701

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

    
6717
	$int_family = remove_ifindex($int);
6718

    
6719
	if (in_array($int_family, $capable)) {
6720
		return true;
6721
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6722
		return true;
6723
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6724
		return true;
6725
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6726
		return true;
6727
	} else {
6728
		return false;
6729
	}
6730
}
6731

    
6732
/****f* interfaces/is_interface_wireless
6733
 * NAME
6734
 *   is_interface_wireless - Returns if an interface is wireless
6735
 * RESULT
6736
 *   $tmp       - Returns if an interface is wireless
6737
 ******/
6738
function is_interface_wireless($interface) {
6739
	global $config, $g;
6740

    
6741
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6742
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6743
		if (preg_match($g['wireless_regex'], $interface)) {
6744
			if (isset($config['interfaces'][$friendly])) {
6745
				$config['interfaces'][$friendly]['wireless'] = array();
6746
			}
6747
			return true;
6748
		}
6749
		return false;
6750
	} else {
6751
		return true;
6752
	}
6753
}
6754

    
6755
function get_wireless_modes($interface) {
6756
	/* return wireless modes and channels */
6757
	$wireless_modes = array();
6758

    
6759
	$cloned_interface = get_real_interface($interface);
6760

    
6761
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6762
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6763
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6764
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6765

    
6766
		$interface_channels = "";
6767
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6768
		$interface_channel_count = count($interface_channels);
6769

    
6770
		$c = 0;
6771
		while ($c < $interface_channel_count) {
6772
			$channel_line = explode(",", $interface_channels["$c"]);
6773
			$wireless_mode = trim($channel_line[0]);
6774
			$wireless_channel = trim($channel_line[1]);
6775
			if (trim($wireless_mode) != "") {
6776
				/* if we only have 11g also set 11b channels */
6777
				if ($wireless_mode == "11g") {
6778
					if (!isset($wireless_modes["11b"])) {
6779
						$wireless_modes["11b"] = array();
6780
					}
6781
				} else if ($wireless_mode == "11g ht") {
6782
					if (!isset($wireless_modes["11b"])) {
6783
						$wireless_modes["11b"] = array();
6784
					}
6785
					if (!isset($wireless_modes["11g"])) {
6786
						$wireless_modes["11g"] = array();
6787
					}
6788
					$wireless_mode = "11ng";
6789
				} else if ($wireless_mode == "11a ht") {
6790
					if (!isset($wireless_modes["11a"])) {
6791
						$wireless_modes["11a"] = array();
6792
					}
6793
					$wireless_mode = "11na";
6794
				}
6795
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6796
			}
6797
			$c++;
6798
		}
6799
	}
6800
	return($wireless_modes);
6801
}
6802

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

    
6808
		$interface_channels = "";
6809
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6810
		return $interface_channels;
6811
}
6812

    
6813
/* return wireless HT modes */
6814
function get_wireless_ht_modes($interface) {
6815
	$wireless_hts_supported = array(0 => gettext('Auto'));
6816

    
6817
	$cloned_interface = get_real_interface($interface);
6818

    
6819
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6820
		$interface_channels = get_wireless_channels($cloned_interface);
6821

    
6822
		foreach ($interface_channels as $channel) {
6823
			$channel_line = explode(",", $channel);
6824
			$wireless_ht = trim($channel_line[1]);
6825
			if (!empty($wireless_ht)) {
6826
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
6827
			}
6828
		}
6829
	}
6830
	return($wireless_hts_supported);
6831
}
6832

    
6833
/* return wireless HT by channel/standard */
6834
function get_wireless_ht_list($interface) {
6835
	$wireless_hts = array();
6836

    
6837
	$cloned_interface = get_real_interface($interface);
6838

    
6839
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6840
		$interface_channels = get_wireless_channels($cloned_interface);
6841
		$interface_channel_count = count($interface_channels);
6842

    
6843
		$c = 0;
6844
		while ($c < $interface_channel_count) {
6845
			$channel_line = explode(",", $interface_channels["$c"]);
6846
			$wireless_mode = trim($channel_line[0]);
6847
			$wireless_ht = trim($channel_line[1]);
6848
			$wireless_channel = trim($channel_line[2]);
6849
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
6850
				if ($wireless_mode == "11g") {
6851
					if (!isset($wireless_modes["11g"])) {
6852
						$wireless_hts["11g"] = array();
6853
					}
6854
					$wireless_mode = "11ng";
6855
				} elseif ($wireless_mode == "11a") {
6856
					if (!isset($wireless_modes["11a"])) {
6857
						$wireless_hts["11a"] = array();
6858
					}
6859
					$wireless_mode = "11na";
6860
				}
6861
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
6862
			}
6863
			$c++;
6864
		}
6865
	}
6866
	return($wireless_hts);
6867
}
6868

    
6869
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6870
function get_wireless_channel_info($interface) {
6871
	$wireless_channels = array();
6872

    
6873
	$cloned_interface = get_real_interface($interface);
6874

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

    
6880
		$interface_channels = "";
6881
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6882

    
6883
		foreach ($interface_channels as $channel_line) {
6884
			$channel_line = explode(",", $channel_line);
6885
			if (!isset($wireless_channels[$channel_line[0]])) {
6886
				$wireless_channels[$channel_line[0]] = $channel_line;
6887
			}
6888
		}
6889
	}
6890
	return($wireless_channels);
6891
}
6892

    
6893
function set_interface_mtu($interface, $mtu) {
6894

    
6895
	/* LAGG interface must be destroyed and re-created to change MTU */
6896
	if ((substr($interface, 0, 4) == 'lagg') &&
6897
	    (!strstr($interface, "."))) {
6898
		if (isset($config['laggs']['lagg']) &&
6899
		    is_array($config['laggs']['lagg'])) {
6900
			foreach ($config['laggs']['lagg'] as $lagg) {
6901
				if ($lagg['laggif'] == $interface) {
6902
					interface_lagg_configure($lagg);
6903
					break;
6904
				}
6905
			}
6906
		}
6907
	} else {
6908
		pfSense_interface_mtu($interface, $mtu);
6909
		set_ipv6routes_mtu($interface, $mtu);
6910
	}
6911
}
6912

    
6913
/****f* interfaces/get_interface_mtu
6914
 * NAME
6915
 *   get_interface_mtu - Return the mtu of an interface
6916
 * RESULT
6917
 *   $tmp       - Returns the mtu of an interface
6918
 ******/
6919
function get_interface_mtu($interface) {
6920
	$mtu = pfSense_interface_getmtu($interface);
6921
	return $mtu['mtu'];
6922
}
6923

    
6924
function get_interface_mac($interface) {
6925
	$macinfo = pfSense_get_interface_addresses($interface);
6926
	return $macinfo["macaddr"];
6927
}
6928

    
6929
function get_interface_vendor_mac($interface) {
6930
	global $config, $g;
6931

    
6932
	$macinfo = pfSense_get_interface_addresses($interface);
6933
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
6934
	    "00:00:00:00:00:00") {
6935
		return ($macinfo["hwaddr"]);
6936
	}
6937

    
6938
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
6939
	if (file_exists($hwaddr_file)) {
6940
		$macaddr = trim(file_get_contents($hwaddr_file));
6941
		if (is_macaddr($macaddr)) {
6942
			return ($macaddr);
6943
		}
6944
	} elseif (is_macaddr($macinfo['macaddr'])) {
6945
		/* Save original macaddress to be restored when necessary */
6946
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
6947
	}
6948

    
6949
	return (NULL);
6950
}
6951

    
6952
/****f* pfsense-utils/generate_random_mac_address
6953
 * NAME
6954
 *   generate_random_mac - generates a random mac address
6955
 * INPUTS
6956
 *   none
6957
 * RESULT
6958
 *   $mac - a random mac address
6959
 ******/
6960
function generate_random_mac_address() {
6961
	$mac = "02";
6962
	for ($x = 0; $x < 5; $x++) {
6963
		$mac .= ":" . dechex(rand(16, 255));
6964
	}
6965
	return $mac;
6966
}
6967

    
6968
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6969
	global $g;
6970

    
6971
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6972

    
6973
	if (!empty($iface) && !empty($pppif)) {
6974
		$cron_cmd = <<<EOD
6975
#!/bin/sh
6976
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
6977
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
6978

    
6979
EOD;
6980

    
6981
		@file_put_contents($cron_file, $cron_cmd);
6982
		chmod($cron_file, 0755);
6983
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
6984
	} else {
6985
		unlink_if_exists($cron_file);
6986
	}
6987
}
6988

    
6989
function get_interface_default_mtu($type = "ethernet") {
6990
	switch ($type) {
6991
		case "gre":
6992
			return 1476;
6993
			break;
6994
		case "gif":
6995
			return 1280;
6996
			break;
6997
		case "tun":
6998
		case "vlan":
6999
		case "tap":
7000
		case "ethernet":
7001
		default:
7002
			return 1500;
7003
			break;
7004
	}
7005

    
7006
	/* Never reached */
7007
	return 1500;
7008
}
7009

    
7010
function get_vip_descr($ipaddress) {
7011
	global $config;
7012

    
7013
	foreach ($config['virtualip']['vip'] as $vip) {
7014
		if ($vip['subnet'] == $ipaddress) {
7015
			return ($vip['descr']);
7016
		}
7017
	}
7018
	return "";
7019
}
7020

    
7021
function interfaces_staticarp_configure($if) {
7022
	global $config, $g;
7023
	if (isset($config['system']['developerspew'])) {
7024
		$mt = microtime();
7025
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7026
	}
7027

    
7028
	$ifcfg = $config['interfaces'][$if];
7029

    
7030
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
7031
		return 0;
7032
	}
7033

    
7034
	/* Enable staticarp, if enabled */
7035
	if (isset($config['dhcpd'][$if]['staticarp'])) {
7036
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7037
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7038
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
7039
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
7040
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
7041
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7042
				}
7043
			}
7044
		}
7045
	} else {
7046
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7047
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7048
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
7049
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
7050
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
7051
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7052
				}
7053
			}
7054
		}
7055
	}
7056

    
7057
	return 0;
7058
}
7059

    
7060
function get_failover_interface($interface, $family = "all") {
7061
	global $config;
7062

    
7063
	/* shortcut to get_real_interface if we find it in the config */
7064
	if (is_array($config['interfaces'][$interface])) {
7065
		return get_real_interface($interface, $family);
7066
	}
7067

    
7068
	/* compare against gateway groups */
7069
	$a_groups = return_gateway_groups_array(true);
7070
	if (is_array($a_groups[$interface])) {
7071
		/* we found a gateway group, fetch the interface or vip */
7072
		if (!empty($a_groups[$interface][0]['vip'])) {
7073
			return $a_groups[$interface][0]['vip'];
7074
		} else {
7075
			return $a_groups[$interface][0]['int'];
7076
		}
7077
	}
7078
	/* fall through to get_real_interface */
7079
	/* XXX: Really needed? */
7080
	return get_real_interface($interface, $family);
7081
}
7082

    
7083
/****f* interfaces/interface_has_dhcp
7084
 * NAME
7085
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7086
 * INPUTS
7087
 *   interface or gateway group name
7088
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7089
 * RESULT
7090
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7091
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7092
 ******/
7093
function interface_has_dhcp($interface, $family = 4) {
7094
	global $config;
7095

    
7096
	if ($config['interfaces'][$interface]) {
7097
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
7098
			return true;
7099
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
7100
			return true;
7101
		} else {
7102
			return false;
7103
		}
7104
	}
7105

    
7106
	if (!is_array($config['gateways']['gateway_group'])) {
7107
		return false;
7108
	}
7109

    
7110
	if ($family == 6) {
7111
		$dhcp_string = "_DHCP6";
7112
	} else {
7113
		$dhcp_string = "_DHCP";
7114
	}
7115

    
7116
	foreach ($config['gateways']['gateway_group'] as $group) {
7117
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7118
			continue;
7119
		}
7120
		foreach ($group['item'] as $item) {
7121
			$item_data = explode("|", $item);
7122
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7123
				return true;
7124
			}
7125
		}
7126
	}
7127

    
7128
	return false;
7129
}
7130

    
7131
function remove_ifindex($ifname) {
7132
	return preg_replace("/[0-9]+$/", "", $ifname);
7133
}
7134

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

    
7138
	$viplist = get_configured_vip_list($family, $type);
7139
	foreach ($viplist as $vip => $address) {
7140
		$interfaces[$vip] = $address;
7141
		if ($type = VIP_CARP) {
7142
			$vip = get_configured_vip($vipid);
7143
			if (isset($vip) && is_array($vip) ) {
7144
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7145
			}
7146
		}
7147
		if (get_vip_descr($address)) {
7148
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
7149
		}
7150
	}
7151
	return $interfaces;
7152
}
7153

    
7154
function return_gateway_groups_array_with_descr() {
7155
	$interfaces = array();
7156
	$grouplist = return_gateway_groups_array();
7157
	foreach ($grouplist as $name => $group) {
7158
		if ($group[0]['vip'] != "") {
7159
			$vipif = $group[0]['vip'];
7160
		} else {
7161
			$vipif = $group[0]['int'];
7162
		}
7163

    
7164
		$interfaces[$name] = "GW Group {$name}";
7165
	}
7166
	return $interfaces;
7167
}
7168

    
7169
function get_serial_ports() {
7170
	$linklist = array();
7171
	if (!is_dir("/var/spool/lock")) {
7172
		mwexec("/bin/mkdir -p /var/spool/lock");
7173
	}
7174
	$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);
7175
	foreach ($serialports as $port) {
7176
		$linklist[$port] = trim($port);
7177
	}
7178
	return $linklist;
7179
}
7180

    
7181
function get_interface_ports() {
7182
	global $config;
7183
	$linklist = array();
7184
	$portlist = get_interface_list();
7185
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7186
		foreach ($config['vlans']['vlan'] as $vlan) {
7187
			$portlist[$vlan['vlanif']] = $vlan;
7188
		}
7189
	}
7190

    
7191
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7192
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7193
			$members = explode(" ", $qinq['members']);
7194
			foreach ($members as $mem) {
7195
				$qentry = $qinq['vlanif'] . "." . $mem;
7196
				$portlist[$qentry] = $qentry;
7197
			}
7198
		}
7199
	}
7200

    
7201
	foreach ($portlist as $ifn => $ifinfo) {
7202
		$string = "";
7203
		if (is_array($ifinfo)) {
7204
			$string .= $ifn;
7205
			if ($ifinfo['mac']) {
7206
				$string .= " ({$ifinfo['mac']})";
7207
			}
7208
			if ($ifinfo['friendly']) {
7209
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7210
			} elseif ($ifinfo['descr']) {
7211
				$string .= " - {$ifinfo['descr']}";
7212
			}
7213
		} else {
7214
			$string .= $ifinfo;
7215
		}
7216

    
7217
		$linklist[$ifn] = $string;
7218
	}
7219
	return $linklist;
7220
}
7221

    
7222
function build_ppps_link_list() {
7223
	global $pconfig;
7224

    
7225
	$linklist = array('list' => array(), 'selected' => array());
7226

    
7227
	if ($pconfig['type'] == 'ppp') {
7228
		$linklist['list'] = get_serial_ports();
7229
	} else {
7230
		$iflist = get_interface_ports();
7231

    
7232
		$viplist = array();
7233
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7234
		foreach ($carplist as $vid => $vaddr) {
7235
			$vip = get_configured_vip($vid);
7236
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7237
		}
7238

    
7239
		$linklist['list'] = array_merge($iflist, $viplist);
7240

    
7241
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7242
		$lagglist = get_lagg_interface_list();
7243
		foreach ($lagglist as $laggif => $lagg) {
7244
			/* LAGG members cannot be assigned */
7245
			$laggmembers = explode(',', $lagg['members']);
7246
			foreach ($laggmembers as $lagm) {
7247
				if (isset($linklist['list'][$lagm])) {
7248
					unset($linklist['list'][$lagm]);
7249
				}
7250
			}
7251
		}
7252
	}
7253

    
7254
	$selected_ports = array();
7255
	if (is_array($pconfig['interfaces'])) {
7256
		$selected_ports = $pconfig['interfaces'];
7257
	} elseif (!empty($pconfig['interfaces'])) {
7258
		$selected_ports = explode(',', $pconfig['interfaces']);
7259
	}
7260
	foreach ($selected_ports as $port) {
7261
		if (isset($linklist['list'][$port])) {
7262
			array_push($linklist['selected'], $port);
7263
		}
7264
	}
7265
	return($linklist);
7266
}
7267

    
7268
function create_interface_list() {
7269
	global $config;
7270

    
7271
	$iflist = array();
7272

    
7273
	// add group interfaces
7274
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7275
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7276
			if (have_ruleint_access($ifgen['ifname'])) {
7277
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7278
			}
7279
		}
7280
	}
7281

    
7282
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7283
		if (have_ruleint_access($ifent)) {
7284
			$iflist[$ifent] = $ifdesc;
7285
		}
7286
	}
7287

    
7288
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
7289
		$iflist['l2tp'] = gettext('L2TP VPN');
7290
	}
7291

    
7292
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
7293
		$iflist['pppoe'] = gettext("PPPoE Server");
7294
	}
7295

    
7296
	// add ipsec interfaces
7297
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
7298
		$iflist["enc0"] = gettext("IPsec");
7299
	}
7300

    
7301
	// add openvpn/tun interfaces
7302
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7303
		$iflist["openvpn"] = gettext("OpenVPN");
7304
	}
7305

    
7306
	return($iflist);
7307
}
7308

    
7309
function is_pseudo_interface($inf, $tap=true) {
7310
	global $config;
7311
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7312
	foreach ($psifs as $pif) {
7313
		if (substr($inf, 0, strlen($pif)) == $pif) {
7314
			if (($pif == 'ovpn') && $tap) {
7315
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7316
				$type = ($m[1] == 'c') ? 'client' : 'server';
7317
				foreach ($config['openvpn']['openvpn-'.$type] as $ovpn) {
7318
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7319
						return false; 	
7320
					} elseif ($ovpn['vpnid'] == $m[2]) {
7321
						return true;
7322
					}
7323
				}
7324
			} else {
7325
				return true;
7326
			}
7327
		}
7328
	}
7329
	return false;
7330
}
7331

    
7332
function is_stf_interface($inf) {
7333
	global $config;
7334

    
7335
	if (is_array($config['interfaces'][$inf]) &&
7336
	    (($config['interfaces'][$inf]['ipaddrv6'] == '6rd') ||
7337
	    ($config['interfaces'][$inf]['ipaddrv6'] == '6to4'))) {
7338
	    return true;
7339
	}
7340

    
7341
	return false;
7342
}
7343

    
7344
?>
(22-22/60)