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

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

    
711
function interface_bridge_configure(&$bridge, $checkmember = 0) {
712
	global $config, $g;
713

    
714
	if (!is_array($bridge)) {
715
		return;
716
	}
717

    
718
	if (empty($bridge['members'])) {
719
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
720
		return;
721
	}
722

    
723
	$members = explode(',', $bridge['members']);
724
	if (!count($members)) {
725
		return;
726
	}
727

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

    
753
	/* Just in case anything is not working well */
754
	if ($smallermtu == 0) {
755
		$smallermtu = 1500;
756
	}
757

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

    
769
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
770
	if ($bridgemtu > $smallermtu) {
771
		$smallermtu = $bridgemtu;
772
	}
773

    
774
	$checklist = get_configured_interface_list();
775

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

    
793
	if (isset($bridge['enablestp'])) {
794
		interface_bridge_configure_stp($bridge);
795
	}
796

    
797
	interface_bridge_configure_advanced($bridge);
798

    
799
	interface_bridge_configure_ip6linklocal($bridge);
800

    
801
	if ($bridge['bridgeif']) {
802
		interfaces_bring_up($bridge['bridgeif']);
803
	} else {
804
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
805
	}
806
}
807

    
808
function interface_bridge_configure_stp($bridge) {
809
	if (isset($bridge['enablestp'])) {
810
		$bridgeif = trim($bridge['bridgeif']);
811
		/* configure spanning tree proto */
812
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
813

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

    
867
function interface_bridge_configure_advanced($bridge) {
868
	$bridgeif = trim($bridge['bridgeif']);
869

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

    
927
function interface_bridge_configure_ip6linklocal($bridge) {
928
	$bridgeif = trim($bridge['bridgeif']);
929

    
930
	$members = explode(',', $bridge['members']);
931
	if (!count($members)) {
932
		return;
933
	}
934

    
935
	$auto_linklocal = isset($bridge['ip6linklocal']);
936
	$bridgeop = $auto_linklocal ? '' : '-';
937
	$memberop = $auto_linklocal ? '-' : '';
938

    
939
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
940
	foreach ($members as $member) {
941
		$realif = get_real_interface($member);
942
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
943
	}
944
}
945

    
946
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
947
	global $config;
948

    
949
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
950
		return;
951
	}
952

    
953
	if ($flagsapplied == false) {
954
		$mtu = get_interface_mtu($bridgeif);
955
		$mtum = get_interface_mtu($interface);
956
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
957
			pfSense_interface_mtu($interface, $mtu);
958
		}
959

    
960
		hardware_offloading_applyflags($interface);
961
		interfaces_bring_up($interface);
962
	}
963

    
964
	pfSense_bridge_add_member($bridgeif, $interface);
965
	if (is_array($config['bridges']['bridged'])) {
966
		foreach ($config['bridges']['bridged'] as $bridge) {
967
			if ($bridgeif == $bridge['bridgeif']) {
968
				interface_bridge_configure_stp($bridge);
969
				interface_bridge_configure_advanced($bridge);
970
			}
971
		}
972
	}
973
}
974

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

    
999
function interface_lagg_configure($lagg) {
1000
	global $config, $g;
1001

    
1002
	if (!is_array($lagg)) {
1003
		return -1;
1004
	}
1005

    
1006
	$members = explode(',', $lagg['members']);
1007
	if (!count($members)) {
1008
		return -1;
1009
	}
1010

    
1011
	if (platform_booting() || !(empty($lagg['laggif']))) {
1012
		pfSense_interface_destroy($lagg['laggif']);
1013
		pfSense_interface_create($lagg['laggif']);
1014
		$laggif = $lagg['laggif'];
1015
	} else {
1016
		$laggif = pfSense_interface_create("lagg");
1017
	}
1018

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

    
1032
	/* Just in case anything is not working well */
1033
	if ($lagg_mtu == 0) {
1034
		$lagg_mtu = 1500;
1035
	}
1036

    
1037
	// put failover master interface on top of list
1038
	if (($lagg['proto'] == 'failover') && isset($lagg['failovermaster']) &&
1039
	    ($lagg['failovermaster'] != 'auto')) {
1040
		unset($members[array_search($lagg['failovermaster'], $members)]);
1041
		$members = array_merge(array($lagg['failovermaster']), $members);
1042
	}
1043

    
1044
	if (($lagg['proto'] == 'lacp') && isset($lagg['lacptimeout']) &&
1045
	    ($lagg['lacptimeout'] != 'slow')) {
1046
		$lacptimeout = 'lacp_fast_timeout';
1047
	} else {
1048
		$lacptimeout = '';
1049
	}
1050

    
1051
	foreach ($members as $member) {
1052
		if (!does_interface_exist($member)) {
1053
			continue;
1054
		}
1055

    
1056
		/* make sure the parent interface is up */
1057
		pfSense_interface_mtu($member, $lagg_mtu);
1058
		interfaces_bring_up($member);
1059
		hardware_offloading_applyflags($member);
1060

    
1061
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
1062
		$laggif = str_replace("\0", "", $laggif);
1063
		$member = str_replace("\0", "", $member);
1064
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
1065
	}
1066

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

    
1069
	interfaces_bring_up($laggif);
1070

    
1071
	return $laggif;
1072
}
1073

    
1074
function interfaces_gre_configure($checkparent = 0, $realif = "") {
1075
	global $config;
1076

    
1077
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
1078
		foreach ($config['gres']['gre'] as $i => $gre) {
1079
			if (empty($gre['greif'])) {
1080
				$gre['greif'] = "gre{$i}";
1081
			}
1082
			if (!empty($realif) && $realif != $gre['greif']) {
1083
				continue;
1084
			}
1085

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

    
1108
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
1109
function interface_gre_configure(&$gre, $grekey = "") {
1110
	global $config, $g;
1111

    
1112
	if (!is_array($gre)) {
1113
		return -1;
1114
	}
1115

    
1116
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1117
	if (!interface_is_vlan($realif)) {
1118
		$realif = get_real_interface($gre['if']);
1119
	}
1120
	$realifip = get_interface_ip($gre['if']);
1121
	$realifip6 = get_interface_ipv6($gre['if']);
1122

    
1123
	/* make sure the parent interface is up */
1124
	interfaces_bring_up($realif);
1125

    
1126
	if (platform_booting() || !(empty($gre['greif']))) {
1127
		pfSense_interface_destroy($gre['greif']);
1128
		pfSense_interface_create($gre['greif']);
1129
		$greif = $gre['greif'];
1130
	} else {
1131
		$greif = pfSense_interface_create("gre");
1132
	}
1133

    
1134
	$tunnel_type = '';
1135
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1136
		$tunnel_type = 'v4';
1137
	}
1138
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1139
		$tunnel_type .= 'v6';
1140
	}
1141

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

    
1156
	$parentif = get_real_interface($gre['if']);
1157
	if ($parentif) {
1158
		interfaces_bring_up($parentif);
1159
	} else {
1160
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1161
	}
1162

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

    
1178
	interfaces_bring_up($greif);
1179

    
1180
	return $greif;
1181
}
1182

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

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

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

    
1217
function is_greipsec($if) {
1218
	global $config;
1219

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

    
1239
function interfaces_gif_configure($checkparent = 0, $realif = "") {
1240
	global $config;
1241

    
1242
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
1243
		foreach ($config['gifs']['gif'] as $i => $gif) {
1244
			if (empty($gif['gifif'])) {
1245
				$gre['gifif'] = "gif{$i}";
1246
			}
1247
			if (!empty($realif) && $realif != $gif['gifif']) {
1248
				continue;
1249
			}
1250

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

    
1274
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1275
function interface_gif_configure(&$gif, $gifkey = "") {
1276
	global $config, $g;
1277

    
1278
	if (!is_array($gif)) {
1279
		return -1;
1280
	}
1281

    
1282
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1283
	if (!interface_is_vlan($realif)) {
1284
		$realif = get_real_interface($gif['if']);
1285
	}
1286
	$ipaddr = get_interface_ip($gif['if']);
1287

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

    
1311
	if (platform_booting() || !(empty($gif['gifif']))) {
1312
		pfSense_interface_destroy($gif['gifif']);
1313
		pfSense_interface_create($gif['gifif']);
1314
		$gifif = $gif['gifif'];
1315
	} else {
1316
		$gifif = pfSense_interface_create("gif");
1317
	}
1318

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

    
1358
	if (!platform_booting()) {
1359
		$iflist = get_configured_interface_list();
1360
		foreach ($iflist as $ifname) {
1361
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1362
				if (get_interface_gateway($ifname)) {
1363
					system_routing_configure($ifname);
1364
					break;
1365
				}
1366
				if (get_interface_gateway_v6($ifname)) {
1367
					system_routing_configure($ifname);
1368
					break;
1369
				}
1370
			}
1371
		}
1372
	}
1373

    
1374

    
1375
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1376
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1377
	}
1378
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1379
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1380
	}
1381

    
1382
	if (is_ipaddrv4($realifgw)) {
1383
		route_add_or_change("-host {$gif['remote-addr']} {$realifgw}");
1384
	}
1385
	if (is_ipaddrv6($realifgw)) {
1386
		route_add_or_change("-host -inet6 {$gif['remote-addr']} {$realifgw}");
1387
	}
1388

    
1389
	interfaces_bring_up($gifif);
1390

    
1391
	return $gifif;
1392
}
1393

    
1394
/* Build a list of IPsec interfaces */
1395
function interface_ipsec_vti_list_p1($ph1ent) {
1396
	global $config;
1397
	$iface_list = array();
1398

    
1399
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1400
		return $iface_list;
1401
	}
1402

    
1403
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1404
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1405
		return $iface_list;
1406
	}
1407

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

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

    
1457
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1458
		return false;
1459
	}
1460

    
1461
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1462
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1463
		return false;
1464
	}
1465

    
1466
	$left_spec = ipsec_get_phase1_src($ph1ent);
1467
	$right_spec = $ph1ent['remote-gateway'];
1468

    
1469
	$iface_addrs = array();
1470

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

    
1508
	foreach ($iface_addrs as $ipsecifnum => $addrs) {
1509
		$ipsecif = "ipsec{$ipsecifnum}";
1510
		if (!is_array($addrs)) {
1511
			continue;
1512
		}
1513
		// Create IPsec interface
1514
		if (!platform_booting() && does_interface_exist($ipsecif)) {
1515
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy", false);
1516
		}
1517
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1518

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

    
1523
		/* Loop through all of the addresses for this interface and apply them as needed */
1524
		foreach ($addrs as $addr) {
1525
			// apply interface addresses
1526
			if (is_v6($addr['left'])) {
1527
				$inet = "inet6";
1528
				$gwtype = "v6";
1529
				$right = '';
1530
			} else {
1531
				$inet = "inet";
1532
				$gwtype = "";
1533
				$right = escapeshellarg($addr['right']);
1534
			}
1535

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

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

    
1579
function interfaces_configure() {
1580
	global $config, $g;
1581

    
1582
	/* Set up our loopback interface */
1583
	interfaces_loopback_configure();
1584

    
1585
	/* create the unconfigured wireless clones */
1586
	interfaces_create_wireless_clones();
1587

    
1588
	/* set up LAGG virtual interfaces */
1589
	interfaces_lagg_configure();
1590

    
1591
	/* set up VLAN virtual interfaces */
1592
	interfaces_vlan_configure();
1593

    
1594
	interfaces_qinq_configure();
1595

    
1596
	/* set up IPsec VTI interfaces */
1597
	interfaces_ipsec_vti_configure();
1598

    
1599
	$iflist = get_configured_interface_with_descr();
1600
	$delayed_list = array();
1601
	$bridge_list = array();
1602
	$track6_list = array();
1603

    
1604
	/* This is needed to speedup interfaces on bootup. */
1605
	$reload = false;
1606
	if (!platform_booting()) {
1607
		$reload = true;
1608
	}
1609

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

    
1630
			if ($g['debug']) {
1631
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1632
			}
1633
			interface_configure($if, $reload);
1634
			if (platform_booting()) {
1635
				echo gettext("done.") . "\n";
1636
			}
1637
		}
1638
	}
1639

    
1640
	/*
1641
	 * NOTE: The following function parameter consists of
1642
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1643
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1644
	 */
1645

    
1646
	/* set up GRE virtual interfaces */
1647
	interfaces_gre_configure(1);
1648

    
1649
	/* set up GIF virtual interfaces */
1650
	interfaces_gif_configure(1);
1651

    
1652
	/* set up BRIDGe virtual interfaces */
1653
	interfaces_bridge_configure(1);
1654

    
1655
	foreach ($track6_list as $if => $ifname) {
1656
		if (platform_booting()) {
1657
			printf(gettext("Configuring %s interface..."), $ifname);
1658
		}
1659
		if ($g['debug']) {
1660
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1661
		}
1662

    
1663
		interface_configure($if, $reload);
1664

    
1665
		if (platform_booting()) {
1666
			echo gettext("done.") . "\n";
1667
		}
1668
	}
1669

    
1670
	/* bring up vip interfaces */
1671
	interfaces_vips_configure();
1672

    
1673
	/* set up GRE virtual interfaces */
1674
	interfaces_gre_configure(2);
1675

    
1676
	/* set up GIF virtual interfaces */
1677
	interfaces_gif_configure(2);
1678

    
1679
	foreach ($delayed_list as $if => $ifname) {
1680
		if (platform_booting()) {
1681
			printf(gettext("Configuring %s interface..."), $ifname);
1682
		}
1683
		if ($g['debug']) {
1684
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1685
		}
1686

    
1687
		interface_configure($if, $reload);
1688

    
1689
		if (platform_booting()) {
1690
			echo gettext("done.") . "\n";
1691
		}
1692
	}
1693

    
1694
	/* set up BRIDGe virtual interfaces */
1695
	interfaces_bridge_configure(2);
1696

    
1697
	foreach ($bridge_list as $if => $ifname) {
1698
		if (platform_booting()) {
1699
			printf(gettext("Configuring %s interface..."), $ifname);
1700
		}
1701
		if ($g['debug']) {
1702
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1703
		}
1704

    
1705
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1706
		// redmine #3997
1707
		interface_reconfigure($if, $reload);
1708
		interfaces_vips_configure($if);
1709

    
1710
		if (platform_booting()) {
1711
			echo gettext("done.") . "\n";
1712
		}
1713
	}
1714

    
1715
	/* configure interface groups */
1716
	interfaces_group_setup();
1717

    
1718
	if (!platform_booting()) {
1719
		/* reconfigure static routes (kernel may have deleted them) */
1720
		system_routing_configure();
1721

    
1722
		/* reload IPsec tunnels */
1723
		ipsec_configure();
1724

    
1725
		/* restart dns servers (defering dhcpd reload) */
1726
		if (isset($config['dnsmasq']['enable'])) {
1727
			services_dnsmasq_configure(false);
1728
		}
1729
		if (isset($config['unbound']['enable'])) {
1730
			services_unbound_configure(false);
1731
		}
1732

    
1733
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1734
		services_dhcpd_configure();
1735
	}
1736

    
1737
	return 0;
1738
}
1739

    
1740
function interface_reconfigure($interface = "wan", $reloadall = false) {
1741
	interface_bring_down($interface);
1742
	interface_configure($interface, $reloadall);
1743
}
1744

    
1745
function interface_vip_bring_down($vip) {
1746
	global $g;
1747

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

    
1777
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1778
	global $config, $g;
1779

    
1780
	if (!isset($config['interfaces'][$interface])) {
1781
		return;
1782
	}
1783

    
1784
	if ($g['debug']) {
1785
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1786
	}
1787

    
1788
	/*
1789
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1790
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1791
	 * Keep this in mind while doing changes here!
1792
	 */
1793
	if ($ifacecfg === false) {
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
	} elseif (!is_array($ifacecfg)) {
1799
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1800
		$ifcfg = $config['interfaces'][$interface];
1801
		$ppps = $config['ppps']['ppp'];
1802
		$realif = get_real_interface($interface);
1803
		$realifv6 = get_real_interface($interface, "inet6", true);
1804
	} else {
1805
		$ifcfg = $ifacecfg['ifcfg'];
1806
		$ppps = $ifacecfg['ppps'];
1807
		if (isset($ifacecfg['ifcfg']['realif'])) {
1808
			$realif = $ifacecfg['ifcfg']['realif'];
1809
			/* XXX: Any better way? */
1810
			$realifv6 = $realif;
1811
		} else {
1812
			$realif = get_real_interface($interface);
1813
			$realifv6 = get_real_interface($interface, "inet6", true);
1814
		}
1815
	}
1816

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

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

    
1925
	if (!empty($track6) && is_array($track6)) {
1926
		if (!function_exists('services_dhcpd_configure')) {
1927
			require_once('services.inc');
1928
		}
1929
		/* Bring down radvd and dhcp6 on these interfaces */
1930
		services_dhcpd_configure('inet6', $track6);
1931
	}
1932

    
1933
	$old_router = '';
1934
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1935
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1936
	}
