Project

General

Profile

Download (208 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
	foreach ($members as $member) {
1038
		if (!does_interface_exist($member)) {
1039
			continue;
1040
		}
1041

    
1042
		/* make sure the parent interface is up */
1043
		pfSense_interface_mtu($member, $lagg_mtu);
1044
		interfaces_bring_up($member);
1045
		hardware_offloading_applyflags($member);
1046

    
1047
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
1048
		$laggif = str_replace("\0", "", $laggif);
1049
		$member = str_replace("\0", "", $member);
1050
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
1051
	}
1052

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

    
1055
	interfaces_bring_up($laggif);
1056

    
1057
	return $laggif;
1058
}
1059

    
1060
function interfaces_gre_configure($checkparent = 0, $realif = "") {
1061
	global $config;
1062

    
1063
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
1064
		foreach ($config['gres']['gre'] as $i => $gre) {
1065
			if (empty($gre['greif'])) {
1066
				$gre['greif'] = "gre{$i}";
1067
			}
1068
			if (!empty($realif) && $realif != $gre['greif']) {
1069
				continue;
1070
			}
1071

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

    
1094
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
1095
function interface_gre_configure(&$gre, $grekey = "") {
1096
	global $config, $g;
1097

    
1098
	if (!is_array($gre)) {
1099
		return -1;
1100
	}
1101

    
1102
	$realif = get_real_interface($gre['if']);
1103
	$realifip = get_interface_ip($gre['if']);
1104
	$realifip6 = get_interface_ipv6($gre['if']);
1105

    
1106
	/* make sure the parent interface is up */
1107
	interfaces_bring_up($realif);
1108

    
1109
	if (platform_booting() || !(empty($gre['greif']))) {
1110
		pfSense_interface_destroy($gre['greif']);
1111
		pfSense_interface_create($gre['greif']);
1112
		$greif = $gre['greif'];
1113
	} else {
1114
		$greif = pfSense_interface_create("gre");
1115
	}
1116

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

    
1131
	if ($greif) {
1132
		interfaces_bring_up($greif);
1133
	} else {
1134
		log_error(gettext("Could not bring greif up -- variable not defined."));
1135
	}
1136

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

    
1147
	interfaces_bring_up($greif);
1148

    
1149
	return $greif;
1150
}
1151

    
1152
function interface_is_type($if = NULL, $type) {
1153
	global $config;
1154
	switch ($type) {
1155
		case "gre":
1156
			$list = 'gres';
1157
			$entry = 'gre';
1158
			$entif = 'greif';
1159
			break;
1160
		case "gif":
1161
			$list = 'gifs';
1162
			$entry = 'gif';
1163
			$entif = 'gifif';
1164
			break;
1165
		case "lagg":
1166
			$list = 'laggs';
1167
			$entry = 'lagg';
1168
			$entif = 'laggif';
1169
			break;
1170
		default:
1171
			break;
1172
	}
1173

    
1174
	if (!isset($config[$list][$entry]) || !is_array($config[$list][$entry])) {
1175
		return (NULL);
1176
	}
1177

    
1178
	foreach ($config[$list][$entry] as $ent) {
1179
		if ($ent[$entif] == $if) {
1180
			return ($ent);
1181
		}
1182
	}
1183
	return (NULL);
1184
}
1185

    
1186
function is_greipsec($if) {
1187
	global $config;
1188

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

    
1208
function interfaces_gif_configure($checkparent = 0, $realif = "") {
1209
	global $config;
1210

    
1211
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
1212
		foreach ($config['gifs']['gif'] as $i => $gif) {
1213
			if (empty($gif['gifif'])) {
1214
				$gre['gifif'] = "gif{$i}";
1215
			}
1216
			if (!empty($realif) && $realif != $gif['gifif']) {
1217
				continue;
1218
			}
1219

    
1220
			if ($checkparent == 1) {
1221
				if (substr($gif['if'], 0, 4) == '_vip') {
1222
					continue;
1223
				}
1224
				if (substr($gif['if'], 0, 5) == '_lloc') {
1225
					continue;
1226
				}
1227
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
1228
					continue;
1229
				}
1230
			}
1231
			else if ($checkparent == 2) {
1232
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
1233
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
1234
					continue;
1235
				}
1236
			}
1237
			/* XXX: Maybe we should report any errors?! */
1238
			interface_gif_configure($gif);
1239
		}
1240
	}
1241
}
1242

    
1243
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1244
function interface_gif_configure(&$gif, $gifkey = "") {
1245
	global $config, $g;
1246

    
1247
	if (!is_array($gif)) {
1248
		return -1;
1249
	}
1250

    
1251
	$realif = get_real_interface($gif['if']);
1252
	$ipaddr = get_interface_ip($gif['if']);
1253

    
1254
	if (is_ipaddrv4($gif['remote-addr'])) {
1255
		if (is_ipaddrv4($ipaddr)) {
1256
			$realifip = $ipaddr;
1257
		} else {
1258
			$realifip = get_interface_ip($gif['if']);
1259
		}
1260
		$realifgw = get_interface_gateway($gif['if']);
1261
	} else if (is_ipaddrv6($gif['remote-addr'])) {
1262
		if (is_ipaddrv6($ipaddr)) {
1263
			$realifip = $ipaddr;
1264
		} else {
1265
			$realifip = get_interface_ipv6($gif['if']);
1266
		}
1267
		$realifgw = get_interface_gateway_v6($gif['if']);
1268
	}
1269
	/* make sure the parent interface is up */
1270
	if ($realif) {
1271
		interfaces_bring_up($realif);
1272
	} else {
1273
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
1274
	}
1275

    
1276
	if (platform_booting() || !(empty($gif['gifif']))) {
1277
		pfSense_interface_destroy($gif['gifif']);
1278
		pfSense_interface_create($gif['gifif']);
1279
		$gifif = $gif['gifif'];
1280
	} else {
1281
		$gifif = pfSense_interface_create("gif");
1282
	}
1283

    
1284
	/* Do not change the order here for more see gif(4) NOTES section. */
1285
	if (is_ipaddrv6($gif['remote-addr'])) {
1286
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1287
	} else {
1288
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1289
	}
1290
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1291
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1292
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1293
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1294
	} else {
1295
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1296
	}
1297
	if (isset($gif['link1'])) {
1298
		pfSense_interface_flags($gifif, IFF_LINK1);
1299
	}
1300
	if (isset($gif['link2'])) {
1301
		pfSense_interface_flags($gifif, IFF_LINK2);
1302
	}
1303
	if ($gifif) {
1304
		interfaces_bring_up($gifif);
1305
		$gifmtu = "";
1306
		$currentgifmtu = get_interface_mtu($gifif);
1307
		foreach ($config['interfaces'] as $tmpinterface) {
1308
			if ($tmpinterface['if'] == $gifif) {
1309
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1310
					$gifmtu = $tmpinterface['mtu'];
1311
				}
1312
			}
1313
		}
1314
		if (is_numericint($gifmtu)) {
1315
			if ($gifmtu != $currentgifmtu) {
1316
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1317
			}
1318
		}
1319
	} else {
1320
		log_error(gettext("could not bring gifif up -- variable not defined"));
1321
	}
1322

    
1323
	if (!platform_booting()) {
1324
		$iflist = get_configured_interface_list();
1325
		foreach ($iflist as $ifname) {
1326
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1327
				if (get_interface_gateway($ifname)) {
1328
					system_routing_configure($ifname);
1329
					break;
1330
				}
1331
				if (get_interface_gateway_v6($ifname)) {
1332
					system_routing_configure($ifname);
1333
					break;
1334
				}
1335
			}
1336
		}
1337
	}
1338

    
1339

    
1340
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1341
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1342
	}
1343
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1344
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1345
	}
1346

    
1347
	if (is_ipaddrv4($realifgw)) {
1348
		route_add_or_change("-host {$gif['remote-addr']} {$realifgw}");
1349
	}
1350
	if (is_ipaddrv6($realifgw)) {
1351
		route_add_or_change("-host -inet6 {$gif['remote-addr']} {$realifgw}");
1352
	}
1353

    
1354
	interfaces_bring_up($gifif);
1355

    
1356
	return $gifif;
1357
}
1358

    
1359
/* Build a list of IPsec interfaces */
1360
function interface_ipsec_vti_list_p1($ph1ent) {
1361
	global $config;
1362
	$iface_list = array();
1363

    
1364
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1365
		return $iface_list;
1366
	}
1367

    
1368
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1369
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1370
		return $iface_list;
1371
	}
1372

    
1373
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1374
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1375
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1376
			$iface_list["ipsec{$ph1ent['ikeid']}00{$idx}"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1377
		}
1378
	} else {
1379
		/* For IKEv2, only create one interface with additional addresses as aliases */
1380
		$iface_list["ipsec{$ph1ent['ikeid']}000"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1381
	}
1382
	return $iface_list;
1383
}
1384
function interface_ipsec_vti_list_all() {
1385
	global $config;
1386
	$iface_list = array();
1387
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1388
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1389
			if ($ph1ent['disabled']) {
1390
				continue;
1391
			}
1392
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1393
		}
1394
	}
1395
	return $iface_list;
1396
}
1397

    
1398
function is_interface_ipsec_vti_assigned($phase2) {
1399
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1400
	$vti_interface = null;
1401
	$vtisubnet_spec = ipsec_vti($phase1, true);
1402
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1403
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1404
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1405
			foreach ($vtisubnet_spec as $idx => $vtisub) {
1406
				/* Is this for this P2? */
1407
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1408
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1409
					$vti_interface = "ipsec{$phase1['ikeid']}00{$idx}";
1410
				}
1411
			}
1412
		} else {
1413
			$vti_interface = "ipsec{$phase1['ikeid']}000";
1414
		}
1415
	}
1416
	/* Check if this interface is assigned */
1417
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1418
}
1419
function interface_ipsec_vti_configure($ph1ent) {
1420
	global $config;
1421

    
1422
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1423
		return false;
1424
	}
1425

    
1426
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1427
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1428
		return false;
1429
	}
1430

    
1431
	$left_spec = ipsec_get_phase1_src($ph1ent);
1432
	$right_spec = $ph1ent['remote-gateway'];
1433

    
1434
	$iface_addrs = array();
1435

    
1436
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1437
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1438
		/* Form a single interface for each P2 entry */
1439
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1440
			$ipsecifnum = "{$ph1ent['ikeid']}00{$idx}";
1441
			if (!is_array($iface_addrs[$ipsecifnum])) {
1442
				$iface_addrs[$ipsecifnum] = array();
1443
			}
1444
			$vtisub['alias'] = "";
1445
			$iface_addrs[$ipsecifnum][] = $vtisub;
1446
		}
1447
	} else {
1448
		/* For IKEv2, only create one interface with additional addresses as aliases */
1449
		$ipsecifnum = "{$ph1ent['ikeid']}000";
1450
		if (!is_array($iface_addrs[$ipsecifnum])) {
1451
			$iface_addrs[$ipsecifnum] = array();
1452
		}
1453
		$have_v4 = false;
1454
		$have_v6 = false;
1455
		foreach ($vtisubnet_spec as $vtisub) {
1456
			// Alias stuff
1457
			$vtisub['alias'] = "";
1458
			if (is_ipaddrv6($vtisub['left'])) {
1459
				if ($have_v6) {
1460
					$vtisub['alias'] = " alias";
1461
				}
1462
				$have_v6 = true;
1463
			} else {
1464
				if ($have_v4) {
1465
					$vtisub['alias'] = " alias";
1466
				}
1467
				$have_v4 = true;
1468
			}
1469
			$iface_addrs[$ipsecifnum][] = $vtisub;
1470
		}
1471
	}
1472

    
1473
	foreach ($iface_addrs as $ipsecifnum => $addrs) {
1474
		$ipsecif = "ipsec{$ipsecifnum}";
1475
		if (!is_array($addrs)) {
1476
			continue;
1477
		}
1478
		// Create IPsec interface
1479
		if (!platform_booting() && does_interface_exist($ipsecif)) {
1480
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy", false);
1481
		}
1482
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1483

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

    
1488
		/* Loop through all of the addresses for this interface and apply them as needed */
1489
		foreach ($addrs as $addr) {
1490
			// apply interface addresses
1491
			if (is_v6($addr['left'])) {
1492
				$inet = "inet6";
1493
				$gwtype = "v6";
1494
				$right = '';
1495
			} else {
1496
				$inet = "inet";
1497
				$gwtype = "";
1498
				$right = escapeshellarg($addr['right']);
1499
			}
1500

    
1501
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias'], false);
1502
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1503
			if (empty($addr['alias'])) {
1504
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1505
			}
1506
		}
1507
		/* Check/set the MTU if the user configured a custom value.
1508
		 * https://redmine.pfsense.org/issues/9111 */
1509
		$currentvtimtu = get_interface_mtu($ipsecif);
1510
		foreach ($config['interfaces'] as $tmpinterface) {
1511
			if ($tmpinterface['if'] == $ipsecif) {
1512
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1513
					$vtimtu = $tmpinterface['mtu'];
1514
				}
1515
			}
1516
		}
1517
		if (is_numericint($vtimtu)) {
1518
			if ($vtimtu != $currentvtimtu) {
1519
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1520
			}
1521
		}
1522
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1523
	}
1524
}
1525

    
1526
function interfaces_ipsec_vti_configure() {
1527
	global $config;
1528
	if (platform_booting()) {
1529
		echo gettext("Configuring IPsec VTI interfaces...");
1530
	}
1531
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1532
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1533
			if ($ph1ent['disabled']) {
1534
				continue;
1535
			}
1536
			interface_ipsec_vti_configure($ph1ent);
1537
		}
1538
	}
1539
	if (platform_booting()) {
1540
		echo gettext("done.") . "\n";
1541
	}
1542
}
1543

    
1544
function interfaces_configure() {
1545
	global $config, $g;
1546

    
1547
	/* Set up our loopback interface */
1548
	interfaces_loopback_configure();
1549

    
1550
	/* create the unconfigured wireless clones */
1551
	interfaces_create_wireless_clones();
1552

    
1553
	/* set up LAGG virtual interfaces */
1554
	interfaces_lagg_configure();
1555

    
1556
	/* set up VLAN virtual interfaces */
1557
	interfaces_vlan_configure();
1558

    
1559
	interfaces_qinq_configure();
1560

    
1561
	/* set up IPsec VTI interfaces */
1562
	interfaces_ipsec_vti_configure();
1563

    
1564
	$iflist = get_configured_interface_with_descr();
1565
	$delayed_list = array();
1566
	$bridge_list = array();
1567
	$track6_list = array();
1568

    
1569
	/* This is needed to speedup interfaces on bootup. */
1570
	$reload = false;
1571
	if (!platform_booting()) {
1572
		$reload = true;
1573
	}
1574

    
1575
	foreach ($iflist as $if => $ifname) {
1576
		$realif = $config['interfaces'][$if]['if'];
1577
		if (strstr($realif, "bridge")) {
1578
			$bridge_list[$if] = $ifname;
1579
		} else if (strstr($realif, "gre")) {
1580
			$delayed_list[$if] = $ifname;
1581
		} else if (strstr($realif, "gif")) {
1582
			$delayed_list[$if] = $ifname;
1583
		} else if (strstr($realif, "ovpn")) {
1584
			//echo "Delaying OpenVPN interface configuration...done.\n";
1585
			continue;
1586
		} else if (strstr($realif, "ipsec")) {
1587
			continue;
1588
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1589
			$track6_list[$if] = $ifname;
1590
		} else {
1591
			if (platform_booting()) {
1592
				printf(gettext("Configuring %s interface..."), $ifname);
1593
			}
1594

    
1595
			if ($g['debug']) {
1596
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1597
			}
1598
			interface_configure($if, $reload);
1599
			if (platform_booting()) {
1600
				echo gettext("done.") . "\n";
1601
			}
1602
		}
1603
	}
1604

    
1605
	/*
1606
	 * NOTE: The following function parameter consists of
1607
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1608
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1609
	 */
1610

    
1611
	/* set up GRE virtual interfaces */
1612
	interfaces_gre_configure(1);
1613

    
1614
	/* set up GIF virtual interfaces */
1615
	interfaces_gif_configure(1);
1616

    
1617
	/* set up BRIDGe virtual interfaces */
1618
	interfaces_bridge_configure(1);
1619

    
1620
	foreach ($track6_list as $if => $ifname) {
1621
		if (platform_booting()) {
1622
			printf(gettext("Configuring %s interface..."), $ifname);
1623
		}
1624
		if ($g['debug']) {
1625
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1626
		}
1627

    
1628
		interface_configure($if, $reload);
1629

    
1630
		if (platform_booting()) {
1631
			echo gettext("done.") . "\n";
1632
		}
1633
	}
1634

    
1635
	/* bring up vip interfaces */
1636
	interfaces_vips_configure();
1637

    
1638
	/* set up GRE virtual interfaces */
1639
	interfaces_gre_configure(2);
1640

    
1641
	/* set up GIF virtual interfaces */
1642
	interfaces_gif_configure(2);
1643

    
1644
	foreach ($delayed_list as $if => $ifname) {
1645
		if (platform_booting()) {
1646
			printf(gettext("Configuring %s interface..."), $ifname);
1647
		}
1648
		if ($g['debug']) {
1649
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1650
		}
1651

    
1652
		interface_configure($if, $reload);
1653

    
1654
		if (platform_booting()) {
1655
			echo gettext("done.") . "\n";
1656
		}
1657
	}
1658

    
1659
	/* set up BRIDGe virtual interfaces */
1660
	interfaces_bridge_configure(2);
1661

    
1662
	foreach ($bridge_list as $if => $ifname) {
1663
		if (platform_booting()) {
1664
			printf(gettext("Configuring %s interface..."), $ifname);
1665
		}
1666
		if ($g['debug']) {
1667
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1668
		}
1669

    
1670
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1671
		// redmine #3997
1672
		interface_reconfigure($if, $reload);
1673
		interfaces_vips_configure($if);
1674

    
1675
		if (platform_booting()) {
1676
			echo gettext("done.") . "\n";
1677
		}
1678
	}
1679

    
1680
	/* configure interface groups */
1681
	interfaces_group_setup();
1682

    
1683
	if (!platform_booting()) {
1684
		/* reconfigure static routes (kernel may have deleted them) */
1685
		system_routing_configure();
1686

    
1687
		/* reload IPsec tunnels */
1688
		ipsec_configure();
1689

    
1690
		/* restart dns servers (defering dhcpd reload) */
1691
		if (isset($config['dnsmasq']['enable'])) {
1692
			services_dnsmasq_configure(false);
1693
		}
1694
		if (isset($config['unbound']['enable'])) {
1695
			services_unbound_configure(false);
1696
		}
1697

    
1698
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1699
		services_dhcpd_configure();
1700
	}
1701

    
1702
	return 0;
1703
}
1704

    
1705
function interface_reconfigure($interface = "wan", $reloadall = false) {
1706
	interface_bring_down($interface);
1707
	interface_configure($interface, $reloadall);
1708
}
1709

    
1710
function interface_vip_bring_down($vip) {
1711
	global $g;
1712

    
1713
	$vipif = get_real_interface($vip['interface']);
1714
	switch ($vip['mode']) {
1715
		case "proxyarp":
1716
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1717
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1718
			}
1719
			break;
1720
		case "ipalias":
1721
			if (does_interface_exist($vipif)) {
1722
				if (is_ipaddrv6($vip['subnet'])) {
1723
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1724
				} else {
1725
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1726
				}
1727
			}
1728
			break;
1729
		case "carp":
1730
			/* XXX: Is enough to delete ip address? */
1731
			if (does_interface_exist($vipif)) {
1732
				if (is_ipaddrv6($vip['subnet'])) {
1733
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1734
				} else {
1735
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1736
				}
1737
			}
1738
			break;
1739
	}
1740
}
1741

    
1742
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1743
	global $config, $g;
1744

    
1745
	if (!isset($config['interfaces'][$interface])) {
1746
		return;
1747
	}
1748

    
1749
	if ($g['debug']) {
1750
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1751
	}
1752

    
1753
	/*
1754
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1755
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1756
	 * Keep this in mind while doing changes here!
1757
	 */
1758
	if ($ifacecfg === false) {
1759
		$ifcfg = $config['interfaces'][$interface];
1760
		$ppps = $config['ppps']['ppp'];
1761
		$realif = get_real_interface($interface);
1762
		$realifv6 = get_real_interface($interface, "inet6", true);
1763
	} elseif (!is_array($ifacecfg)) {
1764
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1765
		$ifcfg = $config['interfaces'][$interface];
1766
		$ppps = $config['ppps']['ppp'];
1767
		$realif = get_real_interface($interface);
1768
		$realifv6 = get_real_interface($interface, "inet6", true);
1769
	} else {
1770
		$ifcfg = $ifacecfg['ifcfg'];
1771
		$ppps = $ifacecfg['ppps'];
1772
		if (isset($ifacecfg['ifcfg']['realif'])) {
1773
			$realif = $ifacecfg['ifcfg']['realif'];
1774
			/* XXX: Any better way? */
1775
			$realifv6 = $realif;
1776
		} else {
1777
			$realif = get_real_interface($interface);
1778
			$realifv6 = get_real_interface($interface, "inet6", true);
1779
		}
1780
	}
1781

    
1782
	switch ($ifcfg['ipaddr']) {
1783
		case "ppp":
1784
		case "pppoe":
1785
		case "pptp":
1786
		case "l2tp":
1787
			if (is_array($ppps) && count($ppps)) {
1788
				foreach ($ppps as $pppid => $ppp) {
1789
					if ($realif == $ppp['if']) {
1790
						if (isset($ppp['ondemand']) && !$destroy) {
1791
							send_event("interface reconfigure {$interface}");
1792
							break;
1793
						}
1794
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1795
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1796
							sleep(2);
1797
						}
1798
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1799
						break;
1800
					}
1801
				}
1802
			}
1803
			break;
1804
		case "dhcp":
1805
			kill_dhclient_process($realif);
1806
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1807
			if (does_interface_exist("$realif")) {
1808
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1809
				interface_vip_cleanup($interface, "inet4");
1810
				if ($destroy == true) {
1811
					pfSense_interface_flags($realif, -IFF_UP);
1812
				}
1813
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1814
			}