1937

    
1938
	/* remove interface up file if it exists */
1939
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1940
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1941
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1942
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1943
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1944
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1945
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1946

    
1947
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1948
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1949
	if (is_array($ifcfg['wireless'])) {
1950
		kill_hostapd($realif);
1951
		mwexec(kill_wpasupplicant($realif));
1952
	}
1953

    
1954
	if ($destroy == true) {
1955
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^ipsec|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1956
			pfSense_interface_destroy($realif);
1957
		}
1958
	}
1959

    
1960
	return;
1961
}
1962

    
1963
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1964
	global $config;
1965
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1966
		unset($config["virtualip_carp_maintenancemode"]);
1967
		write_config("Leave CARP maintenance mode");
1968
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1969
		$config["virtualip_carp_maintenancemode"] = true;
1970
		write_config(gettext("Enter CARP maintenance mode"));
1971
	}
1972
	init_config_arr(array('virtualip', 'vip'));
1973
	$viparr = &$config['virtualip']['vip'];
1974

    
1975
	if (is_array($viparr)) {
1976
		foreach ($viparr as $vip) {
1977
			if ($vip['mode'] == "carp") {
1978
				interface_carp_configure($vip, true);
1979
			}
1980
		}
1981
	}
1982
}
1983

    
1984
function interface_wait_tentative($interface, $timeout = 10) {
1985
	if (!does_interface_exist($interface)) {
1986
		return false;
1987
	}
1988

    
1989
	$time = 0;
1990
	while ($time <= $timeout) {
1991
		$if = pfSense_get_interface_addresses($interface);
1992
		if (!isset($if['tentative'])) {
1993
			return true;
1994
		}
1995
		sleep(1);
1996
		$time++;
1997
	}
1998

    
1999
	return false;
2000
}
2001

    
2002
function interface_isppp_type($interface) {
2003
	global $config;
2004

    
2005
	if (!is_array($config['interfaces'][$interface])) {
2006
		return false;
2007
	}
2008

    
2009
	switch ($config['interfaces'][$interface]['ipaddr']) {
2010
		case 'pptp':
2011
		case 'l2tp':
2012
		case 'pppoe':
2013
		case 'ppp':
2014
			return true;
2015
			break;
2016
		default:
2017
			return false;
2018
			break;
2019
	}
2020
}
2021

    
2022
function interfaces_ptpid_used($ptpid) {
2023
	global $config;
2024

    
2025
	if (is_array($config['ppps']['ppp'])) {
2026
		foreach ($config['ppps']['ppp'] as & $settings) {
2027
			if ($ptpid == $settings['ptpid']) {
2028
				return true;
2029
			}
2030
		}
2031
	}
2032

    
2033
	return false;
2034
}
2035

    
2036
function interfaces_ptpid_next() {
2037

    
2038
	$ptpid = 0;
2039
	while (interfaces_ptpid_used($ptpid)) {
2040
		$ptpid++;
2041
	}
2042

    
2043
	return $ptpid;
2044
}
2045

    
2046
function getMPDCRONSettings($pppif) {
2047
	global $config;
2048

    
2049
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2050
	if (is_array($config['cron']['item'])) {
2051
		foreach ($config['cron']['item'] as $i => $item) {
2052
			if (stripos($item['command'], $cron_cmd_file) !== false) {
2053
				return array("ID" => $i, "ITEM" => $item);
2054
			}
2055
		}
2056
	}
2057

    
2058
	return NULL;
2059
}
2060

    
2061
function handle_pppoe_reset($post_array) {
2062
	global $config, $g;
2063

    
2064
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2065
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2066

    
2067
	if (!is_array($config['cron']['item'])) {
2068
		$config['cron']['item'] = array();
2069
	}
2070

    
2071
	$itemhash = getMPDCRONSettings($pppif);
2072

    
2073
	// reset cron items if necessary and return
2074
	if (empty($post_array['pppoe-reset-type'])) {
2075
		if (isset($itemhash)) {
2076
			unset($config['cron']['item'][$itemhash['ID']]);
2077
		}
2078
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2079
		return;
2080
	}
2081

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

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

    
2165
/*
2166
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2167
 * It writes the mpd config file to /var/etc every time the link is opened.
2168
 */
2169
function interface_ppps_configure($interface) {
2170
	global $config, $g;
2171

    
2172
	/* Return for unassigned interfaces. This is a minimum requirement. */
2173
	if (empty($config['interfaces'][$interface])) {
2174
		return 0;
2175
	}
2176
	$ifcfg = $config['interfaces'][$interface];
2177
	if (!isset($ifcfg['enable'])) {
2178
		return 0;
2179
	}
2180

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

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

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

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

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

    
2279
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2280
	    (is_array($ports) && count($ports) > 1)) {
2281
		$multilink = "enable";
2282
	} else {
2283
		$multilink = "disable";
2284
	}
2285

    
2286
	if ($type == "modem") {
2287
		if (is_ipaddr($ppp['localip'])) {
2288
			$localip = $ppp['localip'];
2289
		} else {
2290
			$localip = '0.0.0.0';
2291
		}
2292

    
2293
		if (is_ipaddr($ppp['gateway'])) {
2294
			$gateway = $ppp['gateway'];
2295
		} else {
2296
			$gateway = "10.64.64.{$pppid}";
2297
		}
2298
		$ranges = "{$localip}/0 {$gateway}/0";
2299

    
2300
		if (empty($ppp['apnum'])) {
2301
			$ppp['apnum'] = 1;
2302
		}
2303
	} else {
2304
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2305
	}
2306

    
2307
	if (isset($ppp['ondemand'])) {
2308
		$ondemand = "enable";
2309
	} else {
2310
		$ondemand = "disable";
2311
	}
2312
	if (!isset($ppp['idletimeout'])) {
2313
		$ppp['idletimeout'] = 0;
2314
	}
2315

    
2316
	if (empty($ppp['username']) && $type == "modem") {
2317
		$ppp['username'] = "user";
2318
		$ppp['password'] = "none";
2319
	}
2320
	if (empty($ppp['password']) && $type == "modem") {
2321
		$passwd = "none";
2322
	} else {
2323
		$passwd = base64_decode($ppp['password']);
2324
	}
2325

    
2326
	$bandwidths = explode(',', $ppp['bandwidth']);
2327
	$defaultmtu = "1492";
2328
	if (!empty($ifcfg['mtu'])) {
2329
		$defaultmtu = intval($ifcfg['mtu']);
2330
	}
2331
	if (isset($ppp['mtu'])) {
2332
		$mtus = explode(',', $ppp['mtu']);
2333
	}
2334
	if (isset($ppp['mru'])) {
2335
		$mrus = explode(',', $ppp['mru']);
2336
	}
2337
	if (isset($ppp['mrru'])) {
2338
		$mrrus = explode(',', $ppp['mrru']);
2339
	}
2340
	if (!empty($ifcfg['ipaddrv6'])) {
2341
		$ipv6cp = "set bundle enable ipv6cp";
2342
	}
2343

    
2344
	// Construct the mpd.conf file
2345
	$mpdconf = <<<EOD
2346
startup:
2347
	# configure the console
2348
	set console close
2349
	# configure the web server
2350
	set web close
2351

    
2352
default:
2353
{$ppp['type']}client:
2354
	create bundle static {$interface}
2355
	{$ipv6cp}
2356
	set iface name {$pppif}
2357

    
2358
EOD;
2359
	$setdefaultgw = false;
2360
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2361
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2362
	if ($defgw4['interface'] == $interface) {
2363
		$setdefaultgw = true;
2364
	}
2365

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

    
2375
EOD;
2376
	}
2377

    
2378
	$mpdconf .= <<<EOD
2379
	set iface {$ondemand} on-demand
2380
	set iface idle {$ppp['idletimeout']}
2381

    
2382
EOD;
2383

    
2384
	if (isset($ppp['ondemand'])) {
2385
		$mpdconf .= <<<EOD
2386
	set iface addrs 10.10.1.1 10.10.1.2
2387

    
2388
EOD;
2389
	}
2390

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

    
2411
EOD;
2412
	}
2413

    
2414
	if (isset($ppp['tcpmssfix'])) {
2415
		$tcpmss = "disable";
2416
	} else {
2417
		$tcpmss = "enable";
2418
	}
2419
	$mpdconf .= <<<EOD
2420
	set iface {$tcpmss} tcpmssfix
2421

    
2422
EOD;
2423

    
2424
	$mpdconf .= <<<EOD
2425
	set iface up-script /usr/local/sbin/ppp-linkup
2426
	set iface down-script /usr/local/sbin/ppp-linkdown
2427
	set ipcp ranges {$ranges}
2428

    
2429
EOD;
2430
	if (isset($ppp['vjcomp'])) {
2431
		$mpdconf .= <<<EOD
2432
	set ipcp no vjcomp
2433

    
2434
EOD;
2435
	}
2436

    
2437
	if (isset($config['system']['dnsallowoverride'])) {
2438
		$mpdconf .= <<<EOD
2439
	set ipcp enable req-pri-dns
2440
	set ipcp enable req-sec-dns
2441

    
2442
EOD;
2443
	}
2444

    
2445
	if (!isset($ppp['verbose_log'])) {
2446
		$mpdconf .= <<<EOD
2447
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2448

    
2449
EOD;
2450
	}
2451

    
2452
	foreach ($ports as $pid => $port) {
2453
		$port = get_real_interface($port);
2454
		$mpdconf .= <<<EOD
2455

    
2456
	create link static {$interface}_link{$pid} {$type}
2457
	set link action bundle {$interface}
2458
	set link {$multilink} multilink
2459
	set link keep-alive 10 60
2460
	set link max-redial 0
2461

    
2462
EOD;
2463
		if (isset($ppp['shortseq'])) {
2464
			$mpdconf .= <<<EOD
2465
	set link no shortseq
2466

    
2467
EOD;
2468
		}
2469

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

    
2474
EOD;
2475
		}
2476

    
2477
		if (isset($ppp['protocomp'])) {
2478
			$mpdconf .= <<<EOD
2479
	set link no protocomp
2480

    
2481
EOD;
2482
		}
2483

    
2484
		$mpdconf .= <<<EOD
2485
	set link disable chap pap
2486
	set link accept chap pap eap
2487
	set link disable incoming
2488

    
2489
EOD;
2490

    
2491

    
2492
		if (!empty($bandwidths[$pid])) {
2493
			$mpdconf .= <<<EOD
2494
	set link bandwidth {$bandwidths[$pid]}
2495

    
2496
EOD;
2497
		}
2498

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

    
2514
EOD;
2515
		}
2516

    
2517
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2518
		    !isset($ppp['mtu-override']) &&
2519
		    !empty($mrus[$pid])) {
2520
			$mpdconf .= <<<EOD
2521
	set link mru {$mrus[$pid]}
2522

    
2523
EOD;
2524
		}
2525

    
2526
		if (!empty($mrrus[$pid])) {
2527
			$mpdconf .= <<<EOD
2528
	set link mrru {$mrrus[$pid]}
2529

    
2530
EOD;
2531
		}
2532

    
2533
		$mpdconf .= <<<EOD
2534
	set auth authname "{$ppp['username']}"
2535
	set auth password {$passwd}
2536

    
2537
EOD;
2538
		if ($type == "modem") {
2539
			$mpdconf .= <<<EOD
2540
	set modem device {$ppp['ports']}
2541
	set modem script DialPeer
2542
	set modem idle-script Ringback
2543
	set modem watch -cd
2544
	set modem var \$DialPrefix "DT"
2545
	set modem var \$Telephone "{$ppp['phone']}"
2546

    
2547
EOD;
2548
		}
2549
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2550
			$mpdconf .= <<<EOD
2551
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2552

    
2553
EOD;
2554
		}
2555
		if (isset($ppp['initstr']) && $type == "modem") {
2556
			$initstr = base64_decode($ppp['initstr']);
2557
			$mpdconf .= <<<EOD
2558
	set modem var \$InitString "{$initstr}"
2559

    
2560
EOD;
2561
		}