1815
			break;
1816
		default:
1817
			if (does_interface_exist("$realif")) {
1818
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1819
				interface_vip_cleanup($interface, "inet4");
1820
				if ($destroy == true) {
1821
					pfSense_interface_flags($realif, -IFF_UP);
1822
				}
1823
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1824
			}
1825
			break;
1826
	}
1827

    
1828
	$track6 = array();
1829
	switch ($ifcfg['ipaddrv6']) {
1830
		case "slaac":
1831
		case "dhcp6":
1832
			kill_dhcp6client_process($realif, $destroy, false);
1833
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1834
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1835
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1836
			if (does_interface_exist($realifv6)) {
1837
				$ip6 = find_interface_ipv6($realifv6);
1838
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1839
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1840
				}
1841
				interface_vip_cleanup($interface, "inet6");
1842
				if ($destroy == true) {
1843
					pfSense_interface_flags($realif, -IFF_UP);
1844
				}
1845
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1846
			}
1847
			$track6 = link_interface_to_track6($interface);
1848
			break;
1849
		case "6rd":
1850
		case "6to4":
1851
			$realif = "{$interface}_stf";
1852
			if (does_interface_exist("$realif")) {
1853
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1854
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1855
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1856
					$destroy = true;
1857
				} else {
1858
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1859
					$ip6 = get_interface_ipv6($interface);
1860
					if (is_ipaddrv6($ip6)) {
1861
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1862
					}
1863
				}
1864
				interface_vip_cleanup($interface, "inet6");
1865
				if ($destroy == true) {
1866
					pfSense_interface_flags($realif, -IFF_UP);
1867
				}
1868
			}
1869
			$track6 = link_interface_to_track6($interface);
1870
			break;
1871
		default:
1872
			if (does_interface_exist("$realif")) {
1873
				$ip6 = get_interface_ipv6($interface);
1874
				if (is_ipaddrv6($ip6)) {
1875
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1876
				}
1877
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1878
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1879
				}
1880
				interface_vip_cleanup($interface, "inet6");
1881
				if ($destroy == true) {
1882
					pfSense_interface_flags($realif, -IFF_UP);
1883
				}
1884
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1885
			}
1886
			$track6 = link_interface_to_track6($interface);
1887
			break;
1888
	}
1889

    
1890
	if (!empty($track6) && is_array($track6)) {
1891
		if (!function_exists('services_dhcpd_configure')) {
1892
			require_once('services.inc');
1893
		}
1894
		/* Bring down radvd and dhcp6 on these interfaces */
1895
		services_dhcpd_configure('inet6', $track6);
1896
	}
1897

    
1898
	$old_router = '';
1899
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1900
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1901
	}
1902

    
1903
	/* remove interface up file if it exists */
1904
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1905
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1906
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1907
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1908
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1909
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1910
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1911

    
1912
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1913
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1914
	if (is_array($ifcfg['wireless'])) {
1915
		kill_hostapd($realif);
1916
		mwexec(kill_wpasupplicant($realif));
1917
	}
1918

    
1919
	if ($destroy == true) {
1920
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^ipsec|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1921
			pfSense_interface_destroy($realif);
1922
		}
1923
	}
1924

    
1925
	return;
1926
}
1927

    
1928
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1929
	global $config;
1930
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1931
		unset($config["virtualip_carp_maintenancemode"]);
1932
		write_config("Leave CARP maintenance mode");
1933
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1934
		$config["virtualip_carp_maintenancemode"] = true;
1935
		write_config(gettext("Enter CARP maintenance mode"));
1936
	}
1937
	init_config_arr(array('virtualip', 'vip'));
1938
	$viparr = &$config['virtualip']['vip'];
1939

    
1940
	if (is_array($viparr)) {
1941
		foreach ($viparr as $vip) {
1942
			if ($vip['mode'] == "carp") {
1943
				interface_carp_configure($vip, true);
1944
			}
1945
		}
1946
	}
1947
}
1948

    
1949
function interface_wait_tentative($interface, $timeout = 10) {
1950
	if (!does_interface_exist($interface)) {
1951
		return false;
1952
	}
1953

    
1954
	$time = 0;
1955
	while ($time <= $timeout) {
1956
		$if = pfSense_get_interface_addresses($interface);
1957
		if (!isset($if['tentative'])) {
1958
			return true;
1959
		}
1960
		sleep(1);
1961
		$time++;
1962
	}
1963

    
1964
	return false;
1965
}
1966

    
1967
function interface_isppp_type($interface) {
1968
	global $config;
1969

    
1970
	if (!is_array($config['interfaces'][$interface])) {
1971
		return false;
1972
	}
1973

    
1974
	switch ($config['interfaces'][$interface]['ipaddr']) {
1975
		case 'pptp':
1976
		case 'l2tp':
1977
		case 'pppoe':
1978
		case 'ppp':
1979
			return true;
1980
			break;
1981
		default:
1982
			return false;
1983
			break;
1984
	}
1985
}
1986

    
1987
function interfaces_ptpid_used($ptpid) {
1988
	global $config;
1989

    
1990
	if (is_array($config['ppps']['ppp'])) {
1991
		foreach ($config['ppps']['ppp'] as & $settings) {
1992
			if ($ptpid == $settings['ptpid']) {
1993
				return true;
1994
			}
1995
		}
1996
	}
1997

    
1998
	return false;
1999
}
2000

    
2001
function interfaces_ptpid_next() {
2002

    
2003
	$ptpid = 0;
2004
	while (interfaces_ptpid_used($ptpid)) {
2005
		$ptpid++;
2006
	}
2007

    
2008
	return $ptpid;
2009
}
2010

    
2011
function getMPDCRONSettings($pppif) {
2012
	global $config;
2013

    
2014
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2015
	if (is_array($config['cron']['item'])) {
2016
		foreach ($config['cron']['item'] as $i => $item) {
2017
			if (stripos($item['command'], $cron_cmd_file) !== false) {
2018
				return array("ID" => $i, "ITEM" => $item);
2019
			}
2020
		}
2021
	}
2022

    
2023
	return NULL;
2024
}
2025

    
2026
function handle_pppoe_reset($post_array) {
2027
	global $config, $g;
2028

    
2029
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2030
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2031

    
2032
	if (!is_array($config['cron']['item'])) {
2033
		$config['cron']['item'] = array();
2034
	}
2035

    
2036
	$itemhash = getMPDCRONSettings($pppif);
2037

    
2038
	// reset cron items if necessary and return
2039
	if (empty($post_array['pppoe-reset-type'])) {
2040
		if (isset($itemhash)) {
2041
			unset($config['cron']['item'][$itemhash['ID']]);
2042
		}
2043
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2044
		return;
2045
	}
2046

    
2047
	if (empty($itemhash)) {
2048
		$itemhash = array();
2049
	}
2050
	$item = array();
2051
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2052
		$item['minute'] = $post_array['pppoe_resetminute'];
2053
		$item['hour'] = $post_array['pppoe_resethour'];
2054
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2055
			$date = explode("/", $post_array['pppoe_resetdate']);
2056
			$item['mday'] = $date[1];
2057
			$item['month'] = $date[0];
2058
		} else {
2059
			$item['mday'] = "*";
2060
			$item['month'] = "*";
2061
		}
2062
		$item['wday'] = "*";
2063
		$item['who'] = "root";
2064
		$item['command'] = $cron_cmd_file;
2065
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2066
		switch ($post_array['pppoe_pr_preset_val']) {
2067
			case "monthly":
2068
				$item['minute'] = "0";
2069
				$item['hour'] = "0";
2070
				$item['mday'] = "1";
2071
				$item['month'] = "*";
2072
				$item['wday'] = "*";
2073
				break;
2074
			case "weekly":
2075
				$item['minute'] = "0";
2076
				$item['hour'] = "0";
2077
				$item['mday'] = "*";
2078
				$item['month'] = "*";
2079
				$item['wday'] = "0";
2080
				break;
2081
			case "daily":
2082
				$item['minute'] = "0";
2083
				$item['hour'] = "0";
2084
				$item['mday'] = "*";
2085
				$item['month'] = "*";
2086
				$item['wday'] = "*";
2087
				break;
2088
			case "hourly":
2089
				$item['minute'] = "0";
2090
				$item['hour'] = "*";
2091
				$item['mday'] = "*";
2092
				$item['month'] = "*";
2093
				$item['wday'] = "*";
2094
				break;
2095
		} // end switch
2096
		$item['who'] = "root";
2097
		$item['command'] = $cron_cmd_file;
2098
	}
2099
	if (empty($item)) {
2100
		return;
2101
	}
2102
	if (isset($itemhash['ID'])) {
2103
		$config['cron']['item'][$itemhash['ID']] = $item;
2104
	} else {
2105
		$config['cron']['item'][] = $item;
2106
	}
2107
}
2108

    
2109
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2110
	global $config;
2111
	$ppp_list = array();
2112
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2113
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2114
			$ports = explode(",", $ppp['ports']);
2115
			foreach($ports as $port) {
2116
				foreach($triggerinterfaces as $vip) {
2117
					if ($port == "_vip{$vip['uniqid']}") {
2118
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2119
						$ppp_list[$if] = 1;
2120
					}
2121
				}
2122
			}
2123
		}
2124
	}
2125
	foreach($ppp_list as $pppif => $dummy) {
2126
		interface_ppps_configure($pppif);
2127
	}
2128
}
2129

    
2130
/*
2131
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2132
 * It writes the mpd config file to /var/etc every time the link is opened.
2133
 */
2134
function interface_ppps_configure($interface) {
2135
	global $config, $g;
2136

    
2137
	/* Return for unassigned interfaces. This is a minimum requirement. */
2138
	if (empty($config['interfaces'][$interface])) {
2139
		return 0;
2140
	}
2141
	$ifcfg = $config['interfaces'][$interface];
2142
	if (!isset($ifcfg['enable'])) {
2143
		return 0;
2144
	}
2145

    
2146
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2147
	if (!is_dir("/var/spool/lock")) {
2148
		mkdir("/var/spool/lock", 0777, true);
2149
	}
2150
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2151
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2152
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2153
	}
2154

    
2155
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2156
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2157
			if ($ifcfg['if'] == $ppp['if']) {
2158
				break;
2159
			}
2160
		}
2161
	}
2162
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2163
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2164
		return 0;
2165
	}
2166
	$pppif = $ifcfg['if'];
2167
	if ($ppp['type'] == "ppp") {
2168
		$type = "modem";
2169
	} else {
2170
		$type = $ppp['type'];
2171
	}
2172
	$upper_type = strtoupper($ppp['type']);
2173

    
2174
	$confports = explode(',', $ppp['ports']);
2175
	if ($type == "modem") {
2176
		$ports = $confports;
2177
	} else {
2178
		$ports = array();
2179
		foreach ($confports as $pid => $port) {
2180
			if (strstr($port, "_vip")) {
2181
				if (get_carp_interface_status($port) != "MASTER") {
2182
					continue;
2183
				}
2184
			}
2185
			$ports[$pid] = get_real_interface($port);
2186
			if (empty($ports[$pid])) {
2187
				return 0;
2188
			}
2189
		}
2190
	}
2191
	$localips = explode(',', $ppp['localip']);
2192
	$gateways = explode(',', $ppp['gateway']);
2193
	$subnets = explode(',', $ppp['subnet']);
2194

    
2195
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2196
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2197
	 */
2198
	foreach ($ports as $pid => $port) {
2199
		switch ($ppp['type']) {
2200
			case "pppoe":
2201
				/* Bring the parent interface up */
2202
				interfaces_bring_up($port);
2203
				pfSense_ngctl_attach(".", $port);
2204
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2205
				$ngif = str_replace(".", "_", $port);
2206
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2207
				break;
2208
			case "pptp":
2209
			case "l2tp":
2210
				/* configure interface */
2211
				if (is_ipaddr($localips[$pid])) {
2212
					// Manually configure interface IP/subnet
2213
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2214
					interfaces_bring_up($port);
2215
				} else if (empty($localips[$pid])) {
2216
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2217
				}
2218

    
2219
				if (!is_ipaddr($localips[$pid])) {
2220
					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));
2221
					$localips[$pid] = "0.0.0.0";
2222
				}
2223
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2224
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2225
				}
2226
				if (!is_ipaddr($gateways[$pid])) {
2227
					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));
2228
					return 0;
2229
				}
2230
				pfSense_ngctl_attach(".", $port);
2231
				break;
2232
			case "ppp":
2233
				if (!file_exists("{$port}")) {
2234
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2235
					return 0;
2236
				}
2237
				break;
2238
			default:
2239
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2240
				break;
2241
		}
2242
	}
2243

    
2244
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2245
	    (is_array($ports) && count($ports) > 1)) {
2246
		$multilink = "enable";
2247
	} else {
2248
		$multilink = "disable";
2249
	}
2250

    
2251
	if ($type == "modem") {
2252
		if (is_ipaddr($ppp['localip'])) {
2253
			$localip = $ppp['localip'];
2254
		} else {
2255
			$localip = '0.0.0.0';
2256
		}
2257

    
2258
		if (is_ipaddr($ppp['gateway'])) {
2259
			$gateway = $ppp['gateway'];
2260
		} else {
2261
			$gateway = "10.64.64.{$pppid}";
2262
		}
2263
		$ranges = "{$localip}/0 {$gateway}/0";
2264

    
2265
		if (empty($ppp['apnum'])) {
2266
			$ppp['apnum'] = 1;
2267
		}
2268
	} else {
2269
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2270
	}
2271

    
2272
	if (isset($ppp['ondemand'])) {
2273
		$ondemand = "enable";
2274
	} else {
2275
		$ondemand = "disable";
2276
	}
2277
	if (!isset($ppp['idletimeout'])) {
2278
		$ppp['idletimeout'] = 0;
2279
	}
2280

    
2281
	if (empty($ppp['username']) && $type == "modem") {
2282
		$ppp['username'] = "user";
2283
		$ppp['password'] = "none";
2284
	}
2285
	if (empty($ppp['password']) && $type == "modem") {
2286
		$passwd = "none";
2287
	} else {
2288
		$passwd = base64_decode($ppp['password']);
2289
	}
2290

    
2291
	$bandwidths = explode(',', $ppp['bandwidth']);
2292
	$defaultmtu = "1492";
2293
	if (!empty($ifcfg['mtu'])) {
2294
		$defaultmtu = intval($ifcfg['mtu']);
2295
	}
2296
	if (isset($ppp['mtu'])) {
2297
		$mtus = explode(',', $ppp['mtu']);
2298
	}
2299
	if (isset($ppp['mru'])) {
2300
		$mrus = explode(',', $ppp['mru']);
2301
	}
2302
	if (isset($ppp['mrru'])) {
2303
		$mrrus = explode(',', $ppp['mrru']);
2304
	}
2305
	if (!empty($ifcfg['ipaddrv6'])) {
2306
		$ipv6cp = "set bundle enable ipv6cp";
2307
	}
2308

    
2309
	// Construct the mpd.conf file
2310
	$mpdconf = <<<EOD
2311
startup:
2312
	# configure the console
2313
	set console close
2314
	# configure the web server
2315
	set web close
2316

    
2317
default:
2318
{$ppp['type']}client:
2319
	create bundle static {$interface}
2320
	{$ipv6cp}
2321
	set iface name {$pppif}
2322

    
2323
EOD;
2324
	$setdefaultgw = false;
2325
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2326
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2327
	if ($defgw4['interface'] == $interface) {
2328
		$setdefaultgw = true;
2329
	}
2330

    
2331
/* Omit this, we maintain the default route by other means, and it causes problems with
2332
 * default gateway switching. See redmine #1837 for original issue
2333
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2334
 * edge case. redmine #6495 open to address.
2335
 */
2336
	if ($setdefaultgw == true) {
2337
		$mpdconf .= <<<EOD
2338
	set iface route default
2339

    
2340
EOD;
2341
	}
2342

    
2343
	$mpdconf .= <<<EOD
2344
	set iface {$ondemand} on-demand
2345
	set iface idle {$ppp['idletimeout']}
2346

    
2347
EOD;
2348

    
2349
	if (isset($ppp['ondemand'])) {
2350
		$mpdconf .= <<<EOD
2351
	set iface addrs 10.10.1.1 10.10.1.2
2352

    
2353
EOD;
2354
	}
2355

    
2356
	if (isset($ppp['mtu-override']) &&
2357
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2358
		/* Find the smaller MTU set on ports */
2359
		$mtu = $defaultmtu;
2360
		foreach ($ports as $pid => $port) {
2361
			if (empty($mtus[$pid])) {
2362
				$mtus[$pid] = $defaultmtu;
2363
			}
2364
			if ($type == "pppoe") {
2365
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2366
					$mtus[$pid] = get_interface_mtu($port) - 8;
2367
				}
2368
			}
2369
			if ($mtu > $mtus[$pid]) {
2370
				$mtu = $mtus[$pid];
2371
			}
2372
		}
2373
		$mpdconf .= <<<EOD
2374
	set iface mtu {$mtu} override
2375

    
2376
EOD;
2377
	}
2378

    
2379
	if (isset($ppp['tcpmssfix'])) {
2380
		$tcpmss = "disable";
2381
	} else {
2382
		$tcpmss = "enable";
2383
	}
2384
	$mpdconf .= <<<EOD
2385
	set iface {$tcpmss} tcpmssfix
2386

    
2387
EOD;
2388

    
2389
	$mpdconf .= <<<EOD
2390
	set iface up-script /usr/local/sbin/ppp-linkup
2391
	set iface down-script /usr/local/sbin/ppp-linkdown
2392
	set ipcp ranges {$ranges}
2393

    
2394
EOD;
2395
	if (isset($ppp['vjcomp'])) {
2396
		$mpdconf .= <<<EOD
2397
	set ipcp no vjcomp
2398

    
2399
EOD;
2400
	}
2401

    
2402
	if (isset($config['system']['dnsallowoverride'])) {
2403
		$mpdconf .= <<<EOD
2404
	set ipcp enable req-pri-dns
2405
	set ipcp enable req-sec-dns
2406

    
2407
EOD;
2408
	}
2409

    
2410
	if (!isset($ppp['verbose_log'])) {
2411
		$mpdconf .= <<<EOD
2412
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2413

    
2414
EOD;
2415
	}
2416

    
2417
	foreach ($ports as $pid => $port) {
2418
		$port = get_real_interface($port);
2419
		$mpdconf .= <<<EOD
2420

    
2421
	create link static {$interface}_link{$pid} {$type}
2422
	set link action bundle {$interface}
2423
	set link {$multilink} multilink
2424
	set link keep-alive 10 60
2425
	set link max-redial 0
2426

    
2427
EOD;
2428
		if (isset($ppp['shortseq'])) {
2429
			$mpdconf .= <<<EOD
2430
	set link no shortseq
2431

    
2432
EOD;
2433
		}
2434

    
2435
		if (isset($ppp['acfcomp'])) {
2436
			$mpdconf .= <<<EOD
2437
	set link no acfcomp
2438

    
2439
EOD;
2440
		}
2441

    
2442
		if (isset($ppp['protocomp'])) {
2443
			$mpdconf .= <<<EOD
2444
	set link no protocomp
2445

    
2446
EOD;
2447
		}
2448

    
2449
		$mpdconf .= <<<EOD
2450
	set link disable chap pap
2451
	set link accept chap pap eap
2452
	set link disable incoming
2453

    
2454
EOD;
2455

    
2456

    
2457
		if (!empty($bandwidths[$pid])) {
2458
			$mpdconf .= <<<EOD
2459
	set link bandwidth {$bandwidths[$pid]}
2460

    
2461
EOD;
2462
		}
2463

    
2464
		if (empty($mtus[$pid])) {
2465
			$mtus[$pid] = $defaultmtu;
2466
		}
2467
		if ($type == "pppoe") {
2468
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2469
				$mtus[$pid] = get_interface_mtu($port) - 8;
2470
			}
2471
		}
2472
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2473
		    !isset($ppp['mtu-override']) &&
2474
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2475
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2476
			$mpdconf .= <<<EOD
2477
	set link mtu {$mtus[$pid]}
2478

    
2479
EOD;
2480
		}
2481

    
2482
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2483
		    !isset($ppp['mtu-override']) &&
2484
		    !empty($mrus[$pid])) {
2485
			$mpdconf .= <<<EOD
2486
	set link mru {$mrus[$pid]}
2487

    
2488
EOD;
2489
		}
2490

    
2491
		if (!empty($mrrus[$pid])) {
2492
			$mpdconf .= <<<EOD
2493
	set link mrru {$mrrus[$pid]}
2494

    
2495
EOD;
2496
		}
2497

    
2498
		$mpdconf .= <<<EOD
2499
	set auth authname "{$ppp['username']}"
2500
	set auth password {$passwd}
2501

    
2502
EOD;
2503
		if ($type == "modem") {
2504
			$mpdconf .= <<<EOD
2505
	set modem device {$ppp['ports']}
2506
	set modem script DialPeer
2507
	set modem idle-script Ringback
2508
	set modem watch -cd
2509
	set modem var \$DialPrefix "DT"
2510
	set modem var \$Telephone "{$ppp['phone']}"
2511

    
2512
EOD;
2513
		}
2514
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2515
			$mpdconf .= <<<EOD
2516
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2517

    
2518
EOD;
2519
		}
2520
		if (isset($ppp['initstr']) && $type == "modem") {
2521
			$initstr = base64_decode($ppp['initstr']);
2522
			$mpdconf .= <<<EOD
2523
	set modem var \$InitString "{$initstr}"
2524

    
2525
EOD;
2526
		}
2527
		if (isset($ppp['simpin']) && $type == "modem") {
2528
			if ($ppp['pin-wait'] == "") {
2529
				$ppp['pin-wait'] = 0;
2530
			}
2531
			$mpdconf .= <<<EOD
2532
	set modem var \$SimPin "{$ppp['simpin']}"
2533
	set modem var \$PinWait "{$ppp['pin-wait']}"
2534

    
2535
EOD;
2536
		}
2537
		if (isset($ppp['apn']) && $type == "modem") {
2538
			$mpdconf .= <<<EOD
2539
	set modem var \$APN "{$ppp['apn']}"
2540
	set modem var \$APNum "{$ppp['apnum']}"
2541

    
2542
EOD;
2543
		}
2544
		if ($type == "pppoe") {
2545
			// Send a null service name if none is set.
2546
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2547
			$mpdconf .= <<<EOD
2548
	set pppoe service "{$provider}"
2549

    
2550
EOD;
2551
		}
2552
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
2553
			$mpdconf .= <<<EOD
2554
	set pppoe max-payload {$mtus[$pid]}
2555

    
2556
EOD;
2557
		}
2558
		if ($type == "pppoe") {
2559
			$mpdconf .= <<<EOD
2560
	set pppoe iface {$port}
2561

    
2562
EOD;
2563
		}
2564

    
2565
		if ($type == "pptp" || $type == "l2tp") {
2566
			$mpdconf .= <<<EOD
2567
	set {$type} self {$localips[$pid]}
2568
	set {$type} peer {$gateways[$pid]}
2569

    
2570
EOD;
2571
		}
2572

    
2573
		$mpdconf .= "\topen\n";
2574
	} //end foreach ($port)
2575

    
2576

    
2577
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2578
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2579
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2580
	} else {
2581
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2582
		if (!$fd) {
2583
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2584
			return 0;
2585
		}
2586
		// Write out mpd_ppp.conf
2587
		fwrite($fd, $mpdconf);
2588
		fclose($fd);
2589
		unset($mpdconf);
2590
	}
2591

    
2592
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2593
	if (isset($ppp['uptime'])) {
2594
		if (!file_exists("/conf/{$pppif}.log")) {
2595
			file_put_contents("/conf/{$pppif}.log", '');
2596
		}
2597
	} else {
2598
		if (file_exists("/conf/{$pppif}.log")) {
2599
			@unlink("/conf/{$pppif}.log");
2600
		}
2601
	}
2602

    
2603
	/* clean up old lock files */
2604
	foreach ($ports as $port) {
2605
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2606
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2607
		}
2608
	}
2609

    
2610
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2611
	/* random IPv6 interface identifier during boot. More details at */
2612
	/* https://forum.netgate.com/post/592474 */
2613
	if (platform_booting() && is_array($config['interfaces'])) {
2614
		$count = 0;
2615
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2616
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2617
				$tempaddr[$count]['if'] = $tempiface['if'];
2618
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2619
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2620
				$count++;
2621
			}
2622
			// Maximum /31 is is x.y.z.254/31
2623
			if ($count > 122) {
2624
				break;
2625
			}
2626
		}
2627
		unset($count);
2628
	}
2629

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

    
2635
	// Check for PPPoE periodic reset request
2636
	if ($type == "pppoe") {
2637
		if (!empty($ppp['pppoe-reset-type'])) {
2638
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2639
		} else {
2640
			interface_setup_pppoe_reset_file($ppp['if']);
2641
		}
2642
	}
2643
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2644
	$i = 0;
2645
	while ($i < 10) {
2646
		if (does_interface_exist($ppp['if'], true)) {
2647
			break;
2648
		}
2649
		sleep(3);
2650
		$i++;
2651
	}
2652

    
2653
	/* Remove all temporary bogon IPv4 addresses */
2654
	if (is_array($tempaddr)) {
2655
		foreach ($tempaddr as $tempiface) {
2656
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2657
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2658
			}
2659
		}
2660
		unset ($tempaddr);
2661
	}
2662

    
2663
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2664
	/* We should be able to launch the right version for each modem */
2665
	/* We can also guess the mondev from the manufacturer */
2666
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2667
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2668
	foreach ($ports as $port) {
2669
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2670
			$mondev = substr(basename($port), 0, -1);
2671
			$devlist = glob("/dev/{$mondev}?");
2672
			$mondev = basename(end($devlist));
2673
		}
2674
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2675
			$mondev = substr(basename($port), 0, -1) . "1";
2676
		}
2677
		if ($mondev != '') {
2678
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2679
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2680
		}
2681
	}
2682

    
2683
	return 1;
2684
}
2685

    
2686
function interfaces_sync_setup() {
2687
	global $g, $config;
2688

    
2689
	if (isset($config['system']['developerspew'])) {
2690
		$mt = microtime();
2691
		echo "interfaces_sync_setup() being called $mt\n";
2692
	}
2693

    
2694
	if (platform_booting()) {
2695
		echo gettext("Configuring CARP settings...");
2696
		mute_kernel_msgs();
2697
	}
2698

    
2699
	/* suck in configuration items */
2700
	if ($config['hasync']) {
2701
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2702
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2703
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2704
	} else {
2705
		unset($pfsyncinterface);
2706
		unset($pfsyncenabled);
2707
	}
2708

    
2709
	set_sysctl(array(
2710
		"net.inet.carp.preempt" => "1",
2711
		"net.inet.carp.log" => "1")
2712
	);
2713

    
2714
	if (!empty($pfsyncinterface)) {
2715
		$carp_sync_int = get_real_interface($pfsyncinterface);
2716
	} else {
2717
		unset($carp_sync_int);
2718
	}
2719

    
2720
	/* setup pfsync interface */
2721
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2722
		if (is_ipaddr($pfsyncpeerip)) {
2723
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2724
		} else {
2725
			$syncpeer = "-syncpeer";
2726
		}
2727

    
2728
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2729
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2730

    
2731
		sleep(1);
2732

    
2733
		/* 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
2734
		 * for existing sessions.
2735
		 */
2736
		log_error(gettext("waiting for pfsync..."));
2737
		$i = 0;
2738
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2739
			$i++;
2740
			sleep(1);
2741
		}
2742
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2743
		log_error(gettext("Configuring CARP settings finalize..."));
2744
	} else {
2745
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2746
	}
2747

    
2748
	$carplist = get_configured_vip_list('all', VIP_CARP);
2749
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2750
		set_single_sysctl("net.inet.carp.allow", "1");
2751
	} else {
2752
		set_single_sysctl("net.inet.carp.allow", "0");
2753
	}
2754

    
2755
	if (platform_booting()) {
2756
		unmute_kernel_msgs();
2757
		echo gettext("done.") . "\n";
2758
	}
2759
}
2760

    
2761
function interface_proxyarp_configure($interface = "") {
2762
	global $config, $g;
2763
	if (isset($config['system']['developerspew'])) {
2764
		$mt = microtime();
2765
		echo "interface_proxyarp_configure() being called $mt\n";
2766
	}
2767

    
2768
	/* kill any running choparp */
2769
	if (empty($interface)) {
2770
		killbyname("choparp");
2771
	} else {
2772
		$vipif = get_real_interface($interface);
2773
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2774
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2775
		}
2776
	}
2777

    
2778
	$paa = array();
2779
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2780

    
2781
		/* group by interface */
2782
		foreach ($config['virtualip']['vip'] as $vipent) {
2783
			if ($vipent['mode'] === "proxyarp") {
2784
				if ($vipent['interface']) {
2785
					$proxyif = $vipent['interface'];
2786
				} else {
2787
					$proxyif = "wan";
2788
				}
2789

    
2790
				if (!empty($interface) && $interface != $proxyif) {
2791
					continue;
2792
				}
2793

    
2794
				if (!is_array($paa[$proxyif])) {
2795
					$paa[$proxyif] = array();
2796
				}
2797

    
2798
				$paa[$proxyif][] = $vipent;
2799
			}
2800
		}
2801
	}
2802

    
2803
	if (!empty($interface)) {
2804
		if (is_array($paa[$interface])) {
2805
			$paaifip = get_interface_ip($interface);
2806
			if (!is_ipaddr($paaifip)) {
2807
				return;
2808
			}
2809
			$vipif = get_real_interface($interface);
2810
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2811
			$args .= $vipif . " auto";
2812
			foreach ($paa[$interface] as $paent) {
2813
				if (isset($paent['subnet'])) {
2814
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2815
				} else if (isset($paent['range'])) {
2816
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2817
				}
2818
			}
2819
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2820
		}
2821
	} else if (count($paa) > 0) {
2822
		foreach ($paa as $paif => $paents) {
2823
			$paaifip = get_interface_ip($paif);
2824
			if (!is_ipaddr($paaifip)) {
2825
				continue;
2826
			}
2827
			$vipif = get_real_interface($paif);
2828
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2829
			$args .= $vipif . " auto";
2830
			foreach ($paents as $paent) {
2831
				if (isset($paent['subnet'])) {
2832
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2833
				} else if (isset($paent['range'])) {
2834
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2835
				}
2836
			}
2837
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2838
		}
2839
	}
2840
}
2841

    
2842
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2843
	global $g, $config;
2844

    
2845
	if (is_array($config['virtualip']['vip'])) {
2846
		foreach ($config['virtualip']['vip'] as $vip) {
2847

    
2848
			$iface = $vip['interface'];
2849
			if (substr($iface, 0, 4) == "_vip")
2850
				$iface = get_configured_vip_interface($vip['interface']);
2851
			if ($iface != $interface)
2852
				continue;
2853
			if ($type == VIP_CARP) {
2854
				if ($vip['mode'] != "carp")
2855
					continue;
2856
			} elseif ($type == VIP_IPALIAS) {
2857
				if ($vip['mode'] != "ipalias")
2858
					continue;
2859
			} else {
2860
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2861
					continue;
2862
			}
2863

    
2864
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2865
				interface_vip_bring_down($vip);
2866
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2867
				interface_vip_bring_down($vip);
2868
			else if ($inet == "all")
2869
				interface_vip_bring_down($vip);
2870
		}
2871
	}
2872
}
2873

    
2874
function interfaces_vips_configure($interface = "") {
2875
	global $g, $config;
2876
	if (isset($config['system']['developerspew'])) {
2877
		$mt = microtime();
2878
		echo "interfaces_vips_configure() being called $mt\n";
2879
	}
2880
	$paa = array();
2881
	if (is_array($config['virtualip']['vip'])) {
2882
		$carp_setuped = false;
2883
		$anyproxyarp = false;
2884
		foreach ($config['virtualip']['vip'] as $vip) {
2885
			if ($interface <> "" && get_root_interface($vip['interface']) <> $interface) {
2886
				continue;
2887
			}
2888
			switch ($vip['mode']) {
2889
				case "proxyarp":
2890
					/* nothing it is handled on interface_proxyarp_configure() */
2891
					$anyproxyarp = true;
2892
					break;
2893
				case "ipalias":
2894
					interface_ipalias_configure($vip);
2895
					break;
2896
				case "carp":
2897
					if ($carp_setuped == false) {
2898
						$carp_setuped = true;
2899
					}
2900
					interface_carp_configure($vip);
2901
					break;
2902
			}
2903
		}
2904
		if ($carp_setuped == true) {
2905
			interfaces_sync_setup();
2906
		}
2907
		if ($anyproxyarp == true) {
2908
			interface_proxyarp_configure();
2909
		}
2910
	}
2911
}
2912

    
2913
function interface_ipalias_configure(&$vip) {
2914
	global $config;
2915

    
2916
	if ($vip['mode'] != 'ipalias') {
2917
		return;
2918
	}
2919

    
2920
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2921
	if ($realif != "lo0") {
2922
		$if = convert_real_interface_to_friendly_interface_name($realif);
2923
		if (!isset($config['interfaces'][$if]) ||
2924
		    !isset($config['interfaces'][$if]['enable'])) {
2925
			return;
2926
		}
2927
	}
2928

    
2929
	$af = 'inet';
2930
	if (is_ipaddrv6($vip['subnet'])) {
2931
		$af = 'inet6';
2932
	}
2933
	$iface = $vip['interface'];
2934
	$vhid = '';
2935
	if (substr($vip['interface'], 0, 4) == "_vip") {
2936
		$carpvip = get_configured_vip($vip['interface']);
2937
		$iface = $carpvip['interface'];
2938
		$vhid = "vhid {$carpvip['vhid']}";
2939
	}
2940
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2941
	unset($iface, $af, $realif, $carpvip, $vhid);
2942
}
2943

    
2944
function interface_carp_configure(&$vip, $maintenancemode_only = false) {
2945
	global $config, $g;
2946
	if (isset($config['system']['developerspew'])) {
2947
		$mt = microtime();
2948
		echo "interface_carp_configure() being called $mt\n";
2949
	}
2950

    
2951
	if ($vip['mode'] != "carp") {
2952
		return;
2953
	}
2954

    
2955
	$realif = get_real_interface($vip['interface']);
2956
	if (!does_interface_exist($realif)) {
2957
		file_notice("CARP", sprintf(gettext(
2958
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
2959
		    $vip['subnet']), "Firewall: Virtual IP", "");
2960
		return;
2961
	}
2962
	if ($realif != "lo0") {
2963
		if (!isset($config['interfaces'][$vip['interface']]) ||
2964
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
2965
			return;
2966
		}
2967
	}
2968

    
2969
	$vip_password = $vip['password'];
2970
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
2971
	    $vip_password)));
2972
	if ($vip['password'] != "") {
2973
		$password = " pass {$vip_password}";
2974
	}
2975

    
2976
	$advbase = "";
2977
	if (!empty($vip['advbase'])) {
2978
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2979
	}
2980

    
2981
	$carp_maintenancemode = isset(
2982
	    $config["virtualip_carp_maintenancemode"]);
2983
	if ($carp_maintenancemode) {
2984
		$advskew = "advskew 254";
2985
	} else {
2986
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2987
	}
2988

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

    
2992
	if (!$maintenancemode_only) {
2993
		if (is_ipaddrv4($vip['subnet'])) {
2994
			mwexec("/sbin/ifconfig {$realif} " .
2995
			    escapeshellarg($vip['subnet']) . "/" .
2996
			    escapeshellarg($vip['subnet_bits']) .
2997
			    " alias vhid " . escapeshellarg($vip['vhid']));
2998
		} else if (is_ipaddrv6($vip['subnet'])) {
2999
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3000
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3001
			    escapeshellarg($vip['subnet_bits']) .
3002
			    " alias vhid " . escapeshellarg($vip['vhid']));
3003
		}
3004
	}
3005

    
3006
	return $realif;
3007
}
3008

    
3009
function interface_wireless_clone($realif, $wlcfg) {
3010
	global $config, $g;
3011
	/*   Check to see if interface has been cloned as of yet.
3012
	 *   If it has not been cloned then go ahead and clone it.
3013
	 */
3014
	$needs_clone = false;
3015
	if (is_array($wlcfg['wireless'])) {
3016
		$wlcfg_mode = $wlcfg['wireless']['mode'];
3017
	} else {
3018
		$wlcfg_mode = $wlcfg['mode'];
3019
	}
3020
	switch ($wlcfg_mode) {
3021
		case "hostap":
3022
			$mode = "wlanmode hostap";
3023
			break;
3024
		case "adhoc":
3025
			$mode = "wlanmode adhoc";
3026
			break;
3027
		default:
3028
			$mode = "";
3029
			break;
3030
	}
3031
	$baseif = interface_get_wireless_base($wlcfg['if']);
3032
	if (does_interface_exist($realif)) {
3033
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
3034
		$ifconfig_str = implode($output);
3035
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
3036
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
3037
			$needs_clone = true;
3038
		}
3039
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
3040
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
3041
			$needs_clone = true;
3042
		}
3043
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3044
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3045
			$needs_clone = true;
3046
		}
3047
	} else {
3048
		$needs_clone = true;
3049
	}
3050

    
3051
	if ($needs_clone == true) {
3052
		/* remove previous instance if it exists */
3053
		if (does_interface_exist($realif)) {
3054
			pfSense_interface_destroy($realif);
3055
		}
3056

    
3057
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3058
		// Create the new wlan interface. FreeBSD returns the new interface name.
3059
		// example:  wlan2
3060
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3061
		if ($ret <> 0) {
3062
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3063
			return false;
3064
		}
3065
		$newif = trim($out[0]);
3066
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3067
		pfSense_interface_rename($newif, $realif);
3068
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3069
	}
3070
	return true;
3071
}
3072

    
3073
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3074
	global $config, $g;
3075

    
3076
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3077
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3078
				 'regdomain', 'regcountry', 'reglocation');
3079

    
3080
	if (!is_interface_wireless($ifcfg['if'])) {
3081
		return;
3082
	}
3083

    
3084
	$baseif = interface_get_wireless_base($ifcfg['if']);
3085

    
3086
	// Sync shared settings for assigned clones
3087
	$iflist = get_configured_interface_list(true);
3088
	foreach ($iflist as $if) {
3089
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
3090
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
3091
				foreach ($shared_settings as $setting) {
3092
					if ($sync_changes) {
3093
						if (isset($ifcfg['wireless'][$setting])) {
3094
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
3095
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3096
							unset($config['interfaces'][$if]['wireless'][$setting]);
3097
						}
3098
					} else {
3099
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3100
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
3101
						} else if (isset($ifcfg['wireless'][$setting])) {
3102
							unset($ifcfg['wireless'][$setting]);
3103
						}
3104
					}
3105
				}
3106
				if (!$sync_changes) {
3107
					break;
3108
				}
3109
			}
3110
		}
3111
	}
3112

    
3113
	// Read or write settings at shared area
3114
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3115
		foreach ($shared_settings as $setting) {
3116
			if ($sync_changes) {
3117
				if (isset($ifcfg['wireless'][$setting])) {
3118
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3119
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3120
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3121
				}
3122
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3123
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3124
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3125
				} else if (isset($ifcfg['wireless'][$setting])) {
3126
					unset($ifcfg['wireless'][$setting]);
3127
				}
3128
			}
3129
		}
3130
	}
3131

    
3132
	// Sync the mode on the clone creation page with the configured mode on the interface
3133
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3134
		foreach ($config['wireless']['clone'] as &$clone) {
3135
			if ($clone['cloneif'] == $ifcfg['if']) {
3136
				if ($sync_changes) {
3137
					$clone['mode'] = $ifcfg['wireless']['mode'];
3138
				} else {
3139
					$ifcfg['wireless']['mode'] = $clone['mode'];
3140
				}
3141
				break;
3142
			}
3143
		}
3144
		unset($clone);
3145
	}
3146
}
3147

    
3148
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3149
	global $config, $g;
3150

    
3151
	/*    open up a shell script that will be used to output the commands.
3152
	 *    since wireless is changing a lot, these series of commands are fragile
3153
	 *    and will sometimes need to be verified by a operator by executing the command
3154
	 *    and returning the output of the command to the developers for inspection.  please
3155
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3156
	 */
3157

    
3158
	// Remove script file
3159
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3160

    
3161
	// Clone wireless nic if needed.
3162
	interface_wireless_clone($if, $wl);
3163

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

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

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

    
3173
	/* set values for /path/program */
3174
	if (file_exists("/usr/local/sbin/hostapd")) {
3175
		$hostapd = "/usr/local/sbin/hostapd";
3176
	} else {
3177
		$hostapd = "/usr/sbin/hostapd";
3178
	}
3179
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3180
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3181
	} else {
3182
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3183
	}
3184
	$ifconfig = "/sbin/ifconfig";
3185
	$sysctl = "/sbin/sysctl";
3186
	$sysctl_args = "-q";
3187
	$killall = "/usr/bin/killall";
3188

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

    
3191
	$wlcmd = array();
3192
	$wl_sysctl = array();
3193
	/* Set a/b/g standard */
3194
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3195
	/* skip mode entirely for "auto" */
3196
	if ($wlcfg['standard'] != "auto") {
3197
		$wlcmd[] = "mode " . escapeshellarg($standard);
3198
	}
3199

    
3200
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3201
	 * to prevent massive packet loss under certain conditions. */
3202
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3203
		$wlcmd[] = "-ampdu";
3204
	}
3205

    
3206
	/* Set ssid */
3207
	if ($wlcfg['ssid']) {
3208
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3209
	}
3210

    
3211
	/* Set 802.11g protection mode */
3212
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3213

    
3214
	/* set wireless channel value */
3215
	if (isset($wlcfg['channel'])) {
3216
		if ($wlcfg['channel'] == "0") {
3217
			$wlcmd[] = "channel any";
3218
		} else {
3219
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
3220
		}
3221
	}
3222

    
3223
	/* Set antenna diversity value */
3224
	if (isset($wlcfg['diversity'])) {
3225
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3226
	}
3227

    
3228
	/* Set txantenna value */
3229
	if (isset($wlcfg['txantenna'])) {
3230
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3231
	}
3232

    
3233
	/* Set rxantenna value */
3234
	if (isset($wlcfg['rxantenna'])) {
3235
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3236
	}
3237

    
3238
	/* set Distance value */
3239
	if ($wlcfg['distance']) {
3240
		$distance = escapeshellarg($wlcfg['distance']);
3241
	}
3242

    
3243
	/* Set wireless hostap mode */
3244
	if ($wlcfg['mode'] == "hostap") {
3245
		$wlcmd[] = "mediaopt hostap";
3246
	} else {
3247
		$wlcmd[] = "-mediaopt hostap";
3248
	}
3249

    
3250
	/* Set wireless adhoc mode */
3251
	if ($wlcfg['mode'] == "adhoc") {
3252
		$wlcmd[] = "mediaopt adhoc";
3253
	} else {
3254
		$wlcmd[] = "-mediaopt adhoc";
3255
	}
3256

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

    
3259
	/* handle hide ssid option */
3260
	if (isset($wlcfg['hidessid']['enable'])) {
3261
		$wlcmd[] = "hidessid";
3262
	} else {
3263
		$wlcmd[] = "-hidessid";
3264
	}
3265

    
3266
	/* handle pureg (802.11g) only option */
3267
	if (isset($wlcfg['pureg']['enable'])) {
3268
		$wlcmd[] = "mode 11g pureg";
3269
	} else {
3270
		$wlcmd[] = "-pureg";
3271
	}
3272

    
3273
	/* handle puren (802.11n) only option */
3274
	if (isset($wlcfg['puren']['enable'])) {
3275
		$wlcmd[] = "puren";
3276
	} else {
3277
		$wlcmd[] = "-puren";
3278
	}
3279

    
3280
	/* enable apbridge option */