2562
		if (isset($ppp['simpin']) && $type == "modem") {
2563
			if ($ppp['pin-wait'] == "") {
2564
				$ppp['pin-wait'] = 0;
2565
			}
2566
			$mpdconf .= <<<EOD
2567
	set modem var \$SimPin "{$ppp['simpin']}"
2568
	set modem var \$PinWait "{$ppp['pin-wait']}"
2569

    
2570
EOD;
2571
		}
2572
		if (isset($ppp['apn']) && $type == "modem") {
2573
			$mpdconf .= <<<EOD
2574
	set modem var \$APN "{$ppp['apn']}"
2575
	set modem var \$APNum "{$ppp['apnum']}"
2576

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

    
2593
EOD;
2594
		}
2595
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2596
			$mpdconf .= <<<EOD
2597
	set pppoe max-payload {$mtus[$pid]}
2598

    
2599
EOD;
2600
		}
2601
		if ($type == "pppoe") {
2602
			$mpdconf .= <<<EOD
2603
	set pppoe iface {$port}
2604

    
2605
EOD;
2606
		}
2607

    
2608
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2609
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2610
			$mpdconf .= <<<EOD
2611
	set l2tp secret "{$secret}"
2612

    
2613
EOD;
2614
		}
2615

    
2616
		if (($type == "pptp") || ($type == "l2tp")) {
2617
			$mpdconf .= <<<EOD
2618
	set {$type} self {$localips[$pid]}
2619
	set {$type} peer {$gateways[$pid]}
2620

    
2621
EOD;
2622
		}
2623

    
2624
		$mpdconf .= "\topen\n";
2625
	} //end foreach ($port)
2626

    
2627

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

    
2643
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2644
	if (isset($ppp['uptime'])) {
2645
		if (!file_exists("/conf/{$pppif}.log")) {
2646
			file_put_contents("/conf/{$pppif}.log", '');
2647
		}
2648
	} else {
2649
		if (file_exists("/conf/{$pppif}.log")) {
2650
			@unlink("/conf/{$pppif}.log");
2651
		}
2652
	}
2653

    
2654
	/* clean up old lock files */
2655
	foreach ($ports as $port) {
2656
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2657
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2658
		}
2659
	}
2660

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

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

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

    
2704
	/* Remove all temporary bogon IPv4 addresses */
2705
	if (is_array($tempaddr)) {
2706
		foreach ($tempaddr as $tempiface) {
2707
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2708
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2709
			}
2710
		}
2711
		unset ($tempaddr);
2712
	}
2713

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

    
2734
	return 1;
2735
}
2736

    
2737
function interfaces_sync_setup() {
2738
	global $g, $config;
2739

    
2740
	if (isset($config['system']['developerspew'])) {
2741
		$mt = microtime();
2742
		echo "interfaces_sync_setup() being called $mt\n";
2743
	}
2744

    
2745
	if (platform_booting()) {
2746
		echo gettext("Configuring CARP settings...");
2747
		mute_kernel_msgs();
2748
	}
2749

    
2750
	/* suck in configuration items */
2751
	if ($config['hasync']) {
2752
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2753
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2754
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2755
	} else {
2756
		unset($pfsyncinterface);
2757
		unset($pfsyncenabled);
2758
	}
2759

    
2760
	set_sysctl(array(
2761
		"net.inet.carp.preempt" => "1",
2762
		"net.inet.carp.log" => "1")
2763
	);
2764

    
2765
	if (!empty($pfsyncinterface)) {
2766
		$carp_sync_int = get_real_interface($pfsyncinterface);
2767
	} else {
2768
		unset($carp_sync_int);
2769
	}
2770

    
2771
	/* setup pfsync interface */
2772
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2773
		if (is_ipaddr($pfsyncpeerip)) {
2774
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2775
		} else {
2776
			$syncpeer = "-syncpeer";
2777
		}
2778

    
2779
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2780
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2781

    
2782
		sleep(1);
2783

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

    
2799
	$carplist = get_configured_vip_list('all', VIP_CARP);
2800
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2801
		set_single_sysctl("net.inet.carp.allow", "1");
2802
	} else {
2803
		set_single_sysctl("net.inet.carp.allow", "0");
2804
	}
2805

    
2806
	if (platform_booting()) {
2807
		unmute_kernel_msgs();
2808
		echo gettext("done.") . "\n";
2809
	}
2810
}
2811

    
2812
function interface_proxyarp_configure($interface = "") {
2813
	global $config, $g;
2814
	if (isset($config['system']['developerspew'])) {
2815
		$mt = microtime();
2816
		echo "interface_proxyarp_configure() being called $mt\n";
2817
	}
2818

    
2819
	/* kill any running choparp */
2820
	if (empty($interface)) {
2821
		killbyname("choparp");
2822
	} else {
2823
		$vipif = get_real_interface($interface);
2824
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2825
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2826
		}
2827
	}
2828

    
2829
	$paa = array();
2830
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2831

    
2832
		/* group by interface */
2833
		foreach ($config['virtualip']['vip'] as $vipent) {
2834
			if ($vipent['mode'] === "proxyarp") {
2835
				if ($vipent['interface']) {
2836
					$proxyif = $vipent['interface'];
2837
				} else {
2838
					$proxyif = "wan";
2839
				}
2840

    
2841
				if (!empty($interface) && $interface != $proxyif) {
2842
					continue;
2843
				}
2844

    
2845
				if (!is_array($paa[$proxyif])) {
2846
					$paa[$proxyif] = array();
2847
				}
2848

    
2849
				$paa[$proxyif][] = $vipent;
2850
			}
2851
		}
2852
	}
2853

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

    
2893
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2894
	global $g, $config;
2895

    
2896
	if (is_array($config['virtualip']['vip'])) {
2897
		foreach ($config['virtualip']['vip'] as $vip) {
2898

    
2899
			$iface = $vip['interface'];
2900
			if (substr($iface, 0, 4) == "_vip")
2901
				$iface = get_configured_vip_interface($vip['interface']);
2902
			if ($iface != $interface)
2903
				continue;
2904
			if ($type == VIP_CARP) {
2905
				if ($vip['mode'] != "carp")
2906
					continue;
2907
			} elseif ($type == VIP_IPALIAS) {
2908
				if ($vip['mode'] != "ipalias")
2909
					continue;
2910
			} else {
2911
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2912
					continue;
2913
			}
2914

    
2915
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2916
				interface_vip_bring_down($vip);
2917
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2918
				interface_vip_bring_down($vip);
2919
			else if ($inet == "all")
2920
				interface_vip_bring_down($vip);
2921
		}
2922
	}
2923
}
2924

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

    
2964
function interface_ipalias_configure(&$vip) {
2965
	global $config;
2966

    
2967
	if ($vip['mode'] != 'ipalias') {
2968
		return;
2969
	}
2970

    
2971
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2972
	if ($realif != "lo0") {
2973
		$if = convert_real_interface_to_friendly_interface_name($realif);
2974
		if (!isset($config['interfaces'][$if]) ||
2975
		    !isset($config['interfaces'][$if]['enable'])) {
2976
			return;
2977
		}
2978
	}
2979

    
2980
	$af = 'inet';
2981
	if (is_ipaddrv6($vip['subnet'])) {
2982
		$af = 'inet6';
2983
	}
2984
	$iface = $vip['interface'];
2985
	$vhid = '';
2986
	if (substr($vip['interface'], 0, 4) == "_vip") {
2987
		$carpvip = get_configured_vip($vip['interface']);
2988
		$iface = $carpvip['interface'];
2989
		$vhid = "vhid {$carpvip['vhid']}";
2990
	}
2991
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2992
	unset($iface, $af, $realif, $carpvip, $vhid);
2993
}
2994

    
2995
function interface_carp_configure(&$vip, $maintenancemode_only = false) {
2996
	global $config, $g;
2997
	if (isset($config['system']['developerspew'])) {
2998
		$mt = microtime();
2999
		echo "interface_carp_configure() being called $mt\n";
3000
	}
3001

    
3002
	if ($vip['mode'] != "carp") {
3003
		return;
3004
	}
3005

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

    
3020
	$vip_password = $vip['password'];
3021
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3022
	    $vip_password)));
3023
	if ($vip['password'] != "") {
3024
		$password = " pass {$vip_password}";
3025
	}
3026

    
3027
	$advbase = "";
3028
	if (!empty($vip['advbase'])) {
3029
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3030
	}
3031

    
3032
	$carp_maintenancemode = isset(
3033
	    $config["virtualip_carp_maintenancemode"]);
3034
	if ($carp_maintenancemode) {
3035
		$advskew = "advskew 254";
3036
	} else {
3037
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3038
	}
3039

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

    
3043
	if (!$maintenancemode_only) {
3044
		if (is_ipaddrv4($vip['subnet'])) {
3045
			mwexec("/sbin/ifconfig {$realif} " .
3046
			    escapeshellarg($vip['subnet']) . "/" .
3047
			    escapeshellarg($vip['subnet_bits']) .
3048
			    " alias vhid " . escapeshellarg($vip['vhid']));
3049
		} else if (is_ipaddrv6($vip['subnet'])) {
3050
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3051
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3052
			    escapeshellarg($vip['subnet_bits']) .
3053
			    " alias vhid " . escapeshellarg($vip['vhid']));
3054
		}
3055
	}
3056

    
3057
	return $realif;
3058
}
3059

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

    
3102
	if ($needs_clone == true) {
3103
		/* remove previous instance if it exists */
3104
		if (does_interface_exist($realif)) {
3105
			pfSense_interface_destroy($realif);
3106
		}
3107

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

    
3124
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3125
	global $config, $g;
3126

    
3127
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3128
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3129
				 'regdomain', 'regcountry', 'reglocation');
3130

    
3131
	if (!is_interface_wireless($ifcfg['if'])) {
3132
		return;
3133
	}
3134

    
3135
	$baseif = interface_get_wireless_base($ifcfg['if']);
3136

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

    
3164
	// Read or write settings at shared area
3165
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3166
		foreach ($shared_settings as $setting) {
3167
			if ($sync_changes) {
3168
				if (isset($ifcfg['wireless'][$setting])) {
3169
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3170
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3171
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3172
				}
3173
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3174
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3175
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3176
				} else if (isset($ifcfg['wireless'][$setting])) {
3177
					unset($ifcfg['wireless'][$setting]);
3178
				}
3179
			}
3180
		}
3181
	}
3182

    
3183
	// Sync the mode on the clone creation page with the configured mode on the interface
3184
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3185
		foreach ($config['wireless']['clone'] as &$clone) {
3186
			if ($clone['cloneif'] == $ifcfg['if']) {
3187
				if ($sync_changes) {
3188
					$clone['mode'] = $ifcfg['wireless']['mode'];
3189
				} else {
3190
					$ifcfg['wireless']['mode'] = $clone['mode'];
3191
				}
3192
				break;
3193
			}
3194
		}
3195
		unset($clone);
3196
	}
3197
}
3198

    
3199
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3200
	global $config, $g;
3201

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

    
3209
	// Remove script file
3210
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3211

    
3212
	// Clone wireless nic if needed.
3213
	interface_wireless_clone($if, $wl);
3214

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

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

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

    
3224
	/* set values for /path/program */
3225
	if (file_exists("/usr/local/sbin/hostapd")) {
3226
		$hostapd = "/usr/local/sbin/hostapd";
3227
	} else {
3228
		$hostapd = "/usr/sbin/hostapd";
3229
	}
3230
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3231
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3232
	} else {
3233
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3234
	}
3235
	$ifconfig = "/sbin/ifconfig";
3236
	$sysctl = "/sbin/sysctl";
3237
	$sysctl_args = "-q";
3238
	$killall = "/usr/bin/killall";
3239

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

    
3242
	$wlcmd = array();
3243
	$wl_sysctl = array();
3244
	/* Set a/b/g standard */
3245
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3246
	/* skip mode entirely for "auto" */
3247
	if ($wlcfg['standard'] != "auto") {
3248
		$wlcmd[] = "mode " . escapeshellarg($standard);
3249
	}
3250

    
3251
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3252
	 * to prevent massive packet loss under certain conditions. */
3253
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3254
		$wlcmd[] = "-ampdu";
3255
	}
3256

    
3257
	/* Set ssid */
3258
	if ($wlcfg['ssid']) {
3259
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3260
	}
3261

    
3262
	/* Set 802.11g protection mode */
3263
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3264

    
3265
	/* set wireless channel value */
3266
	if (isset($wlcfg['channel'])) {
3267
		if ($wlcfg['channel'] == "0") {
3268
			$wlcmd[] = "channel any";
3269
		} else {
3270
			if ($wlcfg['channel_width'] != "0") {
3271
				$channel_width = ":" . $wlcfg['channel_width'];
3272
			} else {
3273
				$channel_width = '';
3274
			}
3275
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3276
		}
3277
	}
3278

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

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

    
3289
	/* Set rxantenna value */
3290
	if (isset($wlcfg['rxantenna'])) {
3291
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3292
	}
3293

    
3294
	/* set Distance value */
3295
	if ($wlcfg['distance']) {
3296
		$distance = escapeshellarg($wlcfg['distance']);
3297
	}
3298

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

    
3306
	/* Set wireless adhoc mode */
3307
	if ($wlcfg['mode'] == "adhoc") {
3308
		$wlcmd[] = "mediaopt adhoc";
3309
	} else {
3310
		$wlcmd[] = "-mediaopt adhoc";
3311
	}
3312

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

    
3315
	/* handle hide ssid option */
3316
	if (isset($wlcfg['hidessid']['enable'])) {
3317
		$wlcmd[] = "hidessid";
3318
	} else {
3319
		$wlcmd[] = "-hidessid";
3320
	}
3321

    
3322
	/* handle pureg (802.11g) only option */
3323
	if (isset($wlcfg['pureg']['enable'])) {
3324
		$wlcmd[] = "mode 11g pureg";
3325
	} else {
3326
		$wlcmd[] = "-pureg";
3327
	}
3328

    
3329
	/* handle puren (802.11n) only option */
3330
	if (isset($wlcfg['puren']['enable'])) {
3331
		$wlcmd[] = "puren";
3332
	} else {
3333
		$wlcmd[] = "-puren";
3334
	}
3335

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

    
3343
	/* handle turbo option */
3344
	if (isset($wlcfg['turbo']['enable'])) {
3345
		$wlcmd[] = "mediaopt turbo";
3346
	} else {
3347
		$wlcmd[] = "-mediaopt turbo";
3348
	}