3281
	if (isset($wlcfg['apbridge']['enable'])) {
3282
		$wlcmd[] = "apbridge";
3283
	} else {
3284
		$wlcmd[] = "-apbridge";
3285
	}
3286

    
3287
	/* handle turbo option */
3288
	if (isset($wlcfg['turbo']['enable'])) {
3289
		$wlcmd[] = "mediaopt turbo";
3290
	} else {
3291
		$wlcmd[] = "-mediaopt turbo";
3292
	}
3293

    
3294
	/* handle txpower setting */
3295
	// or don't. this has issues at the moment.
3296
	/*
3297
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3298
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3299
	}*/
3300

    
3301
	/* handle wme option */
3302
	if (isset($wlcfg['wme']['enable'])) {
3303
		$wlcmd[] = "wme";
3304
	} else {
3305
		$wlcmd[] = "-wme";
3306
	}
3307

    
3308
	/* Enable wpa if it's configured. No WEP support anymore. */
3309
	if (isset($wlcfg['wpa']['enable'])) {
3310
		$wlcmd[] = "authmode wpa wepmode off ";
3311
	} else {
3312
		$wlcmd[] = "authmode open wepmode off ";
3313
	}
3314

    
3315
	kill_hostapd($if);
3316
	mwexec(kill_wpasupplicant("{$if}"));
3317

    
3318
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3319

    
3320
	switch ($wlcfg['mode']) {
3321
		case 'bss':
3322
			if (isset($wlcfg['wpa']['enable'])) {
3323
				$wpa .= <<<EOD
3324
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3325
ctrl_interface_group=0
3326
ap_scan=1
3327
#fast_reauth=1
3328
network={
3329
ssid="{$wlcfg['ssid']}"
3330
scan_ssid=1
3331
priority=5
3332
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3333
psk="{$wlcfg['wpa']['passphrase']}"
3334
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3335
group={$wlcfg['wpa']['wpa_pairwise']}
3336
}
3337
EOD;
3338

    
3339
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
3340
				unset($wpa);
3341
			}
3342
			break;
3343
		case 'hostap':
3344
			if (!empty($wlcfg['wpa']['passphrase'])) {
3345
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3346
			} else {
3347
				$wpa_passphrase = "";
3348
			}
3349
			if (isset($wlcfg['wpa']['enable'])) {
3350
				$wpa .= <<<EOD
3351
interface={$if}
3352
driver=bsd
3353
logger_syslog=-1
3354
logger_syslog_level=0
3355
logger_stdout=-1
3356
logger_stdout_level=0
3357
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3358
ctrl_interface={$g['varrun_path']}/hostapd
3359
ctrl_interface_group=wheel
3360
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3361
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3362
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3363
ssid={$wlcfg['ssid']}
3364
debug={$wlcfg['wpa']['debug_mode']}
3365
wpa={$wlcfg['wpa']['wpa_mode']}
3366
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3367
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3368
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3369
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3370
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3371
{$wpa_passphrase}
3372

    
3373
EOD;
3374

    
3375
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3376
					$wpa .= <<<EOD
3377
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3378
rsn_preauth=1
3379
rsn_preauth_interfaces={$if}
3380

    
3381
EOD;
3382
				}
3383
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3384
					$wpa .= "ieee8021x=1\n";
3385

    
3386
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3387
						$auth_server_port = "1812";
3388
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3389
							$auth_server_port = intval($wlcfg['auth_server_port']);
3390
						}
3391
						$wpa .= <<<EOD
3392

    
3393
auth_server_addr={$wlcfg['auth_server_addr']}
3394
auth_server_port={$auth_server_port}
3395
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3396

    
3397
EOD;
3398
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3399
							$auth_server_port2 = "1812";
3400
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3401
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3402
							}
3403

    
3404
							$wpa .= <<<EOD
3405
auth_server_addr={$wlcfg['auth_server_addr2']}
3406
auth_server_port={$auth_server_port2}
3407
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3408

    
3409
EOD;
3410
						}
3411
					}
3412
				}
3413

    
3414
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3415
				unset($wpa);
3416
			}
3417
			break;
3418
	}
3419

    
3420
	/*
3421
	 *    all variables are set, lets start up everything
3422
	 */
3423

    
3424
	$baseif = interface_get_wireless_base($if);
3425
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3426
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3427

    
3428
	/* set sysctls for the wireless interface */
3429
	if (!empty($wl_sysctl)) {
3430
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3431
		foreach ($wl_sysctl as $wl_sysctl_line) {
3432
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3433
		}
3434
	}
3435

    
3436
	/* set ack timers according to users preference (if he/she has any) */
3437
	if ($distance) {
3438
		fwrite($fd_set, "# Enable ATH distance settings\n");
3439
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3440
	}
3441

    
3442
	if (isset($wlcfg['wpa']['enable'])) {
3443
		if ($wlcfg['mode'] == "bss") {
3444
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3445
		}
3446
		if ($wlcfg['mode'] == "hostap") {
3447
			/* add line to script to restore old mac to make hostapd happy */
3448
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3449
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3450
				$if_curmac = get_interface_mac($if);
3451
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3452
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3453
						" link " . escapeshellarg($if_oldmac) . "\n");
3454
				}
3455
			}
3456

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

    
3459
			/* add line to script to restore spoofed mac after running hostapd */
3460
			if ($wl['spoofmac']) {
3461
				$if_curmac = get_interface_mac($if);
3462
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3463
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3464
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3465
				}
3466
			}
3467
		}
3468
	}
3469

    
3470
	fclose($fd_set);
3471

    
3472
	/* Making sure regulatory settings have actually changed
3473
	 * before applying, because changing them requires bringing
3474
	 * down all wireless networks on the interface. */
3475
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3476
	$ifconfig_str = implode($output);
3477
	unset($output);
3478
	$reg_changing = false;
3479

    
3480
	/* special case for the debug country code */
3481
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3482
		$reg_changing = true;
3483
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3484
		$reg_changing = true;
3485
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3486
		$reg_changing = true;
3487
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3488
		$reg_changing = true;
3489
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3490
		$reg_changing = true;
3491
	}
3492

    
3493
	if ($reg_changing) {
3494
		/* set regulatory domain */
3495
		if ($wlcfg['regdomain']) {
3496
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3497
		}
3498

    
3499
		/* set country */
3500
		if ($wlcfg['regcountry']) {
3501
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3502
		}
3503

    
3504
		/* set location */
3505
		if ($wlcfg['reglocation']) {
3506
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3507
		}
3508

    
3509
		$wlregcmd_args = implode(" ", $wlregcmd);
3510

    
3511
		/* build a complete list of the wireless clones for this interface */
3512
		$clone_list = array();
3513
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3514
			$clone_list[] = interface_get_wireless_clone($baseif);
3515
		}
3516
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3517
			foreach ($config['wireless']['clone'] as $clone) {
3518
				if ($clone['if'] == $baseif) {
3519
					$clone_list[] = $clone['cloneif'];
3520
				}
3521
			}
3522
		}
3523

    
3524
		/* find which clones are up and bring them down */
3525
		$clones_up = array();
3526
		foreach ($clone_list as $clone_if) {
3527
			$clone_status = pfSense_get_interface_addresses($clone_if);
3528
			if ($clone_status['status'] == 'up') {
3529
				$clones_up[] = $clone_if;
3530
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3531
			}
3532
		}
3533

    
3534
		/* apply the regulatory settings */
3535
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3536
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3537

    
3538
		/* bring the clones back up that were previously up */
3539
		foreach ($clones_up as $clone_if) {
3540
			interfaces_bring_up($clone_if);
3541

    
3542
			/*
3543
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3544
			 * is in infrastructure mode, and WPA is enabled.
3545
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3546
			 */
3547
			if ($clone_if != $if) {
3548
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3549
				if ((!empty($friendly_if)) &&
3550
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3551
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3552
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3553
				}
3554
			}
3555
		}
3556
	}
3557

    
3558
	/* The mode must be specified in a separate command before ifconfig
3559
	 * will allow the mode and channel at the same time in the next.
3560
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3561
	 */
3562
	if ($wlcfg['mode'] == "hostap") {
3563
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3564
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3565
	}
3566

    
3567
	/* configure wireless */
3568
	$wlcmd_args = implode(" ", $wlcmd);
3569
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3570
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3571
	/* Bring the interface up only after setting up all the other parameters. */
3572
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3573
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3574
	fclose($wlan_setup_log);
3575

    
3576
	unset($wlcmd_args, $wlcmd);
3577

    
3578

    
3579
	sleep(1);
3580
	/* execute hostapd and wpa_supplicant if required in shell */
3581
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3582

    
3583
	return 0;
3584

    
3585
}
3586

    
3587
function kill_hostapd($interface) {
3588
	global $g;
3589

    
3590
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3591
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3592
	}
3593
}
3594

    
3595
function kill_wpasupplicant($interface) {
3596
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3597
}
3598

    
3599
function find_dhclient_process($interface) {
3600
	if ($interface) {
3601
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3602
	} else {
3603
		$pid = 0;
3604
	}
3605

    
3606
	return intval($pid);
3607
}
3608

    
3609
function kill_dhclient_process($interface) {
3610
	if (empty($interface) || !does_interface_exist($interface)) {
3611
		return;
3612
	}
3613

    
3614
	$i = 0;
3615
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3616
		/* 3rd time make it die for sure */
3617
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3618
		posix_kill($pid, $sig);
3619
		sleep(1);
3620
		$i++;
3621
	}
3622
	unset($i);
3623
}
3624

    
3625
function find_dhcp6c_process($interface) {
3626
	global $g;
3627

    
3628
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3629
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3630
	} else {
3631
		return(false);
3632
	}
3633

    
3634
	return intval($pid);
3635
}
3636

    
3637
function kill_dhcp6client_process($interface, $force, $release = false) {
3638
	global $g;
3639

    
3640
	$i = 0;
3641

    
3642
	/*
3643
	Beware of the following: Reason, the interface may be down, but
3644
	dhcp6c may still be running, it just complains it cannot send
3645
	and carries on. Commented out as will stop the call to kill.
3646

    
3647
	if (empty($interface) || !does_interface_exist($interface)) {
3648
		return;
3649
	}
3650
	*/
3651

    
3652
	/*********** Notes on signals for dhcp6c and this function *************
3653

    
3654
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3655
	a release and waiting for the response that never comes.
3656
	So we need to tell it that the interface is down and to just die quickly
3657
	otherwise a new client may launch and we have duplicate proceses.
3658
	In this case use SIGUSR1.
3659

    
3660
	If we want to exit normally obeying the no release flag then use SIGTERM.
3661
	If we want to exit with a release overiding the no release flag then
3662
	use SIGUSR2.
3663

    
3664
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3665
	exit quickly without sending release signals.
3666

    
3667
	If $Force is set to false and $release is also set to false dhcp6c will
3668
	follow the no-release flag.
3669

    
3670
	If $Force is set to false and $release is true then dhcp6c will send a
3671
	release regardless of the no-release flag.
3672
	***********************************************************************/
3673

    
3674
	if ($force == true) {
3675
		$psig=SIGUSR1;
3676
	} else if ($release == false) {
3677
		$psig=SIGTERM;
3678
	} else {
3679
		$psig=SIGUSR2;
3680
	}
3681

    
3682
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3683
		/* 3rd time make it die for sure */
3684
		$sig = ($i == 2 ? SIGKILL : $psig);
3685
		posix_kill($pid, $sig);
3686
		sleep(1);
3687
		$i++;
3688
	}
3689
	/* Clear the RTSOLD script created lock & tidy up */
3690
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3691
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
3692
}
3693
function reset_dhcp6client_process($interface) {
3694

    
3695
	$pid = find_dhcp6c_process($interface);
3696

    
3697
	if($pid != 0) {
3698
		posix_kill($pid, SIGHUP);
3699
	}
3700
}
3701

    
3702
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3703
	global $g;
3704

    
3705
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3706
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3707

    
3708
	/*
3709
	 * Only run this if the lock does not exist. In theory the lock being
3710
	 * there in this mode means the user has selected dhcp6withoutRA while
3711
	 * a session is active in the other mode.
3712
	 *
3713
	 * It should not happen as the process should have been killed and the
3714
	 * lock deleted.
3715
	 */
3716

    
3717
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
3718
		kill_dhcp6client_process($interface, true);
3719
		/* Lock it to avoid multiple runs */
3720
		touch("/tmp/dhcp6c_{$interface}_lock");
3721
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3722
		    "{$noreleaseOption} " .
3723
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
3724
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
3725
		    $interface);
3726
		log_error(sprintf(gettext(
3727
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
3728
		    $interface));
3729
	}
3730
}
3731

    
3732
function interface_virtual_create($interface) {
3733
	global $config;
3734

    
3735
	if (interface_is_vlan($interface) != NULL) {
3736
		interfaces_vlan_configure($interface);
3737
	} else if (substr($interface, 0, 3) == "gre") {
3738
		interfaces_gre_configure(0, $interface);
3739
	} else if (substr($interface, 0, 3) == "gif") {
3740
		interfaces_gif_configure(0, $interface);
3741
	} else if (substr($interface, 0, 5) == "ovpns") {
3742
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3743
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3744
				if ($interface == "ovpns{$server['vpnid']}") {
3745
					if (!function_exists('openvpn_resync')) {
3746
						require_once('openvpn.inc');
3747
					}
3748
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3749
					openvpn_resync('server', $server);
3750
				}
3751
			}
3752
			unset($server);
3753
		}
3754
	} else if (substr($interface, 0, 5) == "ovpnc") {
3755
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3756
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3757
				if ($interface == "ovpnc{$client['vpnid']}") {
3758
					if (!function_exists('openvpn_resync')) {
3759
						require_once('openvpn.inc');
3760
					}
3761
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3762
					openvpn_resync('client', $client);
3763
				}
3764
			}
3765
			unset($client);
3766
		}
3767
	} else if (substr($interface, 0, 5) == "ipsec") {
3768
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
3769
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
3770
				if ($ph1ent['disabled']) {
3771
					continue;
3772
				}
3773
				if ($interface == "ipsec{$ph1ent['ikeid']}") {
3774
					interface_ipsec_vti_configure($ph1ent);
3775
				}
3776
			}
3777
		}
3778
	} else if (substr($interface, 0, 4) == "lagg") {
3779
		interfaces_lagg_configure($interface);
3780
	} else if (substr($interface, 0, 6) == "bridge") {
3781
		interfaces_bridge_configure(0, $interface);
3782
	}
3783
}
3784

    
3785
function interface_vlan_mtu_configured($iface) {
3786
	global $config;
3787

    
3788
	$mtu = 0;
3789
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3790
		foreach ($config['vlans']['vlan'] as $vlan) {
3791

    
3792
			if ($vlan['vlanif'] != $iface)
3793
				continue;
3794

    
3795
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3796
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3797
				/* VLAN MTU */
3798
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3799
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3800
				/* Parent MTU */
3801
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3802
			}
3803
		}
3804
	}
3805

    
3806
	return $mtu;
3807
}
3808

    
3809
function interface_mtu_wanted_for_pppoe($realif) {
3810
	global $config;
3811

    
3812
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3813
		return 0;
3814

    
3815
	$mtu = 0;
3816
	foreach ($config['ppps']['ppp'] as $ppp) {
3817
		if ($ppp['type'] != "pppoe") {
3818
			continue;
3819
		}
3820

    
3821
		$mtus = array();
3822
		if (!empty($ppp['mtu'])) {
3823
			$mtus = explode(',', $ppp['mtu']);
3824
		}
3825
		$ports = explode(',', $ppp['ports']);
3826

    
3827
		foreach ($ports as $pid => $port) {
3828
			$parentifa = get_parent_interface($port);
3829
			$parentif = $parentifa[0];
3830
			if ($parentif != $realif)
3831
				continue;
3832

    
3833
			// there is an MTU configured on the port in question
3834
			if (!empty($mtus[$pid])) {
3835
				$mtu = intval($mtus[$pid]) + 8;
3836
			// or use the MTU configured on the interface ...
3837
			} elseif (is_array($config['interfaces'])) {
3838
				foreach ($config['interfaces'] as $interface) {
3839
					if ($interface['if'] == $ppp['if'] &&
3840
					    !empty($interface['mtu'])) {
3841
						$mtu = intval($interface['mtu']) + 8;
3842
						break;
3843
					}
3844
				}
3845
			}
3846
		}
3847
	}
3848

    
3849
	return $mtu;
3850
}
3851

    
3852
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3853
	global $config, $g;
3854
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3855
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3856

    
3857
	$wancfg = $config['interfaces'][$interface];
3858

    
3859
	if (!isset($wancfg['enable'])) {
3860
		return;
3861
	}
3862

    
3863
	$realif = get_real_interface($interface);
3864
	$realhwif_array = get_parent_interface($interface);
3865
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3866
	$realhwif = $realhwif_array[0];
3867

    
3868
	$mac_if_cfg = $wancfg;
3869
	if (interface_is_vlan($realif)) {
3870
		$mac_if = convert_real_interface_to_friendly_interface_name(
3871
		    $realhwif);
3872
		if (is_array($config['interfaces'][$mac_if])) {
3873
			$mac_if_cfg = $config['interfaces'][$mac_if];
3874
		} else {
3875
			$mac_if = $interface;
3876
		}
3877
	}
3878

    
3879
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn") && !(substr($realif, 0, 5) == "ipsec")) {
3880
		/* remove all IPv4 and IPv6 addresses */
3881
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3882
		if (is_array($tmpifaces)) {
3883
			foreach ($tmpifaces as $tmpiface) {
3884
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3885
					if (!is_linklocal($tmpiface)) {
3886
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3887
					}
3888
				} else {
3889
					if (is_subnetv4($tmpiface)) {
3890
						$tmpip = explode('/', $tmpiface);
3891
						$tmpip = $tmpip[0];
3892
					} else {
3893
						$tmpip = $tmpiface;
3894
					}
3895
					pfSense_interface_deladdress($realif, $tmpip);
3896
				}
3897
			}
3898
		}
3899

    
3900
		/* only bring down the interface when both v4 and v6 are set to NONE */
3901
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3902
			interface_bring_down($interface);
3903
		}
3904
	}
3905

    
3906
	$interface_to_check = $realif;
3907
	if (interface_isppp_type($interface)) {
3908
		$interface_to_check = $realhwif;
3909
	}
3910

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

    
3916
	/* Disable Accepting router advertisements unless specifically requested */
3917
	if ($g['debug']) {
3918
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3919
	}
3920
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
3921
	{
3922
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3923
	}
3924
	/* wireless configuration? */
3925
	if (is_array($wancfg['wireless']) && !$linkupevent) {
3926
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3927
	}
3928

    
3929
	$current_mac = get_interface_mac($realhwif);
3930
	$vendor_mac = get_interface_vendor_mac($realhwif);
3931

    
3932
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
3933
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
3934

    
3935
		interface_set_macaddr($realhwif, $mac_addr);
3936
	} else {
3937
		/*
3938
		 * this is not a valid mac address.  generate a
3939
		 * temporary mac address so the machine can get online.
3940
		 */
3941
		echo gettext("Generating new MAC address.");
3942
		$random_mac = generate_random_mac_address();
3943
		interface_set_macaddr($realhwif, $random_mac);
3944
		$config['interfaces'][$mac_if]['spoofmac'] = $random_mac;
3945
		write_config(sprintf(gettext('The invalid MAC address ' .
3946
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
3947
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
3948
		file_notice("MAC Address altered", sprintf(gettext('The ' .
3949
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
3950
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
3951
		    $random_mac), "Interfaces");
3952
	}
3953

    
3954
	/* media */
3955
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3956
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3957
		if ($wancfg['media']) {
3958
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3959
		}
3960
		if ($wancfg['mediaopt']) {
3961
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3962
		}
3963
		mwexec($cmd);
3964
	}
3965

    
3966
	/* Apply hw offloading policies as configured */
3967
	enable_hardware_offloading($interface);
3968

    
3969
	/* invalidate interface/ip/sn cache */
3970
	get_interface_arr(true);
3971
	unset($interface_ip_arr_cache[$realif]);
3972
	unset($interface_sn_arr_cache[$realif]);
3973
	unset($interface_ipv6_arr_cache[$realif]);
3974
	unset($interface_snv6_arr_cache[$realif]);
3975

    
3976
	$tunnelif = substr($realif, 0, 3);
3977

    
3978
	$mtuif = $realif;
3979
	$mtuhwif = $realhwif;
3980

    
3981
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3982
	if (interface_isppp_type($interface)) {
3983
		$mtuif = $realhwif;
3984
		$mtuhwif_array = get_parent_interface($mtuif);
3985
		$mtuhwif = $mtuhwif_array[0];
3986
	}
3987

    
3988
	$wantedmtu = 0;
3989
	if (is_array($config['interfaces'])) {
3990
		foreach ($config['interfaces'] as $tmpinterface) {
3991
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3992
				$wantedmtu = $tmpinterface['mtu'];
3993
				break;
3994
			}
3995
		}
3996
	}
3997

    
3998
	/* MTU is not specified for interface, try the pppoe settings. */
3999
	if ($wantedmtu == 0) {
4000
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4001
	}
4002
	if (($wantedmtu == 0) && interface_is_vlan($mtuif) != NULL && interface_isppp_type($interface)) {
4003
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4004
	}
4005
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4006
		/* set MTU to 1400 for GRE over IPsec */
4007
		if (is_greipsec($mtuif)) {
4008
			$wantedmtu = 1400;
4009
		} else {
4010
			$wantedmtu = 1476;
4011
		}
4012
	}
4013
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4014
		$wantedmtu = 1280;
4015
	}
4016

    
4017
	/* Set the MTU to 1500 if no explicit MTU configured. */
4018
	if ($wantedmtu == 0) {
4019
		$wantedmtu = 1500; /* Default */
4020
	}
4021

    
4022
	if (interface_is_vlan($mtuif) != NULL) {
4023
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4024
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
4025
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
4026
			if ($wancfg['mtu'] > $parentmtu) {
4027
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4028
			}
4029
		}
4030

    
4031
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4032

    
4033
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4034
			$configuredmtu = $parentmtu;
4035
		if ($configuredmtu != 0)
4036
			$mtu = $configuredmtu;
4037
		else
4038
			$mtu = $wantedmtu;
4039

    
4040
		/* Set the parent MTU. */
4041
		if (get_interface_mtu($mtuhwif) < $mtu)
4042
			set_interface_mtu($mtuhwif, $mtu);
4043
		/* Set the VLAN MTU. */
4044
		if (get_interface_mtu($mtuif) != $mtu)
4045
			set_interface_mtu($mtuif, $mtu);
4046
	} else if (substr($mtuif, 0, 4) == 'lagg') {
4047
		/* LAGG interface must be destroyed and re-created to change MTU */
4048
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4049
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
4050
				foreach ($config['laggs']['lagg'] as $lagg) {
4051
					if ($lagg['laggif'] == $mtuif) {
4052
						interface_lagg_configure($lagg);
4053
						break;
4054
					}
4055
				}
4056
			}
4057
		}
4058
	} else {
4059
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4060
			pfSense_interface_mtu($mtuif, $wantedmtu);
4061
		}
4062
	}
4063
	/* XXX: What about gre/gif/.. ? */
4064

    
4065
	if (does_interface_exist($wancfg['if'])) {
4066
		interfaces_bring_up($wancfg['if']);
4067
	}
4068

    
4069
	switch ($wancfg['ipaddr']) {
4070
		case 'dhcp':
4071
			interface_dhcp_configure($interface);
4072
			break;
4073
		case 'pppoe':
4074
		case 'l2tp':
4075
		case 'pptp':
4076
		case 'ppp':
4077
			interface_ppps_configure($interface);
4078
			break;
4079
		default:
4080
			/* XXX: Kludge for now related to #3280 */
4081
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4082
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4083
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4084
				}
4085
			}
4086
			break;
4087
	}
4088

    
4089
	switch ($wancfg['ipaddrv6']) {
4090
		case 'slaac':
4091
		case 'dhcp6':
4092
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4093
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4094
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4095
			/* Remove the check file. Should not be there but just in case */
4096
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
4097
			log_error(gettext("calling interface_dhcpv6_configure."));
4098
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
4099
				interface_dhcpv6_configure($interface, $wancfg);
4100
			}
4101
			break;
4102
		case '6rd':
4103
			interface_6rd_configure($interface, $wancfg);
4104
			break;
4105
		case '6to4':
4106
			interface_6to4_configure($interface, $wancfg);
4107
			break;
4108
		case 'track6':
4109
			interface_track6_configure($interface, $wancfg, $linkupevent);
4110
			break;
4111
		default:
4112
			/* XXX: Kludge for now related to #3280 */
4113
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4114
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4115
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4116
					// FIXME: Add IPv6 Support to the pfSense module
4117
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4118
				}
4119
			}
4120
			break;
4121
	}
4122

    
4123
	interface_netgraph_needed($interface);
4124

    
4125
	if (!platform_booting()) {
4126
		link_interface_to_vips($interface, "update");
4127

    
4128
		if ($tunnelif != 'gre') {
4129
			unset($gre);
4130
			$gre = link_interface_to_gre($interface);
4131
			if (!empty($gre)) {
4132
				array_walk($gre, 'interface_gre_configure');
4133
			}
4134
		}
4135

    
4136
		if ($tunnelif != 'gif') {
4137
			unset($gif);
4138
			$gif = link_interface_to_gif ($interface);
4139
			if (!empty($gif)) {
4140
				array_walk($gif, 'interface_gif_configure');
4141
			}
4142
		}
4143

    
4144
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4145
			unset($bridgetmp);
4146
			$bridgetmp = link_interface_to_bridge($interface);
4147
			if (!empty($bridgetmp)) {
4148
				interface_bridge_add_member($bridgetmp, $realif);
4149
			}
4150
		}
4151

    
4152
		$grouptmp = link_interface_to_group($interface);
4153
		if (!empty($grouptmp)) {
4154
			array_walk($grouptmp, 'interface_group_add_member');
4155
		}
4156

    
4157
		if ($interface == "lan") {
4158
			/* make new hosts file */
4159
			system_hosts_generate();
4160
		}
4161

    
4162
		if ($reloadall == true) {
4163

    
4164
			/* reconfigure static routes (kernel may have deleted them) */
4165
			system_routing_configure($interface);
4166

    
4167
			/* reload ipsec tunnels */
4168
			send_event("service reload ipsecdns");
4169

    
4170
			if (isset($config['dnsmasq']['enable'])) {
4171
				services_dnsmasq_configure();
4172
			}
4173

    
4174
			if (isset($config['unbound']['enable'])) {
4175
				services_unbound_configure();
4176
			}
4177

    
4178
			/* update dyndns */
4179
			send_event("service reload dyndns {$interface}");
4180

    
4181
			/* reload captive portal */
4182
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4183
				require_once('captiveportal.inc');
4184
			}
4185
			captiveportal_init_rules_byinterface($interface);
4186
		}
4187
	}
4188

    
4189
	if (!empty($wancfg['descr'])) {
4190
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4191
	};
4192

    
4193
	interfaces_staticarp_configure($interface);
4194
	return 0;
4195
}
4196

    
4197
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4198
	global $config, $g;
4199

    
4200
	if (!is_array($wancfg)) {
4201
		return;
4202
	}
4203

    
4204
	if (!isset($wancfg['enable'])) {
4205
		return;
4206
	}
4207

    
4208
	/* If the interface is not configured via another, exit */
4209
	if (empty($wancfg['track6-interface'])) {
4210
		return;
4211
	}
4212

    
4213
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4214
	$realif = get_real_interface($interface);
4215
	$linklocal = find_interface_ipv6_ll($realif, true);
4216
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4217
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4218
	}
4219

    
4220
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4221
	if (!isset($trackcfg['enable'])) {
4222
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4223
		return;
4224
	}
4225

    
4226
	switch ($trackcfg['ipaddrv6']) {
4227
		case "6to4":
4228
			if ($g['debug']) {
4229
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4230
			}
4231
			interface_track6_6to4_configure($interface, $wancfg);
4232
			break;
4233
		case "6rd":
4234
			if ($g['debug']) {
4235
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4236
			}
4237
			interface_track6_6rd_configure($interface, $wancfg);
4238
			break;
4239
		case "dhcp6":
4240
			if ($linkupevent == true) {
4241
				/*
4242
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4243
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4244
				 *
4245
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4246
				 */
4247
				$parentrealif = get_real_interface($wancfg['track6-interface']);
4248
				$pidv6 = find_dhcp6c_process($parentrealif);
4249
				if ($pidv6) {
4250
					posix_kill($pidv6, SIGHUP);
4251
				}
4252
			}
4253
			break;
4254
	}
4255

    
4256
	if ($linkupevent == false && !platform_booting()) {
4257
		if (!function_exists('services_dhcpd_configure')) {
4258
			require_once("services.inc");
4259
		}
4260

    
4261
		/* restart dns servers (defering dhcpd reload) */
4262
		if (isset($config['unbound']['enable'])) {
4263
			services_unbound_configure(false);
4264
		}
4265
		if (isset($config['dnsmasq']['enable'])) {
4266
			services_dnsmasq_configure(false);
4267
		}
4268

    
4269
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4270
		services_dhcpd_configure("inet6");
4271
	}
4272

    
4273
	return 0;
4274
}
4275

    
4276
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4277
	global $config, $g;
4278
	global $interface_ipv6_arr_cache;
4279
	global $interface_snv6_arr_cache;
4280

    
4281
	if (!is_array($lancfg)) {
4282
		return;
4283
	}
4284

    
4285
	/* If the interface is not configured via another, exit */
4286
	if (empty($lancfg['track6-interface'])) {
4287
		return;
4288
	}
4289

    
4290
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4291
	if (empty($wancfg)) {
4292
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4293
		return;
4294
	}
4295

    
4296
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4297
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4298
		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']));
4299
		return;
4300
	}
4301
	$hexwanv4 = return_hex_ipv4($ip4address);
4302

    
4303
	/* create the long prefix notation for math, save the prefix length */
4304
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4305
	$rd6prefixlen = $rd6prefix[1];
4306
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4307

    
4308
	/* binary presentation of the prefix for all 128 bits. */
4309
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4310

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

    
4316
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4317
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4318
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4319
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4320
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4321
	/* fill the rest out with zeros */
4322
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4323

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

    
4327
	$lanif = get_real_interface($interface);
4328
	$oip = find_interface_ipv6($lanif);
4329
	if (is_ipaddrv6($oip)) {
4330
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4331
	}
4332
	unset($interface_ipv6_arr_cache[$lanif]);
4333
	unset($interface_snv6_arr_cache[$lanif]);
4334
	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));
4335
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4336

    
4337
	return 0;
4338
}
4339

    
4340
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4341
	global $config, $g;
4342
	global $interface_ipv6_arr_cache;
4343
	global $interface_snv6_arr_cache;
4344

    
4345
	if (!is_array($lancfg)) {
4346
		return;
4347
	}
4348

    
4349
	/* If the interface is not configured via another, exit */
4350
	if (empty($lancfg['track6-interface'])) {
4351
		return;
4352
	}
4353

    
4354
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4355
	if (empty($wancfg)) {
4356
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4357
		return;
4358
	}
4359

    
4360
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4361
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4362
		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']));
4363
		return;
4364
	}
4365
	$hexwanv4 = return_hex_ipv4($ip4address);
4366

    
4367
	/* create the long prefix notation for math, save the prefix length */
4368
	$sixto4prefix = "2002::";
4369
	$sixto4prefixlen = 16;
4370
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4371

    
4372
	/* binary presentation of the prefix for all 128 bits. */
4373
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4374

    
4375
	/* just save the left prefix length bits */
4376
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4377
	/* add the v4 address */
4378
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4379
	/* add the custom prefix id */
4380
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4381
	/* fill the rest out with zeros */
4382
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4383

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

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

    
4397
	return 0;
4398
}
4399

    
4400
function interface_6rd_configure($interface = "wan", $wancfg) {
4401
	global $config, $g;
4402

    
4403
	/* because this is a tunnel interface we can only function
4404
	 *	with a public IPv4 address on the interface */
4405

    
4406
	if (!is_array($wancfg)) {
4407
		return;
4408
	}
4409

    
4410
	if (!is_module_loaded('if_stf.ko')) {
4411
		mwexec('/sbin/kldload if_stf.ko');
4412
	}
4413

    
4414
	$wanif = get_real_interface($interface);
4415
	$ip4address = find_interface_ip($wanif);
4416
	if (!is_ipaddrv4($ip4address)) {
4417
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4418
		return false;
4419
	}
4420
	$hexwanv4 = return_hex_ipv4($ip4address);
4421

    
4422
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4423
		$wancfg['prefix-6rd-v4plen'] = 0;
4424
	}
4425

    
4426
	/* create the long prefix notation for math, save the prefix length */
4427
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4428
	$rd6prefixlen = $rd6prefix[1];
4429
	$brgw = explode('.', $wancfg['gateway-6rd']);
4430
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4431
	$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);
4432
	if (strlen($rd6brgw) < 128) {
4433
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4434
	}
4435
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4436
	unset($brgw);
4437
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4438

    
4439
	/* binary presentation of the prefix for all 128 bits. */
4440
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4441

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

    
4449
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4450
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4451

    
4452

    
4453
	/* XXX: need to extend to support variable prefix size for v4 */
4454
	$stfiface = "{$interface}_stf";
4455
	if (does_interface_exist($stfiface)) {
4456
		pfSense_interface_destroy($stfiface);
4457
	}
4458
	$tmpstfiface = pfSense_interface_create("stf");
4459
	pfSense_interface_rename($tmpstfiface, $stfiface);
4460
	pfSense_interface_flags($stfiface, IFF_LINK2);
4461
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4462
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4463
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4464
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4465
	}
4466
	if ($g['debug']) {
4467
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4468
	}
4469

    
4470
	/* write out a default router file */
4471
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4472
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4473

    
4474
	$ip4gateway = get_interface_gateway($interface);
4475
	if (is_ipaddrv4($ip4gateway)) {
4476
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
4477
	}
4478

    
4479
	/* configure dependent interfaces */
4480
	if (!platform_booting()) {
4481
		link_interface_to_track6($interface, "update");
4482
	}
4483

    
4484
	return 0;
4485
}
4486

    
4487
function interface_6to4_configure($interface = "wan", $wancfg) {
4488
	global $config, $g;
4489

    
4490
	/* because this is a tunnel interface we can only function
4491
	 *	with a public IPv4 address on the interface */
4492

    
4493
	if (!is_array($wancfg)) {
4494
		return;
4495
	}
4496

    
4497
	$wanif = get_real_interface($interface);
4498
	$ip4address = find_interface_ip($wanif);
4499
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4500
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4501
		return false;
4502
	}
4503

    
4504
	/* create the long prefix notation for math, save the prefix length */
4505
	$stfprefixlen = 16;
4506
	$stfprefix = Net_IPv6::uncompress("2002::");
4507
	$stfarr = explode(":", $stfprefix);
4508
	$v4prefixlen = "0";
4509

    
4510
	/* we need the hex form of the interface IPv4 address */
4511
	$ip4arr = explode(".", $ip4address);
4512
	$hexwanv4 = "";
4513
	foreach ($ip4arr as $octet) {
4514
		$hexwanv4 .= sprintf("%02x", $octet);
4515
	}
4516

    
4517
	/* we need the hex form of the broker IPv4 address */
4518
	$ip4arr = explode(".", "192.88.99.1");
4519
	$hexbrv4 = "";
4520
	foreach ($ip4arr as $octet) {
4521
		$hexbrv4 .= sprintf("%02x", $octet);
4522
	}
4523

    
4524
	/* binary presentation of the prefix for all 128 bits. */
4525
	$stfprefixbin = "";
4526
	foreach ($stfarr as $element) {
4527
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4528
	}
4529
	/* just save the left prefix length bits */
4530
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4531

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

    
4536
	/* for the local subnet too. */
4537
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4538
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4539

    
4540
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4541
	$stfbrarr = array();
4542
	$stfbrbinarr = array();
4543
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4544
	foreach ($stfbrbinarr as $bin) {
4545
		$stfbrarr[] = dechex(bindec($bin));
4546
	}
4547
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4548

    
4549
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4550
	$stflanarr = array();
4551
	$stflanbinarr = array();
4552
	$stflanbinarr = str_split($stflanbin, 16);
4553
	foreach ($stflanbinarr as $bin) {
4554
		$stflanarr[] = dechex(bindec($bin));
4555
	}
4556
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4557
	$stflanarr[7] = 1;
4558
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4559

    
4560
	/* setup the stf interface */
4561
	if (!is_module_loaded("if_stf")) {
4562
		mwexec("/sbin/kldload if_stf.ko");
4563
	}
4564
	$stfiface = "{$interface}_stf";
4565
	if (does_interface_exist($stfiface)) {
4566
		pfSense_interface_destroy($stfiface);
4567
	}
4568
	$tmpstfiface = pfSense_interface_create("stf");
4569
	pfSense_interface_rename($tmpstfiface, $stfiface);
4570
	pfSense_interface_flags($stfiface, IFF_LINK2);
4571
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4572

    
4573
	if ($g['debug']) {
4574
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4575
	}
4576

    
4577
	/* write out a default router file */
4578
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4579
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4580

    
4581
	$ip4gateway = get_interface_gateway($interface);
4582
	if (is_ipaddrv4($ip4gateway)) {
4583
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
4584
	}
4585

    
4586
	if (!platform_booting()) {
4587
		link_interface_to_track6($interface, "update");
4588
	}
4589

    
4590
	return 0;
4591
}
4592

    
4593
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4594
	global $config, $g;
4595

    
4596
	if (!is_array($wancfg)) {
4597
		return;
4598
	}
4599

    
4600
	$wanif = get_real_interface($interface, "inet6");
4601
	$dhcp6cconf = "";
4602

    
4603
	if (!empty($config['system']['global-v6duid'])) {
4604
		// Write the DUID file
4605
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4606
		    log_error(gettext("Failed to write user DUID file!"));
4607
		}
4608
	}
4609

    
4610
	/* accept router advertisements for this interface                 */
4611
	/* Moved to early in the function as sometimes interface not ready */
4612
	/* RTSOLD fails as interface does not accept .....                 */
4613

    
4614
	log_error("Accept router advertisements on interface {$wanif} ");
4615
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4616

    
4617
	if ($wancfg['adv_dhcp6_config_file_override']) {
4618
		// DHCP6 Config File Override
4619
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4620
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4621
		// DHCP6 Config File Advanced
4622
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4623
	} else {
4624
		// DHCP6 Config File Basic
4625
		$dhcp6cconf .= "interface {$wanif} {\n";
4626

    
4627
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4628
		if ($wancfg['ipaddrv6'] == "slaac") {
4629
			$dhcp6cconf .= "\tinformation-only;\n";
4630
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4631
			$dhcp6cconf .= "\trequest domain-name;\n";
4632
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4633
			$dhcp6cconf .= "};\n";
4634
		} else {
4635
			$trackiflist = array();
4636
			$iflist = link_interface_to_track6($interface);
4637
			foreach ($iflist as $ifname => $ifcfg) {
4638
				if (is_numeric($ifcfg['track6-prefix-id'])) {
4639
					$trackiflist[$ifname] = $ifcfg;
4640
				}
4641
			}
4642

    
4643
			/* skip address request if this is set */
4644
			if (!isset($wancfg['dhcp6prefixonly'])) {
4645
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4646
			}
4647
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4648
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4649
			}
4650

    
4651
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4652
			$dhcp6cconf .= "\trequest domain-name;\n";
4653

    
4654
			/*
4655
			 * dhcp6c will run different scripts depending on
4656
			 * whether dhcpwithoutra is set or unset.
4657
			 */
4658
			if (isset($wancfg['dhcp6withoutra'])) {
4659
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4660
			} else {
4661
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4662
			}
4663
			$dhcp6cconf .= "};\n";
4664

    
4665
			if (!isset($wancfg['dhcp6prefixonly'])) {
4666
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4667
			}
4668

    
4669
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4670
				/* Setup the prefix delegation */
4671
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4672
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4673
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4674
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4675
				}
4676
				foreach ($trackiflist as $friendly => $ifcfg) {
4677
					if ($g['debug']) {
4678
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4679
					}
4680
					$realif = get_real_interface($friendly);
4681
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4682
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4683
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4684
					$dhcp6cconf .= "\t};\n";
4685
				}
4686
				unset($preflen, $iflist, $ifcfg, $ifname);
4687
				$dhcp6cconf .= "};\n";
4688
			}
4689
			unset($trackiflist);
4690
		}
4691
	}
4692

    
4693
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4694
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4695

    
4696
	/* wide-dhcp6c works for now. */
4697
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4698
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4699
		unset($dhcp6cconf);
4700
		return 1;
4701
	}
4702
	unset($dhcp6cconf);
4703

    
4704
	/*************** Script Debug Logging ***************************
4705
	Both dhcp6 scripts now have a logging message built in.
4706
	These logging messages ONLY appear if dhcp6c debug logging is set.
4707
	The logging messages appear in the dhcp section of the logs,
4708
	not in system.
4709

    
4710
	These scripts now also take advantage of the REASON= env vars
4711
	supplied by dhcp6c.
4712
	****************************************************************/
4713

    
4714
	/* Script create for dhcp6withoutRA mode */
4715
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4716
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4717
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4718
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4719
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4720
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4721
	// Need to pass params to  the final script
4722
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4723
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4724
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4725
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4726
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
4727
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
4728
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4729
	if ($debugOption == '-D') {
4730
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4731
	}
4732
	$dhcp6cscriptwithoutra .= ";;\n";
4733
	$dhcp6cscriptwithoutra .= "REBIND)\n";
4734
	if ($debugOption == '-D') {
4735
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4736
	}
4737
	$dhcp6cscriptwithoutra .= ";;\n";
4738
	if (isset($wancfg['dhcp6norelease'])) {
4739
		$dhcp6cscriptwithoutra .= "EXIT)\n";
4740
	} else {
4741
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
4742
	}
4743
	if ($debugOption == '-D') {
4744
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4745
	}
4746
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4747
	$dhcp6cscriptwithoutra .= ";;\n";
4748
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
4749
	if ($debugOption == '-D') {
4750
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4751
	}
4752
	$dhcp6cscriptwithoutra .= "esac\n";
4753
	if (!@file_put_contents(
4754
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4755
	    $dhcp6cscriptwithoutra)) {
4756
		printf("Error: cannot open " .
4757
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4758
		    "interface_dhcpv6_configure() for writing.\n");
4759
		unset($dhcp6cscriptwithoutra);
4760
		return 1;
4761
	}
4762

    
4763
	unset($dhcp6cscriptwithoutra);
4764
	@chmod(
4765
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4766
	    0755);
4767

    
4768
	/*
4769
	 * Dual mode wan_dhcp6c script with variations depending on node
4770
	 * dhcp6 will run the wan ipv6 configure
4771
	 */
4772
	$dhcp6cscript  = "#!/bin/sh\n";
4773
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4774
	if (!isset($wancfg['dhcp6withoutra'])) {
4775
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4776
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4777
		$dhcp6cscript .= "case \$REASON in\n";
4778
		$dhcp6cscript .= "REQUEST)\n";
4779
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4780
		if ($debugOption == '-D') {
4781
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4782
		}
4783
		$dhcp6cscript .= ";;\n";
4784
		$dhcp6cscript .= "REBIND)\n";
4785
		if ($debugOption == '-D') {
4786
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4787
		}
4788
		$dhcp6cscript .= ";;\n";
4789
		if (isset($wancfg['dhcp6norelease'])) {
4790
			$dhcp6cscript .= "EXIT)\n";
4791
		} else {
4792
			$dhcp6cscript .= "RELEASE)\n";
4793
		}
4794
		if ($debugOption == '-D') {
4795
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4796
		}
4797
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4798
		$dhcp6cscript .= ";;\n";
4799
		$dhcp6cscript .= "RENEW|INFO)\n";
4800
		if ($debugOption == '-D') {
4801
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4802
		}
4803
		$dhcp6cscript .= "esac\n";
4804
	} else {
4805
		// Need to get the parameters from the dhcp6cwithoutRA run
4806
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
4807
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
4808
		$dhcp6cscript .= "/bin/sleep 1\n";
4809
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4810
	}