3349

    
3350
	/* handle txpower setting */
3351
	// or don't. this has issues at the moment.
3352
	/*
3353
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3354
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3355
	}*/
3356

    
3357
	/* handle wme option */
3358
	if (isset($wlcfg['wme']['enable'])) {
3359
		$wlcmd[] = "wme";
3360
	} else {
3361
		$wlcmd[] = "-wme";
3362
	}
3363

    
3364
	/* Enable wpa if it's configured. No WEP support anymore. */
3365
	if (isset($wlcfg['wpa']['enable'])) {
3366
		$wlcmd[] = "authmode wpa wepmode off ";
3367
	} else {
3368
		$wlcmd[] = "authmode open wepmode off ";
3369
	}
3370

    
3371
	kill_hostapd($if);
3372
	mwexec(kill_wpasupplicant("{$if}"));
3373

    
3374
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3375

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

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

    
3429
EOD;
3430

    
3431
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3432
					$wpa .= <<<EOD
3433
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3434
rsn_preauth=1
3435
rsn_preauth_interfaces={$if}
3436

    
3437
EOD;
3438
				}
3439
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3440
					$wpa .= "ieee8021x=1\n";
3441

    
3442
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3443
						$auth_server_port = "1812";
3444
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3445
							$auth_server_port = intval($wlcfg['auth_server_port']);
3446
						}
3447
						$wpa .= <<<EOD
3448

    
3449
auth_server_addr={$wlcfg['auth_server_addr']}
3450
auth_server_port={$auth_server_port}
3451
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3452

    
3453
EOD;
3454
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3455
							$auth_server_port2 = "1812";
3456
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3457
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3458
							}
3459

    
3460
							$wpa .= <<<EOD
3461
auth_server_addr={$wlcfg['auth_server_addr2']}
3462
auth_server_port={$auth_server_port2}
3463
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3464

    
3465
EOD;
3466
						}
3467
					}
3468
				}
3469

    
3470
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3471
				unset($wpa);
3472
			}
3473
			break;
3474
	}
3475

    
3476
	/*
3477
	 *    all variables are set, lets start up everything
3478
	 */
3479

    
3480
	$baseif = interface_get_wireless_base($if);
3481
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3482
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3483

    
3484
	/* set sysctls for the wireless interface */
3485
	if (!empty($wl_sysctl)) {
3486
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3487
		foreach ($wl_sysctl as $wl_sysctl_line) {
3488
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3489
		}
3490
	}
3491

    
3492
	/* set ack timers according to users preference (if he/she has any) */
3493
	if ($distance) {
3494
		fwrite($fd_set, "# Enable ATH distance settings\n");
3495
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3496
	}
3497

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

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

    
3515
			/* add line to script to restore spoofed mac after running hostapd */
3516
			if ($wl['spoofmac']) {
3517
				$if_curmac = get_interface_mac($if);
3518
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3519
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3520
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3521
				}
3522
			}
3523
		}
3524
	}
3525

    
3526
	fclose($fd_set);
3527

    
3528
	/* Making sure regulatory settings have actually changed
3529
	 * before applying, because changing them requires bringing
3530
	 * down all wireless networks on the interface. */
3531
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3532
	$ifconfig_str = implode($output);
3533
	unset($output);
3534
	$reg_changing = false;
3535

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

    
3549
	if ($reg_changing) {
3550
		/* set regulatory domain */
3551
		if ($wlcfg['regdomain']) {
3552
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3553
		}
3554

    
3555
		/* set country */
3556
		if ($wlcfg['regcountry']) {
3557
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3558
		}
3559

    
3560
		/* set location */
3561
		if ($wlcfg['reglocation']) {
3562
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3563
		}
3564

    
3565
		$wlregcmd_args = implode(" ", $wlregcmd);
3566

    
3567
		/* build a complete list of the wireless clones for this interface */
3568
		$clone_list = array();
3569
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3570
			$clone_list[] = interface_get_wireless_clone($baseif);
3571
		}
3572
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3573
			foreach ($config['wireless']['clone'] as $clone) {
3574
				if ($clone['if'] == $baseif) {
3575
					$clone_list[] = $clone['cloneif'];
3576
				}
3577
			}
3578
		}
3579

    
3580
		/* find which clones are up and bring them down */
3581
		$clones_up = array();
3582
		foreach ($clone_list as $clone_if) {
3583
			$clone_status = pfSense_get_interface_addresses($clone_if);
3584
			if ($clone_status['status'] == 'up') {
3585
				$clones_up[] = $clone_if;
3586
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3587
			}
3588
		}
3589

    
3590
		/* apply the regulatory settings */
3591
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3592
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3593

    
3594
		/* bring the clones back up that were previously up */
3595
		foreach ($clones_up as $clone_if) {
3596
			interfaces_bring_up($clone_if);
3597

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

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

    
3623
	/* configure wireless */
3624
	$wlcmd_args = implode(" ", $wlcmd);
3625
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3626
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3627
	/* Bring the interface up only after setting up all the other parameters. */
3628
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3629
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3630
	fclose($wlan_setup_log);
3631

    
3632
	unset($wlcmd_args, $wlcmd);
3633

    
3634

    
3635
	sleep(1);
3636
	/* execute hostapd and wpa_supplicant if required in shell */
3637
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3638

    
3639
	return 0;
3640

    
3641
}
3642

    
3643
function kill_hostapd($interface) {
3644
	global $g;
3645

    
3646
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3647
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3648
	}
3649
}
3650

    
3651
function kill_wpasupplicant($interface) {
3652
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3653
}
3654

    
3655
function find_dhclient_process($interface) {
3656
	if ($interface) {
3657
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3658
	} else {
3659
		$pid = 0;
3660
	}
3661

    
3662
	return intval($pid);
3663
}
3664

    
3665
function kill_dhclient_process($interface) {
3666
	if (empty($interface) || !does_interface_exist($interface)) {
3667
		return;
3668
	}
3669

    
3670
	$i = 0;
3671
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3672
		/* 3rd time make it die for sure */
3673
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3674
		posix_kill($pid, $sig);
3675
		sleep(1);
3676
		$i++;
3677
	}
3678
	unset($i);
3679
}
3680

    
3681
function find_dhcp6c_process($interface) {
3682
	global $g;
3683

    
3684
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3685
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3686
	} else {
3687
		return(false);
3688
	}
3689

    
3690
	return intval($pid);
3691
}
3692

    
3693
function kill_dhcp6client_process($interface, $force, $release = false) {
3694
	global $g;
3695

    
3696
	$i = 0;
3697

    
3698
	/*
3699
	Beware of the following: Reason, the interface may be down, but
3700
	dhcp6c may still be running, it just complains it cannot send
3701
	and carries on. Commented out as will stop the call to kill.
3702

    
3703
	if (empty($interface) || !does_interface_exist($interface)) {
3704
		return;
3705
	}
3706
	*/
3707

    
3708
	/*********** Notes on signals for dhcp6c and this function *************
3709

    
3710
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3711
	a release and waiting for the response that never comes.
3712
	So we need to tell it that the interface is down and to just die quickly
3713
	otherwise a new client may launch and we have duplicate proceses.
3714
	In this case use SIGUSR1.
3715

    
3716
	If we want to exit normally obeying the no release flag then use SIGTERM.
3717
	If we want to exit with a release overiding the no release flag then
3718
	use SIGUSR2.
3719

    
3720
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3721
	exit quickly without sending release signals.
3722

    
3723
	If $Force is set to false and $release is also set to false dhcp6c will
3724
	follow the no-release flag.
3725

    
3726
	If $Force is set to false and $release is true then dhcp6c will send a
3727
	release regardless of the no-release flag.
3728
	***********************************************************************/
3729

    
3730
	if ($force == true) {
3731
		$psig=SIGUSR1;
3732
	} else if ($release == false) {
3733
		$psig=SIGTERM;
3734
	} else {
3735
		$psig=SIGUSR2;
3736
	}
3737

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

    
3751
	$pid = find_dhcp6c_process($interface);
3752

    
3753
	if($pid != 0) {
3754
		posix_kill($pid, SIGHUP);
3755
	}
3756
}
3757

    
3758
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3759
	global $g;
3760

    
3761
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3762
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3763

    
3764
	/*
3765
	 * Only run this if the lock does not exist. In theory the lock being
3766
	 * there in this mode means the user has selected dhcp6withoutRA while
3767
	 * a session is active in the other mode.
3768
	 *
3769
	 * It should not happen as the process should have been killed and the
3770
	 * lock deleted.
3771
	 */
3772

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

    
3788
function interface_virtual_create($interface) {
3789
	global $config;
3790

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

    
3841
function interface_vlan_mtu_configured($iface) {
3842
	global $config;
3843

    
3844
	$mtu = 0;
3845
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3846
		foreach ($config['vlans']['vlan'] as $vlan) {
3847

    
3848
			if ($vlan['vlanif'] != $iface)
3849
				continue;
3850

    
3851
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3852
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3853
				/* VLAN MTU */
3854
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3855
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3856
				/* Parent MTU */
3857
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3858
			}
3859
		}
3860
	}
3861

    
3862
	return $mtu;
3863
}
3864

    
3865
function interface_mtu_wanted_for_pppoe($realif) {
3866
	global $config;
3867

    
3868
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3869
		return 0;
3870

    
3871
	$mtu = 0;
3872
	foreach ($config['ppps']['ppp'] as $ppp) {
3873
		if ($ppp['type'] != "pppoe") {
3874
			continue;
3875
		}
3876

    
3877
		$mtus = array();
3878
		if (!empty($ppp['mtu'])) {
3879
			$mtus = explode(',', $ppp['mtu']);
3880
		}
3881
		$ports = explode(',', $ppp['ports']);
3882

    
3883
		foreach ($ports as $pid => $port) {
3884
			$parentifa = get_parent_interface($port);
3885
			$parentif = $parentifa[0];
3886
			if ($parentif != $realif)
3887
				continue;
3888

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

    
3905
	return $mtu;
3906
}
3907

    
3908
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3909
	global $config, $g;
3910
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3911
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3912

    
3913
	$wancfg = $config['interfaces'][$interface];
3914

    
3915
	if (!isset($wancfg['enable'])) {
3916
		return;
3917
	}
3918

    
3919
	$realif = get_real_interface($interface);
3920
	$realhwif_array = get_parent_interface($interface);
3921
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3922
	$realhwif = $realhwif_array[0];
3923

    
3924
	$mac_if_cfg = $wancfg;
3925
	if (interface_is_vlan($realif)) {
3926
		$mac_if = convert_real_interface_to_friendly_interface_name(
3927
		    $realhwif);
3928
		if (is_array($config['interfaces'][$mac_if])) {
3929
			$mac_if_cfg = $config['interfaces'][$mac_if];
3930
		} else {
3931
			$mac_if = $interface;
3932
		}
3933
	}
3934

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

    
3958
		/* only bring down the interface when both v4 and v6 are set to NONE */
3959
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3960
			interface_bring_down($interface);
3961
		}
3962
	}
3963

    
3964
	$interface_to_check = $realif;
3965
	if (interface_isppp_type($interface)) {
3966
		$interface_to_check = $realhwif;
3967
	}
3968

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

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

    
3987
	$current_mac = get_interface_mac($realhwif);
3988
	$vendor_mac = get_interface_vendor_mac($realhwif);
3989

    
3990
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
3991
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
3992

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

    
4012
	/* media */
4013
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4014
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4015
		if ($wancfg['media']) {
4016
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4017
		}
4018
		if ($wancfg['mediaopt']) {
4019
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4020
		}
4021
		mwexec($cmd);
4022
	}
4023

    
4024
	/* Apply hw offloading policies as configured */
4025
	enable_hardware_offloading($interface);
4026

    
4027
	/* invalidate interface/ip/sn cache */
4028
	get_interface_arr(true);
4029
	unset($interface_ip_arr_cache[$realif]);
4030
	unset($interface_sn_arr_cache[$realif]);
4031
	unset($interface_ipv6_arr_cache[$realif]);
4032
	unset($interface_snv6_arr_cache[$realif]);
4033

    
4034
	$tunnelif = substr($realif, 0, 3);
4035

    
4036
	$mtuif = $realif;
4037
	$mtuhwif = $realhwif;
4038

    
4039
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4040
	if (interface_isppp_type($interface)) {
4041
		$mtuif = $realhwif;
4042
		$mtuhwif_array = get_parent_interface($mtuif);
4043
		$mtuhwif = $mtuhwif_array[0];
4044
	}
4045

    
4046
	$wantedmtu = 0;
4047
	if (is_array($config['interfaces'])) {
4048
		foreach ($config['interfaces'] as $tmpinterface) {
4049
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4050
				$wantedmtu = $tmpinterface['mtu'];
4051
				break;
4052
			}
4053
		}
4054
	}
4055

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

    
4075
	/* Set the MTU to 1500 if no explicit MTU configured. */
4076
	if ($wantedmtu == 0) {
4077
		$wantedmtu = 1500; /* Default */
4078
	}
4079

    
4080
	if (interface_is_vlan($mtuif) != NULL) {
4081
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4082
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
4083
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
4084
			if ($wancfg['mtu'] > $parentmtu) {
4085
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4086
			}
4087
		}
4088

    
4089
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4090

    
4091
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4092
			$configuredmtu = $parentmtu;
4093
		if ($configuredmtu != 0)
4094
			$mtu = $configuredmtu;
4095
		else
4096
			$mtu = $wantedmtu;
4097

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

    
4124
	if (does_interface_exist($wancfg['if'])) {
4125
		interfaces_bring_up($wancfg['if']);
4126
	}
4127

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

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

    
4182
	interface_netgraph_needed($interface);
4183

    
4184
	if (!platform_booting()) {
4185
		link_interface_to_vips($interface, "update");
4186

    
4187
		if ($tunnelif != 'gre') {
4188
			unset($gre);
4189
			$gre = link_interface_to_gre($interface);
4190
			if (!empty($gre)) {
4191
				array_walk($gre, 'interface_gre_configure');
4192
			}
4193
		}
4194

    
4195
		if ($tunnelif != 'gif') {
4196
			unset($gif);
4197
			$gif = link_interface_to_gif ($interface);
4198
			if (!empty($gif)) {
4199
				array_walk($gif, 'interface_gif_configure');
4200
			}
4201
		}
4202

    
4203
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4204
			unset($bridgetmp);
4205
			$bridgetmp = link_interface_to_bridge($interface);
4206
			if (!empty($bridgetmp)) {
4207
				interface_bridge_add_member($bridgetmp, $realif);
4208
			}
4209
		}