4811

    
4812
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4813
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4814
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4815
		unset($dhcp6cscript);
4816
		return 1;
4817
	}
4818
	unset($dhcp6cscript);
4819
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4820

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

    
4827
	/* non ipoe Process */
4828
	if (!isset($wancfg['dhcp6withoutra'])) {
4829
		/*
4830
		 * We only want this script to run once, and if it runs twice
4831
		 * then do not launch dhcp6c again, this only happens if
4832
		 * dhcpwithoutra is not set.
4833
		 *
4834
		 * Check for a lock file, trying to prevent multiple instances
4835
		 * of dhcp6c being launched
4836
		 */
4837
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
4838
		/*
4839
		 * Create the lock file, trying to prevent multiple instances
4840
		 * of dhcp6c being launched
4841
		 */
4842
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
4843
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
4844
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4845
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4846
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
4847
		$rtsoldscript .= "\tfi\n";
4848
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
4849
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
4850
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4851
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4852
		$rtsoldscript .= "else\n";
4853
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
4854
		$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c_{$wanif}.pid\")\n";
4855
		$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
4856
		$rtsoldscript .= "fi\n";
4857
	} else {
4858
		/*
4859
		 * The script needs to run in dhcp6withoutra mode as RA may
4860
		 * not have been received, or there can be a delay with
4861
		 * certain ISPs
4862
		 */
4863
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
4864
		$rtsoldscript .= "/bin/sleep 1\n";
4865
	}
4866
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4867
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4868
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4869
		unset($rtsoldscript);
4870
		return 1;
4871
	}
4872
	unset($rtsoldscript);
4873
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4874

    
4875
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4876
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4877
		log_error("Killing running rtsold process");
4878
		sleep(2);
4879
	}
4880

    
4881
	if (isset($wancfg['dhcp6withoutra'])) {
4882
		/*
4883
		 * Start dhcp6c here if we don't want to wait for ra - calls
4884
		 * separate function
4885
		 *
4886
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
4887
		 * will then run the configure on receipt of the RA.
4888
		 *
4889
		 * Already started. interface_dhcpv6_configure() appears to get
4890
		 * called multiple times.
4891
		 *
4892
		 * Taking the interface down or releasing will kill the client.
4893
		 */
4894
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
4895
		{
4896
			/*
4897
			 * If the interface is being brought up, wait for the
4898
			 * interface to configure accept RA before launching.
4899
			 * Otherwise it is not ready to accept and will fail.
4900
			 */
4901
			sleep(3);
4902
			run_dhcp6client_process($wanif,$interface,$wancfg);
4903
		}
4904
	} else {
4905
		/*
4906
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
4907
		 * ( it does not background, it exits! ) It will launch dhcp6c
4908
		 * if dhcpwihtoutra is not set
4909
		 */
4910
		log_error("Starting rtsold process");
4911
		sleep(2);
4912
		mwexec("/usr/sbin/rtsold -1 " .
4913
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
4914
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
4915
		    $wanif);
4916
	}
4917
	/*
4918
	 * NOTE: will be called from rtsold invoked script
4919
	 * link_interface_to_track6($interface, "update");
4920
	 */
4921

    
4922
	return 0;
4923
}
4924

    
4925
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4926
	global $g;
4927

    
4928
	$send_options = "";
4929
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4930
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4931
		foreach ($options as $option) {
4932
			$send_options .= "\tsend " . trim($option) . ";\n";
4933
		}
4934
	}
4935

    
4936
	$request_options = "";
4937
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4938
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4939
		foreach ($options as $option) {
4940
			$request_options .= "\trequest " . trim($option) . ";\n";
4941
		}
4942
	}
4943

    
4944
	$information_only = "";
4945
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4946
		$information_only = "\tinformation-only;\n";
4947
	}
4948

    
4949
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4950
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4951
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4952
	}
4953

    
4954
	$interface_statement  = "interface";
4955
	$interface_statement .= " {$wanif}";
4956
	$interface_statement .= " {\n";
4957
	$interface_statement .= "$send_options";
4958
	$interface_statement .= "$request_options";
4959
	$interface_statement .= "$information_only";
4960
	$interface_statement .= "$script";
4961
	$interface_statement .= "};\n";
4962

    
4963
	$id_assoc_statement_address = "";
4964
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4965
		$id_assoc_statement_address .= "id-assoc";
4966
		$id_assoc_statement_address .= " na";
4967
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4968
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4969
		}
4970
		$id_assoc_statement_address .= " { ";
4971

    
4972
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4973
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4974
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4975
			$id_assoc_statement_address .= "\n\taddress";
4976
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4977
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4978
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4979
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4980
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4981
			}
4982
			$id_assoc_statement_address .= ";\n";
4983
		}
4984

    
4985
		$id_assoc_statement_address .= "};\n";
4986
	}
4987

    
4988
	$id_assoc_statement_prefix = "";
4989
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4990
		$id_assoc_statement_prefix .= "id-assoc";
4991
		$id_assoc_statement_prefix .= " pd";
4992
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4993
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4994
		}
4995
		$id_assoc_statement_prefix .= " { ";
4996

    
4997
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4998
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4999
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5000
			$id_assoc_statement_prefix .= "\n\tprefix";
5001
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5002
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5003
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5004
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5005
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5006
			}
5007
			$id_assoc_statement_prefix .= ";";
5008
		}
5009

    
5010
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5011
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5012
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5013
			$id_assoc_statement_prefix .= " {$realif}";
5014
			$id_assoc_statement_prefix .= " {\n";
5015
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5016
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5017
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5018
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5019
			}
5020
			$id_assoc_statement_prefix .= "\t};";
5021
		}
5022

    
5023
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5024
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5025
			$id_assoc_statement_prefix .= "\n";
5026
		}
5027

    
5028
		$id_assoc_statement_prefix .= "};\n";
5029
	}
5030

    
5031
	$authentication_statement = "";
5032
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5033
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5034
		$authentication_statement .= "authentication";
5035
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5036
		$authentication_statement .= " {\n";
5037
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5038
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5039
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5040
		}
5041
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5042
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5043
		}
5044
		$authentication_statement .= "};\n";
5045
	}
5046

    
5047
	$key_info_statement = "";
5048
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5049
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5050
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5051
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5052
		$key_info_statement .= "keyinfo";
5053
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5054
		$key_info_statement .= " {\n";
5055
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5056
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5057
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5058
		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'])) {
5059
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5060
		}
5061
		$key_info_statement .= "};\n";
5062
	}
5063

    
5064
	$dhcp6cconf  = $interface_statement;
5065
	$dhcp6cconf .= $id_assoc_statement_address;
5066
	$dhcp6cconf .= $id_assoc_statement_prefix;
5067
	$dhcp6cconf .= $authentication_statement;
5068
	$dhcp6cconf .= $key_info_statement;
5069

    
5070
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5071

    
5072
	return $dhcp6cconf;
5073
}
5074

    
5075

    
5076
function DHCP6_Config_File_Override($wancfg, $wanif) {
5077

    
5078
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5079

    
5080
	if ($dhcp6cconf === false) {
5081
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5082
		return '';
5083
	} else {
5084
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5085
	}
5086
}
5087

    
5088

    
5089
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5090

    
5091
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5092

    
5093
	return $dhcp6cconf;
5094
}
5095

    
5096

    
5097
function interface_dhcp_configure($interface = "wan") {
5098
	global $config, $g, $vlanprio_values;
5099

    
5100
	$ifcfg = $config['interfaces'][$interface];
5101
	if (empty($ifcfg)) {
5102
		$ifcfg = array();
5103
	}
5104

    
5105
	$dhclientconf_vlantag = "";
5106
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5107
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5108
	}
5109

    
5110
	/* generate dhclient_wan.conf */
5111
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5112
	if (!$fd) {
5113
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5114
		return 1;
5115
	}
5116

    
5117
	if ($ifcfg['dhcphostname']) {
5118
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5119
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5120
	} else {
5121
		$dhclientconf_hostname = "";
5122
	}
5123

    
5124
	$realif = get_real_interface($interface);
5125
	if (empty($realif)) {
5126
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5127
		return 0;
5128
	}
5129
	$dhclientconf = "";
5130

    
5131
	$dhclientconf .= <<<EOD
5132
interface "{$realif}" {
5133
	supersede interface-mtu 0;
5134
	timeout 60;
5135
	retry 15;
5136
	select-timeout 0;
5137
	initial-interval 1;
5138
	{$dhclientconf_vlantag}
5139
	{$dhclientconf_hostname}
5140
	script "/usr/local/sbin/pfSense-dhclient-script";
5141
EOD;
5142

    
5143
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5144
		$dhclientconf .= <<<EOD
5145

    
5146
	reject {$ifcfg['dhcprejectfrom']};
5147
EOD;
5148
	}
5149
	$dhclientconf .= <<<EOD
5150

    
5151
}
5152

    
5153
EOD;
5154

    
5155
	// DHCP Config File Advanced
5156
	if ($ifcfg['adv_dhcp_config_advanced']) {
5157
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5158
	}
5159

    
5160
	if (is_ipaddr($ifcfg['alias-address'])) {
5161
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5162
		$dhclientconf .= <<<EOD
5163
alias {
5164
	interface "{$realif}";
5165
	fixed-address {$ifcfg['alias-address']};
5166
	option subnet-mask {$subnetmask};
5167
}
5168

    
5169
EOD;
5170
	}
5171

    
5172
	// DHCP Config File Override
5173
	if ($ifcfg['adv_dhcp_config_file_override']) {
5174
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5175
	}
5176

    
5177
	fwrite($fd, $dhclientconf);
5178
	fclose($fd);
5179

    
5180
	/* bring wan interface up before starting dhclient */
5181
	if ($realif) {
5182
		interfaces_bring_up($realif);
5183
	}
5184

    
5185
	/* Make sure dhclient is not running */
5186
	kill_dhclient_process($realif);
5187

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

    
5191
	return 0;
5192
}
5193

    
5194
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5195

    
5196
	$hostname = "";
5197
	if ($ifcfg['dhcphostname'] != '') {
5198
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5199
	}
5200

    
5201
	/* DHCP Protocol Timings */
5202
	$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");
5203
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5204
		$pt_variable = "{$Protocol_Timing}";
5205
		${$pt_variable} = "";
5206
		if ($ifcfg[$Protocol_Timing] != "") {
5207
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5208
		}
5209
	}
5210

    
5211
	$send_options = "";
5212
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5213
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5214
		foreach ($options as $option) {
5215
			$send_options .= "\tsend " . trim($option) . ";\n";
5216
		}
5217
	}
5218

    
5219
	$request_options = "";
5220
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5221
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5222
	}
5223

    
5224
	$required_options = "";
5225
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5226
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5227
	}
5228

    
5229
	$option_modifiers = "";
5230
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5231
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5232
		foreach ($modifiers as $modifier) {
5233
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5234
		}
5235
	}
5236

    
5237
	$dhclientconf  = "interface \"{$realif}\" {\n";
5238
	$dhclientconf .= "\n";
5239
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5240
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5241
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5242
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5243
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5244
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5245
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5246
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5247
	$dhclientconf .= "\n";
5248
	$dhclientconf .= "# DHCP Protocol Options\n";
5249
	$dhclientconf .= "{$hostname}";
5250
	$dhclientconf .= "{$send_options}";
5251
	$dhclientconf .= "{$request_options}";
5252
	$dhclientconf .= "{$required_options}";
5253
	$dhclientconf .= "{$option_modifiers}";
5254
	$dhclientconf .= "\n";
5255
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5256
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5257
	}
5258
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5259
	$dhclientconf .= "}\n";
5260

    
5261
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5262

    
5263
	return $dhclientconf;
5264
}
5265

    
5266
function DHCP_Config_Option_Split($option_string) {
5267
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5268
	return $matches ? $matches[0] : [];
5269
}
5270

    
5271
function DHCP_Config_File_Override($ifcfg, $realif) {
5272

    
5273
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5274

    
5275
	if ($dhclientconf === false) {
5276
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5277
		return '';
5278
	} else {
5279
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5280
	}
5281
}
5282

    
5283

    
5284
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5285

    
5286
	/* Apply Interface Substitutions */
5287
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5288

    
5289
	/* Apply Hostname Substitutions */
5290
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5291

    
5292
	/* Arrays of MAC Address Types, Cases, Delimiters */
5293
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5294
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5295
	$various_mac_cases      = array("U", "L");
5296
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5297

    
5298
	/* Apply MAC Address Substitutions */
5299
	foreach ($various_mac_types as $various_mac_type) {
5300
		foreach ($various_mac_cases as $various_mac_case) {
5301
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5302

    
5303
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5304
				if ($res !== false) {
5305

    
5306
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5307
					if ("$various_mac_case" == "U") {
5308
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5309
					}
5310
					if ("$various_mac_case" == "L") {
5311
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5312
					}
5313

    
5314
					if ("$various_mac_type" == "mac_addr_hex") {
5315
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5316
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5317
						$dhcpclientconf_mac_hex = "";
5318
						$delimiter = "";
5319
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5320
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5321
							$delimiter = ":";
5322
						}
5323
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5324
					}
5325

    
5326
					/* MAC Address Delimiter Substitutions */
5327
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5328

    
5329
					/* Apply MAC Address Substitutions */
5330
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5331
				}
5332
			}
5333
		}
5334
	}
5335

    
5336
	return $dhclientconf;
5337
}
5338

    
5339
function interfaces_group_setup() {
5340
	global $config;
5341

    
5342
	if (!isset($config['ifgroups']['ifgroupentry']) || !is_array($config['ifgroups']['ifgroupentry'])) {
5343
		return;
5344
	}
5345

    
5346
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5347
		interface_group_setup($groupar);
5348
	}
5349

    
5350
	return;
5351
}
5352

    
5353
function interface_group_setup(&$groupname /* The parameter is an array */) {
5354
	global $config;
5355

    
5356
	if (!is_array($groupname)) {
5357
		return;
5358
	}
5359
	$members = explode(" ", $groupname['members']);
5360
	foreach ($members as $ifs) {
5361
		$realif = get_real_interface($ifs);
5362
		if ($realif && does_interface_exist($realif)) {
5363
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5364
		}
5365
	}
5366

    
5367
	return;
5368
}
5369

    
5370
function is_interface_group($if) {
5371
	global $config;
5372

    
5373
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5374
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5375
			if ($groupentry['ifname'] === $if) {
5376
				return true;
5377
			}
5378
		}
5379
	}
5380

    
5381
	return false;
5382
}
5383

    
5384
function interface_group_add_member($interface, $groupname) {
5385
	$interface = get_real_interface($interface);
5386
	if (does_interface_exist($interface)) {
5387
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5388
	}
5389
}
5390

    
5391
/* COMPAT Function */
5392
function convert_friendly_interface_to_real_interface_name($interface) {
5393
	return get_real_interface($interface);
5394
}
5395

    
5396
/* COMPAT Function */
5397
function get_real_wan_interface($interface = "wan") {
5398
	return get_real_interface($interface);
5399
}
5400

    
5401
/* COMPAT Function */
5402
function get_current_wan_address($interface = "wan") {
5403
	return get_interface_ip($interface);
5404
}
5405

    
5406
/*
5407
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5408
 */
5409
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5410
	global $config;
5411

    
5412
	/* XXX: For speed reasons reference directly the interface array */
5413
	init_config_arr(array('interfaces'));
5414
	$ifdescrs = &$config['interfaces'];
5415
	//$ifdescrs = get_configured_interface_list(true);
5416

    
5417
	foreach ($ifdescrs as $if => $ifname) {
5418
		if ($if == $interface || $ifname['if'] == $interface) {
5419
			return $if;
5420
		}
5421

    
5422
		if (get_real_interface($if) == $interface) {
5423
			return $if;
5424
		}
5425

    
5426
		if ($checkparent == false) {
5427
			continue;
5428
		}
5429

    
5430
		$int = get_parent_interface($if, true);
5431
		if (is_array($int)) {
5432
			foreach ($int as $iface) {
5433
				if ($iface == $interface) {
5434
					return $if;
5435
				}
5436
			}
5437
		}
5438
	}
5439

    
5440
	if ($interface == "enc0") {
5441
		return 'IPsec';
5442
	}
5443
}
5444

    
5445
/* attempt to resolve interface to friendly descr */
5446
function convert_friendly_interface_to_friendly_descr($interface) {
5447
	global $config;
5448

    
5449
	switch ($interface) {
5450
		case "l2tp":
5451
			$ifdesc = "L2TP";
5452
			break;
5453
		case "pptp":
5454
			$ifdesc = "PPTP";
5455
			break;
5456
		case "pppoe":
5457
			$ifdesc = "PPPoE";
5458
			break;
5459
		case "openvpn":
5460
			$ifdesc = "OpenVPN";
5461
			break;
5462
		case "lo0":
5463
			$ifdesc = "Loopback";
5464
			break;
5465
		case "enc0":
5466
		case "ipsec":
5467
		case "IPsec":
5468
			$ifdesc = "IPsec";
5469
			break;
5470
		default:
5471
			if (isset($config['interfaces'][$interface])) {
5472
				if (empty($config['interfaces'][$interface]['descr'])) {
5473
					$ifdesc = strtoupper($interface);
5474
				} else {
5475
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5476
				}
5477
				break;
5478
			} else if (substr($interface, 0, 4) == '_vip') {
5479
				if (is_array($config['virtualip']['vip'])) {
5480
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5481
						if ($vip['mode'] == "carp") {
5482
							if ($interface == "_vip{$vip['uniqid']}") {
5483
								$descr = $vip['subnet'];
5484
								$descr .= " (vhid {$vip['vhid']})";
5485
								if (!empty($vip['descr'])) {
5486
									$descr .= " - " .$vip['descr'];
5487
								}
5488
								return $descr;
5489
							}
5490
						}
5491
					}
5492
				}
5493
			} else if (substr($interface, 0, 5) == '_lloc') {
5494
				return get_interface_linklocal($interface);
5495
			} else {
5496
				if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5497
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5498
						if ($ifgen['ifname'] === $interface) {
5499
							return $ifgen['ifname'];
5500
						}
5501
					}
5502
				}
5503

    
5504
				/* if list */
5505
				$ifdescrs = get_configured_interface_with_descr(true);
5506
				foreach ($ifdescrs as $if => $ifname) {
5507
					if ($if == $interface || $ifname == $interface) {
5508
						return $ifname;
5509
					}
5510
				}
5511
			}
5512
			break;
5513
	}
5514

    
5515
	return $ifdesc;
5516
}
5517

    
5518
function convert_real_interface_to_friendly_descr($interface) {
5519

    
5520
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5521

    
5522
	if (!empty($ifdesc)) {
5523
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5524
	}
5525

    
5526
	return $interface;
5527
}
5528

    
5529
/*
5530
 *  get_parent_interface($interface):
5531
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5532
 *				or virtual interface (i.e. vlan)
5533
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5534
 *			-- returns $interface passed in if $interface parent is not found
5535
 *			-- returns empty array if an invalid interface is passed
5536
 *	(Only handles ppps and vlans now.)
5537
 */
5538
function get_parent_interface($interface, $avoidrecurse = false) {
5539
	global $config;
5540

    
5541
	$parents = array();
5542
	//Check that we got a valid interface passed
5543
	$realif = get_real_interface($interface);
5544
	if ($realif == NULL) {
5545
		return $parents;
5546
	}
5547

    
5548
	// If we got a real interface, find it's friendly assigned name
5549
	if ($interface == $realif && $avoidrecurse == false) {
5550
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5551
	}
5552

    
5553
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5554
		$ifcfg = $config['interfaces'][$interface];
5555
		switch ($ifcfg['ipaddr']) {
5556
			case "ppp":
5557
			case "pppoe":
5558
			case "pptp":
5559
			case "l2tp":
5560
				if (empty($parents)) {
5561
					if (is_array($config['ppps']['ppp'])) {
5562
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5563
							if ($ifcfg['if'] == $ppp['if']) {
5564
								$ports = explode(',', $ppp['ports']);
5565
								foreach ($ports as $pid => $parent_if) {
5566
									$parents[$pid] = get_real_interface($parent_if);
5567
								}
5568
								break;
5569
							}
5570
						}
5571
					}
5572
				}
5573
				break;
5574
			case "dhcp":
5575
			case "static":
5576
			default:
5577
				// Handle _vlans
5578
				$vlan = interface_is_vlan($ifcfg['if']);
5579
				if ($vlan != NULL) {
5580
					$parents[0] = $vlan['if'];
5581
				}
5582
				break;
5583
		}
5584
	}
5585

    
5586
	if (empty($parents)) {
5587
		// Handle _vlans not assigned to an interface
5588
		$vlan = interface_is_vlan($realif);
5589
		if ($vlan != NULL) {
5590
			$parents[0] = $vlan['if'];
5591
		}
5592
	}
5593

    
5594
	if (empty($parents)) {
5595
		/* Handle LAGGs. */
5596
		$lagg = interface_is_type($realif, 'lagg');
5597
		if ($lagg != NULL && isset($lagg['members'])) {
5598
			$parents = explode(",", $lagg['members']);
5599
		}
5600
	}
5601

    
5602
	if (empty($parents)) {
5603
		$parents[0] = $realif;
5604
	}
5605

    
5606
	return $parents;
5607
}
5608

    
5609
/*
5610
 *  get_parent_physical_interface($interface):
5611
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5612
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5613
 */
5614
function get_parent_physical_interface($interface) {
5615
	global $config;
5616

    
5617
	$realif = get_parent_interface($interface);
5618

    
5619
	if (substr($realif[0], 0, 4) == "lagg") {
5620
		foreach ($config['laggs']['lagg'] as $lagg) {
5621
			if ($realif[0] == $lagg['laggif']) {
5622
				return explode(",", $lagg['members']);
5623
			}
5624
		}
5625
	} else {
5626
		return $realif;
5627
	}
5628
}
5629

    
5630
function interface_is_wireless_clone($wlif) {
5631
	if (!stristr($wlif, "_wlan")) {
5632
		return false;
5633
	} else {
5634
		return true;
5635
	}
5636
}
5637

    
5638
function interface_get_wireless_base($wlif) {
5639
	if (!stristr($wlif, "_wlan")) {
5640
		return $wlif;
5641
	} else {
5642
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5643
	}
5644
}
5645

    
5646
function interface_get_wireless_clone($wlif) {
5647
	if (!stristr($wlif, "_wlan")) {
5648
		return $wlif . "_wlan0";
5649
	} else {
5650
		return $wlif;
5651
	}
5652
}
5653

    
5654
function interface_list_wireless() {
5655
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5656

    
5657
	$result = array();
5658
	foreach ($portlist as $port) {
5659
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5660
			continue;
5661
		}
5662

    
5663
		$desc = $port . " ( " . get_single_sysctl(
5664
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5665

    
5666
		$result[] = array(
5667
		    "if" => $port,
5668
		    "descr" => $desc
5669
		);
5670
	}
5671

    
5672
	return $result;
5673
}
5674

    
5675
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
5676
	global $config, $g;
5677

    
5678
	$wanif = NULL;
5679

    
5680
	switch ($interface) {
5681
		case "l2tp":
5682
			$wanif = "l2tp";
5683
			break;
5684
		case "pptp":
5685
			$wanif = "pptp";
5686
			break;
5687
		case "pppoe":
5688
			$wanif = "pppoe";
5689
			break;
5690
		case "openvpn":
5691
			$wanif = "openvpn";
5692
			break;
5693
		case "IPsec":
5694
		case "ipsec":
5695
		case "enc0":
5696
			$wanif = "enc0";
5697
			break;
5698
		case "ppp":
5699
			$wanif = "ppp";
5700
			break;
5701
		default:
5702
			if (substr($interface, 0, 4) == '_vip') {
5703
				$wanif = get_configured_vip_interface($interface);
5704
				if (!empty($wanif)) {
5705
					$wanif = get_real_interface($wanif);
5706
				}
5707
				break;
5708
			} else if (substr($interface, 0, 5) == '_lloc') {
5709
				$interface = substr($interface, 5);
5710
			} else if (interface_is_vlan($interface) != NULL ||
5711
			    does_interface_exist($interface, $flush)) {
5712
				/*
5713
				 * If a real interface was already passed simply
5714
				 * pass the real interface back.  This encourages
5715
				 * the usage of this function in more cases so that
5716
				 * we can combine logic for more flexibility.
5717
				 */
5718
				$wanif = $interface;
5719
				break;
5720
			}
5721

    
5722
			if (empty($config['interfaces'][$interface])) {
5723
				break;
5724
			}
5725

    
5726
			$cfg = &$config['interfaces'][$interface];
5727

    
5728
			if ($family == "inet6") {
5729
				switch ($cfg['ipaddrv6']) {
5730
					case "6rd":
5731
					case "6to4":
5732
						$wanif = "{$interface}_stf";
5733
						break;
5734
					case 'pppoe':
5735
					case 'ppp':
5736
					case 'l2tp':
5737
					case 'pptp':
5738
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5739
							$wanif = interface_get_wireless_clone($cfg['if']);
5740
						} else {
5741
							$wanif = $cfg['if'];
5742
						}
5743
						break;
5744
					default:
5745
						switch ($cfg['ipaddr']) {
5746
							case 'pppoe':
5747
							case 'ppp':
5748
							case 'l2tp':
5749
							case 'pptp':
5750
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
5751
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) || 
5752
								    isset($cfg['ipv6usev4iface']) || isset($cfg['slaacusev4iface'])) {
5753
									$wanif = $cfg['if'];
5754
								} else {
5755
									$parents = get_parent_interface($interface);
5756
									if (!empty($parents[0])) {
5757
										$wanif = $parents[0];
5758
									} else {
5759
										$wanif = $cfg['if'];
5760
									}
5761
								}
5762
								break;
5763
							default:
5764
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5765
									$wanif = interface_get_wireless_clone($cfg['if']);
5766
								} else {
5767
									$wanif = $cfg['if'];
5768
								}
5769
								break;
5770
						}
5771
						break;
5772
				}
5773
			} else {
5774
				// Wireless cloned NIC support (FreeBSD 8+)
5775
				// interface name format: $parentnic_wlanparentnic#
5776
				// example: ath0_wlan0
5777
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5778
					$wanif = interface_get_wireless_clone($cfg['if']);
5779
				} else {
5780
					$wanif = $cfg['if'];
5781
				}
5782
			}
5783
			break;
5784
	}
5785

    
5786
	return $wanif;
5787
}
5788

    
5789
/* Guess the physical interface by providing a IP address */
5790
function guess_interface_from_ip($ipaddress) {
5791

    
5792
	$family = '';
5793
	if (is_ipaddrv4($ipaddress)) {
5794
		$family = 'inet';
5795
	}
5796
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5797
		$family = 'inet6';
5798
	}
5799

    
5800
	if (empty($family)) {
5801
		return false;
5802
	}
5803

    
5804
	/* create a route table we can search */
5805
	$output = '';
5806
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
5807
	$output[0] = trim($output[0], " \n");
5808
	if (!empty($output[0])) {
5809
		return $output[0];
5810
	}
5811

    
5812
	return false;
5813
}
5814

    
5815
/*
5816
 * find_ip_interface($ip): return the interface where an ip is defined
5817
 *   (or if $bits is specified, where an IP within the subnet is defined)
5818
 */
5819
function find_ip_interface($ip, $bits = null) {
5820
	if (!is_ipaddr($ip)) {
5821
		return false;
5822
	}
5823

    
5824
	$isv6ip = is_ipaddrv6($ip);
5825

    
5826
	/* if list */
5827
	$ifdescrs = get_configured_interface_list();
5828

    
5829
	foreach ($ifdescrs as $ifdescr => $ifname) {
5830
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
5831
		if (is_null($ifip)) {
5832
			continue;
5833
		}
5834
		if (is_null($bits)) {
5835
			if ($ip == $ifip) {
5836
				$int = get_real_interface($ifname);
5837
				return $int;
5838
			}
5839
		} else {
5840
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
5841
				$int = get_real_interface($ifname);
5842
				return $int;
5843
			}
5844
		}
5845
	}
5846

    
5847
	return false;
5848
}
5849

    
5850
/*
5851
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5852
 *   (or if $bits is specified, where an IP within the subnet is found)
5853
 */
5854
function find_virtual_ip_alias($ip, $bits = null) {
5855
	global $config;
5856

    
5857
	if (!is_array($config['virtualip']['vip'])) {
5858
		return false;
5859
	}
5860
	if (!is_ipaddr($ip)) {
5861
		return false;
5862
	}
5863

    
5864
	$isv6ip = is_ipaddrv6($ip);
5865

    
5866
	foreach ($config['virtualip']['vip'] as $vip) {
5867
		if ($vip['mode'] === "ipalias") {
5868
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
5869
				continue;
5870
			}
5871
			if (is_null($bits)) {
5872
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
5873
					return $vip;
5874
				}
5875
			} else {
5876
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5877
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5878
					return $vip;
5879
				}
5880
			}
5881
		}
5882
	}
5883
	return false;
5884
}
5885

    
5886
function link_interface_to_track6($int, $action = "") {
5887
	global $config;
5888

    
5889
	if (empty($int)) {
5890
		return;
5891
	}
5892

    
5893
	if (is_array($config['interfaces'])) {
5894
		$list = array();
5895
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5896
			if (!isset($ifcfg['enable'])) {
5897
				continue;
5898
			}
5899
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5900
				if ($action == "update") {
5901
					interface_track6_configure($ifname, $ifcfg);
5902
				} else if ($action == "") {
5903
					$list[$ifname] = $ifcfg;
5904
				}
5905
			}
5906
		}
5907
		return $list;
5908
	}
5909
}
5910

    
5911
function interface_find_child_cfgmtu($realiface) {
5912
	global $config;
5913

    
5914
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5915
	$vlans = link_interface_to_vlans($realiface);
5916
	$qinqs = link_interface_to_qinqs($realiface);
5917
	$bridge = link_interface_to_bridge($realiface);
5918
	if (!empty($interface)) {
5919
		$gifs = link_interface_to_gif($interface);
5920
		$gres = link_interface_to_gre($interface);
5921
	} else {
5922
		$gifs = array();
5923
		$gres = array();
5924
	}
5925

    
5926
	$mtu = 0;
5927
	if (is_array($vlans)) {
5928
		foreach ($vlans as $vlan) {
5929
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5930
			if (empty($ifass)) {
5931
				continue;
5932
			}
5933
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5934
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5935
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5936
				}
5937
			}
5938
		}
5939
	}
5940
	if (is_array($qinqs)) {
5941
		foreach ($qinqs as $qinq) {
5942
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5943
			if (empty($ifass)) {
5944
				continue;
5945
			}
5946
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5947
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5948
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5949
				}
5950
			}
5951
		}
5952
	}
5953
	if (is_array($gifs)) {
5954
		foreach ($gifs as $gif) {
5955
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5956
			if (empty($ifass)) {
5957
				continue;
5958
			}
5959
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5960
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5961
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5962
				}
5963
			}
5964
		}
5965
	}
5966
	if (is_array($gres)) {
5967
		foreach ($gres as $gre) {
5968
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5969
			if (empty($ifass)) {
5970
				continue;
5971
			}
5972
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5973
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5974
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5975
				}
5976
			}
5977
		}
5978
	}
5979
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5980
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5981
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5982
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5983
		}
5984
	}
5985
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5986

    
5987
	return $mtu;
5988
}
5989

    
5990
function link_interface_to_vlans($int, $action = "") {
5991
	global $config;
5992

    
5993
	if (empty($int)) {
5994
		return;
5995
	}
5996

    
5997
	if (is_array($config['vlans']['vlan'])) {
5998
		$ifaces = array();
5999
		foreach ($config['vlans']['vlan'] as $vlan) {
6000
			if ($int == $vlan['if']) {
6001
				if ($action == "update") {
6002
					interfaces_bring_up($int);
6003
				} else {
6004
					$ifaces[$vlan['tag']] = $vlan;
6005
				}
6006
			}
6007
		}
6008
		if (!empty($ifaces)) {
6009
			return $ifaces;
6010
		}
6011
	}
6012
}
6013

    
6014
function link_interface_to_qinqs($int, $action = "") {
6015
	global $config;
6016

    
6017
	if (empty($int)) {
6018
		return;
6019
	}
6020

    
6021
	if (is_array($config['qinqs']['qinqentry'])) {
6022
		$ifaces = array();
6023
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
6024
			if ($int == $qinq['if']) {
6025
				if ($action == "update") {
6026
					interfaces_bring_up($int);
6027
				} else {
6028
					$ifaces[$qinq['tag']] = $qinq;
6029
				}
6030
			}
6031
		}
6032
		if (!empty($ifaces)) {
6033
			return $ifaces;
6034
		}
6035
	}
6036
}
6037

    
6038
function link_interface_to_vips($int, $action = "", $vhid = '') {
6039
	global $config;
6040

    
6041
	$updatevips = false;
6042
	if (is_array($config['virtualip']['vip'])) {
6043
		$result = array();
6044
		foreach ($config['virtualip']['vip'] as $vip) {
6045
			if (substr($vip['interface'], 0, 4) == "_vip") {
6046
				$iface = get_configured_vip_interface($vip['interface']);
6047
			} else {
6048
				$iface = $vip['interface'];
6049
			}
6050
			if ($int != $iface) {
6051
				continue;
6052
			}
6053
			if ($action == "update") {
6054
				$updatevips = true;
6055
			} else {
6056
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
6057
				    substr($vip['interface'], 0, 4) == "_vip") {
6058
					$result[] = $vip;
6059
				}
6060
			}
6061
		}
6062
		if ($updatevips === true) {
6063
			interfaces_vips_configure($int);
6064
		}
6065
		return $result;
6066
	}
6067

    
6068
	return NULL;
6069
}
6070

    
6071
/****f* interfaces/link_interface_to_bridge
6072
 * NAME
6073
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6074
 * INPUTS
6075
 *   $ip
6076
 * RESULT
6077
 *   bridge[0-99]
6078
 ******/
6079
function link_interface_to_bridge($int) {
6080
	global $config;
6081

    
6082
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6083
		foreach ($config['bridges']['bridged'] as $bridge) {
6084
			if (in_array($int, explode(',', $bridge['members']))) {
6085
				return "{$bridge['bridgeif']}";
6086
			}
6087
		}
6088
	}
6089
}
6090

    
6091
function link_interface_to_group($int) {
6092
	global $config;
6093

    
6094
	$result = array();
6095

    
6096
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6097
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6098
			if (in_array($int, explode(" ", $group['members']))) {
6099
				$result[$group['ifname']] = $int;
6100
			}
6101
		}
6102
	}
6103

    
6104
	return $result;
6105
}
6106

    
6107
function link_interface_to_gre($interface) {
6108
	global $config;
6109

    
6110
	$result = array();
6111

    
6112
	if (is_array($config['gres']['gre'])) {
6113
		foreach ($config['gres']['gre'] as $gre) {
6114
			if ($gre['if'] == $interface) {
6115
				$result[] = $gre;
6116
			}
6117
		}
6118
	}
6119

    
6120
	return $result;
6121
}
6122

    
6123
function link_interface_to_gif($interface) {
6124
	global $config;
6125

    
6126
	$result = array();
6127

    
6128
	if (is_array($config['gifs']['gif'])) {
6129
		foreach ($config['gifs']['gif'] as $gif) {
6130
			if ($gif['if'] == $interface) {
6131
				$result[] = $gif;
6132
			}
6133
		}
6134
	}
6135

    
6136
	return $result;
6137
}
6138

    
6139
/*
6140
 * find_interface_ip($interface): return the interface ip (first found)
6141
 */
6142
function find_interface_ip($interface, $flush = false) {
6143
	global $interface_ip_arr_cache;
6144
	global $interface_sn_arr_cache;
6145

    
6146
	$interface = str_replace("\n", "", $interface);
6147

    
6148
	if (!does_interface_exist($interface)) {
6149
		return;
6150
	}
6151

    
6152
	/* Setup IP cache */
6153
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6154
		if (file_exists("/var/db/${interface}_ip")) {
6155
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6156
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6157
			foreach ($ifaddrs as $ifaddr) {
6158
				list($ip, $mask) = explode("/", $ifaddr);
6159
				if ($ip == $ifip) {
6160
					$interface_ip_arr_cache[$interface] = $ip;
6161
					$interface_sn_arr_cache[$interface] = $mask;
6162
					break;
6163
				}
6164
			}
6165
		}
6166
		if (!isset($interface_ip_arr_cache[$interface])) {
6167
			$ifinfo = pfSense_get_interface_addresses($interface);
6168
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6169
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6170
		}
6171
	}
6172

    
6173
	return $interface_ip_arr_cache[$interface];
6174
}
6175

    
6176
/*
6177
 * find_interface_ipv6($interface): return the interface ip (first found)
6178
 */
6179
function find_interface_ipv6($interface, $flush = false) {
6180
	global $interface_ipv6_arr_cache;
6181
	global $interface_snv6_arr_cache;
6182
	global $config;
6183

    
6184
	$interface = trim($interface);
6185
	$interface = get_real_interface($interface);
6186

    
6187
	if (!does_interface_exist($interface)) {
6188
		return;
6189
	}
6190

    
6191
	/* Setup IP cache */
6192
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6193
		$ifinfo = pfSense_get_interface_addresses($interface);
6194
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6195
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6196
	}
6197

    
6198
	return $interface_ipv6_arr_cache[$interface];
6199
}
6200

    
6201
/*
6202
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6203
 */
6204
function find_interface_ipv6_ll($interface, $flush = false) {
6205
	global $interface_llv6_arr_cache;
6206
	global $config;
6207

    
6208
	$interface = str_replace("\n", "", $interface);
6209

    
6210
	if (!does_interface_exist($interface)) {
6211
		return;
6212
	}
6213

    
6214
	/* Setup IP cache */
6215
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6216
		$ifinfo = pfSense_getall_interface_addresses($interface);
6217
		foreach ($ifinfo as $line) {
6218
			if (strstr($line, ":")) {
6219
				$parts = explode("/", $line);
6220
				if (is_linklocal($parts[0])) {
6221
					$ifinfo['linklocal'] = $parts[0];
6222
				}
6223
			}
6224
		}
6225
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6226
	}
6227
	return $interface_llv6_arr_cache[$interface];
6228
}
6229

    
6230
function find_interface_subnet($interface, $flush = false) {
6231
	global $interface_sn_arr_cache;
6232
	global $interface_ip_arr_cache;
6233

    
6234
	$interface = str_replace("\n", "", $interface);
6235
	if (does_interface_exist($interface) == false) {
6236
		return;
6237
	}
6238

    
6239
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6240
		$ifinfo = pfSense_get_interface_addresses($interface);
6241
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6242
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6243
	}
6244

    
6245
	return $interface_sn_arr_cache[$interface];
6246
}
6247

    
6248
function find_interface_subnetv6($interface, $flush = false) {
6249
	global $interface_snv6_arr_cache;
6250
	global $interface_ipv6_arr_cache;
6251

    
6252
	$interface = str_replace("\n", "", $interface);
6253
	if (does_interface_exist($interface) == false) {
6254
		return;
6255
	}
6256

    
6257
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6258
		$ifinfo = pfSense_get_interface_addresses($interface);
6259
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6260
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6261
	}
6262

    
6263
	return $interface_snv6_arr_cache[$interface];
6264
}
6265

    
6266
function ip_in_interface_alias_subnet($interface, $ipalias) {
6267
	global $config;
6268

    
6269
	if (empty($interface) || !is_ipaddr($ipalias)) {
6270
		return false;
6271
	}
6272
	if (is_array($config['virtualip']['vip'])) {
6273
		foreach ($config['virtualip']['vip'] as $vip) {
6274
			switch ($vip['mode']) {
6275
				case "ipalias":
6276
					if ($vip['interface'] <> $interface) {
6277
						break;
6278
					}
6279
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6280
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6281
						return true;
6282
					}
6283
					break;
6284
			}
6285
		}
6286
	}
6287

    
6288
	return false;
6289
}
6290

    
6291
function get_possible_listen_ips($include_ipv6_link_local=false) {
6292

    
6293
	$interfaces = get_configured_interface_with_descr();
6294
	foreach ($interfaces as $iface => $ifacename) {
6295
		if ($include_ipv6_link_local) {
6296
			/* This is to avoid going though added ll below */
6297
			if (substr($iface, 0, 5) == '_lloc') {
6298
				continue;
6299
			}
6300
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6301
			if (!empty($llip)) {
6302
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6303
			}
6304
		}
6305
	}
6306
	$viplist = get_configured_vip_list();
6307
	foreach ($viplist as $vip => $address) {
6308
		$interfaces[$vip] = $address;
6309
		if (get_vip_descr($address)) {
6310
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6311
		}
6312
	}
6313

    
6314
	$interfaces['lo0'] = 'Localhost';
6315

    
6316
	return $interfaces;
6317
}
6318

    
6319
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6320
	global $config;
6321

    
6322
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6323
	foreach (array('server', 'client') as $mode) {
6324
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6325
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6326
				if (!isset($setting['disable'])) {
6327
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6328
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6329
				}
6330
			}
6331
		}
6332
	}
6333
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
6334
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
6335
			if ($ph1ent['disabled']) {
6336
				continue;
6337
			}
6338
			if (ipsec_vti($ph1ent)) {
6339
				$sourceips_key = "ipsec{$ph1ent['ikeid']}";
6340
				$sourceips[$sourceips_key] = gettext("IPsec VTI") . ": " . htmlspecialchars($ph1ent['descr']);
6341
			}
6342
		}
6343
	}
6344
	return $sourceips;
6345
}
6346

    
6347
function get_interface_ip($interface = "wan") {
6348
	global $config;
6349

    
6350
	if (substr($interface, 0, 4) == '_vip') {
6351
		return get_configured_vip_ipv4($interface);
6352
	} else if (substr($interface, 0, 5) == '_lloc') {
6353
		/* No link-local address for v4. */
6354
		return null;
6355
	}
6356

    
6357
	$realif = get_failover_interface($interface, 'inet');
6358
	if (!$realif) {
6359
		return null;
6360
	}
6361

    
6362
	if (substr($realif, 0, 4) == '_vip') {
6363
		return get_configured_vip_ipv4($realif);
6364
	} else if (substr($realif, 0, 5) == '_lloc') {
6365
		/* No link-local address for v4. */
6366
		return null;
6367
	}
6368

    
6369
	if (is_array($config['interfaces'][$interface]) &&
6370
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6371
		return ($config['interfaces'][$interface]['ipaddr']);
6372
	}
6373

    
6374
	/*
6375
	 * Beaware that find_interface_ip() is our last option, it will
6376
	 * return the first IP it find on interface, not necessarily the
6377
	 * main IP address.
6378
	 */
6379
	$curip = find_interface_ip($realif);
6380
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6381
		return $curip;
6382
	} else {
6383
		return null;
6384
	}
6385
}
6386

    
6387
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6388
	global $config;
6389

    
6390
	if (substr($interface, 0, 4) == '_vip') {
6391
		return get_configured_vip_ipv6($interface);
6392
	} else if (substr($interface, 0, 5) == '_lloc') {
6393
		return get_interface_linklocal($interface);
6394
	}
6395

    
6396
	$realif = get_failover_interface($interface, 'inet6');
6397
	if (!$realif) {
6398
		return null;
6399
	}
6400

    
6401
	if (substr($realif, 0, 4) == '_vip') {
6402
		return get_configured_vip_ipv6($realif);
6403
	} else if (substr($realif, 0, 5) == '_lloc') {
6404
		return get_interface_linklocal($realif);
6405
	}