4210

    
4211
		$grouptmp = link_interface_to_group($interface);
4212
		if (!empty($grouptmp)) {
4213
			array_walk($grouptmp, 'interface_group_add_member');
4214
		}
4215

    
4216
		if ($interface == "lan") {
4217
			/* make new hosts file */
4218
			system_hosts_generate();
4219
		}
4220

    
4221
		if ($reloadall == true) {
4222

    
4223
			/* reconfigure static routes (kernel may have deleted them) */
4224
			system_routing_configure($interface);
4225

    
4226
			/* reload ipsec tunnels */
4227
			send_event("service reload ipsecdns");
4228

    
4229
			if (isset($config['dnsmasq']['enable'])) {
4230
				services_dnsmasq_configure();
4231
			}
4232

    
4233
			if (isset($config['unbound']['enable'])) {
4234
				services_unbound_configure();
4235
			}
4236

    
4237
			/* update dyndns */
4238
			send_event("service reload dyndns {$interface}");
4239

    
4240
			/* reload captive portal */
4241
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4242
				require_once('captiveportal.inc');
4243
			}
4244
			captiveportal_init_rules_byinterface($interface);
4245
		}
4246
	}
4247

    
4248
	if (!empty($wancfg['descr'])) {
4249
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4250
	};
4251

    
4252
	interfaces_staticarp_configure($interface);
4253
	return 0;
4254
}
4255

    
4256
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4257
	global $config, $g;
4258

    
4259
	if (!is_array($wancfg)) {
4260
		return;
4261
	}
4262

    
4263
	if (!isset($wancfg['enable'])) {
4264
		return;
4265
	}
4266

    
4267
	/* If the interface is not configured via another, exit */
4268
	if (empty($wancfg['track6-interface'])) {
4269
		return;
4270
	}
4271

    
4272
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4273
	$realif = get_real_interface($interface);
4274
	$linklocal = find_interface_ipv6_ll($realif, true);
4275
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4276
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4277
	}
4278

    
4279
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4280
	if (!isset($trackcfg['enable'])) {
4281
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4282
		return;
4283
	}
4284

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

    
4315
	if ($linkupevent == false && !platform_booting()) {
4316
		if (!function_exists('services_dhcpd_configure')) {
4317
			require_once("services.inc");
4318
		}
4319

    
4320
		/* restart dns servers (defering dhcpd reload) */
4321
		if (isset($config['unbound']['enable'])) {
4322
			services_unbound_configure(false);
4323
		}
4324
		if (isset($config['dnsmasq']['enable'])) {
4325
			services_dnsmasq_configure(false);
4326
		}
4327

    
4328
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4329
		services_dhcpd_configure("inet6");
4330
	}
4331

    
4332
	return 0;
4333
}
4334

    
4335
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4336
	global $config, $g;
4337
	global $interface_ipv6_arr_cache;
4338
	global $interface_snv6_arr_cache;
4339

    
4340
	if (!is_array($lancfg)) {
4341
		return;
4342
	}
4343

    
4344
	/* If the interface is not configured via another, exit */
4345
	if (empty($lancfg['track6-interface'])) {
4346
		return;
4347
	}
4348

    
4349
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4350
	if (empty($wancfg)) {
4351
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4352
		return;
4353
	}
4354

    
4355
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4356
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4357
		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']));
4358
		return;
4359
	}
4360
	$hexwanv4 = return_hex_ipv4($ip4address);
4361

    
4362
	/* create the long prefix notation for math, save the prefix length */
4363
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4364
	$rd6prefixlen = $rd6prefix[1];
4365
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4366

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

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

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

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

    
4386
	$lanif = get_real_interface($interface);
4387
	$oip = find_interface_ipv6($lanif);
4388
	if (is_ipaddrv6($oip)) {
4389
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4390
	}
4391
	unset($interface_ipv6_arr_cache[$lanif]);
4392
	unset($interface_snv6_arr_cache[$lanif]);
4393
	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));
4394
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4395

    
4396
	return 0;
4397
}
4398

    
4399
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4400
	global $config, $g;
4401
	global $interface_ipv6_arr_cache;
4402
	global $interface_snv6_arr_cache;
4403

    
4404
	if (!is_array($lancfg)) {
4405
		return;
4406
	}
4407

    
4408
	/* If the interface is not configured via another, exit */
4409
	if (empty($lancfg['track6-interface'])) {
4410
		return;
4411
	}
4412

    
4413
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4414
	if (empty($wancfg)) {
4415
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4416
		return;
4417
	}
4418

    
4419
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4420
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4421
		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']));
4422
		return;
4423
	}
4424
	$hexwanv4 = return_hex_ipv4($ip4address);
4425

    
4426
	/* create the long prefix notation for math, save the prefix length */
4427
	$sixto4prefix = "2002::";
4428
	$sixto4prefixlen = 16;
4429
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4430

    
4431
	/* binary presentation of the prefix for all 128 bits. */
4432
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4433

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

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

    
4446
	$lanif = get_real_interface($interface);
4447
	$oip = find_interface_ipv6($lanif);
4448
	if (is_ipaddrv6($oip)) {
4449
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4450
	}
4451
	unset($interface_ipv6_arr_cache[$lanif]);
4452
	unset($interface_snv6_arr_cache[$lanif]);
4453
	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));
4454
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4455

    
4456
	return 0;
4457
}
4458

    
4459
function interface_6rd_configure($interface = "wan", $wancfg) {
4460
	global $config, $g;
4461

    
4462
	/* because this is a tunnel interface we can only function
4463
	 *	with a public IPv4 address on the interface */
4464

    
4465
	if (!is_array($wancfg)) {
4466
		return;
4467
	}
4468

    
4469
	if (!is_module_loaded('if_stf.ko')) {
4470
		mwexec('/sbin/kldload if_stf.ko');
4471
	}
4472

    
4473
	$wanif = get_real_interface($interface);
4474
	$ip4address = find_interface_ip($wanif);
4475
	if (!is_ipaddrv4($ip4address)) {
4476
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4477
		return false;
4478
	}
4479
	$hexwanv4 = return_hex_ipv4($ip4address);
4480

    
4481
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4482
		$wancfg['prefix-6rd-v4plen'] = 0;
4483
	}
4484

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

    
4498
	/* binary presentation of the prefix for all 128 bits. */
4499
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4500

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

    
4508
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4509
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4510

    
4511

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

    
4535
	/* write out a default router file */
4536
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4537
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4538

    
4539
	$ip4gateway = get_interface_gateway($interface);
4540
	if (is_ipaddrv4($ip4gateway)) {
4541
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
4542
	}
4543

    
4544
	/* configure dependent interfaces */
4545
	if (!platform_booting()) {
4546
		link_interface_to_track6($interface, "update");
4547
	}
4548

    
4549
	return 0;
4550
}
4551

    
4552
function interface_6to4_configure($interface = "wan", $wancfg) {
4553
	global $config, $g;
4554

    
4555
	/* because this is a tunnel interface we can only function
4556
	 *	with a public IPv4 address on the interface */
4557

    
4558
	if (!is_array($wancfg)) {
4559
		return;
4560
	}
4561

    
4562
	$wanif = get_real_interface($interface);
4563
	$ip4address = find_interface_ip($wanif);
4564
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4565
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4566
		return false;
4567
	}
4568

    
4569
	/* create the long prefix notation for math, save the prefix length */
4570
	$stfprefixlen = 16;
4571
	$stfprefix = Net_IPv6::uncompress("2002::");
4572
	$stfarr = explode(":", $stfprefix);
4573
	$v4prefixlen = "0";
4574

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

    
4582
	/* we need the hex form of the broker IPv4 address */
4583
	$ip4arr = explode(".", "192.88.99.1");
4584
	$hexbrv4 = "";
4585
	foreach ($ip4arr as $octet) {
4586
		$hexbrv4 .= sprintf("%02x", $octet);
4587
	}
4588

    
4589
	/* binary presentation of the prefix for all 128 bits. */
4590
	$stfprefixbin = "";
4591
	foreach ($stfarr as $element) {
4592
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4593
	}
4594
	/* just save the left prefix length bits */
4595
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4596

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

    
4601
	/* for the local subnet too. */
4602
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4603
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4604

    
4605
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4606
	$stfbrarr = array();
4607
	$stfbrbinarr = array();
4608
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4609
	foreach ($stfbrbinarr as $bin) {
4610
		$stfbrarr[] = dechex(bindec($bin));
4611
	}
4612
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4613

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

    
4625
	/* setup the stf interface */
4626
	if (!is_module_loaded("if_stf")) {
4627
		mwexec("/sbin/kldload if_stf.ko");
4628
	}
4629
	$stfiface = "{$interface}_stf";
4630
	if (does_interface_exist($stfiface)) {
4631
		pfSense_interface_destroy($stfiface);
4632
	}
4633
	$tmpstfiface = pfSense_interface_create("stf");
4634
	pfSense_interface_rename($tmpstfiface, $stfiface);
4635
	pfSense_interface_flags($stfiface, IFF_LINK2);
4636
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4637

    
4638
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4639
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4640
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4641
	} elseif ($parentmtu > 1300) {
4642
		set_interface_mtu($stfiface, $parentmtu - 20);
4643
	}
4644
	if ($g['debug']) {
4645
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4646
	}
4647

    
4648
	/* write out a default router file */
4649
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4650
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4651

    
4652
	$ip4gateway = get_interface_gateway($interface);
4653
	if (is_ipaddrv4($ip4gateway)) {
4654
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
4655
	}
4656

    
4657
	if (!platform_booting()) {
4658
		link_interface_to_track6($interface, "update");
4659
	}
4660

    
4661
	return 0;
4662
}
4663

    
4664
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4665
	global $config, $g;
4666

    
4667
	if (!is_array($wancfg)) {
4668
		return;
4669
	}
4670

    
4671
	$wanif = get_real_interface($interface, "inet6");
4672
	$dhcp6cconf = "";
4673

    
4674
	if (!empty($config['system']['global-v6duid'])) {
4675
		// Write the DUID file
4676
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4677
		    log_error(gettext("Failed to write user DUID file!"));
4678
		}
4679
	}
4680

    
4681
	/* accept router advertisements for this interface                 */
4682
	/* Moved to early in the function as sometimes interface not ready */
4683
	/* RTSOLD fails as interface does not accept .....                 */
4684

    
4685
	log_error("Accept router advertisements on interface {$wanif} ");
4686
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4687

    
4688
	if ($wancfg['adv_dhcp6_config_file_override']) {
4689
		// DHCP6 Config File Override
4690
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4691
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4692
		// DHCP6 Config File Advanced
4693
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4694
	} else {
4695
		// DHCP6 Config File Basic
4696
		$dhcp6cconf .= "interface {$wanif} {\n";
4697

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

    
4714
			/* skip address request if this is set */
4715
			if (!isset($wancfg['dhcp6prefixonly'])) {
4716
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4717
			}
4718
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4719
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4720
			}
4721

    
4722
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4723
			$dhcp6cconf .= "\trequest domain-name;\n";
4724

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

    
4736
			if (!isset($wancfg['dhcp6prefixonly'])) {
4737
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4738
			}
4739

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

    
4764
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4765
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4766

    
4767
	/* wide-dhcp6c works for now. */
4768
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4769
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4770
		unset($dhcp6cconf);
4771
		return 1;
4772
	}
4773
	unset($dhcp6cconf);
4774

    
4775
	/*************** Script Debug Logging ***************************
4776
	Both dhcp6 scripts now have a logging message built in.
4777
	These logging messages ONLY appear if dhcp6c debug logging is set.
4778
	The logging messages appear in the dhcp section of the logs,
4779
	not in system.
4780

    
4781
	These scripts now also take advantage of the REASON= env vars
4782
	supplied by dhcp6c.
4783
	****************************************************************/
4784

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

    
4834
	unset($dhcp6cscriptwithoutra);
4835
	@chmod(
4836
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4837
	    0755);
4838

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

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

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

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

    
4940
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4941
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4942
		log_error("Killing running rtsold process");
4943
		sleep(2);
4944
	}
4945

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

    
4987
	return 0;
4988
}
4989

    
4990
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4991
	global $g;
4992

    
4993
	$send_options = "";
4994
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4995
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4996
		foreach ($options as $option) {
4997
			$send_options .= "\tsend " . trim($option) . ";\n";
4998
		}
4999
	}
5000

    
5001
	$request_options = "";
5002
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5003
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5004
		foreach ($options as $option) {
5005
			$request_options .= "\trequest " . trim($option) . ";\n";
5006
		}
5007
	}
5008

    
5009
	$information_only = "";
5010
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5011
		$information_only = "\tinformation-only;\n";
5012
	}
5013

    
5014
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5015
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5016
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5017
	}
5018

    
5019
	$interface_statement  = "interface";
5020
	$interface_statement .= " {$wanif}";
5021
	$interface_statement .= " {\n";
5022
	$interface_statement .= "$send_options";
5023
	$interface_statement .= "$request_options";
5024
	$interface_statement .= "$information_only";
5025
	$interface_statement .= "$script";
5026
	$interface_statement .= "};\n";
5027

    
5028
	$id_assoc_statement_address = "";
5029
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5030
		$id_assoc_statement_address .= "id-assoc";
5031
		$id_assoc_statement_address .= " na";
5032
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5033
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5034
		}
5035
		$id_assoc_statement_address .= " { ";
5036

    
5037
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5038
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5039
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5040
			$id_assoc_statement_address .= "\n\taddress";
5041
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5042
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5043
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5044
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5045
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5046
			}
5047
			$id_assoc_statement_address .= ";\n";
5048
		}
5049

    
5050
		$id_assoc_statement_address .= "};\n";
5051
	}
5052

    
5053
	$id_assoc_statement_prefix = "";
5054
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5055
		$id_assoc_statement_prefix .= "id-assoc";
5056
		$id_assoc_statement_prefix .= " pd";
5057
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5058
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5059
		}
5060
		$id_assoc_statement_prefix .= " { ";
5061

    
5062
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5063
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5064
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5065
			$id_assoc_statement_prefix .= "\n\tprefix";
5066
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5067
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5068
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5069
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5070
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5071
			}
5072
			$id_assoc_statement_prefix .= ";";
5073
		}
5074

    
5075
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5076
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5077
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5078
			$id_assoc_statement_prefix .= " {$realif}";
5079
			$id_assoc_statement_prefix .= " {\n";
5080
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5081
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5082
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5083
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5084
			}