6406

    
6407
	if (is_array($config['interfaces'][$interface])) {
6408
		switch ($config['interfaces'][$interface]['ipaddr']) {
6409
			case 'pppoe':
6410
			case 'l2tp':
6411
			case 'pptp':
6412
			case 'ppp':
6413
				if (($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') ||
6414
				    ($config['interfaces'][$interface]['ipaddrv6'] == 'slaac')) {
6415
					$realif = get_real_interface($interface, 'inet6', false);
6416
				}
6417
				break;
6418
		}
6419
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6420
			return ($config['interfaces'][$interface]['ipaddrv6']);
6421
		}
6422
	}
6423

    
6424
	/*
6425
	 * Beaware that find_interface_ip() is our last option, it will
6426
	 * return the first IP it find on interface, not necessarily the
6427
	 * main IP address.
6428
	 */
6429
	$curip = find_interface_ipv6($realif, $flush);
6430
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6431
		return $curip;
6432
	} else {
6433
		/*
6434
		 * NOTE: On the case when only the prefix is requested,
6435
		 * the communication on WAN will be done over link-local.
6436
		 */
6437
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6438
			$curip = find_interface_ipv6_ll($realif, $flush);
6439
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6440
				return $curip;
6441
			}
6442
		}
6443
	}
6444
	return null;
6445
}
6446

    
6447
function get_interface_linklocal($interface = "wan") {
6448

    
6449
	$realif = get_failover_interface($interface, 'inet6');
6450
	if (!$realif) {
6451
		return null;
6452
	}
6453

    
6454
	if (substr($interface, 0, 4) == '_vip') {
6455
		$realif = get_real_interface($interface);
6456
	} else if (substr($interface, 0, 5) == '_lloc') {
6457
		$realif = get_real_interface(substr($interface, 5));
6458
	}
6459

    
6460
	$curip = find_interface_ipv6_ll($realif);
6461
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6462
		return $curip;
6463
	} else {
6464
		return null;
6465
	}
6466
}
6467

    
6468
function get_interface_subnet($interface = "wan") {
6469
	global $config;
6470

    
6471
	if (substr($interface, 0, 4) == '_vip') {
6472
		return (get_configured_vip_subnetv4($interface));
6473
	}
6474

    
6475
	if (is_array($config['interfaces'][$interface]) &&
6476
		!empty($config['interfaces'][$interface]['subnet'])) {
6477
		return ($config['interfaces'][$interface]['subnet']);
6478
	}
6479

    
6480
	$realif = get_real_interface($interface);
6481
	if (!$realif) {
6482
		return (NULL);
6483
	}
6484

    
6485
	$cursn = find_interface_subnet($realif);
6486
	if (!empty($cursn)) {
6487
		return ($cursn);
6488
	}
6489

    
6490
	return (NULL);
6491
}
6492

    
6493
function get_interface_subnetv6($interface = "wan") {
6494
	global $config;
6495

    
6496
	if (substr($interface, 0, 4) == '_vip') {
6497
		return (get_configured_vip_subnetv6($interface));
6498
	} else if (substr($interface, 0, 5) == '_lloc') {
6499
		$interface = substr($interface, 5);
6500
	}
6501

    
6502
	if (is_array($config['interfaces'][$interface]) &&
6503
		!empty($config['interfaces'][$interface]['subnetv6'])) {
6504
		return ($config['interfaces'][$interface]['subnetv6']);
6505
	}
6506

    
6507
	$realif = get_real_interface($interface, 'inet6');
6508
	if (!$realif) {
6509
		return (NULL);
6510
	}
6511

    
6512
	$cursn = find_interface_subnetv6($realif);
6513
	if (!empty($cursn)) {
6514
		return ($cursn);
6515
	}
6516

    
6517
	return (NULL);
6518
}
6519

    
6520
/* return outside interfaces with a gateway */
6521
function get_interfaces_with_gateway() {
6522
	global $config;
6523

    
6524
	$ints = array();
6525

    
6526
	/* loop interfaces, check config for outbound */
6527
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6528
		switch ($ifname['ipaddr']) {
6529
			case "dhcp":
6530
			case "pppoe":
6531
			case "pptp":
6532
			case "l2tp":
6533
			case "ppp":
6534
				$ints[$ifdescr] = $ifdescr;
6535
				break;
6536
			default:
6537
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6538
				    !empty($ifname['gateway'])) {
6539
					$ints[$ifdescr] = $ifdescr;
6540
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6541
				    !empty($ifname['gateway'])) {
6542
					$ints[$ifdescr] = $ifdescr;
6543
				}
6544

    
6545
				break;
6546
		}
6547
	}
6548
	return $ints;
6549
}
6550

    
6551
/* return true if interface has a gateway */
6552
function interface_has_gateway($friendly) {
6553
	global $config;
6554

    
6555
	if (!empty($config['interfaces'][$friendly])) {
6556
		$ifname = &$config['interfaces'][$friendly];
6557
		switch ($ifname['ipaddr']) {
6558
			case "dhcp":
6559
			case "pppoe":
6560
			case "pptp":
6561
			case "l2tp":
6562
			case "ppp":
6563
				return true;
6564
			break;
6565
			default:
6566
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6567
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6568
					return true;
6569
				}
6570
				$tunnelif = substr($ifname['if'], 0, 3);
6571
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6572
					if (find_interface_ip($ifname['if'])) {
6573
						return true;
6574
					}
6575
				}
6576
				if (!empty($ifname['gateway'])) {
6577
					return true;
6578
				}
6579
			break;
6580
		}
6581
	}
6582

    
6583
	return false;
6584
}
6585

    
6586
/* return true if interface has a gateway */
6587
function interface_has_gatewayv6($friendly) {
6588
	global $config;
6589

    
6590
	if (!empty($config['interfaces'][$friendly])) {
6591
		$ifname = &$config['interfaces'][$friendly];
6592
		switch ($ifname['ipaddrv6']) {
6593
			case "slaac":
6594
			case "dhcp6":
6595
			case "6to4":
6596
			case "6rd":
6597
				return true;
6598
				break;
6599
			default:
6600
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6601
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6602
					return true;
6603
				}
6604
				$tunnelif = substr($ifname['if'], 0, 3);
6605
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6606
					if (find_interface_ipv6($ifname['if'])) {
6607
						return true;
6608
					}
6609
				}
6610
				if (!empty($ifname['gatewayv6'])) {
6611
					return true;
6612
				}
6613
				break;
6614
		}
6615
	}
6616

    
6617
	return false;
6618
}
6619

    
6620
/****f* interfaces/is_altq_capable
6621
 * NAME
6622
 *   is_altq_capable - Test if interface is capable of using ALTQ
6623
 * INPUTS
6624
 *   $int            - string containing interface name
6625
 * RESULT
6626
 *   boolean         - true or false
6627
 ******/
6628

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

    
6644
	$int_family = remove_ifindex($int);
6645

    
6646
	if (in_array($int_family, $capable)) {
6647
		return true;
6648
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6649
		return true;
6650
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6651
		return true;
6652
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6653
		return true;
6654
	} else {
6655
		return false;
6656
	}
6657
}
6658

    
6659
/****f* interfaces/is_interface_wireless
6660
 * NAME
6661
 *   is_interface_wireless - Returns if an interface is wireless
6662
 * RESULT
6663
 *   $tmp       - Returns if an interface is wireless
6664
 ******/
6665
function is_interface_wireless($interface) {
6666
	global $config, $g;
6667

    
6668
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6669
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6670
		if (preg_match($g['wireless_regex'], $interface)) {
6671
			if (isset($config['interfaces'][$friendly])) {
6672
				$config['interfaces'][$friendly]['wireless'] = array();
6673
			}
6674
			return true;
6675
		}
6676
		return false;
6677
	} else {
6678
		return true;
6679
	}
6680
}
6681

    
6682
function get_wireless_modes($interface) {
6683
	/* return wireless modes and channels */
6684
	$wireless_modes = array();
6685

    
6686
	$cloned_interface = get_real_interface($interface);
6687

    
6688
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6689
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6690
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6691
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6692

    
6693
		$interface_channels = "";
6694
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6695
		$interface_channel_count = count($interface_channels);
6696

    
6697
		$c = 0;
6698
		while ($c < $interface_channel_count) {
6699
			$channel_line = explode(",", $interface_channels["$c"]);
6700
			$wireless_mode = trim($channel_line[0]);
6701
			$wireless_channel = trim($channel_line[1]);
6702
			if (trim($wireless_mode) != "") {
6703
				/* if we only have 11g also set 11b channels */
6704
				if ($wireless_mode == "11g") {
6705
					if (!isset($wireless_modes["11b"])) {
6706
						$wireless_modes["11b"] = array();
6707
					}
6708
				} else if ($wireless_mode == "11g ht") {
6709
					if (!isset($wireless_modes["11b"])) {
6710
						$wireless_modes["11b"] = array();
6711
					}
6712
					if (!isset($wireless_modes["11g"])) {
6713
						$wireless_modes["11g"] = array();
6714
					}
6715
					$wireless_mode = "11ng";
6716
				} else if ($wireless_mode == "11a ht") {
6717
					if (!isset($wireless_modes["11a"])) {
6718
						$wireless_modes["11a"] = array();
6719
					}
6720
					$wireless_mode = "11na";
6721
				}
6722
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6723
			}
6724
			$c++;
6725
		}
6726
	}
6727
	return($wireless_modes);
6728
}
6729

    
6730
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6731
function get_wireless_channel_info($interface) {
6732
	$wireless_channels = array();
6733

    
6734
	$cloned_interface = get_real_interface($interface);
6735

    
6736
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6737
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
6738
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6739
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
6740

    
6741
		$interface_channels = "";
6742
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6743

    
6744
		foreach ($interface_channels as $channel_line) {
6745
			$channel_line = explode(",", $channel_line);
6746
			if (!isset($wireless_channels[$channel_line[0]])) {
6747
				$wireless_channels[$channel_line[0]] = $channel_line;
6748
			}
6749
		}
6750
	}
6751
	return($wireless_channels);
6752
}
6753

    
6754
function set_interface_mtu($interface, $mtu) {
6755

    
6756
	/* LAGG interface must be destroyed and re-created to change MTU */
6757
	if (substr($interface, 0, 4) == 'lagg') {
6758
		if (isset($config['laggs']['lagg']) &&
6759
		    is_array($config['laggs']['lagg'])) {
6760
			foreach ($config['laggs']['lagg'] as $lagg) {
6761
				if ($lagg['laggif'] == $interface) {
6762
					interface_lagg_configure($lagg);
6763
					break;
6764
				}
6765
			}
6766
		}
6767
	} else {
6768
		pfSense_interface_mtu($interface, $mtu);
6769
	}
6770
}
6771

    
6772
/****f* interfaces/get_interface_mtu
6773
 * NAME
6774
 *   get_interface_mtu - Return the mtu of an interface
6775
 * RESULT
6776
 *   $tmp       - Returns the mtu of an interface
6777
 ******/
6778
function get_interface_mtu($interface) {
6779
	$mtu = pfSense_interface_getmtu($interface);
6780
	return $mtu['mtu'];
6781
}
6782

    
6783
function get_interface_mac($interface) {
6784
	$macinfo = pfSense_get_interface_addresses($interface);
6785
	return $macinfo["macaddr"];
6786
}
6787

    
6788
function get_interface_vendor_mac($interface) {
6789
	global $config, $g;
6790

    
6791
	$macinfo = pfSense_get_interface_addresses($interface);
6792
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
6793
	    "00:00:00:00:00:00") {
6794
		return ($macinfo["hwaddr"]);
6795
	}
6796

    
6797
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
6798
	if (file_exists($hwaddr_file)) {
6799
		$macaddr = trim(file_get_contents($hwaddr_file));
6800
		if (is_macaddr($macaddr)) {
6801
			return ($macaddr);
6802
		}
6803
	} elseif (is_macaddr($macinfo['macaddr'])) {
6804
		/* Save original macaddress to be restored when necessary */
6805
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
6806
	}
6807

    
6808
	return (NULL);
6809
}
6810

    
6811
/****f* pfsense-utils/generate_random_mac_address
6812
 * NAME
6813
 *   generate_random_mac - generates a random mac address
6814
 * INPUTS
6815
 *   none
6816
 * RESULT
6817
 *   $mac - a random mac address
6818
 ******/
6819
function generate_random_mac_address() {
6820
	$mac = "02";
6821
	for ($x = 0; $x < 5; $x++) {
6822
		$mac .= ":" . dechex(rand(16, 255));
6823
	}
6824
	return $mac;
6825
}
6826

    
6827
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6828
	global $g;
6829

    
6830
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6831

    
6832
	if (!empty($iface) && !empty($pppif)) {
6833
		$cron_cmd = <<<EOD
6834
#!/bin/sh
6835
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
6836
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
6837

    
6838
EOD;
6839

    
6840
		@file_put_contents($cron_file, $cron_cmd);
6841
		chmod($cron_file, 0755);
6842
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
6843
	} else {
6844
		unlink_if_exists($cron_file);
6845
	}
6846
}
6847

    
6848
function get_interface_default_mtu($type = "ethernet") {
6849
	switch ($type) {
6850
		case "gre":
6851
			return 1476;
6852
			break;
6853
		case "gif":
6854
			return 1280;
6855
			break;
6856
		case "tun":
6857
		case "vlan":
6858
		case "tap":
6859
		case "ethernet":
6860
		default:
6861
			return 1500;
6862
			break;
6863
	}
6864

    
6865
	/* Never reached */
6866
	return 1500;
6867
}
6868

    
6869
function get_vip_descr($ipaddress) {
6870
	global $config;
6871

    
6872
	foreach ($config['virtualip']['vip'] as $vip) {
6873
		if ($vip['subnet'] == $ipaddress) {
6874
			return ($vip['descr']);
6875
		}
6876
	}
6877
	return "";
6878
}
6879

    
6880
function interfaces_staticarp_configure($if) {
6881
	global $config, $g;
6882
	if (isset($config['system']['developerspew'])) {
6883
		$mt = microtime();
6884
		echo "interfaces_staticarp_configure($if) being called $mt\n";
6885
	}
6886

    
6887
	$ifcfg = $config['interfaces'][$if];
6888

    
6889
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
6890
		return 0;
6891
	}
6892

    
6893
	/* Enable staticarp, if enabled */
6894
	if (isset($config['dhcpd'][$if]['staticarp'])) {
6895
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
6896
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6897
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
6898
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6899
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6900
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6901
				}
6902
			}
6903
		}
6904
	} else {
6905
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
6906
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6907
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
6908
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6909
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6910
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6911
				}
6912
			}
6913
		}
6914
	}
6915

    
6916
	return 0;
6917
}
6918

    
6919
function get_failover_interface($interface, $family = "all") {
6920
	global $config;
6921

    
6922
	/* shortcut to get_real_interface if we find it in the config */
6923
	if (is_array($config['interfaces'][$interface])) {
6924
		return get_real_interface($interface, $family);
6925
	}
6926

    
6927
	/* compare against gateway groups */
6928
	$a_groups = return_gateway_groups_array(true);
6929
	if (is_array($a_groups[$interface])) {
6930
		/* we found a gateway group, fetch the interface or vip */
6931
		if (!empty($a_groups[$interface][0]['vip'])) {
6932
			return $a_groups[$interface][0]['vip'];
6933
		} else {
6934
			return $a_groups[$interface][0]['int'];
6935
		}
6936
	}
6937
	/* fall through to get_real_interface */
6938
	/* XXX: Really needed? */
6939
	return get_real_interface($interface, $family);
6940
}
6941

    
6942
/****f* interfaces/interface_has_dhcp
6943
 * NAME
6944
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6945
 * INPUTS
6946
 *   interface or gateway group name
6947
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6948
 * RESULT
6949
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6950
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6951
 ******/
6952
function interface_has_dhcp($interface, $family = 4) {
6953
	global $config;
6954

    
6955
	if ($config['interfaces'][$interface]) {
6956
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6957
			return true;
6958
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6959
			return true;
6960
		} else {
6961
			return false;
6962
		}
6963
	}
6964

    
6965
	if (!is_array($config['gateways']['gateway_group'])) {
6966
		return false;
6967
	}
6968

    
6969
	if ($family == 6) {
6970
		$dhcp_string = "_DHCP6";
6971
	} else {
6972
		$dhcp_string = "_DHCP";
6973
	}
6974

    
6975
	foreach ($config['gateways']['gateway_group'] as $group) {
6976
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6977
			continue;
6978
		}
6979
		foreach ($group['item'] as $item) {
6980
			$item_data = explode("|", $item);
6981
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6982
				return true;
6983
			}
6984
		}
6985
	}
6986

    
6987
	return false;
6988
}
6989

    
6990
function remove_ifindex($ifname) {
6991
	return preg_replace("/[0-9]+$/", "", $ifname);
6992
}
6993

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

    
6997
	$viplist = get_configured_vip_list($family, $type);
6998
	foreach ($viplist as $vip => $address) {
6999
		$interfaces[$vip] = $address;
7000
		if ($type = VIP_CARP) {
7001
			$vip = get_configured_vip($vipid);
7002
			if (isset($vip) && is_array($vip) ) {
7003
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7004
			}
7005
		}
7006
		if (get_vip_descr($address)) {
7007
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
7008
		}
7009
	}
7010
	return $interfaces;
7011
}
7012

    
7013
function return_gateway_groups_array_with_descr() {
7014
	$interfaces = array();
7015
	$grouplist = return_gateway_groups_array();
7016
	foreach ($grouplist as $name => $group) {
7017
		if ($group[0]['vip'] != "") {
7018
			$vipif = $group[0]['vip'];
7019
		} else {
7020
			$vipif = $group[0]['int'];
7021
		}
7022

    
7023
		$interfaces[$name] = "GW Group {$name}";
7024
	}
7025
	return $interfaces;
7026
}
7027

    
7028
function get_serial_ports() {
7029
	$linklist = array();
7030
	if (!is_dir("/var/spool/lock")) {
7031
		mwexec("/bin/mkdir -p /var/spool/lock");
7032
	}
7033
	$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);
7034
	foreach ($serialports as $port) {
7035
		$linklist[$port] = trim($port);
7036
	}
7037
	return $linklist;
7038
}
7039

    
7040
function get_interface_ports() {
7041
	global $config;
7042
	$linklist = array();
7043
	$portlist = get_interface_list();
7044
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7045
		foreach ($config['vlans']['vlan'] as $vlan) {
7046
			$portlist[$vlan['vlanif']] = $vlan;
7047
		}
7048
	}
7049

    
7050
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7051
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7052
			$members = explode(" ", $qinq['members']);
7053
			foreach ($members as $mem) {
7054
				$qentry = $qinq['vlanif'] . "." . $mem;
7055
				$portlist[$qentry] = $qentry;
7056
			}
7057
		}
7058
	}
7059

    
7060
	foreach ($portlist as $ifn => $ifinfo) {
7061
		$string = "";
7062
		if (is_array($ifinfo)) {
7063
			$string .= $ifn;
7064
			if ($ifinfo['mac']) {
7065
				$string .= " ({$ifinfo['mac']})";
7066
			}
7067
			if ($ifinfo['friendly']) {
7068
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7069
			} elseif ($ifinfo['descr']) {
7070
				$string .= " - {$ifinfo['descr']}";
7071
			}
7072
		} else {
7073
			$string .= $ifinfo;
7074
		}
7075

    
7076
		$linklist[$ifn] = $string;
7077
	}
7078
	return $linklist;
7079
}
7080

    
7081
function build_ppps_link_list() {
7082
	global $pconfig;
7083

    
7084
	$linklist = array('list' => array(), 'selected' => array());
7085

    
7086
	if ($pconfig['type'] == 'ppp') {
7087
		$linklist['list'] = get_serial_ports();
7088
	} else {
7089
		$iflist = get_interface_ports();
7090

    
7091
		$viplist = array();
7092
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7093
		foreach ($carplist as $vid => $vaddr) {
7094
			$vip = get_configured_vip($vid);
7095
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7096
		}
7097

    
7098
		$linklist['list'] = array_merge($iflist, $viplist);
7099

    
7100
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7101
		$lagglist = get_lagg_interface_list();
7102
		foreach ($lagglist as $laggif => $lagg) {
7103
			/* LAGG members cannot be assigned */
7104
			$laggmembers = explode(',', $lagg['members']);
7105
			foreach ($laggmembers as $lagm) {
7106
				if (isset($linklist['list'][$lagm])) {
7107
					unset($linklist['list'][$lagm]);
7108
				}
7109
			}
7110
		}
7111
	}
7112

    
7113
	$selected_ports = array();
7114
	if (is_array($pconfig['interfaces'])) {
7115
		$selected_ports = $pconfig['interfaces'];
7116
	} elseif (!empty($pconfig['interfaces'])) {
7117
		$selected_ports = explode(',', $pconfig['interfaces']);
7118
	}
7119
	foreach ($selected_ports as $port) {
7120
		if (isset($linklist['list'][$port])) {
7121
			array_push($linklist['selected'], $port);
7122
		}
7123
	}
7124
	return($linklist);
7125
}
7126

    
7127
function create_interface_list() {
7128
	global $config;
7129

    
7130
	$iflist = array();
7131

    
7132
	// add group interfaces
7133
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7134
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7135
			if (have_ruleint_access($ifgen['ifname'])) {
7136
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7137
			}
7138
		}
7139
	}
7140

    
7141
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7142
		if (have_ruleint_access($ifent)) {
7143
			$iflist[$ifent] = $ifdesc;
7144
		}
7145
	}
7146

    
7147
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
7148
		$iflist['l2tp'] = gettext('L2TP VPN');
7149
	}
7150

    
7151
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
7152
		$iflist['pppoe'] = gettext("PPPoE Server");
7153
	}
7154

    
7155
	// add ipsec interfaces
7156
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
7157
		$iflist["enc0"] = gettext("IPsec");
7158
	}
7159

    
7160
	// add openvpn/tun interfaces
7161
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7162
		$iflist["openvpn"] = gettext("OpenVPN");
7163
	}
7164

    
7165
	return($iflist);
7166
}
7167

    
7168
function is_pseudo_interface($inf) {
7169
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7170
	foreach ($psifs as $pif) {
7171
		if (substr($inf, 0, strlen($pif)) == $pif) {
7172
			return true;
7173
		}
7174
	}
7175
	return false;
7176
}
7177

    
7178
?>
(22-22/60)