5085
			$id_assoc_statement_prefix .= "\t};";
5086
		}
5087

    
5088
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5089
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5090
			$id_assoc_statement_prefix .= "\n";
5091
		}
5092

    
5093
		$id_assoc_statement_prefix .= "};\n";
5094
	}
5095

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

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

    
5129
	$dhcp6cconf  = $interface_statement;
5130
	$dhcp6cconf .= $id_assoc_statement_address;
5131
	$dhcp6cconf .= $id_assoc_statement_prefix;
5132
	$dhcp6cconf .= $authentication_statement;
5133
	$dhcp6cconf .= $key_info_statement;
5134

    
5135
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5136

    
5137
	return $dhcp6cconf;
5138
}
5139

    
5140

    
5141
function DHCP6_Config_File_Override($wancfg, $wanif) {
5142

    
5143
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5144

    
5145
	if ($dhcp6cconf === false) {
5146
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5147
		return '';
5148
	} else {
5149
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5150
	}
5151
}
5152

    
5153

    
5154
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5155

    
5156
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5157

    
5158
	return $dhcp6cconf;
5159
}
5160

    
5161

    
5162
function interface_dhcp_configure($interface = "wan") {
5163
	global $config, $g, $vlanprio_values;
5164

    
5165
	$ifcfg = $config['interfaces'][$interface];
5166
	if (empty($ifcfg)) {
5167
		$ifcfg = array();
5168
	}
5169

    
5170
	$dhclientconf_vlantag = "";
5171
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5172
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5173
	}
5174

    
5175
	/* generate dhclient_wan.conf */
5176
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5177
	if (!$fd) {
5178
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5179
		return 1;
5180
	}
5181

    
5182
	if ($ifcfg['dhcphostname']) {
5183
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5184
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5185
	} else {
5186
		$dhclientconf_hostname = "";
5187
	}
5188

    
5189
	$realif = get_real_interface($interface);
5190
	if (empty($realif)) {
5191
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5192
		return 0;
5193
	}
5194
	$dhclientconf = "";
5195

    
5196
	$dhclientconf .= <<<EOD
5197
interface "{$realif}" {
5198
	supersede interface-mtu 0;
5199
	timeout 60;
5200
	retry 15;
5201
	select-timeout 0;
5202
	initial-interval 1;
5203
	{$dhclientconf_vlantag}
5204
	{$dhclientconf_hostname}
5205
	script "/usr/local/sbin/pfSense-dhclient-script";
5206
EOD;
5207

    
5208
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5209
		$dhclientconf .= <<<EOD
5210

    
5211
	reject {$ifcfg['dhcprejectfrom']};
5212
EOD;
5213
	}
5214
	$dhclientconf .= <<<EOD
5215

    
5216
}
5217

    
5218
EOD;
5219

    
5220
	// DHCP Config File Advanced
5221
	if ($ifcfg['adv_dhcp_config_advanced']) {
5222
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5223
	}
5224

    
5225
	if (is_ipaddr($ifcfg['alias-address'])) {
5226
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5227
		$dhclientconf .= <<<EOD
5228
alias {
5229
	interface "{$realif}";
5230
	fixed-address {$ifcfg['alias-address']};
5231
	option subnet-mask {$subnetmask};
5232
}
5233

    
5234
EOD;
5235
	}
5236

    
5237
	// DHCP Config File Override
5238
	if ($ifcfg['adv_dhcp_config_file_override']) {
5239
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5240
	}
5241

    
5242
	fwrite($fd, $dhclientconf);
5243
	fclose($fd);
5244

    
5245
	/* bring wan interface up before starting dhclient */
5246
	if ($realif) {
5247
		interfaces_bring_up($realif);
5248
	}
5249

    
5250
	/* Make sure dhclient is not running */
5251
	kill_dhclient_process($realif);
5252

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

    
5256
	return 0;
5257
}
5258

    
5259
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5260

    
5261
	$hostname = "";
5262
	if ($ifcfg['dhcphostname'] != '') {
5263
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5264
	}
5265

    
5266
	/* DHCP Protocol Timings */
5267
	$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");
5268
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5269
		$pt_variable = "{$Protocol_Timing}";
5270
		${$pt_variable} = "";
5271
		if ($ifcfg[$Protocol_Timing] != "") {
5272
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5273
		}
5274
	}
5275

    
5276
	$send_options = "";
5277
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5278
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5279
		foreach ($options as $option) {
5280
			$send_options .= "\tsend " . trim($option) . ";\n";
5281
		}
5282
	}
5283

    
5284
	$request_options = "";
5285
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5286
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5287
	}
5288

    
5289
	$required_options = "";
5290
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5291
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5292
	}
5293

    
5294
	$option_modifiers = "";
5295
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5296
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5297
		foreach ($modifiers as $modifier) {
5298
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5299
		}
5300
	}
5301

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

    
5326
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5327

    
5328
	return $dhclientconf;
5329
}
5330

    
5331
function DHCP_Config_Option_Split($option_string) {
5332
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5333
	return $matches ? $matches[0] : [];
5334
}
5335

    
5336
function DHCP_Config_File_Override($ifcfg, $realif) {
5337

    
5338
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5339

    
5340
	if ($dhclientconf === false) {
5341
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5342
		return '';
5343
	} else {
5344
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5345
	}
5346
}
5347

    
5348

    
5349
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5350

    
5351
	/* Apply Interface Substitutions */
5352
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5353

    
5354
	/* Apply Hostname Substitutions */
5355
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5356

    
5357
	/* Arrays of MAC Address Types, Cases, Delimiters */
5358
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5359
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5360
	$various_mac_cases      = array("U", "L");
5361
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5362

    
5363
	/* Apply MAC Address Substitutions */
5364
	foreach ($various_mac_types as $various_mac_type) {
5365
		foreach ($various_mac_cases as $various_mac_case) {
5366
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5367

    
5368
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5369
				if ($res !== false) {
5370

    
5371
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5372
					if ("$various_mac_case" == "U") {
5373
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5374
					}
5375
					if ("$various_mac_case" == "L") {
5376
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5377
					}
5378

    
5379
					if ("$various_mac_type" == "mac_addr_hex") {
5380
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5381
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5382
						$dhcpclientconf_mac_hex = "";
5383
						$delimiter = "";
5384
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5385
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5386
							$delimiter = ":";
5387
						}
5388
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5389
					}
5390

    
5391
					/* MAC Address Delimiter Substitutions */
5392
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5393

    
5394
					/* Apply MAC Address Substitutions */
5395
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5396
				}
5397
			}
5398
		}
5399
	}
5400

    
5401
	return $dhclientconf;
5402
}
5403

    
5404
function interfaces_group_setup() {
5405
	global $config;
5406

    
5407
	if (!isset($config['ifgroups']['ifgroupentry']) || !is_array($config['ifgroups']['ifgroupentry'])) {
5408
		return;
5409
	}
5410

    
5411
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5412
		interface_group_setup($groupar);
5413
	}
5414

    
5415
	return;
5416
}
5417

    
5418
function interface_group_setup(&$groupname /* The parameter is an array */) {
5419
	global $config;
5420

    
5421
	if (!is_array($groupname)) {
5422
		return;
5423
	}
5424
	$members = explode(" ", $groupname['members']);
5425
	foreach ($members as $ifs) {
5426
		$realif = get_real_interface($ifs);
5427
		if ($realif && does_interface_exist($realif)) {
5428
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5429
		}
5430
	}
5431

    
5432
	return;
5433
}
5434

    
5435
function is_interface_group($if) {
5436
	global $config;
5437

    
5438
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5439
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5440
			if ($groupentry['ifname'] === $if) {
5441
				return true;
5442
			}
5443
		}
5444
	}
5445

    
5446
	return false;
5447
}
5448

    
5449
function interface_group_add_member($interface, $groupname) {
5450
	$interface = get_real_interface($interface);
5451
	if (does_interface_exist($interface)) {
5452
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5453
	}
5454
}
5455

    
5456
/* COMPAT Function */
5457
function convert_friendly_interface_to_real_interface_name($interface) {
5458
	return get_real_interface($interface);
5459
}
5460

    
5461
/* COMPAT Function */
5462
function get_real_wan_interface($interface = "wan") {
5463
	return get_real_interface($interface);
5464
}
5465

    
5466
/* COMPAT Function */
5467
function get_current_wan_address($interface = "wan") {
5468
	return get_interface_ip($interface);
5469
}
5470

    
5471
/*
5472
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5473
 */
5474
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5475
	global $config;
5476

    
5477
	/* XXX: For speed reasons reference directly the interface array */
5478
	init_config_arr(array('interfaces'));
5479
	$ifdescrs = &$config['interfaces'];
5480
	//$ifdescrs = get_configured_interface_list(true);
5481

    
5482
	foreach ($ifdescrs as $if => $ifname) {
5483
		if ($if == $interface || $ifname['if'] == $interface) {
5484
			return $if;
5485
		}
5486

    
5487
		if (get_real_interface($if) == $interface) {
5488
			return $if;
5489
		}
5490

    
5491
		if ($checkparent == false) {
5492
			continue;
5493
		}
5494

    
5495
		$int = get_parent_interface($if, true);
5496
		if (is_array($int)) {
5497
			foreach ($int as $iface) {
5498
				if ($iface == $interface) {
5499
					return $if;
5500
				}
5501
			}
5502
		}
5503
	}
5504

    
5505
	if ($interface == "enc0") {
5506
		return 'IPsec';
5507
	}
5508
}
5509

    
5510
/* attempt to resolve interface to friendly descr */
5511
function convert_friendly_interface_to_friendly_descr($interface) {
5512
	global $config;
5513

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

    
5569
				/* if list */
5570
				$ifdescrs = get_configured_interface_with_descr(true);
5571
				foreach ($ifdescrs as $if => $ifname) {
5572
					if ($if == $interface || $ifname == $interface) {
5573
						return $ifname;
5574
					}
5575
				}
5576
			}
5577
			break;
5578
	}
5579

    
5580
	return $ifdesc;
5581
}
5582

    
5583
function convert_real_interface_to_friendly_descr($interface) {
5584

    
5585
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5586

    
5587
	if (!empty($ifdesc)) {
5588
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5589
	}
5590

    
5591
	return $interface;
5592
}
5593

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

    
5606
	$parents = array();
5607
	//Check that we got a valid interface passed
5608
	$realif = get_real_interface($interface);
5609
	if ($realif == NULL) {
5610
		return $parents;
5611
	}
5612

    
5613
	// If we got a real interface, find it's friendly assigned name
5614
	if ($interface == $realif && $avoidrecurse == false) {
5615
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5616
	}
5617

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

    
5651
	if (empty($parents)) {
5652
		// Handle _vlans not assigned to an interface
5653
		$vlan = interface_is_vlan($realif);
5654
		if ($vlan != NULL) {
5655
			$parents[0] = $vlan['if'];
5656
		}
5657
	}
5658

    
5659
	if (empty($parents)) {
5660
		/* Handle LAGGs. */
5661
		$lagg = interface_is_type($realif, 'lagg');
5662
		if ($lagg != NULL && isset($lagg['members'])) {
5663
			$parents = explode(",", $lagg['members']);
5664
		}
5665
	}
5666

    
5667
	if (empty($parents)) {
5668
		$parents[0] = $realif;
5669
	}
5670

    
5671
	return $parents;
5672
}
5673

    
5674
/*
5675
 *  get_parent_physical_interface($interface):
5676
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5677
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5678
 */
5679
function get_parent_physical_interface($interface) {
5680
	global $config;
5681

    
5682
	$realif = get_parent_interface($interface);
5683

    
5684
	if (substr($realif[0], 0, 4) == "lagg") {
5685
		foreach ($config['laggs']['lagg'] as $lagg) {
5686
			if ($realif[0] == $lagg['laggif']) {
5687
				return explode(",", $lagg['members']);
5688
			}
5689
		}
5690
	} else {
5691
		return $realif;
5692
	}
5693
}
5694

    
5695
function interface_is_wireless_clone($wlif) {
5696
	if (!stristr($wlif, "_wlan")) {
5697
		return false;
5698
	} else {
5699
		return true;
5700
	}
5701
}
5702

    
5703
function interface_get_wireless_base($wlif) {
5704
	if (!stristr($wlif, "_wlan")) {
5705
		return $wlif;
5706
	} else {
5707
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5708
	}
5709
}
5710

    
5711
function interface_get_wireless_clone($wlif) {
5712
	if (!stristr($wlif, "_wlan")) {
5713
		return $wlif . "_wlan0";
5714
	} else {
5715
		return $wlif;
5716
	}
5717
}
5718

    
5719
function interface_list_wireless() {
5720
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5721

    
5722
	$result = array();
5723
	foreach ($portlist as $port) {
5724
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5725
			continue;
5726
		}
5727

    
5728
		$desc = $port . " ( " . get_single_sysctl(
5729
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5730

    
5731
		$result[] = array(
5732
		    "if" => $port,
5733
		    "descr" => $desc
5734
		);
5735
	}
5736

    
5737
	return $result;
5738
}
5739

    
5740
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
5741
	global $config, $g;
5742

    
5743
	$wanif = NULL;
5744

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

    
5787
			if (empty($config['interfaces'][$interface])) {
5788
				break;
5789
			}
5790

    
5791
			$cfg = &$config['interfaces'][$interface];
5792

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

    
5851
	return $wanif;
5852
}
5853

    
5854
/* Guess the physical interface by providing a IP address */
5855
function guess_interface_from_ip($ipaddress) {
5856

    
5857
	$family = '';
5858
	if (is_ipaddrv4($ipaddress)) {
5859
		$family = 'inet';
5860
	}
5861
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5862
		$family = 'inet6';
5863
	}
5864

    
5865
	if (empty($family)) {
5866
		return false;
5867
	}
5868

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

    
5877
	return false;
5878
}
5879

    
5880
/*
5881
 * find_ip_interface($ip): return the interface where an ip is defined
5882
 *   (or if $bits is specified, where an IP within the subnet is defined)
5883
 */
5884
function find_ip_interface($ip, $bits = null) {
5885
	if (!is_ipaddr($ip)) {
5886
		return false;
5887
	}
5888

    
5889
	$isv6ip = is_ipaddrv6($ip);
5890

    
5891
	/* if list */
5892
	$ifdescrs = get_configured_interface_list();
5893

    
5894
	foreach ($ifdescrs as $ifdescr => $ifname) {
5895
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
5896
		if (is_null($ifip)) {
5897
			continue;
5898
		}
5899
		if (is_null($bits)) {
5900
			if ($ip == $ifip) {
5901
				$int = get_real_interface($ifname);
5902
				return $int;
5903
			}
5904
		} else {
5905
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
5906
				$int = get_real_interface($ifname);
5907
				return $int;
5908
			}
5909
		}
5910
	}
5911

    
5912
	return false;
5913
}
5914

    
5915
/*
5916
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5917
 *   (or if $bits is specified, where an IP within the subnet is found)
5918
 */
5919
function find_virtual_ip_alias($ip, $bits = null) {
5920
	global $config;
5921

    
5922
	if (!is_array($config['virtualip']['vip'])) {
5923
		return false;
5924
	}
5925
	if (!is_ipaddr($ip)) {
5926
		return false;
5927
	}
5928

    
5929
	$isv6ip = is_ipaddrv6($ip);
5930

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

    
5951
function link_interface_to_track6($int, $action = "") {
5952
	global $config;
5953

    
5954
	if (empty($int)) {
5955
		return;
5956
	}
5957

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

    
5976
function interface_find_child_cfgmtu($realiface) {
5977
	global $config;
5978

    
5979
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5980
	$vlans = link_interface_to_vlans($realiface);
5981
	$qinqs = link_interface_to_qinqs($realiface);
5982
	$bridge = link_interface_to_bridge($realiface);
5983
	if (!empty($interface)) {
5984
		$gifs = link_interface_to_gif($interface);
5985
		$gres = link_interface_to_gre($interface);
5986
	} else {
5987
		$gifs = array();
5988
		$gres = array();
5989
	}
5990

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

    
6052
	return $mtu;
6053
}
6054

    
6055
function link_interface_to_vlans($int, $action = "") {
6056
	global $config;
6057

    
6058
	if (empty($int)) {
6059
		return;
6060
	}
6061

    
6062
	if (is_array($config['vlans']['vlan'])) {
6063
		$ifaces = array();
6064
		foreach ($config['vlans']['vlan'] as $vlan) {
6065
			if ($int == $vlan['if']) {
6066
				if ($action == "update") {
6067
					interfaces_bring_up($int);
6068
				} else {
6069
					$ifaces[$vlan['tag']] = $vlan;
6070
				}
6071
			}
6072
		}
6073
		if (!empty($ifaces)) {
6074
			return $ifaces;
6075
		}
6076
	}
6077
}
6078

    
6079
function link_interface_to_qinqs($int, $action = "") {
6080
	global $config;
6081

    
6082
	if (empty($int)) {
6083
		return;
6084
	}
6085

    
6086
	if (is_array($config['qinqs']['qinqentry'])) {
6087
		$ifaces = array();
6088
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
6089
			if ($int == $qinq['if']) {
6090
				if ($action == "update") {
6091
					interfaces_bring_up($int);
6092
				} else {
6093
					$ifaces[$qinq['tag']] = $qinq;
6094
				}
6095
			}
6096
		}
6097
		if (!empty($ifaces)) {
6098
			return $ifaces;
6099
		}
6100
	}
6101
}
6102

    
6103
function link_interface_to_vips($int, $action = "", $vhid = '') {
6104
	global $config;
6105

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

    
6133
	return NULL;
6134
}
6135

    
6136
/****f* interfaces/link_interface_to_bridge
6137
 * NAME
6138
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6139
 * INPUTS
6140
 *   $ip
6141
 * RESULT
6142
 *   bridge[0-99]
6143
 ******/
6144
function link_interface_to_bridge($int) {
6145
	global $config;
6146

    
6147
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6148
		foreach ($config['bridges']['bridged'] as $bridge) {
6149
			if (in_array($int, explode(',', $bridge['members']))) {
6150
				return "{$bridge['bridgeif']}";
6151
			}
6152
		}
6153
	}
6154
}
6155

    
6156
function link_interface_to_lagg($int) {
6157
	global $config;
6158

    
6159
	if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
6160
		foreach ($config['laggs']['lagg'] as $lagg) {
6161
			if (in_array($int, explode(',', $lagg['members']))) {
6162
				return "{$lagg['laggif']}";
6163
			}
6164
		}
6165
	}
6166
}
6167

    
6168
function link_interface_to_group($int) {
6169
	global $config;
6170

    
6171
	$result = array();
6172

    
6173
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6174
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6175
			if (in_array($int, explode(" ", $group['members']))) {
6176
				$result[$group['ifname']] = $int;
6177
			}
6178
		}
6179
	}
6180

    
6181
	return $result;
6182
}
6183

    
6184
function link_interface_to_gre($interface) {
6185
	global $config;
6186

    
6187
	$result = array();
6188

    
6189
	if (is_array($config['gres']['gre'])) {
6190
		foreach ($config['gres']['gre'] as $gre) {
6191
			if ($gre['if'] == $interface) {
6192
				$result[] = $gre;
6193
			}
6194
		}
6195
	}
6196

    
6197
	return $result;
6198
}
6199

    
6200
function link_interface_to_gif($interface) {
6201
	global $config;
6202

    
6203
	$result = array();
6204

    
6205
	if (is_array($config['gifs']['gif'])) {
6206
		foreach ($config['gifs']['gif'] as $gif) {
6207
			if ($gif['if'] == $interface) {
6208
				$result[] = $gif;
6209
			}
6210
		}
6211
	}
6212

    
6213
	return $result;
6214
}
6215

    
6216
/*
6217
 * find_interface_ip($interface): return the interface ip (first found)
6218
 */
6219
function find_interface_ip($interface, $flush = false) {
6220
	global $interface_ip_arr_cache;
6221
	global $interface_sn_arr_cache;
6222

    
6223
	$interface = str_replace("\n", "", $interface);
6224

    
6225
	if (!does_interface_exist($interface)) {
6226
		return;
6227
	}
6228

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

    
6250
	return $interface_ip_arr_cache[$interface];
6251
}
6252

    
6253
/*
6254
 * find_interface_ipv6($interface): return the interface ip (first found)
6255
 */
6256
function find_interface_ipv6($interface, $flush = false) {
6257
	global $interface_ipv6_arr_cache;
6258
	global $interface_snv6_arr_cache;
6259
	global $config;
6260

    
6261
	$interface = trim($interface);
6262
	$interface = get_real_interface($interface);
6263

    
6264
	if (!does_interface_exist($interface)) {
6265
		return;
6266
	}
6267

    
6268
	/* Setup IP cache */
6269
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6270
		$ifinfo = pfSense_get_interface_addresses($interface);
6271
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6272
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6273
	}
6274

    
6275
	return $interface_ipv6_arr_cache[$interface];
6276
}
6277

    
6278
/*
6279
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6280
 */
6281
function find_interface_ipv6_ll($interface, $flush = false) {
6282
	global $interface_llv6_arr_cache;
6283
	global $config;
6284

    
6285
	$interface = str_replace("\n", "", $interface);
6286

    
6287
	if (!does_interface_exist($interface)) {
6288
		return;
6289
	}
6290

    
6291
	/* Setup IP cache */
6292
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6293
		$ifinfo = pfSense_getall_interface_addresses($interface);
6294
		foreach ($ifinfo as $line) {
6295
			if (strstr($line, ":")) {
6296
				$parts = explode("/", $line);
6297
				if (is_linklocal($parts[0])) {
6298
					$ifinfo['linklocal'] = $parts[0];
6299
				}
6300
			}
6301
		}
6302
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6303
	}
6304
	return $interface_llv6_arr_cache[$interface];
6305
}
6306

    
6307
function find_interface_subnet($interface, $flush = false) {
6308
	global $interface_sn_arr_cache;
6309
	global $interface_ip_arr_cache;
6310

    
6311
	$interface = str_replace("\n", "", $interface);
6312
	if (does_interface_exist($interface) == false) {
6313
		return;
6314
	}
6315

    
6316
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6317
		$ifinfo = pfSense_get_interface_addresses($interface);
6318
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6319
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6320
	}
6321

    
6322
	return $interface_sn_arr_cache[$interface];
6323
}
6324

    
6325
function find_interface_subnetv6($interface, $flush = false) {
6326
	global $interface_snv6_arr_cache;
6327
	global $interface_ipv6_arr_cache;
6328

    
6329
	$interface = str_replace("\n", "", $interface);
6330
	if (does_interface_exist($interface) == false) {
6331
		return;
6332
	}
6333

    
6334
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6335
		$ifinfo = pfSense_get_interface_addresses($interface);
6336
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6337
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6338
	}
6339

    
6340
	return $interface_snv6_arr_cache[$interface];
6341
}
6342

    
6343
function ip_in_interface_alias_subnet($interface, $ipalias) {
6344
	global $config;
6345

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

    
6365
	return false;
6366
}
6367

    
6368
function get_possible_listen_ips($include_ipv6_link_local=false) {
6369

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

    
6391
	$interfaces['lo0'] = 'Localhost';
6392

    
6393
	return $interfaces;
6394
}
6395

    
6396
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6397
	global $config;
6398

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

    
6424
function get_interface_ip($interface = "wan") {
6425
	global $config;
6426

    
6427
	if (substr($interface, 0, 4) == '_vip') {
6428
		return get_configured_vip_ipv4($interface);
6429
	} else if (substr($interface, 0, 5) == '_lloc') {
6430
		/* No link-local address for v4. */
6431
		return null;
6432
	}
6433

    
6434
	$realif = get_failover_interface($interface, 'inet');
6435
	if (!$realif) {
6436
		return null;
6437
	}
6438

    
6439
	if (substr($realif, 0, 4) == '_vip') {
6440
		return get_configured_vip_ipv4($realif);
6441
	} else if (substr($realif, 0, 5) == '_lloc') {
6442
		/* No link-local address for v4. */
6443
		return null;
6444
	}
6445

    
6446
	if (is_array($config['interfaces'][$interface]) &&
6447
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6448
		return ($config['interfaces'][$interface]['ipaddr']);
6449
	}
6450

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

    
6464
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6465
	global $config;
6466

    
6467
	if (substr($interface, 0, 4) == '_vip') {
6468
		return get_configured_vip_ipv6($interface);
6469
	} else if (substr($interface, 0, 5) == '_lloc') {
6470
		return get_interface_linklocal($interface);
6471
	}
6472

    
6473
	$realif = get_failover_interface($interface, 'inet6');
6474
	if (!$realif) {
6475
		return null;
6476
	}
6477

    
6478
	if (substr($realif, 0, 4) == '_vip') {
6479
		return get_configured_vip_ipv6($realif);
6480
	} else if (substr($realif, 0, 5) == '_lloc') {
6481
		return get_interface_linklocal($realif);
6482
	}
6483

    
6484
	if (is_array($config['interfaces'][$interface])) {
6485
		switch ($config['interfaces'][$interface]['ipaddr']) {
6486
			case 'pppoe':
6487
			case 'l2tp':
6488
			case 'pptp':
6489
			case 'ppp':
6490
				if (($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') ||
6491
				    ($config['interfaces'][$interface]['ipaddrv6'] == 'slaac')) {
6492
					$realif = get_real_interface($interface, 'inet6', false);
6493
				}
6494
				break;
6495
		}
6496
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6497
			return ($config['interfaces'][$interface]['ipaddrv6']);
6498
		}
6499
	}
6500

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

    
6524
function get_interface_linklocal($interface = "wan") {
6525

    
6526
	$realif = get_failover_interface($interface, 'inet6');
6527
	if (!$realif) {
6528
		return null;
6529
	}
6530

    
6531
	if (substr($interface, 0, 4) == '_vip') {
6532
		$realif = get_real_interface($interface);
6533
	} else if (substr($interface, 0, 5) == '_lloc') {
6534
		$realif = get_real_interface(substr($interface, 5));
6535
	}
6536

    
6537
	$curip = find_interface_ipv6_ll($realif);
6538
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6539
		return $curip;
6540
	} else {
6541
		return null;
6542
	}
6543
}
6544

    
6545
function get_interface_subnet($interface = "wan") {
6546
	global $config;
6547

    
6548
	if (substr($interface, 0, 4) == '_vip') {
6549
		return (get_configured_vip_subnetv4($interface));
6550
	}
6551

    
6552
	if (is_array($config['interfaces'][$interface]) &&
6553
	    !empty($config['interfaces'][$interface]['subnet']) &&
6554
	    is_ipaddrv4($config['interfaces'][$interface]['ipaddr'])) {
6555
		return ($config['interfaces'][$interface]['subnet']);
6556
	}
6557

    
6558
	$realif = get_real_interface($interface);
6559
	if (!$realif) {
6560
		return (NULL);
6561
	}
6562

    
6563
	$cursn = find_interface_subnet($realif);
6564
	if (!empty($cursn)) {
6565
		return ($cursn);
6566
	}
6567

    
6568
	return (NULL);
6569
}
6570

    
6571
function get_interface_subnetv6($interface = "wan") {
6572
	global $config;
6573

    
6574
	if (substr($interface, 0, 4) == '_vip') {
6575
		return (get_configured_vip_subnetv6($interface));
6576
	} else if (substr($interface, 0, 5) == '_lloc') {
6577
		$interface = substr($interface, 5);
6578
	}
6579

    
6580
	if (is_array($config['interfaces'][$interface]) &&
6581
	    !empty($config['interfaces'][$interface]['subnetv6']) &&
6582
	    is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6583
		return ($config['interfaces'][$interface]['subnetv6']);
6584
	}
6585

    
6586
	$realif = get_real_interface($interface, 'inet6');
6587
	if (!$realif) {
6588
		return (NULL);
6589
	}
6590

    
6591
	$cursn = find_interface_subnetv6($realif);
6592
	if (!empty($cursn)) {
6593
		return ($cursn);
6594
	}
6595

    
6596
	return (NULL);
6597
}
6598

    
6599
/* return outside interfaces with a gateway */
6600
function get_interfaces_with_gateway() {
6601
	global $config;
6602

    
6603
	$ints = array();
6604

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

    
6624
				break;
6625
		}
6626
	}
6627
	return $ints;
6628
}
6629

    
6630
/* return true if interface has a gateway */
6631
function interface_has_gateway($friendly) {
6632
	global $config;
6633

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

    
6662
	return false;
6663
}
6664

    
6665
/* return true if interface has a gateway */
6666
function interface_has_gatewayv6($friendly) {
6667
	global $config;
6668

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

    
6696
	return false;
6697
}
6698

    
6699
/****f* interfaces/is_altq_capable
6700
 * NAME
6701
 *   is_altq_capable - Test if interface is capable of using ALTQ
6702
 * INPUTS
6703
 *   $int            - string containing interface name
6704
 * RESULT
6705
 *   boolean         - true or false
6706
 ******/
6707

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

    
6723
	$int_family = remove_ifindex($int);
6724

    
6725
	if (in_array($int_family, $capable)) {
6726
		return true;
6727
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6728
		return true;
6729
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6730
		return true;
6731
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6732
		return true;
6733
	} else {
6734
		return false;
6735
	}
6736
}
6737

    
6738
/****f* interfaces/is_interface_wireless
6739
 * NAME
6740
 *   is_interface_wireless - Returns if an interface is wireless
6741
 * RESULT
6742
 *   $tmp       - Returns if an interface is wireless
6743
 ******/
6744
function is_interface_wireless($interface) {
6745
	global $config, $g;
6746

    
6747
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6748
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6749
		if (preg_match($g['wireless_regex'], $interface)) {
6750
			if (isset($config['interfaces'][$friendly])) {
6751
				$config['interfaces'][$friendly]['wireless'] = array();
6752
			}
6753
			return true;
6754
		}
6755
		return false;
6756
	} else {
6757
		return true;
6758
	}
6759
}
6760

    
6761
function get_wireless_modes($interface) {
6762
	/* return wireless modes and channels */
6763
	$wireless_modes = array();
6764

    
6765
	$cloned_interface = get_real_interface($interface);
6766

    
6767
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6768
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6769
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6770
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6771

    
6772
		$interface_channels = "";
6773
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6774
		$interface_channel_count = count($interface_channels);
6775

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

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

    
6814
		$interface_channels = "";
6815
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6816
		return $interface_channels;
6817
}
6818

    
6819
/* return wireless HT modes */
6820
function get_wireless_ht_modes($interface) {
6821
	$wireless_hts_supported = array(0 => gettext('Auto'));
6822

    
6823
	$cloned_interface = get_real_interface($interface);
6824

    
6825
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6826
		$interface_channels = get_wireless_channels($cloned_interface);
6827

    
6828
		foreach ($interface_channels as $channel) {
6829
			$channel_line = explode(",", $channel);
6830
			$wireless_ht = trim($channel_line[1]);
6831
			if (!empty($wireless_ht)) {
6832
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
6833
			}
6834
		}
6835
	}
6836
	return($wireless_hts_supported);
6837
}
6838

    
6839
/* return wireless HT by channel/standard */
6840
function get_wireless_ht_list($interface) {
6841
	$wireless_hts = array();
6842

    
6843
	$cloned_interface = get_real_interface($interface);
6844

    
6845
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6846
		$interface_channels = get_wireless_channels($cloned_interface);
6847
		$interface_channel_count = count($interface_channels);
6848

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

    
6875
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6876
function get_wireless_channel_info($interface) {
6877
	$wireless_channels = array();
6878

    
6879
	$cloned_interface = get_real_interface($interface);
6880

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

    
6886
		$interface_channels = "";
6887
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6888

    
6889
		foreach ($interface_channels as $channel_line) {
6890
			$channel_line = explode(",", $channel_line);
6891
			if (!isset($wireless_channels[$channel_line[0]])) {
6892
				$wireless_channels[$channel_line[0]] = $channel_line;
6893
			}
6894
		}
6895
	}
6896
	return($wireless_channels);
6897
}
6898

    
6899
function set_interface_mtu($interface, $mtu) {
6900

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

    
6919
/****f* interfaces/get_interface_mtu
6920
 * NAME
6921
 *   get_interface_mtu - Return the mtu of an interface
6922
 * RESULT
6923
 *   $tmp       - Returns the mtu of an interface
6924
 ******/
6925
function get_interface_mtu($interface) {
6926
	$mtu = pfSense_interface_getmtu($interface);
6927
	return $mtu['mtu'];
6928
}
6929

    
6930
function get_interface_mac($interface) {
6931
	$macinfo = pfSense_get_interface_addresses($interface);
6932
	return $macinfo["macaddr"];
6933
}
6934

    
6935
function get_interface_vendor_mac($interface) {
6936
	global $config, $g;
6937

    
6938
	$macinfo = pfSense_get_interface_addresses($interface);
6939
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
6940
	    "00:00:00:00:00:00") {
6941
		return ($macinfo["hwaddr"]);
6942
	}
6943

    
6944
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
6945
	if (file_exists($hwaddr_file)) {
6946
		$macaddr = trim(file_get_contents($hwaddr_file));
6947
		if (is_macaddr($macaddr)) {
6948
			return ($macaddr);
6949
		}
6950
	} elseif (is_macaddr($macinfo['macaddr'])) {
6951
		/* Save original macaddress to be restored when necessary */
6952
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
6953
	}
6954

    
6955
	return (NULL);
6956
}
6957

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

    
6974
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6975
	global $g;
6976

    
6977
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6978

    
6979
	if (!empty($iface) && !empty($pppif)) {
6980
		$cron_cmd = <<<EOD
6981
#!/bin/sh
6982
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
6983
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
6984

    
6985
EOD;
6986

    
6987
		@file_put_contents($cron_file, $cron_cmd);
6988
		chmod($cron_file, 0755);
6989
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
6990
	} else {
6991
		unlink_if_exists($cron_file);
6992
	}
6993
}
6994

    
6995
function get_interface_default_mtu($type = "ethernet") {
6996
	switch ($type) {
6997
		case "gre":
6998
			return 1476;
6999
			break;
7000
		case "gif":
7001
			return 1280;
7002
			break;
7003
		case "tun":
7004
		case "vlan":
7005
		case "tap":
7006
		case "ethernet":
7007
		default:
7008
			return 1500;
7009
			break;
7010
	}
7011

    
7012
	/* Never reached */
7013
	return 1500;
7014
}
7015

    
7016
function get_vip_descr($ipaddress) {
7017
	global $config;
7018

    
7019
	foreach ($config['virtualip']['vip'] as $vip) {
7020
		if ($vip['subnet'] == $ipaddress) {
7021
			return ($vip['descr']);
7022
		}
7023
	}
7024
	return "";
7025
}
7026

    
7027
function interfaces_staticarp_configure($if) {
7028
	global $config, $g;
7029
	if (isset($config['system']['developerspew'])) {
7030
		$mt = microtime();
7031
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7032
	}
7033

    
7034
	$ifcfg = $config['interfaces'][$if];
7035

    
7036
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
7037
		return 0;
7038
	}
7039

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

    
7063
	return 0;
7064
}
7065

    
7066
function get_failover_interface($interface, $family = "all") {
7067
	global $config;
7068

    
7069
	/* shortcut to get_real_interface if we find it in the config */
7070
	if (is_array($config['interfaces'][$interface])) {
7071
		return get_real_interface($interface, $family);
7072
	}
7073

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

    
7089
/****f* interfaces/interface_has_dhcp
7090
 * NAME
7091
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7092
 * INPUTS
7093
 *   interface or gateway group name
7094
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7095
 * RESULT
7096
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7097
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7098
 ******/
7099
function interface_has_dhcp($interface, $family = 4) {
7100
	global $config;
7101

    
7102
	if ($config['interfaces'][$interface]) {
7103
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
7104
			return true;
7105
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
7106
			return true;
7107
		} else {
7108
			return false;
7109
		}
7110
	}
7111

    
7112
	if (!is_array($config['gateways']['gateway_group'])) {
7113
		return false;
7114
	}
7115

    
7116
	if ($family == 6) {
7117
		$dhcp_string = "_DHCP6";
7118
	} else {
7119
		$dhcp_string = "_DHCP";
7120
	}
7121

    
7122
	foreach ($config['gateways']['gateway_group'] as $group) {
7123
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7124
			continue;
7125
		}
7126
		foreach ($group['item'] as $item) {
7127
			$item_data = explode("|", $item);
7128
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7129
				return true;
7130
			}
7131
		}
7132
	}
7133

    
7134
	return false;
7135
}
7136

    
7137
function remove_ifindex($ifname) {
7138
	return preg_replace("/[0-9]+$/", "", $ifname);
7139
}
7140

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

    
7144
	$viplist = get_configured_vip_list($family, $type);
7145
	foreach ($viplist as $vip => $address) {
7146
		$interfaces[$vip] = $address;
7147
		if ($type = VIP_CARP) {
7148
			$vip = get_configured_vip($vipid);
7149
			if (isset($vip) && is_array($vip) ) {
7150
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7151
			}
7152
		}
7153
		if (get_vip_descr($address)) {
7154
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
7155
		}
7156
	}
7157
	return $interfaces;
7158
}
7159

    
7160
function return_gateway_groups_array_with_descr() {
7161
	$interfaces = array();
7162
	$grouplist = return_gateway_groups_array();
7163
	foreach ($grouplist as $name => $group) {
7164
		if ($group[0]['vip'] != "") {
7165
			$vipif = $group[0]['vip'];
7166
		} else {
7167
			$vipif = $group[0]['int'];
7168
		}
7169

    
7170
		$interfaces[$name] = "GW Group {$name}";
7171
	}
7172
	return $interfaces;
7173
}
7174

    
7175
function get_serial_ports() {
7176
	$linklist = array();
7177
	if (!is_dir("/var/spool/lock")) {
7178
		mwexec("/bin/mkdir -p /var/spool/lock");
7179
	}
7180
	$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);
7181
	foreach ($serialports as $port) {
7182
		$linklist[$port] = trim($port);
7183
	}
7184
	return $linklist;
7185
}
7186

    
7187
function get_interface_ports() {
7188
	global $config;
7189
	$linklist = array();
7190
	$portlist = get_interface_list();
7191
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7192
		foreach ($config['vlans']['vlan'] as $vlan) {
7193
			$portlist[$vlan['vlanif']] = $vlan;
7194
		}
7195
	}
7196

    
7197
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7198
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7199
			$members = explode(" ", $qinq['members']);
7200
			foreach ($members as $mem) {
7201
				$qentry = $qinq['vlanif'] . "." . $mem;
7202
				$portlist[$qentry] = $qentry;
7203
			}
7204
		}
7205
	}
7206

    
7207
	foreach ($portlist as $ifn => $ifinfo) {
7208
		$string = "";
7209
		if (is_array($ifinfo)) {
7210
			$string .= $ifn;
7211
			if ($ifinfo['mac']) {
7212
				$string .= " ({$ifinfo['mac']})";
7213
			}
7214
			if ($ifinfo['friendly']) {
7215
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7216
			} elseif ($ifinfo['descr']) {
7217
				$string .= " - {$ifinfo['descr']}";
7218
			}
7219
		} else {
7220
			$string .= $ifinfo;
7221
		}
7222

    
7223
		$linklist[$ifn] = $string;
7224
	}
7225
	return $linklist;
7226
}
7227

    
7228
function build_ppps_link_list() {
7229
	global $pconfig;
7230

    
7231
	$linklist = array('list' => array(), 'selected' => array());
7232

    
7233
	if ($pconfig['type'] == 'ppp') {
7234
		$linklist['list'] = get_serial_ports();
7235
	} else {
7236
		$iflist = get_interface_ports();
7237

    
7238
		$viplist = array();
7239
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7240
		foreach ($carplist as $vid => $vaddr) {
7241
			$vip = get_configured_vip($vid);
7242
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7243
		}
7244

    
7245
		$linklist['list'] = array_merge($iflist, $viplist);
7246

    
7247
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7248
		$lagglist = get_lagg_interface_list();
7249
		foreach ($lagglist as $laggif => $lagg) {
7250
			/* LAGG members cannot be assigned */
7251
			$laggmembers = explode(',', $lagg['members']);
7252
			foreach ($laggmembers as $lagm) {
7253
				if (isset($linklist['list'][$lagm])) {
7254
					unset($linklist['list'][$lagm]);
7255
				}
7256
			}
7257
		}
7258
	}
7259

    
7260
	$selected_ports = array();
7261
	if (is_array($pconfig['interfaces'])) {
7262
		$selected_ports = $pconfig['interfaces'];
7263
	} elseif (!empty($pconfig['interfaces'])) {
7264
		$selected_ports = explode(',', $pconfig['interfaces']);
7265
	}
7266
	foreach ($selected_ports as $port) {
7267
		if (isset($linklist['list'][$port])) {
7268
			array_push($linklist['selected'], $port);
7269
		}
7270
	}
7271
	return($linklist);
7272
}
7273

    
7274
function create_interface_list() {
7275
	global $config;
7276

    
7277
	$iflist = array();
7278

    
7279
	// add group interfaces
7280
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7281
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7282
			if (have_ruleint_access($ifgen['ifname'])) {
7283
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7284
			}
7285
		}
7286
	}
7287

    
7288
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7289
		if (have_ruleint_access($ifent)) {
7290
			$iflist[$ifent] = $ifdesc;
7291
		}
7292
	}
7293

    
7294
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
7295
		$iflist['l2tp'] = gettext('L2TP VPN');
7296
	}
7297

    
7298
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
7299
		$iflist['pppoe'] = gettext("PPPoE Server");
7300
	}
7301

    
7302
	// add ipsec interfaces
7303
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
7304
		$iflist["enc0"] = gettext("IPsec");
7305
	}
7306

    
7307
	// add openvpn/tun interfaces
7308
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7309
		$iflist["openvpn"] = gettext("OpenVPN");
7310
	}
7311

    
7312
	return($iflist);
7313
}
7314

    
7315
function is_pseudo_interface($inf, $tap=true) {
7316
	global $config;
7317
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7318
	foreach ($psifs as $pif) {
7319
		if (substr($inf, 0, strlen($pif)) == $pif) {
7320
			if (($pif == 'ovpn') && $tap) {
7321
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7322
				$type = ($m[1] == 'c') ? 'client' : 'server';
7323
				foreach ($config['openvpn']['openvpn-'.$type] as $ovpn) {
7324
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7325
						return false; 	
7326
					} elseif ($ovpn['vpnid'] == $m[2]) {
7327
						return true;
7328
					}
7329
				}
7330
			} else {
7331
				return true;
7332
			}
7333
		}
7334
	}
7335
	return false;
7336
}
7337

    
7338
function is_stf_interface($inf) {
7339
	global $config;
7340

    
7341
	if (is_array($config['interfaces'][$inf]) &&
7342
	    (($config['interfaces'][$inf]['ipaddrv6'] == '6rd') ||
7343
	    ($config['interfaces'][$inf]['ipaddrv6'] == '6to4'))) {
7344
	    return true;
7345
	}
7346

    
7347
	return false;
7348
}
7349

    
7350
?>
(22-22/60)