Project

General

Profile

Download (222 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-2021 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 = false) {
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
		init_config_arr(array('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
	if ($found == false) {
188
		$realif = get_real_interface($interface);
189
		pfSense_ngctl_detach("{$realif}:", $realif);
190
	}
191
	/* NOTE: We make sure for this on interface_ppps_configure()
192
	 *	no need to do it here again.
193
	 *	else
194
	 *		pfSense_ngctl_attach(".", $realif);
195
	 */
196
}
197

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

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

    
212
function vlan_valid_tag($tag = NULL) {
213

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

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

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

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

    
236
        return (false);
237
}
238

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

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

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

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

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

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

    
277
	return (NULL);
278
}
279

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

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

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

    
294
	return (false);
295
}
296

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

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

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

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

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

    
328
	return (NULL);
329
}
330

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

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

    
344
	$current_mac = get_interface_mac($interface);
345

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

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

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

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

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

    
415
	return (FALSE);
416
}
417

    
418
function interfaces_vlan_configure($parentif = "") {
419
	global $config, $g;
420
	$dhcp6c_list = array();
421

    
422
	if (platform_booting()) {
423
		echo gettext("Configuring VLAN interfaces...");
424
	}
425
	if (is_array($config['vlans']['vlan']) &&
426
	    count($config['vlans']['vlan'])) {
427
		foreach ($config['vlans']['vlan'] as $vlan) {
428
			if (empty($vlan['vlanif'])) {
429
				$vlan['vlanif'] = vlan_interface($vlan);
430
			}
431
			if (!empty($parentif) && ($parentif != $vlan['if'])) {
432
				continue;
433
			}
434
			/* configure dhcp6 enabled VLAN interfaces later
435
			 * see https://redmine.pfsense.org/issues/3965 */
436
			$if = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
437
			if (!empty($config['interfaces'][$if]['ipaddrv6']) &&
438
			    $config['interfaces'][$if]['ipaddrv6'] == "dhcp6") {
439
				$dhcp6c_list[$if] = $vlan;
440
				continue;
441
			}
442

    
443
			/* XXX: Maybe we should report any errors?! */
444
			interface_vlan_configure($vlan, false);
445
		}
446
		foreach ($dhcp6c_list as $if => $vlan) {
447
			interface_vlan_configure($vlan, false);
448
		}
449
	}
450

    
451
	/* Invalidate cache */
452
	get_interface_arr(true);
453

    
454
	if (platform_booting()) {
455
		echo gettext("done.") . "\n";
456
	}
457
}
458

    
459
function interface_vlan_configure(&$vlan, $flush = true) {
460
	global $config, $g;
461

    
462
	if (!is_array($vlan)) {
463
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
464
		return(NULL);
465
	}
466
	$if = $vlan['if'];
467
	if (empty($if)) {
468
		log_error(gettext("interface_vlan_configure called with if undefined."));
469
		return(NULL);
470
	}
471

    
472
	$vlanif = empty($vlan['vlanif']) ? vlan_interface($vlan) : $vlan['vlanif'];
473
	if ($vlanif == NULL) {
474
		log_error(gettext("vlan_interface called with if undefined var."));
475
		return(NULL);
476
	}
477
	$tag = $vlan['tag'];
478
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
479

    
480
	/* make sure the parent interface is up */
481
	interfaces_bring_up($if);
482
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
483
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
484

    
485
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
486
		pfSense_interface_destroy($vlanif);
487
	}
488

    
489
	$tmpvlanif = pfSense_interface_create2("vlan");
490
	pfSense_interface_rename($tmpvlanif, $vlanif);
491
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
492

    
493
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
494

    
495
	interfaces_bring_up($vlanif);
496

    
497
	/* invalidate interface cache */
498
	if ($flush) {
499
		get_interface_arr(true);
500
	}
501

    
502
	/* configure interface if assigned */
503
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
504
	if ($assignedif) {
505
		if (isset($config['interfaces'][$assignedif]['enable'])) {
506
			interface_configure($assignedif, true);
507
		}
508
	}
509

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

    
513
	if (interface_vlan_mtu_configured($vlanif)) {
514
		set_interface_mtu($vlanif, interface_vlan_mtu_configured($vlanif));
515
	}
516

    
517
	return $vlanif;
518
}
519

    
520
/*
521
 * reconfigure VLAN childs interfaces after MTU changes, see
522
 * https://redmine.pfsense.org/issues/11035
523
 */
524
function interfaces_vlan_configure_mtu($parentif = "") {
525
	global $config;
526

    
527
	init_config_arr(array('ppps', 'ppp'));
528
	if (!is_array($config['vlans']['vlan']) ||
529
	    !count($config['vlans']['vlan'])) {
530
		return;
531
	}
532

    
533
	foreach ($config['vlans']['vlan'] as $vlan) {
534
		if ($parentif != $vlan['if']) {
535
			continue;
536
		}
537
		if (interface_vlan_mtu_configured($vlan['vlanif'])) {
538
		       set_interface_mtu($vlan['vlanif'],
539
			   interface_vlan_mtu_configured($vlan['vlanif']));
540
		}
541
		if (empty($config['ppps']['ppp'])) {
542
			continue;
543
		}
544
		// PPP interfaces must be restarted to adjust MTU changes
545
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
546
			$ports = explode(',', $ppp['ports']);
547
			foreach ($ports as $pid => $port) {
548
				if ($port != $vlan['vlanif']) {
549
					continue;
550
				}
551
				$confif = convert_real_interface_to_friendly_interface_name($ppp['if']);
552
				interface_configure($confif);
553
			}
554
		}
555
	}
556
}
557

    
558
function interface_qinq_configure(&$qinq, $fd = NULL, $flush = true) {
559
	global $config, $g;
560

    
561
	if (!is_array($qinq)) {
562
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
563
		return;
564
	}
565

    
566
	$qinqif = $qinq['if'];
567
	$tag = $qinq['tag'];
568
	if (empty($qinqif)) {
569
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
570
		return;
571
	}
572

    
573
	if (!does_interface_exist($qinqif)) {
574
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
575
		return;
576
	}
577

    
578
	$vlanif = interface_vlan_configure($qinq);
579
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
580
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
581
		return;
582
	}
583

    
584
	if ($fd == NULL) {
585
		$exec = true;
586
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
587
	} else {
588
		$exec = false;
589
	}
590
	/* make sure the parent is converted to ng_vlan(4) and is up */
591
	interfaces_bring_up($qinqif);
592

    
593
	pfSense_ngctl_attach(".", $qinqif);
594
	$ngif = str_replace(".", "_", $vlanif);
595
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
596
		exec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1");
597
		exec("/usr/sbin/ngctl msg {$ngif}qinq: gettable > /dev/null 2>&1", $result);
598
		if (empty($result)) {
599
			fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
600
			fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
601
			fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
602
		}
603
	} else {
604
		fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
605
		fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
606
		fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
607
	}
608

    
609
	/* invalidate interface cache */
610
	if ($flush) {
611
		get_interface_arr(true);
612
	}
613

    
614
	if (interface_is_vlan($qinqif) == NULL) {
615
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
616
	}
617

    
618
	$macaddr = get_interface_mac($qinqif);
619
	if (!empty($qinq['members'])) {
620
		$qinqcmdbuf = "";
621
		$members = explode(" ", $qinq['members']);
622
		foreach ($members as $qtag) {
623
			$qinq2 = array();
624
			$qinq2['tag'] = $qtag;
625
			$qinq2['if'] = $vlanif;
626
			interface_qinq2_configure($qinq2, $qinqcmdbuf, $macaddr,
627
			    false);
628
			unset($qinq2);
629
		}
630
		if (strlen($qinqcmdbuf) > 0) {
631
			fwrite($fd, $qinqcmdbuf);
632
		}
633
	}
634
	if ($exec == true) {
635
		fclose($fd);
636
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd > /dev/null 2>&1");
637
	}
638

    
639
	interfaces_bring_up($qinqif);
640
	if (!empty($qinq['members'])) {
641
		$members = explode(" ", $qinq['members']);
642
		foreach ($members as $qtag) {
643
			interfaces_bring_up(qinq_interface($qinq, $qtag));
644
		}
645
	}
646

    
647
	return $vlanif;
648
}
649

    
650
function interfaces_qinq_configure() {
651
	global $config, $g;
652
	if (platform_booting()) {
653
		echo gettext("Configuring QinQ interfaces...");
654
	}
655
	if (is_array($config['qinqs']['qinqentry']) &&
656
	    count($config['qinqs']['qinqentry'])) {
657
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
658
			/* XXX: Maybe we should report any errors?! */
659
			interface_qinq_configure($qinq, NULL, false);
660
		}
661
	}
662

    
663
	/* Invalidate cache */
664
	get_interface_arr(true);
665

    
666
	if (platform_booting()) {
667
		echo gettext("done.") . "\n";
668
	}
669
}
670

    
671
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr, $flush = true) {
672
	global $config, $g;
673

    
674
	if (!is_array($qinq)) {
675
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
676
		return;
677
	}
678

    
679
	$if = $qinq['if'];
680
	if (empty($if)) {
681
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
682
		return;
683
	}
684
	$tag = $qinq['tag'];
685
	$vlanif = "{$if}.{$tag}";
686
	$ngif = str_replace(".", "_", $if);
687
	if (strlen($vlanif) > IF_NAMESIZE) {
688
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
689
		    $vlanif, IF_NAMESIZE, "\n"));
690
		return;
691
	}
692

    
693
	exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1");
694
	$cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n";
695
	$cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n";
696
	$cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n";
697
	$cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n";
698
	$cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n";
699

    
700
	/* invalidate interface cache */
701
	if ($flush) {
702
		get_interface_arr(true);
703
	}
704

    
705
	return $vlanif;
706
}
707

    
708
function interfaces_create_wireless_clones() {
709
	global $config, $g;
710

    
711
	if (platform_booting()) {
712
		echo gettext("Creating wireless clone interfaces...");
713
	}
714

    
715
	$iflist = get_configured_interface_list();
716

    
717
	foreach ($iflist as $if) {
718
		$realif = $config['interfaces'][$if]['if'];
719
		if (!is_interface_wireless($realif)) {
720
			continue;
721
		}
722
		interface_wireless_clone(interface_get_wireless_clone($realif),
723
		    $config['interfaces'][$if]);
724
	}
725

    
726
	if (isset($config['wireless']['clone']) &&
727
	    is_array($config['wireless']['clone']) &&
728
	    count($config['wireless']['clone'])) {
729
		foreach ($config['wireless']['clone'] as $clone) {
730
			if (empty($clone['cloneif'])) {
731
				continue;
732
			}
733
			if (does_interface_exist($clone['cloneif'])) {
734
				continue;
735
			}
736
			/* XXX: Maybe we should report any errors?! */
737
			interface_wireless_clone($clone['cloneif'], $clone);
738
		}
739
	}
740
	if (platform_booting()) {
741
		echo gettext("done.") . "\n";
742
	}
743

    
744
}
745

    
746
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
747
	global $config;
748

    
749
	if (!isset($config['bridges']['bridged']) ||
750
	    !is_array($config['bridges']['bridged']) ||
751
	    !count($config['bridges']['bridged'])) {
752
		return;
753
	}
754

    
755
	$i = 0;
756
	foreach ($config['bridges']['bridged'] as $bridge) {
757
		if (empty($bridge['bridgeif'])) {
758
			$bridge['bridgeif'] = "bridge{$i}";
759
		}
760
		if (!empty($realif) && ($realif != $bridge['bridgeif'])) {
761
			continue;
762
		}
763
		$ifname = false;
764
		foreach ($config['interfaces'] as $intname => $intpar) {
765
			if ($intpar['if'] == $bridge['bridgeif']) {
766
				$ifname = $intname;
767
				break;
768
			}
769
		}
770

    
771
		if ($ifname && ($config['interfaces'][$ifname]['ipaddrv6'] == "track6")) {
772
			if ($checkmember == 1) {
773
				continue;
774
			} else {
775
				$checkmember = 0;
776
			}
777
		} elseif (($checkmember == 2) && !$ifname) {
778
			continue;
779
		}
780

    
781
		/* XXX: Maybe we should report any errors?! */
782
		interface_bridge_configure($bridge, $checkmember, false);
783
		$i++;
784
	}
785

    
786
	/* Invalidate cache */
787
	get_interface_arr(true);
788
}
789

    
790
function interface_bridge_configure(&$bridge, $checkmember = 0, $flush = true) {
791
	global $config, $g;
792

    
793
	if (!is_array($bridge)) {
794
		return;
795
	}
796

    
797
	if (empty($bridge['members'])) {
798
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
799
		return;
800
	}
801

    
802
	$members = explode(',', $bridge['members']);
803
	if (!count($members)) {
804
		return;
805
	}
806

    
807
	/* Calculate smaller mtu and enforce it */
808
	$smallermtu = 0;
809
	$foundgif = false;
810
	foreach ($members as $member) {
811
		$realif = get_real_interface($member);
812
		$mtu = get_interface_mtu($realif);
813
		if (substr($realif, 0, 3) == "gif") {
814
			$foundgif = true;
815
			if ($checkmember == 1) {
816
				return;
817
			}
818
			if ($mtu <= 1500) {
819
				continue;
820
			}
821
		}
822
		if ($smallermtu == 0 && !empty($mtu)) {
823
			$smallermtu = $mtu;
824
		} elseif (!empty($mtu) && $mtu < $smallermtu) {
825
			$smallermtu = $mtu;
826
		}
827
	}
828
	if ($foundgif == false && $checkmember == 2) {
829
		return;
830
	}
831

    
832
	/* Just in case anything is not working well */
833
	if ($smallermtu == 0) {
834
		$smallermtu = 1500;
835
	}
836

    
837
	if (!empty($bridge['bridgeif'])) {
838
		pfSense_interface_destroy($bridge['bridgeif']);
839
		pfSense_interface_create2($bridge['bridgeif']);
840
		$bridgeif = escapeshellarg($bridge['bridgeif']);
841
	} else {
842
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
843
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
844
		$bridgeif = pfSense_interface_create2("bridge");
845
		$bridge['bridgeif'] = $bridgeif;
846
	}
847

    
848
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
849
	if ($bridgemtu > $smallermtu) {
850
		$smallermtu = $bridgemtu;
851
	}
852

    
853
	$checklist = get_configured_interface_list();
854

    
855
	/* Add interfaces to bridge */
856
	foreach ($members as $member) {
857
		if (empty($checklist[$member])) {
858
			continue;
859
		}
860
		$realif = get_real_interface($member);
861
		if (!$realif) {
862
			log_error(gettext("realif not defined in interfaces bridge - up"));
863
			continue;
864
		}
865
		/* make sure the parent interface is up */
866
		pfSense_interface_mtu($realif, $smallermtu);
867
		interfaces_bring_up($realif);
868
		enable_hardware_offloading($member);
869
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
870
	}
871

    
872
	if (isset($bridge['enablestp'])) {
873
		interface_bridge_configure_stp($bridge);
874
	}
875

    
876
	interface_bridge_configure_advanced($bridge);
877

    
878
	interface_bridge_configure_ip6linklocal($bridge);
879

    
880
	if ($flush) {
881
		get_interface_arr(true);
882
	}
883

    
884
	if ($bridge['bridgeif']) {
885
		interfaces_bring_up($bridge['bridgeif']);
886
	} else {
887
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
888
	}
889
}
890

    
891
function interface_bridge_configure_stp($bridge) {
892
	if (isset($bridge['enablestp'])) {
893
		$bridgeif = trim($bridge['bridgeif']);
894
		/* configure spanning tree proto */
895
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
896

    
897
		if (!empty($bridge['stp'])) {
898
			$stpifs = explode(',', $bridge['stp']);
899
			foreach ($stpifs as $stpif) {
900
				$realif = get_real_interface($stpif);
901
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
902
			}
903
		}
904
		if (!empty($bridge['maxage'])) {
905
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
906
		}
907
		if (!empty($bridge['fwdelay'])) {
908
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
909
		}
910
		if (!empty($bridge['hellotime'])) {
911
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
912
		}
913
		if (!empty($bridge['priority'])) {
914
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
915
		}
916
		if (!empty($bridge['holdcnt'])) {
917
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
918
		}
919
		if (!empty($bridge['ifpriority'])) {
920
			$pconfig = explode(",", $bridge['ifpriority']);
921
			$ifpriority = array();
922
			foreach ($pconfig as $cfg) {
923
				$embcfg = explode_assoc(":", $cfg);
924
				foreach ($embcfg as $key => $value) {
925
					$ifpriority[$key] = $value;
926
				}
927
			}
928
			foreach ($ifpriority as $key => $value) {
929
				$realif = get_real_interface($key);
930
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
931
			}
932
		}
933
		if (!empty($bridge['ifpathcost'])) {
934
			$pconfig = explode(",", $bridge['ifpathcost']);
935
			$ifpathcost = array();
936
			foreach ($pconfig as $cfg) {
937
				$embcfg = explode_assoc(":", $cfg);
938
				foreach ($embcfg as $key => $value) {
939
					$ifpathcost[$key] = $value;
940
				}
941
			}
942
			foreach ($ifpathcost as $key => $value) {
943
				$realif = get_real_interface($key);
944
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
945
			}
946
		}
947
	}
948
}
949

    
950
function interface_bridge_configure_advanced($bridge) {
951
	$bridgeif = trim($bridge['bridgeif']);
952

    
953
	if ($bridge['maxaddr'] <> "") {
954
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
955
	}
956
	if ($bridge['timeout'] <> "") {
957
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
958
	}
959
	if (!empty($bridge['span'])) {
960
		$spanifs = explode(",", $bridge['span']);
961
		foreach ($spanifs as $spanif) {
962
			$realif = get_real_interface($spanif);
963
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
964
		}
965
	}
966
	if (!empty($bridge['edge'])) {
967
		$edgeifs = explode(',', $bridge['edge']);
968
		foreach ($edgeifs as $edgeif) {
969
			$realif = get_real_interface($edgeif);
970
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
971
		}
972
	}
973
	if (!empty($bridge['autoedge'])) {
974
		$edgeifs = explode(',', $bridge['autoedge']);
975
		foreach ($edgeifs as $edgeif) {
976
			$realif = get_real_interface($edgeif);
977
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
978
		}
979
	}
980
	if (!empty($bridge['ptp'])) {
981
		$ptpifs = explode(',', $bridge['ptp']);
982
		foreach ($ptpifs as $ptpif) {
983
			$realif = get_real_interface($ptpif);
984
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
985
		}
986
	}
987
	if (!empty($bridge['autoptp'])) {
988
		$ptpifs = explode(',', $bridge['autoptp']);
989
		foreach ($ptpifs as $ptpif) {
990
			$realif = get_real_interface($ptpif);
991
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
992
		}
993
	}
994
	if (!empty($bridge['static'])) {
995
		$stickyifs = explode(',', $bridge['static']);
996
		foreach ($stickyifs as $stickyif) {
997
			$realif = get_real_interface($stickyif);
998
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
999
		}
1000
	}
1001
	if (!empty($bridge['private'])) {
1002
		$privateifs = explode(',', $bridge['private']);
1003
		foreach ($privateifs as $privateif) {
1004
			$realif = get_real_interface($privateif);
1005
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
1006
		}
1007
	}
1008
}
1009

    
1010
function interface_bridge_configure_ip6linklocal($bridge) {
1011
	$bridgeif = trim($bridge['bridgeif']);
1012

    
1013
	$members = explode(',', $bridge['members']);
1014
	if (!count($members)) {
1015
		return;
1016
	}
1017

    
1018
	$auto_linklocal = isset($bridge['ip6linklocal']);
1019
	$bridgeop = $auto_linklocal ? '' : '-';
1020
	$memberop = $auto_linklocal ? '-' : '';
1021

    
1022
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
1023
	foreach ($members as $member) {
1024
		$realif = get_real_interface($member);
1025
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
1026
	}
1027
}
1028

    
1029
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
1030
	global $config;
1031

    
1032
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
1033
		return;
1034
	}
1035

    
1036
	if ($flagsapplied == false) {
1037
		$mtu = get_interface_mtu($bridgeif);
1038
		$mtum = get_interface_mtu($interface);
1039
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
1040
			pfSense_interface_mtu($interface, $mtu);
1041
		}
1042

    
1043
		hardware_offloading_applyflags($interface);
1044
		interfaces_bring_up($interface);
1045
	}
1046

    
1047
	pfSense_bridge_add_member($bridgeif, $interface);
1048
	if (is_array($config['bridges']['bridged'])) {
1049
		foreach ($config['bridges']['bridged'] as $bridge) {
1050
			if ($bridgeif == $bridge['bridgeif']) {
1051
				interface_bridge_configure_stp($bridge);
1052
				interface_bridge_configure_advanced($bridge);
1053
			}
1054
		}
1055
	}
1056
}
1057

    
1058
function interfaces_lagg_configure($realif = "") {
1059
	global $config, $g;
1060
	if (platform_booting()) {
1061
		echo gettext("Configuring LAGG interfaces...");
1062
	}
1063
	$i = 0;
1064
	if (is_array($config['laggs']['lagg']) &&
1065
	    count($config['laggs']['lagg'])) {
1066
		foreach ($config['laggs']['lagg'] as $lagg) {
1067
			if (empty($lagg['laggif'])) {
1068
				$lagg['laggif'] = "lagg{$i}";
1069
			}
1070
			if (!empty($realif) && $realif != $lagg['laggif']) {
1071
				continue;
1072
			}
1073
			/* XXX: Maybe we should report any errors?! */
1074
			interface_lagg_configure($lagg, false);
1075
			$i++;
1076
		}
1077

    
1078
		/* Invalidate cache */
1079
		get_interface_arr(true);
1080
	}
1081
	if (platform_booting()) {
1082
		echo gettext("done.") . "\n";
1083
	}
1084
}
1085

    
1086
function interface_lagg_configure($lagg, $flush = true) {
1087
	global $config, $g;
1088

    
1089
	if (!is_array($lagg)) {
1090
		return -1;
1091
	}
1092

    
1093
	$members = explode(',', $lagg['members']);
1094
	if (!count($members)) {
1095
		return -1;
1096
	}
1097

    
1098
	if (platform_booting() || !(empty($lagg['laggif']))) {
1099
		pfSense_interface_destroy($lagg['laggif']);
1100
		pfSense_interface_create2($lagg['laggif']);
1101
		$laggif = $lagg['laggif'];
1102
	} else {
1103
		$laggif = pfSense_interface_create2("lagg");
1104
	}
1105

    
1106
	/* Check if MTU was defined for this lagg interface */
1107
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
1108
	if ($lagg_mtu == 0 &&
1109
	    is_array($config['interfaces'])) {
1110
		foreach ($config['interfaces'] as $tmpinterface) {
1111
			if ($tmpinterface['if'] == $lagg['laggif'] &&
1112
			    !empty($tmpinterface['mtu'])) {
1113
				$lagg_mtu = $tmpinterface['mtu'];
1114
				break;
1115
			}
1116
		}
1117
	}
1118

    
1119
	/* Just in case anything is not working well */
1120
	if ($lagg_mtu == 0) {
1121
		$lagg_mtu = 1500;
1122
	}
1123

    
1124
	// put failover master interface on top of list
1125
	if (($lagg['proto'] == 'failover') && isset($lagg['failovermaster']) &&
1126
	    ($lagg['failovermaster'] != 'auto')) {
1127
		unset($members[array_search($lagg['failovermaster'], $members)]);
1128
		$members = array_merge(array($lagg['failovermaster']), $members);
1129
	}
1130

    
1131
	if (($lagg['proto'] == 'lacp') && isset($lagg['lacptimeout']) &&
1132
	    ($lagg['lacptimeout'] != 'slow')) {
1133
		$lacptimeout = 'lacp_fast_timeout';
1134
	} else {
1135
		$lacptimeout = '';
1136
	}
1137

    
1138
	foreach ($members as $member) {
1139
		if (!does_interface_exist($member)) {
1140
			continue;
1141
		}
1142

    
1143
		/* make sure the parent interface is up */
1144
		pfSense_interface_mtu($member, $lagg_mtu);
1145
		interfaces_bring_up($member);
1146
		hardware_offloading_applyflags($member);
1147

    
1148
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
1149
		$laggif = str_replace("\0", "", $laggif);
1150
		$member = str_replace("\0", "", $member);
1151
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
1152
	}
1153

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

    
1156
	if ($flush) {
1157
		get_interface_arr(true);
1158
	}
1159

    
1160
	interfaces_bring_up($laggif);
1161

    
1162
	return $laggif;
1163
}
1164

    
1165
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
1166
function interface_gre_configure(&$gre, $grekey = "", $flush = true) {
1167
	global $config, $g;
1168

    
1169
	if (!is_array($gre)) {
1170
		return -1;
1171
	}
1172

    
1173
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1174
	if (!interface_is_vlan($realif)) {
1175
		$realif = get_real_interface($gre['if']);
1176
	}
1177
	$realifip = get_interface_ip($gre['if']);
1178
	$realifip6 = get_interface_ipv6($gre['if']);
1179

    
1180
	/* make sure the parent interface is up */
1181
	interfaces_bring_up($realif);
1182

    
1183
	if (platform_booting() || !(empty($gre['greif']))) {
1184
		pfSense_interface_destroy($gre['greif']);
1185
		pfSense_interface_create2($gre['greif']);
1186
		$greif = $gre['greif'];
1187
	} else {
1188
		$greif = pfSense_interface_create2("gre");
1189
	}
1190

    
1191
	$tunnel_type = '';
1192
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1193
		$tunnel_type = 'v4';
1194
	}
1195
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1196
		$tunnel_type .= 'v6';
1197
	}
1198

    
1199
	/* Do not change the order here for more see gre(4) NOTES section. */
1200
	if (is_ipaddrv6($gre['remote-addr'])) {
1201
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1202
	} else {
1203
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1204
	}
1205
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1206
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1207
	}
1208
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1209
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1210
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr6']) . " " . escapeshellarg($gre['tunnel-remote-addr6']) . " prefixlen 128");
1211
	}
1212

    
1213
	$parentif = get_real_interface($gre['if']);
1214
	if ($parentif) {
1215
		interfaces_bring_up($parentif);
1216
	} else {
1217
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1218
	}
1219

    
1220
	if (isset($gre['link1'])) {
1221
		if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1222
			mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1223
		}
1224
		if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1225
			mwexec("/sbin/route -6 add " . escapeshellarg($gre['tunnel-remote-addr6']) . "/" . escapeshellarg($gre['tunnel-remote-net6']) . " " . escapeshellarg($gre['tunnel-local-addr6']));
1226
		}
1227
	}
1228
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1229
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1230
	}
1231
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1232
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr6']);
1233
	}
1234

    
1235
	if ($flush) {
1236
		get_interface_arr(true);
1237
	}
1238

    
1239
	interfaces_bring_up($greif);
1240

    
1241
	return $greif;
1242
}
1243

    
1244
function interface_is_type($if = NULL, $type) {
1245
	global $config;
1246
	switch ($type) {
1247
		case "gre":
1248
			$list = 'gres';
1249
			$entry = 'gre';
1250
			$entif = 'greif';
1251
			break;
1252
		case "gif":
1253
			$list = 'gifs';
1254
			$entry = 'gif';
1255
			$entif = 'gifif';
1256
			break;
1257
		case "lagg":
1258
			$list = 'laggs';
1259
			$entry = 'lagg';
1260
			$entif = 'laggif';
1261
			break;
1262
		case "vxlan":
1263
			$list = 'vxlans';
1264
			$entry = 'vxlan';
1265
			$entif = 'vxlanif';
1266
			break;
1267
		default:
1268
			break;
1269
	}
1270

    
1271
	if (!isset($config[$list][$entry]) || !is_array($config[$list][$entry])) {
1272
		return (NULL);
1273
	}
1274

    
1275
	foreach ($config[$list][$entry] as $ent) {
1276
		if ($ent[$entif] == $if) {
1277
			return ($ent);
1278
		}
1279
	}
1280
	return (NULL);
1281
}
1282

    
1283
function is_greipsec($if) {
1284
	global $config;
1285

    
1286
	if (ipsec_enabled() && is_array($config['gres']) &&
1287
	    is_array($config['gres']['gre']) &&
1288
	    is_array($config['ipsec']['phase2'])) {
1289
		foreach ($config['gres']['gre'] as $gre) {
1290
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
1291
				foreach ($config['ipsec']['phase2'] as $ph2ent) {
1292
					if (($ph1ent['ikeid'] == $ph2ent['ikeid']) && ($ph2ent['mode'] == 'transport') &&
1293
					    !isset($ph1ent['disabled']) && !isset($ph2ent['disabled']) &&
1294
					    ($ph1ent['interface'] == $gre['if']) && ($gre['greif'] == $if) &&
1295
					    ($ph1ent['remote-gateway'] == $gre['remote-addr'])) {
1296
						    return true;
1297
					}
1298
				}
1299
			}
1300
		}
1301
	}
1302
	return false;
1303
}
1304

    
1305
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1306
function interface_gif_configure(&$gif, $gifkey = "", $flush = true) {
1307
	global $config, $g;
1308

    
1309
	if (!is_array($gif)) {
1310
		return -1;
1311
	}
1312

    
1313
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1314
	if (!interface_is_vlan($realif)) {
1315
		$realif = get_real_interface($gif['if']);
1316
	}
1317
	$ipaddr = get_interface_ip($gif['if']);
1318

    
1319
	if (is_ipaddrv4($gif['remote-addr'])) {
1320
		if (is_ipaddrv4($ipaddr)) {
1321
			$realifip = $ipaddr;
1322
		} else {
1323
			$realifip = get_interface_ip($gif['if']);
1324
		}
1325
		$realifgw = get_interface_gateway($gif['if']);
1326
	} elseif (is_ipaddrv6($gif['remote-addr'])) {
1327
		if (is_ipaddrv6($ipaddr)) {
1328
			$realifip = $ipaddr;
1329
		} else {
1330
			$realifip = get_interface_ipv6($gif['if']);
1331
		}
1332
		$realifgw = get_interface_gateway_v6($gif['if']);
1333
	}
1334
	/* make sure the parent interface is up */
1335
	$parentif = get_real_interface($gif['if']);
1336
	if ($parentif) {
1337
		interfaces_bring_up($parentif);
1338
	} else {
1339
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gif_configure()"));
1340
	}
1341

    
1342
	if (platform_booting() || !(empty($gif['gifif']))) {
1343
		pfSense_interface_destroy($gif['gifif']);
1344
		pfSense_interface_create2($gif['gifif']);
1345
		$gifif = $gif['gifif'];
1346
	} else {
1347
		$gifif = pfSense_interface_create2("gif");
1348
	}
1349

    
1350
	/* Do not change the order here for more see gif(4) NOTES section. */
1351
	if (is_ipaddrv6($gif['remote-addr'])) {
1352
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1353
	} else {
1354
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1355
	}
1356
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1357
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1358
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1359
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1360
	} else {
1361
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1362
	}
1363
	if (isset($gif['link1'])) {
1364
		pfSense_interface_flags($gifif, IFF_LINK1);
1365
	}
1366
	if (isset($gif['link2'])) {
1367
		pfSense_interface_flags($gifif, IFF_LINK2);
1368
	}
1369
	if ($gifif) {
1370
		interfaces_bring_up($gifif);
1371
		$gifmtu = "";
1372
		$currentgifmtu = get_interface_mtu($gifif);
1373
		foreach ($config['interfaces'] as $tmpinterface) {
1374
			if ($tmpinterface['if'] == $gifif) {
1375
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1376
					$gifmtu = $tmpinterface['mtu'];
1377
				}
1378
			}
1379
		}
1380
		if (is_numericint($gifmtu)) {
1381
			if ($gifmtu != $currentgifmtu) {
1382
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1383
			}
1384
		}
1385
	} else {
1386
		log_error(gettext("could not bring gifif up -- variable not defined"));
1387
	}
1388

    
1389
	if (!platform_booting()) {
1390
		$iflist = get_configured_interface_list();
1391
		foreach ($iflist as $ifname) {
1392
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1393
				if (get_interface_gateway($ifname)) {
1394
					system_routing_configure($ifname);
1395
					break;
1396
				}
1397
				if (get_interface_gateway_v6($ifname)) {
1398
					system_routing_configure($ifname);
1399
					break;
1400
				}
1401
			}
1402
		}
1403
	}
1404

    
1405

    
1406
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1407
		file_put_contents("{$g['tmp_path']}/{$gifif}_router",
1408
		    $gif['tunnel-remote-addr']);
1409
	} elseif (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1410
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6",
1411
		    $gif['tunnel-remote-addr']);
1412
	}
1413

    
1414
	route_add_or_change($gif['remote-addr'], $realifgw);
1415

    
1416
	if ($flush) {
1417
		get_interface_arr(true);
1418
	}
1419

    
1420
	interfaces_bring_up($gifif);
1421

    
1422
	return $gifif;
1423
}
1424

    
1425
/*
1426
 * $ipsecifnum = get_ipsecifnum($ikeid, $idx);
1427
 * locates and returns an ipsecifnum in the config.
1428
 */
1429
function get_ipsecifnum($ikeid, $idx) {
1430
	global $config;
1431

    
1432
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1433
	foreach ($config['ipsec']['vtimaps']['item'] as $vtimap) {
1434
		if (($vtimap['reqid'] == $ikeid) &&
1435
		    ($vtimap['index'] == $idx)) {
1436
			return $vtimap['ifnum'];
1437
		}
1438
	}
1439

    
1440
	return false;
1441
}
1442

    
1443
function ipsec_create_vtimap($ikeid, $idx) {
1444
	global $config;
1445

    
1446
	if ((($ikeid < 33) && ($idx < 10)) || (($ikeid < 10) && ($idx < 100))) {
1447
		$oldformat = "{$ikeid}00{$idx}";
1448
		return array(
1449
			"reqid" => $ikeid,
1450
			"index" => $idx,
1451
			"ifnum" => $oldformat
1452
		);
1453
	}
1454

    
1455
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1456

    
1457
	if (count($config['ipsec']['vtimaps']['item']) == 0) {
1458
		return array(
1459
			"reqid" => $ikeid,
1460
			"index" => $idx,
1461
			"ifnum" => 1
1462
		);
1463
	}
1464

    
1465
	$assigned = array_column($config['ipsec']['vtimaps']['item'], 'ifnum');
1466
	asort($assigned, SORT_NUMERIC);
1467
	$new = 1;
1468
	foreach($assigned as $ipsecifnum) {
1469
		if ($ipsecifnum != $new) {
1470
			return array(
1471
				"reqid" => $ikeid,
1472
				"index" => $idx,
1473
				"ifnum" => $new
1474
			);
1475
		}
1476
		if ($new <= 32767) {
1477
			$new++;
1478
		} else {
1479
			log_error(gettext("All 32767 ipsec interface numbers " .
1480
			    "have been assigned!"));
1481
			return(NULL);
1482
		}
1483
	}
1484
}
1485

    
1486
function ipsec_del_vtimap($phase2) {
1487
	global $config;
1488

    
1489
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1490

    
1491
	if (count($config['ipsec']['vtimaps']['item']) == 0) {
1492
		return;
1493
	}
1494

    
1495
	$a_vtimaps = &$config['ipsec']['vtimaps']['item'];
1496
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1497
	$last = '';
1498
	foreach ($a_vtimaps as $id => $vtimap) {
1499
		if ($vtimap['reqid'] == $phase1['ikeid']) {
1500
			$last = $id;
1501
		}
1502
	}
1503
	if (!is_numeric($last)) {
1504
		return false;
1505
	}
1506

    
1507
	$vtisubnet_spec = ipsec_vti($phase1, true);
1508
	if (($phase1['iketype'] == 'ikev1') || isset($phase1['splitconn']) ||
1509
	    (count($vtisubnet_spec) == 1)) {
1510
		unset($a_vtimaps[$last]);
1511
		return true;
1512
	}
1513
}
1514

    
1515
/* NOTE: $vxlankey is not used but useful for passing this function to array_walk. */
1516
function interface_vxlan_configure(&$vxlan, $vxlankey = "", $flush = true) {
1517
	global $config, $g;
1518

    
1519
	if (!is_array($vxlan)) {
1520
		return -1;
1521
	}
1522

    
1523
	$realif = convert_friendly_interface_to_real_interface_name($vxlan['if']);
1524
	if (!interface_is_vlan($realif)) {
1525
		$realif = get_real_interface($vxlan['if']);
1526
	}
1527
	$realifip = get_interface_ip($vxlan['if']);
1528
	$realifip6 = get_interface_ipv6($vxlan['if']);
1529

    
1530
	/* make sure the parent interface is up */
1531
	if ($realif) {
1532
		interfaces_bring_up($realif);
1533
	} else {
1534
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_vxlan_configure()"));
1535
	}
1536

    
1537
	/* Interface is defined */
1538
	if (platform_booting() || !(empty($vxlan['vxlanif']))) {
1539
		pfSense_interface_destroy($vxlan['vxlanif']);
1540
		pfSense_interface_create2($vxlan['vxlanif']);
1541
		$vxlanif = $vxlan['vxlanif'];
1542
	} else {
1543
		$vxlanif = pfSense_interface_create2("vxlan");
1544
	}
1545

    
1546
	$ifconfigcmd = "/sbin/ifconfig " . escapeshellarg($vxlanif) .
1547
	    " vxlanid " .  escapeshellarg($vxlan['vxlanid']);
1548

    
1549
	if (is_mcast($vxlan['remote-addr'])) {
1550
		$ifconfigcmd .= " vxlangroup " .
1551
		    escapeshellarg($vxlan['remote-addr']) . " vxlandev " .
1552
		    escapeshellarg($realif);
1553
	} else {
1554
		$ifconfigcmd .= " vxlanremote " .
1555
		    escapeshellarg($vxlan['remote-addr']);
1556
	}
1557

    
1558
	if (is_ipaddrv6($vxlan['remote-addr']) && $realifip6) {
1559
		$ifconfigcmd .= " vxlanlocal " . escapeshellarg($realifip6);
1560
	} elseif (is_ipaddrv4($vxlan['remote-addr']) && $realifip) {
1561
		$ifconfigcmd .= " vxlanlocal " . escapeshellarg($realifip);
1562
	} else {
1563
		return;
1564
	}
1565

    
1566
	if (!empty($vxlan['vxlanlocalport'])) {
1567
		$ifconfigcmd .= " vxlanlocalport " . escapeshellarg($vxlan['vxlanlocalport']);
1568
	}
1569

    
1570
	if (!empty($vxlan['vxlanremoteport'])) {
1571
		$ifconfigcmd .= " vxlanremoteport " . escapeshellarg($vxlan['vxlanremoteport']);
1572
	}
1573

    
1574
	if (!empty($vxlan['vxlanttl'])) {
1575
		$ifconfigcmd .= " vxlanttl " . escapeshellarg($vxlan['vxlanttl']);
1576
	}
1577

    
1578
	if (isset($vxlan['vxlanlearn'])) {
1579
		$ifconfigcmd .= " vxlanlearn ";
1580
	} else {
1581
		$ifconfigcmd .= " -vxlanlearn ";
1582
	}
1583

    
1584
	mwexec($ifconfigcmd);
1585

    
1586
	if ($flush) {
1587
		get_interface_arr(true);
1588
	}
1589

    
1590
	interfaces_bring_up($vxlanif);
1591

    
1592
	return $vxlanif;
1593
}
1594

    
1595
function interfaces_tunnel_configure($checkparent = 0, $realif = "", $type = "") {
1596
	global $config;
1597

    
1598
	if (!in_array($type, array('gre', 'gif', 'vxlan'))) {
1599
		return;
1600
	}
1601

    
1602
	if (!is_array($config["{$type}s"][$type]) ||
1603
	    !count($config["{$type}s"][$type])) {
1604
		return;
1605
	}
1606

    
1607
	foreach ($config["{$type}s"][$type] as $i => $tunnel) {
1608
		if (empty($tunnel["{$type}if"])) {
1609
			$tunnel["{$type}if"] = $type . $i;
1610
		}
1611
		if (!empty($realif) && $realif != $tunnel["{$type}if"]) {
1612
			continue;
1613
		}
1614

    
1615
		if ($checkparent == 1) {
1616
			if (substr($tunnel['if'], 0, 4) == '_vip') {
1617
				continue;
1618
			}
1619
			if (substr($tunnel['if'], 0, 5) == '_lloc') {
1620
				continue;
1621
			}
1622
			if (!empty($config['interfaces'][$tunnel['if']]) &&
1623
			    $config['interfaces'][$tunnel['if']]['ipaddrv6'] ==
1624
			    "track6") {
1625
				continue;
1626
			}
1627
		} elseif ($checkparent == 2) {
1628
			if ((substr($tunnel['if'], 0, 4) != '_vip' &&
1629
			    substr($tunnel['if'], 0, 5) != '_lloc') &&
1630
			    (empty($config['interfaces'][$tunnel['if']]) ||
1631
			    $config['interfaces'][$tunnel['if']]['ipaddrv6'] !=
1632
			    "track6")) {
1633
				continue;
1634
			}
1635
		}
1636
		if ($type == 'gif') {
1637
			interface_gif_configure($tunnel, "", false);
1638
		} elseif ($type == 'gre') {
1639
			interface_gre_configure($tunnel, "", false);
1640
		} elseif ($type == 'vxlan') {
1641
			interface_vxlan_configure($tunnel, "", false);
1642
		}
1643
	}
1644

    
1645
	/* Invalidate cache */
1646
	get_interface_arr(true);
1647
}
1648

    
1649
/* Build a list of IPsec interfaces */
1650
function interface_ipsec_vti_list_p1($ph1ent) {
1651
	global $config;
1652
	$iface_list = array();
1653

    
1654
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1655
		return $iface_list;
1656
	}
1657

    
1658
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1659
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1660
		return $iface_list;
1661
	}
1662

    
1663
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1664
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1665
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1666
			$iface_list["ipsec".get_ipsecifnum($ph1ent['ikeid'], $idx)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1667
		}
1668
	} else {
1669
		/* For IKEv2, only create one interface with additional addresses as aliases */
1670
		$iface_list["ipsec".get_ipsecifnum($ph1ent['ikeid'], 0)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1671
	}
1672
	return $iface_list;
1673
}
1674
function interface_ipsec_vti_list_all() {
1675
	global $config;
1676
	$iface_list = array();
1677
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1678
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1679
			if ($ph1ent['disabled']) {
1680
				continue;
1681
			}
1682
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1683
		}
1684
	}
1685
	return $iface_list;
1686
}
1687

    
1688
function is_interface_ipsec_vti_assigned($phase2) {
1689
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1690
	$vti_interface = null;
1691
	$vtisubnet_spec = ipsec_vti($phase1, true);
1692
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1693
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1694
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1695
			foreach ($vtisubnet_spec as $idx => $vtisub) {
1696
				/* Is this for this P2? */
1697
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1698
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1699
					$vti_interface = "ipsec".get_ipsecifnum($phase1['ikeid'], $idx);
1700
				}
1701
			}
1702
		} else {
1703
			$vti_interface = "ipsec".get_ipsecifnum($phase1['ikeid'], 0);
1704
		}
1705
	}
1706
	/* Check if this interface is assigned */
1707
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1708
}
1709
function interface_ipsec_vti_configure($ph1ent) {
1710
	global $config;
1711

    
1712
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1713
		return false;
1714
	}
1715

    
1716
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1717
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1718
		return false;
1719
	}
1720

    
1721
	$left_spec = ipsec_get_phase1_src($ph1ent);
1722
	$right_spec = $ph1ent['remote-gateway'];
1723

    
1724
	$iface_addrs = array();
1725

    
1726
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1727
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1728
		/* Form a single interface for each P2 entry */
1729
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1730
			$ipsecifnum = get_ipsecifnum($ph1ent['ikeid'], $idx);
1731
			if (!is_array($iface_addrs[$ipsecifnum])) {
1732
				$iface_addrs[$ipsecifnum] = array();
1733
			}
1734
			$vtisub['alias'] = "";
1735
			$iface_addrs[$ipsecifnum][] = $vtisub;
1736
		}
1737
	} else {
1738
		/* For IKEv2, only create one interface with additional addresses as aliases */
1739
		$ipsecifnum = get_ipsecifnum($ph1ent['ikeid'], 0);
1740
		if (!is_array($iface_addrs[$ipsecifnum])) {
1741
			$iface_addrs[$ipsecifnum] = array();
1742
		}
1743
		$have_v4 = false;
1744
		$have_v6 = false;
1745
		foreach ($vtisubnet_spec as $vtisub) {
1746
			// Alias stuff
1747
			$vtisub['alias'] = "";
1748
			if (is_ipaddrv6($vtisub['left'])) {
1749
				if ($have_v6) {
1750
					$vtisub['alias'] = " alias";
1751
				}
1752
				$have_v6 = true;
1753
			} else {
1754
				if ($have_v4) {
1755
					$vtisub['alias'] = " alias";
1756
				}
1757
				$have_v4 = true;
1758
			}
1759
			$iface_addrs[$ipsecifnum][] = $vtisub;
1760
		}
1761
	}
1762

    
1763
	foreach ($iface_addrs as $ipsecifnum => $addrs) {
1764
		$ipsecif = "ipsec{$ipsecifnum}";
1765
		if (!is_array($addrs)) {
1766
			continue;
1767
		}
1768
		// Create IPsec interface
1769
		if (does_interface_exist($ipsecif)) {
1770
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy");
1771
		}
1772
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum));
1773

    
1774
		/* Apply the outer tunnel addresses to the interface */
1775
		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
1776
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up");
1777

    
1778
		/* Loop through all of the addresses for this interface and apply them as needed */
1779
		foreach ($addrs as $addr) {
1780
			// apply interface addresses
1781
			if (is_v6($addr['left'])) {
1782
				$inet = "inet6";
1783
				$gwtype = "v6";
1784
				$right = '';
1785
			} else {
1786
				$inet = "inet";
1787
				$gwtype = "";
1788
				$right = escapeshellarg($addr['right']);
1789
			}
1790

    
1791
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias']);
1792
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1793
			if (empty($addr['alias'])) {
1794
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1795
			}
1796
		}
1797
		/* Check/set the MTU if the user configured a custom value.
1798
		 * https://redmine.pfsense.org/issues/9111 */
1799
		$currentvtimtu = get_interface_mtu($ipsecif);
1800
		foreach ($config['interfaces'] as $tmpinterface) {
1801
			if ($tmpinterface['if'] == $ipsecif) {
1802
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1803
					$vtimtu = $tmpinterface['mtu'];
1804
				}
1805
			}
1806
		}
1807
		if (is_numericint($vtimtu)) {
1808
			if ($vtimtu != $currentvtimtu) {
1809
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1810
			}
1811
		}
1812
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1813
	}
1814
}
1815

    
1816
function interfaces_ipsec_vti_configure() {
1817
	global $config;
1818
	if (platform_booting()) {
1819
		echo gettext("Configuring IPsec VTI interfaces...");
1820
	}
1821
	if (is_array($config['ipsec']) &&
1822
	    is_array($config['ipsec']['phase1']) &&
1823
	    is_array($config['ipsec']['phase2'])) {
1824
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1825
			if ($ph1ent['disabled']) {
1826
				continue;
1827
			}
1828
			interface_ipsec_vti_configure($ph1ent);
1829
		}
1830
	}
1831
	if (platform_booting()) {
1832
		echo gettext("done.") . "\n";
1833
	}
1834
}
1835

    
1836
function interfaces_configure() {
1837
	global $config, $g;
1838

    
1839
	/* Set up our loopback interface */
1840
	interfaces_loopback_configure();
1841

    
1842
	/* create the unconfigured wireless clones */
1843
	interfaces_create_wireless_clones();
1844

    
1845
	/* set up LAGG virtual interfaces */
1846
	interfaces_lagg_configure();
1847

    
1848
	/* set up VLAN virtual interfaces */
1849
	interfaces_vlan_configure();
1850

    
1851
	interfaces_qinq_configure();
1852

    
1853
	/* set up IPsec VTI interfaces */
1854
	interfaces_ipsec_vti_configure();
1855

    
1856
	$iflist = get_configured_interface_with_descr();
1857
	$delayed_list = array();
1858
	$bridge_list = array();
1859
	$track6_list = array();
1860
	$dhcp6c_list = array();
1861

    
1862
	/* This is needed to speedup interfaces on bootup. */
1863
	$reload = false;
1864
	if (!platform_booting()) {
1865
		$reload = true;
1866
	}
1867

    
1868
	foreach ($iflist as $if => $ifname) {
1869
		$realif = $config['interfaces'][$if]['if'];
1870
		if (strstr($realif, "bridge")) {
1871
			$bridge_list[$if] = $ifname;
1872
		} elseif (strstr($realif, "gre")) {
1873
			$delayed_list[$if] = $ifname;
1874
		} elseif (strstr($realif, "gif")) {
1875
			$delayed_list[$if] = $ifname;
1876
		} elseif (strstr($realif, "vxlan")) {
1877
			$delayed_list[$if] = $ifname;
1878
		} elseif (strstr($realif, "ovpn")) {
1879
			continue;
1880
		} elseif (strstr($realif, "ipsec")) {
1881
			continue;
1882
		} elseif (!empty($config['interfaces'][$if]['ipaddrv6']) &&
1883
		    $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1884
			$track6_list[$if] = $ifname;
1885
		} else {
1886
			/* do not run dhcp6c if track interface does not exists
1887
			 * see https://redmine.pfsense.org/issues/3965 */
1888
			if (!empty($config['interfaces'][$if]['ipaddrv6']) &&
1889
			    $config['interfaces'][$if]['ipaddrv6'] == "dhcp6") {
1890
				$tr6list = link_interface_to_track6($if);
1891
				if (is_array($tr6list) && !empty($tr6list)) {
1892
					foreach ($tr6list as $tr6if) {
1893
						if (!does_interface_exist($tr6if)) {
1894
							$dhcp6c_list[$if] = $ifname;
1895
							continue;
1896
						}
1897
					}
1898
				}
1899
			}
1900
			if (platform_booting()) {
1901
				printf(gettext("Configuring %s interface..."),
1902
				    $ifname);
1903
			}
1904

    
1905
			if ($g['debug']) {
1906
				log_error(sprintf(gettext("Configuring %s"),
1907
				    $ifname));
1908
			}
1909
			interface_configure($if, $reload);
1910
			if (platform_booting()) {
1911
				echo gettext("done.") . "\n";
1912
			}
1913
		}
1914
	}
1915

    
1916
	/*
1917
	 * NOTE: The following function parameter consists of
1918
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1919
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1920
	 */
1921

    
1922
	/* set up GRE virtual interfaces */
1923
	interfaces_tunnel_configure(1,'','gre');
1924

    
1925
	/* set up GIF virtual interfaces */
1926
	interfaces_tunnel_configure(1,'','gif');
1927

    
1928
	/* set up VXLAN virtual interfaces */
1929
	interfaces_tunnel_configure(1,'','vxlan');
1930

    
1931
	/* set up BRIDGe virtual interfaces */
1932
	interfaces_bridge_configure(1);
1933

    
1934
	foreach ($track6_list as $if => $ifname) {
1935
		if (platform_booting()) {
1936
			printf(gettext("Configuring %s interface..."), $ifname);
1937
		}
1938
		if ($g['debug']) {
1939
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1940
		}
1941

    
1942
		interface_configure($if, $reload);
1943

    
1944
		if (platform_booting()) {
1945
			echo gettext("done.") . "\n";
1946
		}
1947
	}
1948

    
1949
	/* bring up vip interfaces */
1950
	interfaces_vips_configure();
1951

    
1952
	/* set up GRE virtual interfaces */
1953
	interfaces_tunnel_configure(2,'','gre');
1954

    
1955
	/* set up GIF virtual interfaces */
1956
	interfaces_tunnel_configure(2,'','gif');
1957

    
1958
	/* set up VXLAN virtual interfaces */
1959
	interfaces_tunnel_configure(2,'','vxlan');
1960

    
1961
	foreach ($delayed_list as $if => $ifname) {
1962
		if (platform_booting()) {
1963
			printf(gettext("Configuring %s interface..."), $ifname);
1964
		}
1965
		if ($g['debug']) {
1966
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1967
		}
1968

    
1969
		interface_configure($if, $reload);
1970

    
1971
		if (platform_booting()) {
1972
			echo gettext("done.") . "\n";
1973
		}
1974
	}
1975

    
1976
	/* set up BRIDGe virtual interfaces */
1977
	interfaces_bridge_configure(2);
1978

    
1979
	foreach ($bridge_list as $if => $ifname) {
1980
		if (platform_booting()) {
1981
			printf(gettext("Configuring %s interface..."), $ifname);
1982
		}
1983
		if ($g['debug']) {
1984
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1985
		}
1986

    
1987
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1988
		// redmine #3997
1989
		interface_reconfigure($if, $reload);
1990
		interfaces_vips_configure($if);
1991

    
1992
		if (platform_booting()) {
1993
			echo gettext("done.") . "\n";
1994
		}
1995
	}
1996

    
1997
	foreach ($dhcp6c_list as $if => $ifname) {
1998
		if (platform_booting()) {
1999
			printf(gettext("Configuring %s interface..."), $ifname);
2000
		}
2001
		if ($g['debug']) {
2002
			log_error(sprintf(gettext("Configuring %s"), $ifname));
2003
		}
2004

    
2005
		interface_configure($if, $reload);
2006

    
2007
		if (platform_booting()) {
2008
			echo gettext("done.") . "\n";
2009
		}
2010
	}
2011

    
2012
	/* configure interface groups */
2013
	interfaces_group_setup();
2014

    
2015
	if (!platform_booting()) {
2016
		/* reconfigure static routes (kernel may have deleted them) */
2017
		system_routing_configure();
2018

    
2019
		/* reload IPsec tunnels */
2020
		ipsec_configure();
2021

    
2022
		/* restart dns servers (defering dhcpd reload) */
2023
		if (isset($config['dnsmasq']['enable'])) {
2024
			services_dnsmasq_configure(false);
2025
		}
2026
		if (isset($config['unbound']['enable'])) {
2027
			services_unbound_configure(false);
2028
		}
2029

    
2030
		/* reload dhcpd (interface enabled/disabled status may have changed) */
2031
		services_dhcpd_configure();
2032
	}
2033

    
2034
	return 0;
2035
}
2036

    
2037
function interface_reconfigure($interface = "wan", $reloadall = false) {
2038
	interface_bring_down($interface);
2039
	interface_configure($interface, $reloadall);
2040
}
2041

    
2042
function interface_vip_bring_down($vip) {
2043
	global $g;
2044

    
2045
	$vipif = get_real_interface($vip['interface']);
2046
	switch ($vip['mode']) {
2047
		case "proxyarp":
2048
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2049
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2050
			}
2051
			break;
2052
		case "ipalias":
2053
			if (does_interface_exist($vipif)) {
2054
				if (is_ipaddrv6($vip['subnet'])) {
2055
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
2056
				} else {
2057
					pfSense_interface_deladdress($vipif, $vip['subnet']);
2058
				}
2059
			}
2060
			break;
2061
		case "carp":
2062
			/* XXX: Is enough to delete ip address? */
2063
			if (does_interface_exist($vipif)) {
2064
				if (is_ipaddrv6($vip['subnet'])) {
2065
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
2066
				} else {
2067
					pfSense_interface_deladdress($vipif, $vip['subnet']);
2068
				}
2069
			}
2070
			break;
2071
	}
2072
}
2073

    
2074
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
2075
	global $config, $g;
2076

    
2077
	if (!isset($config['interfaces'][$interface])) {
2078
		return;
2079
	}
2080

    
2081
	if ($g['debug']) {
2082
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
2083
	}
2084

    
2085
	/*
2086
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
2087
	 * In this case the real $realif of v4 is different from that of v6 for operation.
2088
	 * Keep this in mind while doing changes here!
2089
	 */
2090
	if ($ifacecfg === false) {
2091
		$ifcfg = $config['interfaces'][$interface];
2092
		$ppps = $config['ppps']['ppp'];
2093
		$realif = get_real_interface($interface);
2094
		$realifv6 = get_real_interface($interface, "inet6", true);
2095
	} elseif (!is_array($ifacecfg)) {
2096
		log_error(gettext("Wrong parameters used during interface_bring_down"));
2097
		$ifcfg = $config['interfaces'][$interface];
2098
		$ppps = $config['ppps']['ppp'];
2099
		$realif = get_real_interface($interface);
2100
		$realifv6 = get_real_interface($interface, "inet6", true);
2101
	} else {
2102
		$ifcfg = $ifacecfg['ifcfg'];
2103
		$ppps = $ifacecfg['ppps'];
2104
		if (isset($ifacecfg['ifcfg']['realif'])) {
2105
			$realif = $ifacecfg['ifcfg']['realif'];
2106
			/* XXX: Any better way? */
2107
			$realifv6 = $realif;
2108
		} else {
2109
			$realif = get_real_interface($interface);
2110
			$realifv6 = get_real_interface($interface, "inet6", true);
2111
		}
2112
	}
2113

    
2114
	switch ($ifcfg['ipaddr']) {
2115
		case "ppp":
2116
		case "pppoe":
2117
		case "pptp":
2118
		case "l2tp":
2119
			if (is_array($ppps) && count($ppps)) {
2120
				foreach ($ppps as $pppid => $ppp) {
2121
					if ($realif == $ppp['if']) {
2122
						if (isset($ppp['ondemand']) && !$destroy) {
2123
							send_event("interface reconfigure {$interface}");
2124
							break;
2125
						}
2126
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
2127
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
2128
							sleep(2);
2129
						}
2130
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
2131
						break;
2132
					}
2133
				}
2134
			}
2135
			break;
2136
		case "dhcp":
2137
			kill_dhclient_process($realif);
2138
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
2139
			if (does_interface_exist("$realif")) {
2140
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
2141
				interface_vip_cleanup($interface, "inet4");
2142
				if ($destroy == true) {
2143
					pfSense_interface_flags($realif, -IFF_UP);
2144
				}
2145
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2146
			}
2147
			break;
2148
		default:
2149
			if (does_interface_exist("$realif")) {
2150
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
2151
				interface_vip_cleanup($interface, "inet4");
2152
				if ($destroy == true) {
2153
					pfSense_interface_flags($realif, -IFF_UP);
2154
				}
2155
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2156
			}
2157
			break;
2158
	}
2159

    
2160
	$track6 = array();
2161
	switch ($ifcfg['ipaddrv6']) {
2162
		case "slaac":
2163
		case "dhcp6":
2164
			kill_dhcp6client_process($realif, $destroy, false);
2165
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
2166
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
2167
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh");
2168
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
2169
			if (does_interface_exist($realifv6)) {
2170
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 -accept_rtadv");
2171
				$ip6 = find_interface_ipv6($realifv6);
2172
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
2173
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
2174
				}
2175
				interface_vip_cleanup($interface, "inet6");
2176
				if ($destroy == true) {
2177
					pfSense_interface_flags($realif, -IFF_UP);
2178
				}
2179
			}
2180
			$track6 = link_interface_to_track6($interface);
2181
			break;
2182
		case "6rd":
2183
		case "6to4":
2184
			$realif = "{$interface}_stf";
2185
			if (does_interface_exist("$realif")) {
2186
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
2187
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
2188
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
2189
					$destroy = true;
2190
				} else {
2191
					/* get_interface_ipv6() returns empty value if interface is being disabled */
2192
					$ip6 = get_interface_ipv6($interface);
2193
					if (is_ipaddrv6($ip6)) {
2194
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2195
					}
2196
				}
2197
				interface_vip_cleanup($interface, "inet6");
2198
				if ($destroy == true) {
2199
					pfSense_interface_flags($realif, -IFF_UP);
2200
				}
2201
			}
2202
			$track6 = link_interface_to_track6($interface);
2203
			break;
2204
		default:
2205
			if (does_interface_exist("$realif")) {
2206
				$ip6 = get_interface_ipv6($interface);
2207
				if (is_ipaddrv6($ip6)) {
2208
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2209
				}
2210
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
2211
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
2212
				}
2213
				interface_vip_cleanup($interface, "inet6");
2214
				if ($destroy == true) {
2215
					pfSense_interface_flags($realif, -IFF_UP);
2216
				}
2217
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2218
			}
2219
			$track6 = link_interface_to_track6($interface);
2220
			break;
2221
	}
2222

    
2223
	if (!empty($track6) && is_array($track6)) {
2224
		if (!function_exists('services_dhcpd_configure')) {
2225
			require_once('services.inc');
2226
		}
2227
		/* Bring down radvd and dhcp6 on these interfaces */
2228
		services_dhcpd_configure('inet6', $track6);
2229
	}
2230

    
2231
	$old_router = '';
2232
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
2233
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
2234
	}
2235

    
2236
	/* remove interface up file if it exists */
2237
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
2238
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
2239
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
2240
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
2241
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
2242
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
2243
	unlink_if_exists("{$g['varetc_path']}/nameserver_v6{$interface}");
2244
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
2245
	unlink_if_exists("{$g['varetc_path']}/searchdomain_v6{$interface}");
2246

    
2247
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
2248
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
2249
	if (is_array($ifcfg['wireless'])) {
2250
		kill_hostapd($realif);
2251
		mwexec(kill_wpasupplicant($realif));
2252
	}
2253

    
2254
	if ($destroy == true) {
2255
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^ipsec|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
2256
			pfSense_interface_destroy($realif);
2257

    
2258
			/* Invalidate cache */
2259
			get_interface_arr(true);
2260
		}
2261
	}
2262

    
2263
	return;
2264
}
2265

    
2266
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
2267
	global $config;
2268
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
2269
		unset($config["virtualip_carp_maintenancemode"]);
2270
		write_config("Leave CARP maintenance mode");
2271
	} elseif (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
2272
		$config["virtualip_carp_maintenancemode"] = true;
2273
		write_config(gettext("Enter CARP maintenance mode"));
2274
	}
2275
	init_config_arr(array('virtualip', 'vip'));
2276
	$viparr = &$config['virtualip']['vip'];
2277

    
2278
	if (is_array($viparr)) {
2279
		foreach ($viparr as $vip) {
2280
			if ($vip['mode'] == "carp") {
2281
				interface_carp_configure($vip, true);
2282
			}
2283
		}
2284
	}
2285
}
2286

    
2287
function interface_wait_tentative($interface, $timeout = 10) {
2288
	if (!does_interface_exist($interface)) {
2289
		return false;
2290
	}
2291

    
2292
	$time = 0;
2293
	while ($time <= $timeout) {
2294
		$if = pfSense_get_interface_addresses($interface);
2295
		if (!isset($if['tentative'])) {
2296
			return true;
2297
		}
2298
		sleep(1);
2299
		$time++;
2300
	}
2301

    
2302
	return false;
2303
}
2304

    
2305
function interface_isppp_type($interface) {
2306
	global $config;
2307

    
2308
	if (!is_array($config['interfaces'][$interface])) {
2309
		return false;
2310
	}
2311

    
2312
	switch ($config['interfaces'][$interface]['ipaddr']) {
2313
		case 'pptp':
2314
		case 'l2tp':
2315
		case 'pppoe':
2316
		case 'ppp':
2317
			return true;
2318
			break;
2319
		default:
2320
			return false;
2321
			break;
2322
	}
2323
}
2324

    
2325
function interfaces_ptpid_used($ptpid) {
2326
	global $config;
2327

    
2328
	if (is_array($config['ppps']['ppp'])) {
2329
		foreach ($config['ppps']['ppp'] as & $settings) {
2330
			if ($ptpid == $settings['ptpid']) {
2331
				return true;
2332
			}
2333
		}
2334
	}
2335

    
2336
	return false;
2337
}
2338

    
2339
function interfaces_ptpid_next() {
2340

    
2341
	$ptpid = 0;
2342
	while (interfaces_ptpid_used($ptpid)) {
2343
		$ptpid++;
2344
	}
2345

    
2346
	return $ptpid;
2347
}
2348

    
2349
function getMPDCRONSettings($pppif) {
2350
	global $config;
2351

    
2352
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2353
	if (is_array($config['cron']['item'])) {
2354
		foreach ($config['cron']['item'] as $i => $item) {
2355
			if (stripos($item['command'], $cron_cmd_file) !== false) {
2356
				return array("ID" => $i, "ITEM" => $item);
2357
			}
2358
		}
2359
	}
2360

    
2361
	return NULL;
2362
}
2363

    
2364
function handle_pppoe_reset($post_array) {
2365
	global $config, $g;
2366

    
2367
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2368
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2369

    
2370
	if (!is_array($config['cron']['item'])) {
2371
		$config['cron']['item'] = array();
2372
	}
2373

    
2374
	$itemhash = getMPDCRONSettings($pppif);
2375

    
2376
	// reset cron items if necessary and return
2377
	if (empty($post_array['pppoe-reset-type'])) {
2378
		if (isset($itemhash)) {
2379
			unset($config['cron']['item'][$itemhash['ID']]);
2380
		}
2381
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2382
		return;
2383
	}
2384

    
2385
	if (empty($itemhash)) {
2386
		$itemhash = array();
2387
	}
2388
	$item = array();
2389
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2390
		$item['minute'] = $post_array['pppoe_resetminute'];
2391
		$item['hour'] = $post_array['pppoe_resethour'];
2392
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2393
			$date = explode("/", $post_array['pppoe_resetdate']);
2394
			$item['mday'] = $date[1];
2395
			$item['month'] = $date[0];
2396
		} else {
2397
			$item['mday'] = "*";
2398
			$item['month'] = "*";
2399
		}
2400
		$item['wday'] = "*";
2401
		$item['who'] = "root";
2402
		$item['command'] = $cron_cmd_file;
2403
	} elseif (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2404
		switch ($post_array['pppoe_pr_preset_val']) {
2405
			case "monthly":
2406
				$item['minute'] = "0";
2407
				$item['hour'] = "0";
2408
				$item['mday'] = "1";
2409
				$item['month'] = "*";
2410
				$item['wday'] = "*";
2411
				break;
2412
			case "weekly":
2413
				$item['minute'] = "0";
2414
				$item['hour'] = "0";
2415
				$item['mday'] = "*";
2416
				$item['month'] = "*";
2417
				$item['wday'] = "0";
2418
				break;
2419
			case "daily":
2420
				$item['minute'] = "0";
2421
				$item['hour'] = "0";
2422
				$item['mday'] = "*";
2423
				$item['month'] = "*";
2424
				$item['wday'] = "*";
2425
				break;
2426
			case "hourly":
2427
				$item['minute'] = "0";
2428
				$item['hour'] = "*";
2429
				$item['mday'] = "*";
2430
				$item['month'] = "*";
2431
				$item['wday'] = "*";
2432
				break;
2433
		} // end switch
2434
		$item['who'] = "root";
2435
		$item['command'] = $cron_cmd_file;
2436
	}
2437
	if (empty($item)) {
2438
		return;
2439
	}
2440
	if (isset($itemhash['ID'])) {
2441
		$config['cron']['item'][$itemhash['ID']] = $item;
2442
	} else {
2443
		$config['cron']['item'][] = $item;
2444
	}
2445
}
2446

    
2447
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2448
	global $config;
2449
	$ppp_list = array();
2450
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2451
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2452
			$ports = explode(",", $ppp['ports']);
2453
			foreach($ports as $port) {
2454
				foreach($triggerinterfaces as $vip) {
2455
					if ($port == "_vip{$vip['uniqid']}") {
2456
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2457
						$ppp_list[$if] = 1;
2458
					}
2459
				}
2460
			}
2461
		}
2462
	}
2463
	foreach($ppp_list as $pppif => $dummy) {
2464
		interface_ppps_configure($pppif);
2465
	}
2466
}
2467

    
2468
/*
2469
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2470
 * It writes the mpd config file to /var/etc every time the link is opened.
2471
 */
2472
function interface_ppps_configure($interface) {
2473
	global $config, $g;
2474

    
2475
	/* Return for unassigned interfaces. This is a minimum requirement. */
2476
	if (empty($config['interfaces'][$interface])) {
2477
		return 0;
2478
	}
2479
	$ifcfg = $config['interfaces'][$interface];
2480
	if (!isset($ifcfg['enable'])) {
2481
		return 0;
2482
	}
2483

    
2484
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2485
	if (!is_dir("/var/spool/lock")) {
2486
		mkdir("/var/spool/lock", 0777, true);
2487
	}
2488
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2489
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2490
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2491
	}
2492

    
2493
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2494
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2495
			if ($ifcfg['if'] == $ppp['if']) {
2496
				break;
2497
			}
2498
		}
2499
	}
2500
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2501
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2502
		return 0;
2503
	}
2504
	$pppif = $ifcfg['if'];
2505
	if ($ppp['type'] == "ppp") {
2506
		$type = "modem";
2507
	} else {
2508
		$type = $ppp['type'];
2509
	}
2510
	$upper_type = strtoupper($ppp['type']);
2511

    
2512
	$confports = explode(',', $ppp['ports']);
2513
	if ($type == "modem") {
2514
		$ports = $confports;
2515
	} else {
2516
		$ports = array();
2517
		foreach ($confports as $pid => $port) {
2518
			if (strstr($port, "_vip")) {
2519
				if (get_carp_interface_status($port) != "MASTER") {
2520
					continue;
2521
				}
2522
			}
2523
			$ports[$pid] = get_real_interface($port);
2524
			if (empty($ports[$pid])) {
2525
				return 0;
2526
			}
2527
		}
2528
	}
2529
	$localips = explode(',', $ppp['localip']);
2530
	$gateways = explode(',', $ppp['gateway']);
2531
	$subnets = explode(',', $ppp['subnet']);
2532

    
2533
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2534
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2535
	 */
2536
	foreach ($ports as $pid => $port) {
2537
		switch ($ppp['type']) {
2538
			case "pppoe":
2539
				/* Bring the parent interface up */
2540
				interfaces_bring_up($port);
2541
				pfSense_ngctl_attach(".", $port);
2542
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2543
				$ngif = str_replace(".", "_", $port);
2544
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2545
				break;
2546
			case "pptp":
2547
			case "l2tp":
2548
				/* configure interface */
2549
				if (is_ipaddr($localips[$pid])) {
2550
					// Manually configure interface IP/subnet
2551
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2552
					interfaces_bring_up($port);
2553
				} elseif (empty($localips[$pid])) {
2554
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2555
				}
2556

    
2557
				if (!is_ipaddr($localips[$pid])) {
2558
					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));
2559
					$localips[$pid] = "0.0.0.0";
2560
				}
2561
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2562
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2563
				}
2564
				if (!is_ipaddr($gateways[$pid])) {
2565
					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));
2566
					return 0;
2567
				}
2568
				pfSense_ngctl_attach(".", $port);
2569
				break;
2570
			case "ppp":
2571
				if (!file_exists("{$port}")) {
2572
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2573
					return 0;
2574
				}
2575
				break;
2576
			default:
2577
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2578
				break;
2579
		}
2580
	}
2581

    
2582
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2583
	    (is_array($ports) && count($ports) > 1)) {
2584
		$multilink = "enable";
2585
	} else {
2586
		$multilink = "disable";
2587
	}
2588

    
2589
	if ($type == "modem") {
2590
		if (is_ipaddr($ppp['localip'])) {
2591
			$localip = $ppp['localip'];
2592
		} else {
2593
			$localip = '0.0.0.0';
2594
		}
2595

    
2596
		if (is_ipaddr($ppp['gateway'])) {
2597
			$gateway = $ppp['gateway'];
2598
		} else {
2599
			$gateway = "10.64.64.{$pppid}";
2600
		}
2601
		$ranges = "{$localip}/0 {$gateway}/0";
2602

    
2603
		if (empty($ppp['apnum'])) {
2604
			$ppp['apnum'] = 1;
2605
		}
2606
	} else {
2607
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2608
	}
2609

    
2610
	if (isset($ppp['ondemand'])) {
2611
		$ondemand = "enable";
2612
	} else {
2613
		$ondemand = "disable";
2614
	}
2615
	if (!isset($ppp['idletimeout'])) {
2616
		$ppp['idletimeout'] = 0;
2617
	}
2618

    
2619
	if (empty($ppp['username']) && $type == "modem") {
2620
		$ppp['username'] = "user";
2621
		$ppp['password'] = "none";
2622
	}
2623
	if (empty($ppp['password']) && $type == "modem") {
2624
		$passwd = "none";
2625
	} else {
2626
		$passwd = base64_decode($ppp['password']);
2627
	}
2628

    
2629
	$bandwidths = explode(',', $ppp['bandwidth']);
2630
	$defaultmtu = "1492";
2631
	if (!empty($ifcfg['mtu'])) {
2632
		$defaultmtu = intval($ifcfg['mtu']);
2633
	}
2634
	if (isset($ppp['mtu'])) {
2635
		$mtus = explode(',', $ppp['mtu']);
2636
	}
2637
	if (isset($ppp['mru'])) {
2638
		$mrus = explode(',', $ppp['mru']);
2639
	}
2640
	if (isset($ppp['mrru'])) {
2641
		$mrrus = explode(',', $ppp['mrru']);
2642
	}
2643
	if (!empty($ifcfg['ipaddrv6'])) {
2644
		$ipv6cp = "set bundle enable ipv6cp";
2645
	}
2646

    
2647
	// Construct the mpd.conf file
2648
	$mpdconf = <<<EOD
2649
startup:
2650
	# configure the console
2651
	set console close
2652
	# configure the web server
2653
	set web close
2654

    
2655
default:
2656
{$ppp['type']}client:
2657
	create bundle static {$interface}
2658
	{$ipv6cp}
2659
	set iface name {$pppif}
2660

    
2661
EOD;
2662
	$setdefaultgw = false;
2663
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2664
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2665
	if ($defgw4['interface'] == $interface) {
2666
		$setdefaultgw = true;
2667
	}
2668

    
2669
/* Omit this, we maintain the default route by other means, and it causes problems with
2670
 * default gateway switching. See redmine #1837 for original issue
2671
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2672
 * edge case. redmine #6495 open to address.
2673
 */
2674
	if ($setdefaultgw == true) {
2675
		$mpdconf .= <<<EOD
2676
	set iface route default
2677

    
2678
EOD;
2679
	}
2680

    
2681
	$mpdconf .= <<<EOD
2682
	set iface {$ondemand} on-demand
2683
	set iface idle {$ppp['idletimeout']}
2684

    
2685
EOD;
2686

    
2687
	if (isset($ppp['ondemand'])) {
2688
		$mpdconf .= <<<EOD
2689
	set iface addrs 10.10.1.1 10.10.1.2
2690

    
2691
EOD;
2692
	}
2693

    
2694
	if (isset($ppp['mtu-override']) &&
2695
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2696
		/* Find the smaller MTU set on ports */
2697
		$mtu = $defaultmtu;
2698
		foreach ($ports as $pid => $port) {
2699
			if (empty($mtus[$pid])) {
2700
				$mtus[$pid] = $defaultmtu;
2701
			}
2702
			if ($type == "pppoe") {
2703
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2704
					$mtus[$pid] = get_interface_mtu($port) - 8;
2705
				}
2706
			}
2707
			if ($mtu > $mtus[$pid]) {
2708
				$mtu = $mtus[$pid];
2709
			}
2710
		}
2711
		$mpdconf .= <<<EOD
2712
	set iface mtu {$mtu} override
2713

    
2714
EOD;
2715
	}
2716

    
2717
	if (isset($ppp['tcpmssfix'])) {
2718
		$tcpmss = "disable";
2719
	} else {
2720
		$tcpmss = "enable";
2721
	}
2722
	$mpdconf .= <<<EOD
2723
	set iface {$tcpmss} tcpmssfix
2724

    
2725
EOD;
2726

    
2727
	$mpdconf .= <<<EOD
2728
	set iface up-script /usr/local/sbin/ppp-linkup
2729
	set iface down-script /usr/local/sbin/ppp-linkdown
2730
	set ipcp ranges {$ranges}
2731

    
2732
EOD;
2733
	if (isset($ppp['vjcomp'])) {
2734
		$mpdconf .= <<<EOD
2735
	set ipcp no vjcomp
2736

    
2737
EOD;
2738
	}
2739

    
2740
	if (isset($config['system']['dnsallowoverride'])) {
2741
		$mpdconf .= <<<EOD
2742
	set ipcp enable req-pri-dns
2743
	set ipcp enable req-sec-dns
2744

    
2745
EOD;
2746
	}
2747

    
2748
	if (!isset($ppp['verbose_log'])) {
2749
		$mpdconf .= <<<EOD
2750
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2751

    
2752
EOD;
2753
	}
2754

    
2755
	foreach ($ports as $pid => $port) {
2756
		$port = get_real_interface($port);
2757
		$mpdconf .= <<<EOD
2758

    
2759
	create link static {$interface}_link{$pid} {$type}
2760
	set link action bundle {$interface}
2761
	set link {$multilink} multilink
2762
	set link keep-alive 10 60
2763
	set link max-redial 0
2764

    
2765
EOD;
2766
		if (isset($ppp['shortseq'])) {
2767
			$mpdconf .= <<<EOD
2768
	set link no shortseq
2769

    
2770
EOD;
2771
		}
2772

    
2773
		if (isset($ppp['acfcomp'])) {
2774
			$mpdconf .= <<<EOD
2775
	set link no acfcomp
2776

    
2777
EOD;
2778
		}
2779

    
2780
		if (isset($ppp['protocomp'])) {
2781
			$mpdconf .= <<<EOD
2782
	set link no protocomp
2783

    
2784
EOD;
2785
		}
2786

    
2787
		$mpdconf .= <<<EOD
2788
	set link disable chap pap
2789
	set link accept chap pap eap
2790
	set link disable incoming
2791

    
2792
EOD;
2793

    
2794

    
2795
		if (!empty($bandwidths[$pid])) {
2796
			$mpdconf .= <<<EOD
2797
	set link bandwidth {$bandwidths[$pid]}
2798

    
2799
EOD;
2800
		}
2801

    
2802
		if (empty($mtus[$pid])) {
2803
			$mtus[$pid] = $defaultmtu;
2804
		}
2805
		if ($type == "pppoe") {
2806
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2807
				$mtus[$pid] = get_interface_mtu($port) - 8;
2808
			}
2809
		}
2810
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2811
		    !isset($ppp['mtu-override']) &&
2812
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2813
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2814
			$mpdconf .= <<<EOD
2815
	set link mtu {$mtus[$pid]}
2816

    
2817
EOD;
2818
		}
2819

    
2820
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2821
		    !isset($ppp['mtu-override']) &&
2822
		    !empty($mrus[$pid])) {
2823
			$mpdconf .= <<<EOD
2824
	set link mru {$mrus[$pid]}
2825

    
2826
EOD;
2827
		}
2828

    
2829
		if (!empty($mrrus[$pid])) {
2830
			$mpdconf .= <<<EOD
2831
	set link mrru {$mrrus[$pid]}
2832

    
2833
EOD;
2834
		}
2835

    
2836
		$mpdconf .= <<<EOD
2837
	set auth authname "{$ppp['username']}"
2838
	set auth password {$passwd}
2839

    
2840
EOD;
2841
		if ($type == "modem") {
2842
			$mpdconf .= <<<EOD
2843
	set modem device {$ppp['ports']}
2844
	set modem script DialPeer
2845
	set modem idle-script Ringback
2846
	set modem watch -cd
2847
	set modem var \$DialPrefix "DT"
2848
	set modem var \$Telephone "{$ppp['phone']}"
2849

    
2850
EOD;
2851
		}
2852
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2853
			$mpdconf .= <<<EOD
2854
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2855

    
2856
EOD;
2857
		}
2858
		if (isset($ppp['initstr']) && $type == "modem") {
2859
			$initstr = base64_decode($ppp['initstr']);
2860
			$mpdconf .= <<<EOD
2861
	set modem var \$InitString "{$initstr}"
2862

    
2863
EOD;
2864
		}
2865
		if (isset($ppp['simpin']) && $type == "modem") {
2866
			if ($ppp['pin-wait'] == "") {
2867
				$ppp['pin-wait'] = 0;
2868
			}
2869
			$mpdconf .= <<<EOD
2870
	set modem var \$SimPin "{$ppp['simpin']}"
2871
	set modem var \$PinWait "{$ppp['pin-wait']}"
2872

    
2873
EOD;
2874
		}
2875
		if (isset($ppp['apn']) && $type == "modem") {
2876
			$mpdconf .= <<<EOD
2877
	set modem var \$APN "{$ppp['apn']}"
2878
	set modem var \$APNum "{$ppp['apnum']}"
2879

    
2880
EOD;
2881
		}
2882
		if ($type == "pppoe") {
2883
			$hostuniq = '';
2884
			if (!empty($ppp['hostuniq'])) {
2885
				if (preg_match('/^0x[a-fA-F0-9]+$/', $ppp['hostuniq'])) {
2886
					$hostuniq = strtolower($ppp['hostuniq']) .'|';
2887
				} elseif (preg_match('/^[a-zA-Z0-9]+$/i', $ppp['hostuniq'])) {
2888
					$hostuniq = '0x' . bin2hex($ppp['hostuniq']) . '|';
2889
				}
2890
			}
2891
			// Send a null service name if none is set.
2892
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2893
			$mpdconf .= <<<EOD
2894
	set pppoe service "{$hostuniq}{$provider}"
2895

    
2896
EOD;
2897
		}
2898
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2899
			$mpdconf .= <<<EOD
2900
	set pppoe max-payload {$mtus[$pid]}
2901

    
2902
EOD;
2903
		}
2904
		if ($type == "pppoe") {
2905
			$mpdconf .= <<<EOD
2906
	set pppoe iface {$port}
2907

    
2908
EOD;
2909
		}
2910

    
2911
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2912
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2913
			$mpdconf .= <<<EOD
2914
	set l2tp secret "{$secret}"
2915

    
2916
EOD;
2917
		}
2918

    
2919
		if (($type == "pptp") || ($type == "l2tp")) {
2920
			$mpdconf .= <<<EOD
2921
	set {$type} self {$localips[$pid]}
2922
	set {$type} peer {$gateways[$pid]}
2923

    
2924
EOD;
2925
		}
2926

    
2927
		$mpdconf .= "\topen\n";
2928
	} //end foreach ($port)
2929

    
2930

    
2931
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2932
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2933
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2934
	} else {
2935
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2936
		if (!$fd) {
2937
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2938
			return 0;
2939
		}
2940
		// Write out mpd_ppp.conf
2941
		fwrite($fd, $mpdconf);
2942
		fclose($fd);
2943
		unset($mpdconf);
2944
	}
2945

    
2946
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2947
	if (isset($ppp['uptime'])) {
2948
		if (!file_exists("/conf/{$pppif}.log")) {
2949
			file_put_contents("/conf/{$pppif}.log", '');
2950
		}
2951
	} else {
2952
		if (file_exists("/conf/{$pppif}.log")) {
2953
			@unlink("/conf/{$pppif}.log");
2954
		}
2955
	}
2956

    
2957
	/* clean up old lock files */
2958
	foreach ($ports as $port) {
2959
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2960
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2961
		}
2962
	}
2963

    
2964
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2965
	/* random IPv6 interface identifier during boot. More details at */
2966
	/* https://forum.netgate.com/post/592474 */
2967
	if (platform_booting() && is_array($config['interfaces'])) {
2968
		$count = 0;
2969
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2970
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2971
				$tempaddr[$count]['if'] = $tempiface['if'];
2972
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2973
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2974
				$count++;
2975
			}
2976
			// Maximum /31 is is x.y.z.254/31
2977
			if ($count > 122) {
2978
				break;
2979
			}
2980
		}
2981
		unset($count);
2982
	}
2983

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

    
2989
	// Check for PPPoE periodic reset request
2990
	if ($type == "pppoe") {
2991
		if (!empty($ppp['pppoe-reset-type'])) {
2992
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2993
		} else {
2994
			interface_setup_pppoe_reset_file($ppp['if']);
2995
		}
2996
	}
2997
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2998
	$i = 0;
2999
	while ($i < 10) {
3000
		if (does_interface_exist($ppp['if'], true)) {
3001
			break;
3002
		}
3003
		sleep(3);
3004
		$i++;
3005
	}
3006

    
3007
	/* Remove all temporary bogon IPv4 addresses */
3008
	if (is_array($tempaddr)) {
3009
		foreach ($tempaddr as $tempiface) {
3010
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
3011
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
3012
			}
3013
		}
3014
		unset ($tempaddr);
3015
	}
3016

    
3017
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
3018
	/* We should be able to launch the right version for each modem */
3019
	/* We can also guess the mondev from the manufacturer */
3020
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
3021
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
3022
	foreach ($ports as $port) {
3023
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
3024
			$mondev = substr(basename($port), 0, -1);
3025
			$devlist = glob("/dev/{$mondev}?");
3026
			$mondev = basename(end($devlist));
3027
		}
3028
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
3029
			$mondev = substr(basename($port), 0, -1) . "1";
3030
		}
3031
		if ($mondev != '') {
3032
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
3033
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
3034
		}
3035
	}
3036

    
3037
	return 1;
3038
}
3039

    
3040
function interfaces_sync_setup() {
3041
	global $g, $config;
3042

    
3043
	if (isset($config['system']['developerspew'])) {
3044
		$mt = microtime();
3045
		echo "interfaces_sync_setup() being called $mt\n";
3046
	}
3047

    
3048
	if (platform_booting()) {
3049
		echo gettext("Configuring CARP settings...");
3050
		mute_kernel_msgs();
3051
	}
3052

    
3053
	/* suck in configuration items */
3054
	if ($config['hasync']) {
3055
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
3056
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
3057
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
3058
	}
3059

    
3060
	set_sysctl(array(
3061
		"net.inet.carp.preempt" => "1",
3062
		"net.inet.carp.log" => "1")
3063
	);
3064

    
3065
	if (!empty($pfsyncinterface)) {
3066
		$carp_sync_int = get_real_interface($pfsyncinterface);
3067
	}
3068

    
3069
	/* setup pfsync interface */
3070
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
3071
		if (is_ipaddr($pfsyncpeerip)) {
3072
			$syncpeer = "syncpeer {$pfsyncpeerip}";
3073
		} else {
3074
			$syncpeer = "-syncpeer";
3075
		}
3076

    
3077
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} " .
3078
		    "{$syncpeer} up");
3079
		mwexec("/sbin/ifconfig pfsync0 -defer");
3080

    
3081
		/*
3082
		 * XXX: Handle an issue with pfsync(4) and carp(4). In a
3083
		 * cluster carp will come up before pfsync(4) has updated and
3084
		 * so will cause issues for existing sessions.
3085
		 */
3086
		log_error(gettext("waiting for pfsync..."));
3087

    
3088
		$i = 0;
3089
		do {
3090
			sleep(1);
3091
			$_gb = exec('/sbin/ifconfig pfsync0 | ' .
3092
			    '/usr/bin/grep -q "syncok: 0" 2>/dev/null', $output,
3093
			    $rc);
3094
			$i++;
3095
		} while ($rc != 0 && $i <= 30);
3096

    
3097
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
3098
		log_error(gettext("Configuring CARP settings finalize..."));
3099
	} else {
3100
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down");
3101
	}
3102

    
3103
	$carplist = get_configured_vip_list('all', VIP_CARP);
3104
	if (is_array($carplist) && count($carplist) > 0) {
3105
		set_single_sysctl("net.inet.carp.allow", "1");
3106
	} else {
3107
		set_single_sysctl("net.inet.carp.allow", "0");
3108
	}
3109

    
3110
	if (platform_booting()) {
3111
		unmute_kernel_msgs();
3112
		echo gettext("done.") . "\n";
3113
	}
3114
}
3115

    
3116
function interface_proxyarp_configure($interface = "") {
3117
	global $config, $g;
3118
	if (isset($config['system']['developerspew'])) {
3119
		$mt = microtime();
3120
		echo "interface_proxyarp_configure() being called $mt\n";
3121
	}
3122

    
3123
	/* kill any running choparp */
3124
	if (empty($interface)) {
3125
		killbyname("choparp");
3126
	} else {
3127
		$vipif = get_real_interface($interface);
3128
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
3129
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
3130
		}
3131
	}
3132

    
3133
	$paa = array();
3134
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
3135

    
3136
		/* group by interface */
3137
		foreach ($config['virtualip']['vip'] as $vipent) {
3138
			if ($vipent['mode'] === "proxyarp") {
3139
				if ($vipent['interface']) {
3140
					$proxyif = $vipent['interface'];
3141
				} else {
3142
					$proxyif = "wan";
3143
				}
3144

    
3145
				if (!empty($interface) && $interface != $proxyif) {
3146
					continue;
3147
				}
3148

    
3149
				if (!is_array($paa[$proxyif])) {
3150
					$paa[$proxyif] = array();
3151
				}
3152

    
3153
				$paa[$proxyif][] = $vipent;
3154
			}
3155
		}
3156
	}
3157

    
3158
	if (!empty($interface)) {
3159
		if (is_array($paa[$interface])) {
3160
			$paaifip = get_interface_ip($interface);
3161
			if (!is_ipaddr($paaifip)) {
3162
				return;
3163
			}
3164
			$vipif = get_real_interface($interface);
3165
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
3166
			$args .= $vipif . " auto";
3167
			foreach ($paa[$interface] as $paent) {
3168
				if (isset($paent['subnet'])) {
3169
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
3170
				} elseif (isset($paent['range'])) {
3171
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
3172
				}
3173
			}
3174
			mwexec_bg("/usr/local/sbin/choparp " . $args);
3175
		}
3176
	} elseif (count($paa) > 0) {
3177
		foreach ($paa as $paif => $paents) {
3178
			$paaifip = get_interface_ip($paif);
3179
			if (!is_ipaddr($paaifip)) {
3180
				continue;
3181
			}
3182
			$vipif = get_real_interface($paif);
3183
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
3184
			$args .= $vipif . " auto";
3185
			foreach ($paents as $paent) {
3186
				if (isset($paent['subnet'])) {
3187
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
3188
				} elseif (isset($paent['range'])) {
3189
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
3190
				}
3191
			}
3192
			mwexec_bg("/usr/local/sbin/choparp " . $args);
3193
		}
3194
	}
3195
}
3196

    
3197
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
3198
	global $g, $config;
3199

    
3200
	if (is_array($config['virtualip']['vip'])) {
3201
		foreach ($config['virtualip']['vip'] as $vip) {
3202

    
3203
			$iface = $vip['interface'];
3204
			if (substr($iface, 0, 4) == "_vip")
3205
				$iface = get_configured_vip_interface($vip['interface']);
3206
			if ($iface != $interface)
3207
				continue;
3208
			if ($type == VIP_CARP) {
3209
				if ($vip['mode'] != "carp")
3210
					continue;
3211
			} elseif ($type == VIP_IPALIAS) {
3212
				if ($vip['mode'] != "ipalias")
3213
					continue;
3214
			} else {
3215
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
3216
					continue;
3217
			}
3218

    
3219
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
3220
				interface_vip_bring_down($vip);
3221
			elseif ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
3222
				interface_vip_bring_down($vip);
3223
			elseif ($inet == "all")
3224
				interface_vip_bring_down($vip);
3225
		}
3226
	}
3227
}
3228

    
3229
function interfaces_vips_configure($interface = "") {
3230
	global $g, $config;
3231
	if (isset($config['system']['developerspew'])) {
3232
		$mt = microtime();
3233
		echo "interfaces_vips_configure() being called $mt\n";
3234
	}
3235

    
3236
	if (!is_array($config['virtualip']['vip'])) {
3237
		return;
3238
	}
3239

    
3240
	$carp_setuped = false;
3241
	$anyproxyarp = false;
3242
	foreach ($config['virtualip']['vip'] as $vip) {
3243
		if ($interface <> "" &&
3244
		    get_root_interface($vip['interface']) <> $interface) {
3245
			continue;
3246
		}
3247
		switch ($vip['mode']) {
3248
			case "proxyarp":
3249
				/*
3250
				 * nothing it is handled on
3251
				 * interface_proxyarp_configure()
3252
				 */
3253
				$anyproxyarp = true;
3254
				break;
3255
			case "ipalias":
3256
				interface_ipalias_configure($vip);
3257
				break;
3258
			case "carp":
3259
				if ($carp_setuped == false) {
3260
					$carp_setuped = true;
3261
				}
3262
				interface_carp_configure($vip);
3263
				break;
3264
		}
3265
	}
3266
	if ($carp_setuped == true) {
3267
		interfaces_sync_setup();
3268
	}
3269
	if ($anyproxyarp == true) {
3270
		interface_proxyarp_configure();
3271
	}
3272
}
3273

    
3274
function interface_ipalias_configure(&$vip) {
3275
	global $config;
3276

    
3277
	$gateway = '';
3278
	if ($vip['mode'] != 'ipalias') {
3279
		return;
3280
	}
3281

    
3282
	$realif = get_real_interface("_vip{$vip['uniqid']}");
3283
	if ($realif != "lo0") {
3284
		$if = convert_real_interface_to_friendly_interface_name($realif);
3285
		if (!isset($config['interfaces'][$if]) ||
3286
		    !isset($config['interfaces'][$if]['enable'])) {
3287
			return;
3288
		}
3289
		if (is_pseudo_interface($realif)) {
3290
			if (is_ipaddrv4($vip['subnet'])) {
3291
				$gateway = get_interface_gateway($if);
3292
			} else {
3293
				$gateway = get_interface_gateway_v6($if);
3294
			}
3295
		}
3296
	}
3297

    
3298
	$af = 'inet';
3299
	if (is_ipaddrv6($vip['subnet'])) {
3300
		$af = 'inet6';
3301
	}
3302
	$iface = $vip['interface'];
3303
	$vhid = '';
3304
	if (substr($vip['interface'], 0, 4) == "_vip") {
3305
		$carpvip = get_configured_vip($vip['interface']);
3306
		$iface = $carpvip['interface'];
3307
		$vhid = "vhid {$carpvip['vhid']}";
3308
	}
3309
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$gateway} {$vhid}");
3310
	unset($iface, $af, $realif, $carpvip, $vhid, $gateway);
3311
}
3312

    
3313
function interface_carp_configure(&$vip, $maintenancemode_only = false) {
3314
	global $config, $g;
3315
	if (isset($config['system']['developerspew'])) {
3316
		$mt = microtime();
3317
		echo "interface_carp_configure() being called $mt\n";
3318
	}
3319

    
3320
	if ($vip['mode'] != "carp") {
3321
		return;
3322
	}
3323

    
3324
	$realif = get_real_interface($vip['interface']);
3325
	if (!does_interface_exist($realif)) {
3326
		file_notice("CARP", sprintf(gettext(
3327
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
3328
		    $vip['subnet']), "Firewall: Virtual IP", "");
3329
		return;
3330
	}
3331
	if ($realif != "lo0") {
3332
		if (!isset($config['interfaces'][$vip['interface']]) ||
3333
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
3334
			return;
3335
		}
3336
	}
3337

    
3338
	$vip_password = $vip['password'];
3339
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3340
	    $vip_password)));
3341
	if ($vip['password'] != "") {
3342
		$password = " pass {$vip_password}";
3343
	}
3344

    
3345
	$advbase = "";
3346
	if (!empty($vip['advbase'])) {
3347
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3348
	}
3349

    
3350
	$carp_maintenancemode = isset(
3351
	    $config["virtualip_carp_maintenancemode"]);
3352
	if ($carp_maintenancemode) {
3353
		$advskew = "advskew 254";
3354
	} else {
3355
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3356
	}
3357

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

    
3361
	if (!$maintenancemode_only) {
3362
		if (is_ipaddrv4($vip['subnet'])) {
3363
			mwexec("/sbin/ifconfig {$realif} " .
3364
			    escapeshellarg($vip['subnet']) . "/" .
3365
			    escapeshellarg($vip['subnet_bits']) .
3366
			    " alias vhid " . escapeshellarg($vip['vhid']));
3367
		} elseif (is_ipaddrv6($vip['subnet'])) {
3368
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3369
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3370
			    escapeshellarg($vip['subnet_bits']) .
3371
			    " alias vhid " . escapeshellarg($vip['vhid']));
3372
		}
3373
	}
3374

    
3375
	return $realif;
3376
}
3377

    
3378
function interface_wireless_clone($realif, $wlcfg) {
3379
	global $config, $g;
3380
	/*   Check to see if interface has been cloned as of yet.
3381
	 *   If it has not been cloned then go ahead and clone it.
3382
	 */
3383
	$needs_clone = false;
3384
	if (is_array($wlcfg['wireless'])) {
3385
		$wlcfg_mode = $wlcfg['wireless']['mode'];
3386
	} else {
3387
		$wlcfg_mode = $wlcfg['mode'];
3388
	}
3389
	switch ($wlcfg_mode) {
3390
		case "hostap":
3391
			$mode = "wlanmode hostap";
3392
			break;
3393
		case "adhoc":
3394
			$mode = "wlanmode adhoc";
3395
			break;
3396
		default:
3397
			$mode = "";
3398
			break;
3399
	}
3400
	$baseif = interface_get_wireless_base($wlcfg['if']);
3401
	if (does_interface_exist($realif)) {
3402
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
3403
		$ifconfig_str = implode($output);
3404
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
3405
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
3406
			$needs_clone = true;
3407
		}
3408
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
3409
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
3410
			$needs_clone = true;
3411
		}
3412
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3413
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3414
			$needs_clone = true;
3415
		}
3416
	} else {
3417
		$needs_clone = true;
3418
	}
3419

    
3420
	if ($needs_clone == true) {
3421
		/* remove previous instance if it exists */
3422
		if (does_interface_exist($realif)) {
3423
			pfSense_interface_destroy($realif);
3424

    
3425
			/* Invalidate cache */
3426
			get_interface_arr(true);
3427
		}
3428

    
3429
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3430
		// Create the new wlan interface. FreeBSD returns the new interface name.
3431
		// example:  wlan2
3432
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3433
		if ($ret <> 0) {
3434
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3435
			return false;
3436
		}
3437
		$newif = trim($out[0]);
3438
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3439
		pfSense_interface_rename($newif, $realif);
3440
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3441
	}
3442
	return true;
3443
}
3444

    
3445
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3446
	global $config, $g;
3447

    
3448
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3449
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3450
				 'regdomain', 'regcountry', 'reglocation');
3451

    
3452
	if (!is_interface_wireless($ifcfg['if'])) {
3453
		return;
3454
	}
3455

    
3456
	$baseif = interface_get_wireless_base($ifcfg['if']);
3457

    
3458
	// Sync shared settings for assigned clones
3459
	$iflist = get_configured_interface_list(true);
3460
	foreach ($iflist as $if) {
3461
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
3462
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
3463
				foreach ($shared_settings as $setting) {
3464
					if ($sync_changes) {
3465
						if (isset($ifcfg['wireless'][$setting])) {
3466
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
3467
						} elseif (isset($config['interfaces'][$if]['wireless'][$setting])) {
3468
							unset($config['interfaces'][$if]['wireless'][$setting]);
3469
						}
3470
					} else {
3471
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3472
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
3473
						} elseif (isset($ifcfg['wireless'][$setting])) {
3474
							unset($ifcfg['wireless'][$setting]);
3475
						}
3476
					}
3477
				}
3478
				if (!$sync_changes) {
3479
					break;
3480
				}
3481
			}
3482
		}
3483
	}
3484

    
3485
	// Read or write settings at shared area
3486
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3487
		foreach ($shared_settings as $setting) {
3488
			if ($sync_changes) {
3489
				if (isset($ifcfg['wireless'][$setting])) {
3490
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3491
				} elseif (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3492
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3493
				}
3494
			} elseif (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3495
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3496
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3497
				} elseif (isset($ifcfg['wireless'][$setting])) {
3498
					unset($ifcfg['wireless'][$setting]);
3499
				}
3500
			}
3501
		}
3502
	}
3503

    
3504
	// Sync the mode on the clone creation page with the configured mode on the interface
3505
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3506
		foreach ($config['wireless']['clone'] as &$clone) {
3507
			if ($clone['cloneif'] == $ifcfg['if']) {
3508
				if ($sync_changes) {
3509
					$clone['mode'] = $ifcfg['wireless']['mode'];
3510
				} else {
3511
					$ifcfg['wireless']['mode'] = $clone['mode'];
3512
				}
3513
				break;
3514
			}
3515
		}
3516
		unset($clone);
3517
	}
3518
}
3519

    
3520
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3521
	global $config, $g;
3522

    
3523
	/*    open up a shell script that will be used to output the commands.
3524
	 *    since wireless is changing a lot, these series of commands are fragile
3525
	 *    and will sometimes need to be verified by a operator by executing the command
3526
	 *    and returning the output of the command to the developers for inspection.  please
3527
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3528
	 */
3529

    
3530
	// Remove script file
3531
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3532

    
3533
	// Clone wireless nic if needed.
3534
	interface_wireless_clone($if, $wl);
3535

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

    
3539
	$fd_set = fopen("{$g['tmp_path']}/{$if}_setup.sh", "w");
3540
	fwrite($fd_set, "#!/bin/sh\n");
3541
	fwrite($fd_set, "# {$g['product_label']} wireless configuration script.\n\n");
3542

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

    
3545
	/* set values for /path/program */
3546
	if (file_exists("/usr/local/sbin/hostapd")) {
3547
		$hostapd = "/usr/local/sbin/hostapd";
3548
	} else {
3549
		$hostapd = "/usr/sbin/hostapd";
3550
	}
3551
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3552
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3553
	} else {
3554
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3555
	}
3556
	$ifconfig = "/sbin/ifconfig";
3557
	$sysctl = "/sbin/sysctl";
3558
	$sysctl_args = "-q";
3559
	$killall = "/usr/bin/killall";
3560

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

    
3563
	$wlcmd = array();
3564
	$wl_sysctl = array();
3565
	/* Set a/b/g standard */
3566
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3567
	/* skip mode entirely for "auto" */
3568
	if ($wlcfg['standard'] != "auto") {
3569
		$wlcmd[] = "mode " . escapeshellarg($standard);
3570
	}
3571

    
3572
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3573
	 * to prevent massive packet loss under certain conditions. */
3574
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3575
		$wlcmd[] = "-ampdu";
3576
	}
3577

    
3578
	/* Set ssid */
3579
	if ($wlcfg['ssid']) {
3580
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3581
	}
3582

    
3583
	/* Set 802.11g protection mode */
3584
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3585

    
3586
	/* set wireless channel value */
3587
	if (isset($wlcfg['channel'])) {
3588
		if ($wlcfg['channel'] == "0") {
3589
			$wlcmd[] = "channel any";
3590
		} else {
3591
			if ($wlcfg['channel_width'] != "0") {
3592
				$channel_width = ":" . $wlcfg['channel_width'];
3593
			} else {
3594
				$channel_width = '';
3595
			}
3596
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3597
		}
3598
	}
3599

    
3600
	/* Set antenna diversity value */
3601
	if (isset($wlcfg['diversity'])) {
3602
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3603
	}
3604

    
3605
	/* Set txantenna value */
3606
	if (isset($wlcfg['txantenna'])) {
3607
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3608
	}
3609

    
3610
	/* Set rxantenna value */
3611
	if (isset($wlcfg['rxantenna'])) {
3612
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3613
	}
3614

    
3615
	/* set Distance value */
3616
	if ($wlcfg['distance']) {
3617
		$distance = escapeshellarg($wlcfg['distance']);
3618
	}
3619

    
3620
	/* Set wireless hostap mode */
3621
	if ($wlcfg['mode'] == "hostap") {
3622
		$wlcmd[] = "mediaopt hostap";
3623
	} else {
3624
		$wlcmd[] = "-mediaopt hostap";
3625
	}
3626

    
3627
	/* Set wireless adhoc mode */
3628
	if ($wlcfg['mode'] == "adhoc") {
3629
		$wlcmd[] = "mediaopt adhoc";
3630
	} else {
3631
		$wlcmd[] = "-mediaopt adhoc";
3632
	}
3633

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

    
3636
	/* handle hide ssid option */
3637
	if (isset($wlcfg['hidessid']['enable'])) {
3638
		$wlcmd[] = "hidessid";
3639
	} else {
3640
		$wlcmd[] = "-hidessid";
3641
	}
3642

    
3643
	/* handle pureg (802.11g) only option */
3644
	if (isset($wlcfg['pureg']['enable'])) {
3645
		$wlcmd[] = "mode 11g pureg";
3646
	} else {
3647
		$wlcmd[] = "-pureg";
3648
	}
3649

    
3650
	/* handle puren (802.11n) only option */
3651
	if (isset($wlcfg['puren']['enable'])) {
3652
		$wlcmd[] = "puren";
3653
	} else {
3654
		$wlcmd[] = "-puren";
3655
	}
3656

    
3657
	/* enable apbridge option */
3658
	if (isset($wlcfg['apbridge']['enable'])) {
3659
		$wlcmd[] = "apbridge";
3660
	} else {
3661
		$wlcmd[] = "-apbridge";
3662
	}
3663

    
3664
	/* handle turbo option */
3665
	if (isset($wlcfg['turbo']['enable'])) {
3666
		$wlcmd[] = "mediaopt turbo";
3667
	} else {
3668
		$wlcmd[] = "-mediaopt turbo";
3669
	}
3670

    
3671
	/* handle txpower setting */
3672
	// or don't. this has issues at the moment.
3673
	/*
3674
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3675
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3676
	}*/
3677

    
3678
	/* handle wme option */
3679
	if (isset($wlcfg['wme']['enable'])) {
3680
		$wlcmd[] = "wme";
3681
	} else {
3682
		$wlcmd[] = "-wme";
3683
	}
3684

    
3685
	/* Enable wpa if it's configured. No WEP support anymore. */
3686
	if (isset($wlcfg['wpa']['enable'])) {
3687
		$wlcmd[] = "authmode wpa wepmode off ";
3688
	} else {
3689
		$wlcmd[] = "authmode open wepmode off ";
3690
	}
3691

    
3692
	kill_hostapd($if);
3693
	mwexec(kill_wpasupplicant("{$if}"));
3694

    
3695
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3696

    
3697
	switch ($wlcfg['mode']) {
3698
		case 'bss':
3699
			if (isset($wlcfg['wpa']['enable'])) {
3700
				$wpa .= <<<EOD
3701
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3702
ctrl_interface_group=0
3703
ap_scan=1
3704
#fast_reauth=1
3705
network={
3706
ssid="{$wlcfg['ssid']}"
3707
scan_ssid=1
3708
priority=5
3709
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3710
psk="{$wlcfg['wpa']['passphrase']}"
3711
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3712
group={$wlcfg['wpa']['wpa_pairwise']}
3713
}
3714
EOD;
3715

    
3716
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
3717
				unset($wpa);
3718
			}
3719
			break;
3720
		case 'hostap':
3721
			if (!empty($wlcfg['wpa']['passphrase'])) {
3722
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3723
			} else {
3724
				$wpa_passphrase = "";
3725
			}
3726
			if (isset($wlcfg['wpa']['enable'])) {
3727
				$wpa .= <<<EOD
3728
interface={$if}
3729
driver=bsd
3730
logger_syslog=-1
3731
logger_syslog_level=0
3732
logger_stdout=-1
3733
logger_stdout_level=0
3734
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3735
ctrl_interface={$g['varrun_path']}/hostapd
3736
ctrl_interface_group=wheel
3737
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3738
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3739
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3740
ssid={$wlcfg['ssid']}
3741
debug={$wlcfg['wpa']['debug_mode']}
3742
wpa={$wlcfg['wpa']['wpa_mode']}
3743
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3744
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3745
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3746
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3747
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3748
{$wpa_passphrase}
3749

    
3750
EOD;
3751

    
3752
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3753
					$wpa .= <<<EOD
3754
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3755
rsn_preauth=1
3756
rsn_preauth_interfaces={$if}
3757

    
3758
EOD;
3759
				}
3760
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3761
					$wpa .= "ieee8021x=1\n";
3762

    
3763
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3764
						$auth_server_port = "1812";
3765
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3766
							$auth_server_port = intval($wlcfg['auth_server_port']);
3767
						}
3768
						$wpa .= <<<EOD
3769

    
3770
auth_server_addr={$wlcfg['auth_server_addr']}
3771
auth_server_port={$auth_server_port}
3772
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3773

    
3774
EOD;
3775
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3776
							$auth_server_port2 = "1812";
3777
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3778
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3779
							}
3780

    
3781
							$wpa .= <<<EOD
3782
auth_server_addr={$wlcfg['auth_server_addr2']}
3783
auth_server_port={$auth_server_port2}
3784
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3785

    
3786
EOD;
3787
						}
3788
					}
3789
				}
3790

    
3791
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3792
				unset($wpa);
3793
			}
3794
			break;
3795
	}
3796

    
3797
	/*
3798
	 *    all variables are set, lets start up everything
3799
	 */
3800

    
3801
	$baseif = interface_get_wireless_base($if);
3802
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3803
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3804

    
3805
	/* set sysctls for the wireless interface */
3806
	if (!empty($wl_sysctl)) {
3807
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3808
		foreach ($wl_sysctl as $wl_sysctl_line) {
3809
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3810
		}
3811
	}
3812

    
3813
	/* set ack timers according to users preference (if he/she has any) */
3814
	if ($distance) {
3815
		fwrite($fd_set, "# Enable ATH distance settings\n");
3816
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3817
	}
3818

    
3819
	if (isset($wlcfg['wpa']['enable'])) {
3820
		if ($wlcfg['mode'] == "bss") {
3821
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3822
		}
3823
		if ($wlcfg['mode'] == "hostap") {
3824
			/* add line to script to restore old mac to make hostapd happy */
3825
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3826
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3827
				$if_curmac = get_interface_mac($if);
3828
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3829
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3830
						" link " . escapeshellarg($if_oldmac) . "\n");
3831
				}
3832
			}
3833

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

    
3836
			/* add line to script to restore spoofed mac after running hostapd */
3837
			if ($wl['spoofmac']) {
3838
				$if_curmac = get_interface_mac($if);
3839
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3840
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3841
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3842
				}
3843
			}
3844
		}
3845
	}
3846

    
3847
	fclose($fd_set);
3848

    
3849
	/* Making sure regulatory settings have actually changed
3850
	 * before applying, because changing them requires bringing
3851
	 * down all wireless networks on the interface. */
3852
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3853
	$ifconfig_str = implode($output);
3854
	unset($output);
3855
	$reg_changing = false;
3856

    
3857
	/* special case for the debug country code */
3858
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3859
		$reg_changing = true;
3860
	} elseif ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3861
		$reg_changing = true;
3862
	} elseif ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3863
		$reg_changing = true;
3864
	} elseif ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3865
		$reg_changing = true;
3866
	} elseif ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3867
		$reg_changing = true;
3868
	}
3869

    
3870
	if ($reg_changing) {
3871
		/* set regulatory domain */
3872
		if ($wlcfg['regdomain']) {
3873
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3874
		}
3875

    
3876
		/* set country */
3877
		if ($wlcfg['regcountry']) {
3878
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3879
		}
3880

    
3881
		/* set location */
3882
		if ($wlcfg['reglocation']) {
3883
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3884
		}
3885

    
3886
		$wlregcmd_args = implode(" ", $wlregcmd);
3887

    
3888
		/* build a complete list of the wireless clones for this interface */
3889
		$clone_list = array();
3890
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3891
			$clone_list[] = interface_get_wireless_clone($baseif);
3892
		}
3893
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3894
			foreach ($config['wireless']['clone'] as $clone) {
3895
				if ($clone['if'] == $baseif) {
3896
					$clone_list[] = $clone['cloneif'];
3897
				}
3898
			}
3899
		}
3900

    
3901
		/* find which clones are up and bring them down */
3902
		$clones_up = array();
3903
		foreach ($clone_list as $clone_if) {
3904
			$clone_status = pfSense_get_interface_addresses($clone_if);
3905
			if ($clone_status['status'] == 'up') {
3906
				$clones_up[] = $clone_if;
3907
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3908
			}
3909
		}
3910

    
3911
		/* apply the regulatory settings */
3912
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3913
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3914

    
3915
		/* bring the clones back up that were previously up */
3916
		foreach ($clones_up as $clone_if) {
3917
			interfaces_bring_up($clone_if);
3918

    
3919
			/*
3920
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3921
			 * is in infrastructure mode, and WPA is enabled.
3922
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3923
			 */
3924
			if ($clone_if != $if) {
3925
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3926
				if ((!empty($friendly_if)) &&
3927
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3928
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3929
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3930
				}
3931
			}
3932
		}
3933
	}
3934

    
3935
	/* The mode must be specified in a separate command before ifconfig
3936
	 * will allow the mode and channel at the same time in the next.
3937
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3938
	 */
3939
	if ($wlcfg['mode'] == "hostap") {
3940
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3941
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3942
	}
3943

    
3944
	/* configure wireless */
3945
	$wlcmd_args = implode(" ", $wlcmd);
3946
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args);
3947
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3948
	/* Bring the interface up only after setting up all the other parameters. */
3949
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up");
3950
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3951
	fclose($wlan_setup_log);
3952

    
3953
	unset($wlcmd_args, $wlcmd);
3954

    
3955

    
3956
	sleep(1);
3957
	/* execute hostapd and wpa_supplicant if required in shell */
3958
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3959

    
3960
	return 0;
3961

    
3962
}
3963

    
3964
function kill_hostapd($interface) {
3965
	global $g;
3966

    
3967
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3968
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3969
	}
3970
}
3971

    
3972
function kill_wpasupplicant($interface) {
3973
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3974
}
3975

    
3976
function find_dhclient_process($interface) {
3977
	if ($interface) {
3978
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3979
	} else {
3980
		$pid = 0;
3981
	}
3982

    
3983
	return intval($pid);
3984
}
3985

    
3986
function kill_dhclient_process($interface) {
3987
	if (empty($interface) || !does_interface_exist($interface)) {
3988
		return;
3989
	}
3990

    
3991
	$i = 0;
3992
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3993
		/* 3rd time make it die for sure */
3994
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3995
		posix_kill($pid, $sig);
3996
		sleep(1);
3997
		$i++;
3998
	}
3999
	unset($i);
4000
}
4001

    
4002
function find_dhcp6c_process($interface) {
4003
	global $g;
4004

    
4005
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
4006
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
4007
	} else {
4008
		return(false);
4009
	}
4010

    
4011
	return intval($pid);
4012
}
4013

    
4014
function kill_dhcp6client_process($interface, $force, $release = false) {
4015
	global $g;
4016

    
4017
	$i = 0;
4018

    
4019
	/*
4020
	Beware of the following: Reason, the interface may be down, but
4021
	dhcp6c may still be running, it just complains it cannot send
4022
	and carries on. Commented out as will stop the call to kill.
4023

    
4024
	if (empty($interface) || !does_interface_exist($interface)) {
4025
		return;
4026
	}
4027
	*/
4028

    
4029
	/*********** Notes on signals for dhcp6c and this function *************
4030

    
4031
	If we have Taken the WAN interface down, then dhcp6c sits there sending
4032
	a release and waiting for the response that never comes.
4033
	So we need to tell it that the interface is down and to just die quickly
4034
	otherwise a new client may launch and we have duplicate proceses.
4035
	In this case use SIGUSR1.
4036

    
4037
	If we want to exit normally obeying the no release flag then use SIGTERM.
4038
	If we want to exit with a release overiding the no release flag then
4039
	use SIGUSR2.
4040

    
4041
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
4042
	exit quickly without sending release signals.
4043

    
4044
	If $Force is set to false and $release is also set to false dhcp6c will
4045
	follow the no-release flag.
4046

    
4047
	If $Force is set to false and $release is true then dhcp6c will send a
4048
	release regardless of the no-release flag.
4049
	***********************************************************************/
4050

    
4051
	if ($force == true) {
4052
		$psig=SIGUSR1;
4053
	} elseif ($release == false) {
4054
		$psig=SIGTERM;
4055
	} else {
4056
		$psig=SIGUSR2;
4057
	}
4058

    
4059
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
4060
		/* 3rd time make it die for sure */
4061
		$sig = ($i == 2 ? SIGKILL : $psig);
4062
		posix_kill($pid, $sig);
4063
		sleep(1);
4064
		$i++;
4065
	}
4066
	/* Clear the RTSOLD script created lock & tidy up */
4067
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
4068
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
4069
}
4070
function reset_dhcp6client_process($interface) {
4071

    
4072
	$pid = find_dhcp6c_process($interface);
4073

    
4074
	if($pid != 0) {
4075
		posix_kill($pid, SIGHUP);
4076
	}
4077
}
4078

    
4079
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
4080
	global $g;
4081

    
4082
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4083
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4084

    
4085
	/*
4086
	 * Only run this if the lock does not exist. In theory the lock being
4087
	 * there in this mode means the user has selected dhcp6withoutRA while
4088
	 * a session is active in the other mode.
4089
	 *
4090
	 * It should not happen as the process should have been killed and the
4091
	 * lock deleted.
4092
	 */
4093

    
4094
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
4095
		kill_dhcp6client_process($interface, true);
4096
		/* Lock it to avoid multiple runs */
4097
		touch("/tmp/dhcp6c_{$interface}_lock");
4098
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
4099
		    "{$noreleaseOption} " .
4100
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
4101
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
4102
		    $interface);
4103
		log_error(sprintf(gettext(
4104
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
4105
		    $interface));
4106
	}
4107
}
4108

    
4109
function interface_virtual_create($interface) {
4110
	global $config;
4111

    
4112
	if (interface_is_vlan($interface) != NULL) {
4113
		interface_vlan_configure(interface_is_vlan($interface));
4114
	} elseif (substr($interface, 0, 3) == "gre") {
4115
		interfaces_tunnel_configure(0, $interface, 'gre');
4116
	} elseif (substr($interface, 0, 3) == "gif") {
4117
		interfaces_tunnel_configure(0, $interface, 'gif');
4118
	} elseif (substr($interface, 0, 5) == "ovpns") {
4119
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
4120
			foreach ($config['openvpn']['openvpn-server'] as $server) {
4121
				if ($interface == "ovpns{$server['vpnid']}") {
4122
					if (!function_exists('openvpn_resync')) {
4123
						require_once('openvpn.inc');
4124
					}
4125
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
4126
					openvpn_resync('server', $server);
4127
				}
4128
			}
4129
			unset($server);
4130
		}
4131
	} elseif (substr($interface, 0, 5) == "ovpnc") {
4132
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
4133
			foreach ($config['openvpn']['openvpn-client'] as $client) {
4134
				if ($interface == "ovpnc{$client['vpnid']}") {
4135
					if (!function_exists('openvpn_resync')) {
4136
						require_once('openvpn.inc');
4137
					}
4138
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
4139
					openvpn_resync('client', $client);
4140
				}
4141
			}
4142
			unset($client);
4143
		}
4144
	} elseif (substr($interface, 0, 5) == "ipsec") {
4145
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
4146
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
4147
				if ($ph1ent['disabled']) {
4148
					continue;
4149
				}
4150
				if ($interface == "ipsec{$ph1ent['ikeid']}") {
4151
					interface_ipsec_vti_configure($ph1ent);
4152
				}
4153
			}
4154
		}
4155
	} elseif (substr($interface, 0, 4) == "lagg") {
4156
		interfaces_lagg_configure($interface);
4157
	} elseif (substr($interface, 0, 6) == "bridge") {
4158
		interfaces_bridge_configure(0, $interface);
4159
	}
4160
}
4161

    
4162
function interface_vlan_mtu_configured($iface) {
4163
	global $config;
4164

    
4165
	$mtu = 0;
4166
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
4167
		foreach ($config['vlans']['vlan'] as $vlan) {
4168

    
4169
			if ($vlan['vlanif'] != $iface)
4170
				continue;
4171

    
4172
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4173
			$parentinf = convert_real_interface_to_friendly_interface_name($vlan['if']);
4174
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
4175
				/* VLAN MTU */
4176
				$mtu = $config['interfaces'][$assignedport]['mtu'];
4177
			} elseif (!empty($config['interfaces'][$parentinf]['mtu'])) {
4178
				/* Parent MTU */
4179
				$mtu = $config['interfaces'][$parentinf]['mtu'];
4180
			}
4181
		}
4182
	}
4183

    
4184
	return $mtu;
4185
}
4186

    
4187
function interface_mtu_wanted_for_pppoe($realif) {
4188
	global $config;
4189

    
4190
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
4191
		return 0;
4192

    
4193
	$mtu = 0;
4194
	foreach ($config['ppps']['ppp'] as $ppp) {
4195
		if ($ppp['type'] != "pppoe") {
4196
			continue;
4197
		}
4198

    
4199
		$mtus = array();
4200
		if (!empty($ppp['mtu'])) {
4201
			$mtus = explode(',', $ppp['mtu']);
4202
		}
4203
		$ports = explode(',', $ppp['ports']);
4204

    
4205
		foreach ($ports as $pid => $port) {
4206
			$parentifa = get_parent_interface($port);
4207
			$parentif = $parentifa[0];
4208
			if ($parentif != $realif)
4209
				continue;
4210

    
4211
			// there is an MTU configured on the port in question
4212
			if (!empty($mtus[$pid])) {
4213
				$mtu = intval($mtus[$pid]) + 8;
4214
			// or use the MTU configured on the interface ...
4215
			} elseif (is_array($config['interfaces'])) {
4216
				foreach ($config['interfaces'] as $interface) {
4217
					if ($interface['if'] == $ppp['if'] &&
4218
					    !empty($interface['mtu'])) {
4219
						$mtu = intval($interface['mtu']) + 8;
4220
						break;
4221
					}
4222
				}
4223
			}
4224
		}
4225
	}
4226

    
4227
	return $mtu;
4228
}
4229

    
4230
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
4231
	global $config, $g;
4232
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
4233
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
4234

    
4235
	$wancfg = $config['interfaces'][$interface];
4236

    
4237
	if (!isset($wancfg['enable'])) {
4238
		return;
4239
	}
4240

    
4241
	$realif = get_real_interface($interface);
4242
	$realhwif_array = get_parent_interface($interface);
4243
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
4244
	$realhwif = $realhwif_array[0];
4245

    
4246
	$mac_if_cfg = $wancfg;
4247
	if (interface_is_vlan($realif)) {
4248
		$mac_if = convert_real_interface_to_friendly_interface_name(
4249
		    $realhwif);
4250
		if (is_array($config['interfaces'][$mac_if])) {
4251
			$mac_if_cfg = $config['interfaces'][$mac_if];
4252
		} else {
4253
			$mac_if = $interface;
4254
		}
4255
	}
4256

    
4257
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn") && !(substr($realif, 0, 5) == "ipsec")) {
4258
		/* remove all IPv4 and IPv6 addresses */
4259
		$tmpifaces = pfSense_getall_interface_addresses($realif);
4260
		if (is_array($tmpifaces)) {
4261
			foreach ($tmpifaces as $tmpiface) {
4262
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
4263
					if (!is_linklocal($tmpiface)) {
4264
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
4265
					}
4266
				} elseif (strstr($tmpiface, "fe80::1:1")) {
4267
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 fe80::1:1 -alias");
4268
				} else {
4269
					if (is_subnetv4($tmpiface)) {
4270
						$tmpip = explode('/', $tmpiface);
4271
						$tmpip = $tmpip[0];
4272
					} else {
4273
						$tmpip = $tmpiface;
4274
					}
4275
					pfSense_interface_deladdress($realif, $tmpip);
4276
				}
4277
			}
4278
		}
4279

    
4280
		/* only bring down the interface when both v4 and v6 are set to NONE */
4281
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4282
			interface_bring_down($interface);
4283
		}
4284
	}
4285

    
4286
	$interface_to_check = $realif;
4287
	if (interface_isppp_type($interface)) {
4288
		$interface_to_check = $realhwif;
4289
	}
4290

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

    
4296
	/* Disable Accepting router advertisements unless specifically requested */
4297
	if ($g['debug']) {
4298
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
4299
	}
4300
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
4301
	{
4302
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
4303
	}
4304
	/* wireless configuration? */
4305
	if (is_array($wancfg['wireless']) && !$linkupevent) {
4306
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
4307
	}
4308

    
4309
	$current_mac = get_interface_mac($realhwif);
4310
	$vendor_mac = get_interface_vendor_mac($realhwif);
4311

    
4312
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4313
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4314

    
4315
		interface_set_macaddr($realhwif, $mac_addr);
4316
	} else {
4317
		/*
4318
		 * this is not a valid mac address.  generate a
4319
		 * temporary mac address so the machine can get online.
4320
		 */
4321
		echo gettext("Generating new MAC address.");
4322
		$random_mac = generate_random_mac_address();
4323
		interface_set_macaddr($realhwif, $random_mac);
4324
		$config['interfaces'][$mac_if]['spoofmac'] = $random_mac;
4325
		write_config(sprintf(gettext('The invalid MAC address ' .
4326
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
4327
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
4328
		file_notice("MAC Address altered", sprintf(gettext('The ' .
4329
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
4330
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
4331
		    $random_mac), "Interfaces");
4332
	}
4333

    
4334
	/* media */
4335
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4336
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4337
		if ($wancfg['media']) {
4338
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4339
		}
4340
		if ($wancfg['mediaopt']) {
4341
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4342
		}
4343
		mwexec($cmd);
4344
	}
4345

    
4346
	/* Apply hw offloading policies as configured */
4347
	enable_hardware_offloading($interface);
4348

    
4349
	/* invalidate interface/ip/sn cache */
4350
	get_interface_arr(true);
4351
	unset($interface_ip_arr_cache[$realif]);
4352
	unset($interface_sn_arr_cache[$realif]);
4353
	unset($interface_ipv6_arr_cache[$realif]);
4354
	unset($interface_snv6_arr_cache[$realif]);
4355

    
4356
	$tunnelif = substr($realif, 0, 3);
4357

    
4358
	$mtuif = $realif;
4359
	$mtuhwif = $realhwif;
4360

    
4361
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4362
	if (interface_isppp_type($interface)) {
4363
		$mtuif = $realhwif;
4364
		$mtuhwif_array = get_parent_interface($mtuif);
4365
		$mtuhwif = $mtuhwif_array[0];
4366
	}
4367

    
4368
	$wantedmtu = 0;
4369
	if (is_array($config['interfaces'])) {
4370
		foreach ($config['interfaces'] as $tmpinterface) {
4371
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4372
				$wantedmtu = $tmpinterface['mtu'];
4373
				break;
4374
			}
4375
		}
4376
	}
4377

    
4378
	/* MTU is not specified for interface, try the pppoe settings. */
4379
	if ($wantedmtu == 0) {
4380
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4381
	}
4382
	if (($wantedmtu == 0) && (interface_is_vlan($mtuif) != NULL) && interface_isppp_type($interface)) {
4383
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4384
	}
4385
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4386
		/* set MTU to 1400 for GRE over IPsec */
4387
		if (is_greipsec($mtuif)) {
4388
			$wantedmtu = 1400;
4389
		} else {
4390
			$wantedmtu = 1476;
4391
		}
4392
	}
4393
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4394
		$wantedmtu = 1280;
4395
	}
4396
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'vxlan')) {
4397
		$wantedmtu = 1450;
4398
	}
4399

    
4400
	/* Set the MTU to 1500 if no explicit MTU configured. */
4401
	if ($wantedmtu == 0) {
4402
		$wantedmtu = 1500; /* Default */
4403
	}
4404

    
4405
	if (interface_is_vlan($mtuif) != NULL) {
4406
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4407
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
4408
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
4409
			if ($wancfg['mtu'] > $parentmtu) {
4410
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4411
			}
4412
		}
4413

    
4414
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4415

    
4416
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4417
			$configuredmtu = $parentmtu;
4418
		if ($configuredmtu != 0)
4419
			$mtu = $configuredmtu;
4420
		else
4421
			$mtu = $wantedmtu;
4422

    
4423
		/* Set the parent MTU. */
4424
		if (get_interface_mtu($mtuhwif) < $mtu)
4425
			set_interface_mtu($mtuhwif, $mtu);
4426
		/* Set the VLAN MTU. */
4427
		if (get_interface_mtu($mtuif) != $mtu)
4428
			set_interface_mtu($mtuif, $mtu);
4429
	} elseif (substr($mtuif, 0, 4) == 'lagg') {
4430
		/* LAGG interface must be destroyed and re-created to change MTU */
4431
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4432
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
4433
				foreach ($config['laggs']['lagg'] as $lagg) {
4434
					if ($lagg['laggif'] == $mtuif) {
4435
						interface_lagg_configure($lagg);
4436
						break;
4437
					}
4438
				}
4439
			}
4440
		}
4441
	} else {
4442
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4443
			pfSense_interface_mtu($mtuif, $wantedmtu);
4444
			set_ipv6routes_mtu($mtuif, $wantedmtu);
4445
		}
4446
	}
4447
	/* XXX: What about gre/gif/.. ? */
4448

    
4449
	if (does_interface_exist($wancfg['if'])) {
4450
		interfaces_bring_up($wancfg['if']);
4451
	}
4452

    
4453
	switch ($wancfg['ipaddr']) {
4454
		case 'dhcp':
4455
			interface_dhcp_configure($interface);
4456
			break;
4457
		case 'pppoe':
4458
		case 'l2tp':
4459
		case 'pptp':
4460
		case 'ppp':
4461
			interface_ppps_configure($interface);
4462
			break;
4463
		default:
4464
			/* XXX: Kludge for now related to #3280 */
4465
			if (!in_array($tunnelif, array("gif", "gre", "vxlan", "ovp", "ips"))) {
4466
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4467
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4468
				}
4469
			}
4470
			break;
4471
	}
4472

    
4473
	switch ($wancfg['ipaddrv6']) {
4474
		case 'slaac':
4475
		case 'dhcp6':
4476
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4477
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4478
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4479
			/* Remove the check file. Should not be there but just in case */
4480
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
4481
			log_error(gettext("calling interface_dhcpv6_configure."));
4482
			if ((($wancfg['ipaddrv6'] == 'dhcp6') && !isset($wancfg['dhcp6usev4iface'])) ||
4483
			    (($wancfg['ipaddrv6'] == 'slaac') && !isset($wancfg['slaacusev4iface'])) ||
4484
			    !interface_isppp_type($interface)) {
4485
				interface_dhcpv6_configure($interface, $wancfg);
4486
			}
4487
			break;
4488
		case '6rd':
4489
			interface_6rd_configure($interface, $wancfg);
4490
			break;
4491
		case '6to4':
4492
			interface_6to4_configure($interface, $wancfg);
4493
			break;
4494
		case 'track6':
4495
			interface_track6_configure($interface, $wancfg, $linkupevent);
4496
			break;
4497
		default:
4498
			/* XXX: Kludge for now related to #3280 */
4499
			if (!in_array($tunnelif, array("gif", "gre", "vxlan", "ovp", "ips"))) {
4500
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4501
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4502
					// FIXME: Add IPv6 Support to the pfSense module
4503
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4504
				}
4505
			}
4506
			break;
4507
	}
4508

    
4509
	interface_netgraph_needed($interface);
4510

    
4511
	if (!platform_booting()) {
4512
		link_interface_to_vips($interface, "update");
4513

    
4514
		if ($tunnelif != 'gre') {
4515
			unset($gre);
4516
			$gre = link_interface_to_tunnelif($interface, 'gre');
4517
			if (!empty($gre)) {
4518
				array_walk($gre, 'interface_gre_configure');
4519
			}
4520
		}
4521

    
4522
		if ($tunnelif != 'gif') {
4523
			unset($gif);
4524
			$gif = link_interface_to_tunnelif($interface, 'gif');
4525
			if (!empty($gif)) {
4526
				array_walk($gif, 'interface_gif_configure');
4527
			}
4528
		}
4529

    
4530
		if ($tunnelif != 'vxlan') {
4531
			unset($vxlan);
4532
			$vxlan = link_interface_to_tunnelif($interface, 'vxlan');
4533
			if (!empty($vxlan)) {
4534
				array_walk($vxlan, 'interface_vxlan_configure');
4535
			}
4536
		}
4537

    
4538
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4539
			unset($bridgetmp);
4540
			$bridgetmp = link_interface_to_bridge($interface);
4541
			if (!empty($bridgetmp)) {
4542
				interface_bridge_add_member($bridgetmp, $realif);
4543
			}
4544
		}
4545

    
4546
		$grouptmp = link_interface_to_group($interface);
4547
		if (!empty($grouptmp)) {
4548
			array_walk($grouptmp, 'interface_group_add_member');
4549
		}
4550

    
4551
		if ($interface == "lan") {
4552
			/* make new hosts file */
4553
			system_hosts_generate();
4554
		}
4555

    
4556
		if ($reloadall == true) {
4557

    
4558
			/* reconfigure static routes (kernel may have deleted them) */
4559
			system_routing_configure($interface);
4560

    
4561
			/* reload ipsec tunnels */
4562
			send_event("service reload ipsecdns");
4563

    
4564
			if (isset($config['dnsmasq']['enable'])) {
4565
				services_dnsmasq_configure();
4566
			}
4567

    
4568
			if (isset($config['unbound']['enable'])) {
4569
				services_unbound_configure();
4570
			}
4571

    
4572
			/* update dyndns */
4573
			send_event("service reload dyndns {$interface}");
4574

    
4575
			/* reload captive portal */
4576
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4577
				require_once('captiveportal.inc');
4578
			}
4579
			captiveportal_init_rules_byinterface($interface);
4580
		}
4581
	}
4582

    
4583
	if (!empty($wancfg['descr'])) {
4584
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4585
	};
4586

    
4587
	interfaces_staticarp_configure($interface);
4588
	return 0;
4589
}
4590

    
4591
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4592
	global $config, $g;
4593

    
4594
	if (!is_array($wancfg)) {
4595
		return;
4596
	}
4597

    
4598
	if (!isset($wancfg['enable'])) {
4599
		return;
4600
	}
4601

    
4602
	/* If the interface is not configured via another, exit */
4603
	if (empty($wancfg['track6-interface'])) {
4604
		return;
4605
	}
4606

    
4607
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4608
	$realif = get_real_interface($interface);
4609
	$linklocal = find_interface_ipv6_ll($realif, true);
4610
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4611
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4612
	}
4613

    
4614
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4615
	if (!isset($trackcfg['enable'])) {
4616
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4617
		return;
4618
	}
4619

    
4620
	switch ($trackcfg['ipaddrv6']) {
4621
		case "6to4":
4622
			if ($g['debug']) {
4623
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4624
			}
4625
			interface_track6_6to4_configure($interface, $wancfg);
4626
			break;
4627
		case "6rd":
4628
			if ($g['debug']) {
4629
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4630
			}
4631
			interface_track6_6rd_configure($interface, $wancfg);
4632
			break;
4633
		case "dhcp6":
4634
			if ($linkupevent == true) {
4635
				/*
4636
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4637
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4638
				 *
4639
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4640
				 */
4641
				$parentrealif = get_real_interface($wancfg['track6-interface']);
4642
				$pidv6 = find_dhcp6c_process($parentrealif);
4643
				if ($pidv6) {
4644
					posix_kill($pidv6, SIGHUP);
4645
				}
4646
			}
4647
			break;
4648
	}
4649

    
4650
	if ($linkupevent == false && !platform_booting()) {
4651
		if (!function_exists('services_dhcpd_configure')) {
4652
			require_once("services.inc");
4653
		}
4654

    
4655
		/* restart dns servers (defering dhcpd reload) */
4656
		if (isset($config['unbound']['enable'])) {
4657
			services_unbound_configure(false);
4658
		}
4659
		if (isset($config['dnsmasq']['enable'])) {
4660
			services_dnsmasq_configure(false);
4661
		}
4662

    
4663
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4664
		services_dhcpd_configure("inet6");
4665
	}
4666

    
4667
	return 0;
4668
}
4669

    
4670
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4671
	global $config, $g;
4672
	global $interface_ipv6_arr_cache;
4673
	global $interface_snv6_arr_cache;
4674

    
4675
	if (!is_array($lancfg)) {
4676
		return;
4677
	}
4678

    
4679
	/* If the interface is not configured via another, exit */
4680
	if (empty($lancfg['track6-interface'])) {
4681
		return;
4682
	}
4683

    
4684
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4685
	if (empty($wancfg)) {
4686
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4687
		return;
4688
	}
4689

    
4690
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4691
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4692
		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']));
4693
		return;
4694
	}
4695
	$hexwanv4 = return_hex_ipv4($ip4address);
4696

    
4697
	/* create the long prefix notation for math, save the prefix length */
4698
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4699
	$rd6prefixlen = $rd6prefix[1];
4700
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4701

    
4702
	/* binary presentation of the prefix for all 128 bits. */
4703
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4704

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

    
4710
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4711
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4712
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4713
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4714
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4715
	/* fill the rest out with zeros */
4716
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4717

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

    
4721
	$lanif = get_real_interface($interface);
4722
	$oip = find_interface_ipv6($lanif);
4723
	if (is_ipaddrv6($oip)) {
4724
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4725
	}
4726
	unset($interface_ipv6_arr_cache[$lanif]);
4727
	unset($interface_snv6_arr_cache[$lanif]);
4728
	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));
4729
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4730

    
4731
	return 0;
4732
}
4733

    
4734
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4735
	global $config, $g;
4736
	global $interface_ipv6_arr_cache;
4737
	global $interface_snv6_arr_cache;
4738

    
4739
	if (!is_array($lancfg)) {
4740
		return;
4741
	}
4742

    
4743
	/* If the interface is not configured via another, exit */
4744
	if (empty($lancfg['track6-interface'])) {
4745
		return;
4746
	}
4747

    
4748
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4749
	if (empty($wancfg)) {
4750
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4751
		return;
4752
	}
4753

    
4754
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4755
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4756
		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']));
4757
		return;
4758
	}
4759
	$hexwanv4 = return_hex_ipv4($ip4address);
4760

    
4761
	/* create the long prefix notation for math, save the prefix length */
4762
	$sixto4prefix = "2002::";
4763
	$sixto4prefixlen = 16;
4764
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4765

    
4766
	/* binary presentation of the prefix for all 128 bits. */
4767
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4768

    
4769
	/* just save the left prefix length bits */
4770
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4771
	/* add the v4 address */
4772
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4773
	/* add the custom prefix id */
4774
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4775
	/* fill the rest out with zeros */
4776
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4777

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

    
4781
	$lanif = get_real_interface($interface);
4782
	$oip = find_interface_ipv6($lanif);
4783
	if (is_ipaddrv6($oip)) {
4784
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4785
	}
4786
	unset($interface_ipv6_arr_cache[$lanif]);
4787
	unset($interface_snv6_arr_cache[$lanif]);
4788
	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));
4789
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4790

    
4791
	return 0;
4792
}
4793

    
4794
function interface_6rd_configure($interface = "wan", $wancfg) {
4795
	global $config, $g;
4796

    
4797
	/* because this is a tunnel interface we can only function
4798
	 *	with a public IPv4 address on the interface */
4799

    
4800
	if (!is_array($wancfg)) {
4801
		return;
4802
	}
4803

    
4804
	if (!is_module_loaded('if_stf.ko')) {
4805
		mwexec('/sbin/kldload if_stf.ko');
4806
	}
4807

    
4808
	$wanif = get_real_interface($interface);
4809
	$ip4address = find_interface_ip($wanif);
4810
	if (!is_ipaddrv4($ip4address)) {
4811
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4812
		return false;
4813
	}
4814
	$hexwanv4 = return_hex_ipv4($ip4address);
4815

    
4816
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4817
		$wancfg['prefix-6rd-v4plen'] = 0;
4818
	}
4819

    
4820
	/* create the long prefix notation for math, save the prefix length */
4821
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4822
	$rd6prefixlen = $rd6prefix[1];
4823
	$brgw = explode('.', $wancfg['gateway-6rd']);
4824
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4825
	$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);
4826
	if (strlen($rd6brgw) < 128) {
4827
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4828
	}
4829
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4830
	unset($brgw);
4831
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4832

    
4833
	/* binary presentation of the prefix for all 128 bits. */
4834
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4835

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

    
4843
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4844
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4845

    
4846

    
4847
	/* XXX: need to extend to support variable prefix size for v4 */
4848
	$stfiface = "{$interface}_stf";
4849
	if (does_interface_exist($stfiface)) {
4850
		pfSense_interface_destroy($stfiface);
4851
	}
4852
	$tmpstfiface = pfSense_interface_create2("stf");
4853
	pfSense_interface_rename($tmpstfiface, $stfiface);
4854
	pfSense_interface_flags($stfiface, IFF_LINK2);
4855
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4856
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4857
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4858
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4859
	}
4860
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4861
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4862
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4863
	} elseif ($parentmtu > 1300) {
4864
		set_interface_mtu($stfiface, $parentmtu - 20);
4865
	}
4866
	if ($g['debug']) {
4867
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4868
	}
4869

    
4870
	/* write out a default router file */
4871
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4872
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4873

    
4874
	$ip4gateway = get_interface_gateway($interface);
4875
	if (is_ipaddrv4($ip4gateway)) {
4876
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4877
	}
4878

    
4879
	/* configure dependent interfaces */
4880
	if (!platform_booting()) {
4881
		link_interface_to_track6($interface, "update");
4882
	}
4883

    
4884
	return 0;
4885
}
4886

    
4887
function interface_6to4_configure($interface = "wan", $wancfg) {
4888
	global $config, $g;
4889

    
4890
	/* because this is a tunnel interface we can only function
4891
	 *	with a public IPv4 address on the interface */
4892

    
4893
	if (!is_array($wancfg)) {
4894
		return;
4895
	}
4896

    
4897
	$wanif = get_real_interface($interface);
4898
	$ip4address = find_interface_ip($wanif);
4899
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4900
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4901
		return false;
4902
	}
4903

    
4904
	/* create the long prefix notation for math, save the prefix length */
4905
	$stfprefixlen = 16;
4906
	$stfprefix = Net_IPv6::uncompress("2002::");
4907
	$stfarr = explode(":", $stfprefix);
4908
	$v4prefixlen = "0";
4909

    
4910
	/* we need the hex form of the interface IPv4 address */
4911
	$ip4arr = explode(".", $ip4address);
4912
	$hexwanv4 = "";
4913
	foreach ($ip4arr as $octet) {
4914
		$hexwanv4 .= sprintf("%02x", $octet);
4915
	}
4916

    
4917
	/* we need the hex form of the broker IPv4 address */
4918
	$ip4arr = explode(".", "192.88.99.1");
4919
	$hexbrv4 = "";
4920
	foreach ($ip4arr as $octet) {
4921
		$hexbrv4 .= sprintf("%02x", $octet);
4922
	}
4923

    
4924
	/* binary presentation of the prefix for all 128 bits. */
4925
	$stfprefixbin = "";
4926
	foreach ($stfarr as $element) {
4927
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4928
	}
4929
	/* just save the left prefix length bits */
4930
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4931

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

    
4936
	/* for the local subnet too. */
4937
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4938
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4939

    
4940
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4941
	$stfbrarr = array();
4942
	$stfbrbinarr = array();
4943
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4944
	foreach ($stfbrbinarr as $bin) {
4945
		$stfbrarr[] = dechex(bindec($bin));
4946
	}
4947
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4948

    
4949
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4950
	$stflanarr = array();
4951
	$stflanbinarr = array();
4952
	$stflanbinarr = str_split($stflanbin, 16);
4953
	foreach ($stflanbinarr as $bin) {
4954
		$stflanarr[] = dechex(bindec($bin));
4955
	}
4956
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4957
	$stflanarr[7] = 1;
4958
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4959

    
4960
	/* setup the stf interface */
4961
	if (!is_module_loaded("if_stf")) {
4962
		mwexec("/sbin/kldload if_stf.ko");
4963
	}
4964
	$stfiface = "{$interface}_stf";
4965
	if (does_interface_exist($stfiface)) {
4966
		pfSense_interface_destroy($stfiface);
4967
	}
4968
	$tmpstfiface = pfSense_interface_create2("stf");
4969
	pfSense_interface_rename($tmpstfiface, $stfiface);
4970
	pfSense_interface_flags($stfiface, IFF_LINK2);
4971
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4972

    
4973
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4974
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4975
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4976
	} elseif ($parentmtu > 1300) {
4977
		set_interface_mtu($stfiface, $parentmtu - 20);
4978
	}
4979
	if ($g['debug']) {
4980
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4981
	}
4982

    
4983
	/* write out a default router file */
4984
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4985
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4986

    
4987
	$ip4gateway = get_interface_gateway($interface);
4988
	if (is_ipaddrv4($ip4gateway)) {
4989
		route_add_or_change("192.88.99.1", $ip4gateway);
4990
	}
4991

    
4992
	if (!platform_booting()) {
4993
		link_interface_to_track6($interface, "update");
4994
	}
4995

    
4996
	return 0;
4997
}
4998

    
4999
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
5000
	global $config, $g;
5001

    
5002
	if (!is_array($wancfg)) {
5003
		return;
5004
	}
5005

    
5006
	$wanif = get_real_interface($interface, "inet6");
5007
	$dhcp6cconf = "";
5008

    
5009
	if (!empty($config['system']['global-v6duid'])) {
5010
		// Write the DUID file
5011
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
5012
		    log_error(gettext("Failed to write user DUID file!"));
5013
		}
5014
	}
5015

    
5016
	/* accept router advertisements for this interface                 */
5017
	/* Moved to early in the function as sometimes interface not ready */
5018
	/* RTSOLD fails as interface does not accept .....                 */
5019

    
5020
	log_error("Accept router advertisements on interface {$wanif} ");
5021
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
5022

    
5023
	if ($wancfg['adv_dhcp6_config_file_override']) {
5024
		// DHCP6 Config File Override
5025
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
5026
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
5027
		// DHCP6 Config File Advanced
5028
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
5029
	} else {
5030
		// DHCP6 Config File Basic
5031
		$dhcp6cconf .= "interface {$wanif} {\n";
5032

    
5033
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
5034
		if ($wancfg['ipaddrv6'] == "slaac") {
5035
			$dhcp6cconf .= "\tinformation-only;\n";
5036
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
5037
			$dhcp6cconf .= "\trequest domain-name;\n";
5038
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
5039
			$dhcp6cconf .= "};\n";
5040
		} else {
5041
			$trackiflist = array();
5042
			$iflist = link_interface_to_track6($interface);
5043
			foreach ($iflist as $ifname => $ifcfg) {
5044
				if (is_numeric($ifcfg['track6-prefix-id'])) {
5045
					$trackiflist[$ifname] = $ifcfg;
5046
				}
5047
			}
5048

    
5049
			/* skip address request if this is set */
5050
			if (!isset($wancfg['dhcp6prefixonly'])) {
5051
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
5052
			}
5053
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
5054
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
5055
			}
5056

    
5057
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
5058
			$dhcp6cconf .= "\trequest domain-name;\n";
5059

    
5060
			/*
5061
			 * dhcp6c will run different scripts depending on
5062
			 * whether dhcpwithoutra is set or unset.
5063
			 */
5064
			if (isset($wancfg['dhcp6withoutra'])) {
5065
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
5066
			} else {
5067
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
5068
			}
5069
			$dhcp6cconf .= "};\n";
5070

    
5071
			if (!isset($wancfg['dhcp6prefixonly'])) {
5072
				$dhcp6cconf .= "id-assoc na 0 { };\n";
5073
			}
5074

    
5075
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
5076
				/* Setup the prefix delegation */
5077
				$dhcp6cconf .= "id-assoc pd 0 {\n";
5078
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
5079
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
5080
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
5081
				}
5082
				foreach ($trackiflist as $friendly => $ifcfg) {
5083
					if ($g['debug']) {
5084
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
5085
					}
5086
					$realif = get_real_interface($friendly);
5087
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
5088
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
5089
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
5090
					$dhcp6cconf .= "\t};\n";
5091
				}
5092
				unset($preflen, $iflist, $ifcfg, $ifname);
5093
				$dhcp6cconf .= "};\n";
5094
			}
5095
			unset($trackiflist);
5096
		}
5097
	}
5098

    
5099
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
5100
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
5101

    
5102
	/* wide-dhcp6c works for now. */
5103
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
5104
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
5105
		unset($dhcp6cconf);
5106
		return 1;
5107
	}
5108
	unset($dhcp6cconf);
5109

    
5110
	/*************** Script Debug Logging ***************************
5111
	Both dhcp6 scripts now have a logging message built in.
5112
	These logging messages ONLY appear if dhcp6c debug logging is set.
5113
	The logging messages appear in the dhcp section of the logs,
5114
	not in system.
5115

    
5116
	These scripts now also take advantage of the REASON= env vars
5117
	supplied by dhcp6c.
5118
	****************************************************************/
5119

    
5120
	/* Script create for dhcp6withoutRA mode */
5121
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
5122
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
5123
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
5124
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
5125
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
5126
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
5127
	// Need to pass params to  the final script
5128
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
5129
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
5130
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
5131
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
5132
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
5133
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
5134
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
5135
	if ($debugOption == '-D') {
5136
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rtsold\"\n";
5137
	}
5138
	$dhcp6cscriptwithoutra .= ";;\n";
5139
	$dhcp6cscriptwithoutra .= "REBIND)\n";
5140
	if ($debugOption == '-D') {
5141
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5142
	}
5143
	$dhcp6cscriptwithoutra .= ";;\n";
5144
	if (isset($wancfg['dhcp6norelease'])) {
5145
		$dhcp6cscriptwithoutra .= "EXIT)\n";
5146
	} else {
5147
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
5148
	}
5149
	if ($debugOption == '-D') {
5150
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
5151
	}
5152
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5153
	$dhcp6cscriptwithoutra .= ";;\n";
5154
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
5155
	if ($debugOption == '-D') {
5156
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5157
	}
5158
	$dhcp6cscriptwithoutra .= "esac\n";
5159
	if (!@file_put_contents(
5160
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
5161
	    $dhcp6cscriptwithoutra)) {
5162
		printf("Error: cannot open " .
5163
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
5164
		    "interface_dhcpv6_configure() for writing.\n");
5165
		unset($dhcp6cscriptwithoutra);
5166
		return 1;
5167
	}
5168

    
5169
	unset($dhcp6cscriptwithoutra);
5170
	@chmod(
5171
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
5172
	    0755);
5173

    
5174
	/*
5175
	 * Dual mode wan_dhcp6c script with variations depending on node
5176
	 * dhcp6 will run the wan ipv6 configure
5177
	 */
5178
	$dhcp6cscript  = "#!/bin/sh\n";
5179
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
5180
	if (!isset($wancfg['dhcp6withoutra'])) {
5181
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
5182
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
5183
		$dhcp6cscript .= "case \$REASON in\n";
5184
		$dhcp6cscript .= "REBIND)\n";
5185
		if ($debugOption == '-D') {
5186
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5187
		}
5188
		$dhcp6cscript .= ";;\n";
5189
		$dhcp6cscript .= "REQUEST|";
5190
		if (isset($wancfg['dhcp6norelease'])) {
5191
			$dhcp6cscript .= "EXIT)\n";
5192
		} else {
5193
			$dhcp6cscript .= "RELEASE)\n";
5194
		}
5195
		if ($debugOption == '-D') {
5196
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c RELEASE, REQUEST or EXIT on {$wanif} running rc.newwanipv6\"\n";
5197
		}
5198
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5199
		$dhcp6cscript .= ";;\n";
5200
		$dhcp6cscript .= "RENEW|INFO)\n";
5201
		if ($debugOption == '-D') {
5202
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5203
		}
5204
		$dhcp6cscript .= "esac\n";
5205
	} else {
5206
		// Need to get the parameters from the dhcp6cwithoutRA run
5207
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
5208
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
5209
		$dhcp6cscript .= "/bin/sleep 1\n";
5210
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5211
	}
5212

    
5213
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5214
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
5215
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
5216
		unset($dhcp6cscript);
5217
		return 1;
5218
	}
5219
	unset($dhcp6cscript);
5220
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
5221

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

    
5228
	/* non ipoe Process */
5229
	if (!isset($wancfg['dhcp6withoutra'])) {
5230
		/*
5231
		 * We only want this script to run once, and if it runs twice
5232
		 * then do not launch dhcp6c again, this only happens if
5233
		 * dhcpwithoutra is not set.
5234
		 *
5235
		 * Check for a lock file, trying to prevent multiple instances
5236
		 * of dhcp6c being launched
5237
		 */
5238
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
5239
		/*
5240
		 * Create the lock file, trying to prevent multiple instances
5241
		 * of dhcp6c being launched
5242
		 */
5243
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
5244
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
5245
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
5246
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
5247
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
5248
		$rtsoldscript .= "\tfi\n";
5249
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
5250
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
5251
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
5252
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
5253
		$rtsoldscript .= "else\n";
5254
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
5255
		$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c_{$wanif}.pid\")\n";
5256
		$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
5257
		$rtsoldscript .= "fi\n";
5258
	} else {
5259
		/*
5260
		 * The script needs to run in dhcp6withoutra mode as RA may
5261
		 * not have been received, or there can be a delay with
5262
		 * certain ISPs
5263
		 */
5264
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
5265
		$rtsoldscript .= "/bin/sleep 1\n";
5266
	}
5267
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5268
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
5269
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
5270
		unset($rtsoldscript);
5271
		return 1;
5272
	}
5273
	unset($rtsoldscript);
5274
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
5275

    
5276
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
5277
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
5278
		log_error("Killing running rtsold process");
5279
		sleep(2);
5280
	}
5281

    
5282
	if (isset($wancfg['dhcp6withoutra'])) {
5283
		/*
5284
		 * Start dhcp6c here if we don't want to wait for ra - calls
5285
		 * separate function
5286
		 *
5287
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
5288
		 * will then run the configure on receipt of the RA.
5289
		 *
5290
		 * Already started. interface_dhcpv6_configure() appears to get
5291
		 * called multiple times.
5292
		 *
5293
		 * Taking the interface down or releasing will kill the client.
5294
		 */
5295
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
5296
		{
5297
			/*
5298
			 * If the interface is being brought up, wait for the
5299
			 * interface to configure accept RA before launching.
5300
			 * Otherwise it is not ready to accept and will fail.
5301
			 */
5302
			sleep(3);
5303
			run_dhcp6client_process($wanif,$interface,$wancfg);
5304
		}
5305
	} else {
5306
		/*
5307
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
5308
		 * ( it does not background, it exits! ) It will launch dhcp6c
5309
		 * if dhcpwihtoutra is not set
5310
		 */
5311
		log_error("Starting rtsold process");
5312
		sleep(2);
5313
		mwexec("/usr/sbin/rtsold -1 " .
5314
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
5315
		    "-M {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
5316
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
5317
		    $wanif);
5318
	}
5319
	/*
5320
	 * NOTE: will be called from rtsold invoked script
5321
	 * link_interface_to_track6($interface, "update");
5322
	 */
5323

    
5324
	return 0;
5325
}
5326

    
5327
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5328
	global $g;
5329

    
5330
	$send_options = "";
5331
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5332
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5333
		foreach ($options as $option) {
5334
			$send_options .= "\tsend " . trim($option) . ";\n";
5335
		}
5336
	}
5337

    
5338
	$request_options = "";
5339
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5340
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5341
		foreach ($options as $option) {
5342
			$request_options .= "\trequest " . trim($option) . ";\n";
5343
		}
5344
	}
5345

    
5346
	$information_only = "";
5347
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5348
		$information_only = "\tinformation-only;\n";
5349
	}
5350

    
5351
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5352
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5353
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5354
	}
5355

    
5356
	$interface_statement  = "interface";
5357
	$interface_statement .= " {$wanif}";
5358
	$interface_statement .= " {\n";
5359
	$interface_statement .= "$send_options";
5360
	$interface_statement .= "$request_options";
5361
	$interface_statement .= "$information_only";
5362
	$interface_statement .= "$script";
5363
	$interface_statement .= "};\n";
5364

    
5365
	$id_assoc_statement_address = "";
5366
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5367
		$id_assoc_statement_address .= "id-assoc";
5368
		$id_assoc_statement_address .= " na";
5369
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5370
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5371
		}
5372
		$id_assoc_statement_address .= " { ";
5373

    
5374
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5375
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5376
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5377
			$id_assoc_statement_address .= "\n\taddress";
5378
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5379
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5380
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5381
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5382
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5383
			}
5384
			$id_assoc_statement_address .= ";\n";
5385
		}
5386

    
5387
		$id_assoc_statement_address .= "};\n";
5388
	}
5389

    
5390
	$id_assoc_statement_prefix = "";
5391
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5392
		$id_assoc_statement_prefix .= "id-assoc";
5393
		$id_assoc_statement_prefix .= " pd";
5394
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5395
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5396
		}
5397
		$id_assoc_statement_prefix .= " { ";
5398

    
5399
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5400
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5401
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5402
			$id_assoc_statement_prefix .= "\n\tprefix";
5403
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5404
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5405
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5406
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5407
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5408
			}
5409
			$id_assoc_statement_prefix .= ";";
5410
		}
5411

    
5412
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5413
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5414
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5415
			$id_assoc_statement_prefix .= " {$realif}";
5416
			$id_assoc_statement_prefix .= " {\n";
5417
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5418
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5419
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5420
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5421
			}
5422
			$id_assoc_statement_prefix .= "\t};";
5423
		}
5424

    
5425
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5426
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5427
			$id_assoc_statement_prefix .= "\n";
5428
		}
5429

    
5430
		$id_assoc_statement_prefix .= "};\n";
5431
	}
5432

    
5433
	$authentication_statement = "";
5434
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5435
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5436
		$authentication_statement .= "authentication";
5437
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5438
		$authentication_statement .= " {\n";
5439
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5440
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5441
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5442
		}
5443
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5444
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5445
		}
5446
		$authentication_statement .= "};\n";
5447
	}
5448

    
5449
	$key_info_statement = "";
5450
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5451
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5452
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5453
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5454
		$key_info_statement .= "keyinfo";
5455
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5456
		$key_info_statement .= " {\n";
5457
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5458
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5459
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5460
		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'])) {
5461
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5462
		}
5463
		$key_info_statement .= "};\n";
5464
	}
5465

    
5466
	$dhcp6cconf  = $interface_statement;
5467
	$dhcp6cconf .= $id_assoc_statement_address;
5468
	$dhcp6cconf .= $id_assoc_statement_prefix;
5469
	$dhcp6cconf .= $authentication_statement;
5470
	$dhcp6cconf .= $key_info_statement;
5471

    
5472
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5473

    
5474
	return $dhcp6cconf;
5475
}
5476

    
5477

    
5478
function DHCP6_Config_File_Override($wancfg, $wanif) {
5479

    
5480
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5481

    
5482
	if ($dhcp6cconf === false) {
5483
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5484
		return '';
5485
	} else {
5486
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5487
	}
5488
}
5489

    
5490

    
5491
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5492

    
5493
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5494

    
5495
	return $dhcp6cconf;
5496
}
5497

    
5498

    
5499
function interface_dhcp_configure($interface = "wan") {
5500
	global $config, $g, $vlanprio_values;
5501

    
5502
	$ifcfg = $config['interfaces'][$interface];
5503
	if (empty($ifcfg)) {
5504
		$ifcfg = array();
5505
	}
5506

    
5507
	$dhclientconf_vlantag = "";
5508
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5509
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5510
	}
5511

    
5512
	/* generate dhclient_wan.conf */
5513
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5514
	if (!$fd) {
5515
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5516
		return 1;
5517
	}
5518

    
5519
	if ($ifcfg['dhcphostname']) {
5520
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5521
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5522
	} else {
5523
		$dhclientconf_hostname = "";
5524
	}
5525

    
5526
	$realif = get_real_interface($interface);
5527
	if (empty($realif)) {
5528
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5529
		return 0;
5530
	}
5531
	$dhclientconf = "";
5532

    
5533
	$dhclientconf .= <<<EOD
5534
interface "{$realif}" {
5535
	supersede interface-mtu 0;
5536
	timeout 60;
5537
	retry 15;
5538
	select-timeout 0;
5539
	initial-interval 1;
5540
	{$dhclientconf_vlantag}
5541
	{$dhclientconf_hostname}
5542
	script "/usr/local/sbin/pfSense-dhclient-script";
5543
EOD;
5544

    
5545
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5546
		$dhclientconf .= <<<EOD
5547

    
5548
	reject {$ifcfg['dhcprejectfrom']};
5549
EOD;
5550
	}
5551
	$dhclientconf .= <<<EOD
5552

    
5553
}
5554

    
5555
EOD;
5556

    
5557
	// DHCP Config File Advanced
5558
	if ($ifcfg['adv_dhcp_config_advanced']) {
5559
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5560
	}
5561

    
5562
	if (is_ipaddr($ifcfg['alias-address'])) {
5563
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5564
		$dhclientconf .= <<<EOD
5565
alias {
5566
	interface "{$realif}";
5567
	fixed-address {$ifcfg['alias-address']};
5568
	option subnet-mask {$subnetmask};
5569
}
5570

    
5571
EOD;
5572
	}
5573

    
5574
	// DHCP Config File Override
5575
	if ($ifcfg['adv_dhcp_config_file_override']) {
5576
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5577
	}
5578

    
5579
	fwrite($fd, $dhclientconf);
5580
	fclose($fd);
5581

    
5582
	/* bring wan interface up before starting dhclient */
5583
	if ($realif) {
5584
		interfaces_bring_up($realif);
5585
	}
5586

    
5587
	/* Make sure dhclient is not running */
5588
	kill_dhclient_process($realif);
5589

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

    
5593
	return 0;
5594
}
5595

    
5596
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5597

    
5598
	$hostname = "";
5599
	if ($ifcfg['dhcphostname'] != '') {
5600
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5601
	}
5602

    
5603
	/* DHCP Protocol Timings */
5604
	$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");
5605
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5606
		$pt_variable = "{$Protocol_Timing}";
5607
		${$pt_variable} = "";
5608
		if ($ifcfg[$Protocol_Timing] != "") {
5609
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5610
		}
5611
	}
5612

    
5613
	$send_options = "";
5614
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5615
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5616
		foreach ($options as $option) {
5617
			$send_options .= "\tsend " . trim($option) . ";\n";
5618
		}
5619
	}
5620

    
5621
	$request_options = "";
5622
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5623
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5624
	}
5625

    
5626
	$required_options = "";
5627
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5628
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5629
	}
5630

    
5631
	$option_modifiers = "";
5632
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5633
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5634
		foreach ($modifiers as $modifier) {
5635
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5636
		}
5637
	}
5638

    
5639
	$dhclientconf  = "interface \"{$realif}\" {\n";
5640
	$dhclientconf .= "\n";
5641
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5642
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5643
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5644
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5645
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5646
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5647
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5648
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5649
	$dhclientconf .= "\n";
5650
	$dhclientconf .= "# DHCP Protocol Options\n";
5651
	$dhclientconf .= "{$hostname}";
5652
	$dhclientconf .= "{$send_options}";
5653
	$dhclientconf .= "{$request_options}";
5654
	$dhclientconf .= "{$required_options}";
5655
	$dhclientconf .= "{$option_modifiers}";
5656
	$dhclientconf .= "\n";
5657
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5658
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5659
	}
5660
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5661
	$dhclientconf .= "}\n";
5662

    
5663
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5664

    
5665
	return $dhclientconf;
5666
}
5667

    
5668
function DHCP_Config_Option_Split($option_string) {
5669
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5670
	return $matches ? $matches[0] : [];
5671
}
5672

    
5673
function DHCP_Config_File_Override($ifcfg, $realif) {
5674

    
5675
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5676

    
5677
	if ($dhclientconf === false) {
5678
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5679
		return '';
5680
	} else {
5681
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5682
	}
5683
}
5684

    
5685

    
5686
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5687

    
5688
	/* Apply Interface Substitutions */
5689
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5690

    
5691
	/* Apply Hostname Substitutions */
5692
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5693

    
5694
	/* Arrays of MAC Address Types, Cases, Delimiters */
5695
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5696
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5697
	$various_mac_cases      = array("U", "L");
5698
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5699

    
5700
	/* Apply MAC Address Substitutions */
5701
	foreach ($various_mac_types as $various_mac_type) {
5702
		foreach ($various_mac_cases as $various_mac_case) {
5703
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5704

    
5705
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5706
				if ($res !== false) {
5707

    
5708
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5709
					if ("$various_mac_case" == "U") {
5710
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5711
					}
5712
					if ("$various_mac_case" == "L") {
5713
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5714
					}
5715

    
5716
					if ("$various_mac_type" == "mac_addr_hex") {
5717
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5718
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5719
						$dhcpclientconf_mac_hex = "";
5720
						$delimiter = "";
5721
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5722
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5723
							$delimiter = ":";
5724
						}
5725
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5726
					}
5727

    
5728
					/* MAC Address Delimiter Substitutions */
5729
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5730

    
5731
					/* Apply MAC Address Substitutions */
5732
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5733
				}
5734
			}
5735
		}
5736
	}
5737

    
5738
	return $dhclientconf;
5739
}
5740

    
5741
function interfaces_group_setup() {
5742
	global $config;
5743

    
5744
	if (!isset($config['ifgroups']['ifgroupentry']) ||
5745
	    !is_array($config['ifgroups']['ifgroupentry'])) {
5746
		return;
5747
	}
5748

    
5749
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5750
		interface_group_setup($groupar);
5751
	}
5752

    
5753
	return;
5754
}
5755

    
5756
function interface_group_setup(&$groupname /* The parameter is an array */) {
5757
	global $config;
5758

    
5759
	if (!is_array($groupname)) {
5760
		return;
5761
	}
5762
	$members = explode(" ", $groupname['members']);
5763
	foreach ($members as $ifs) {
5764
		$realif = get_real_interface($ifs);
5765
		if ($realif && does_interface_exist($realif)) {
5766
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5767
		}
5768
	}
5769

    
5770
	return;
5771
}
5772

    
5773
function is_interface_group($if) {
5774
	global $config;
5775

    
5776
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5777
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5778
			if ($groupentry['ifname'] === $if) {
5779
				return true;
5780
			}
5781
		}
5782
	}
5783

    
5784
	return false;
5785
}
5786

    
5787
function interface_group_add_member($interface, $groupname) {
5788
	$interface = get_real_interface($interface);
5789
	if (does_interface_exist($interface)) {
5790
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5791
	}
5792
}
5793

    
5794
/* COMPAT Function */
5795
function convert_friendly_interface_to_real_interface_name($interface) {
5796
	return get_real_interface($interface);
5797
}
5798

    
5799
/* COMPAT Function */
5800
function get_real_wan_interface($interface = "wan") {
5801
	return get_real_interface($interface);
5802
}
5803

    
5804
/* COMPAT Function */
5805
function get_current_wan_address($interface = "wan") {
5806
	return get_interface_ip($interface);
5807
}
5808

    
5809
/*
5810
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5811
 */
5812
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5813
	global $config;
5814

    
5815
	/* XXX: For speed reasons reference directly the interface array */
5816
	init_config_arr(array('interfaces'));
5817
	$ifdescrs = &$config['interfaces'];
5818
	//$ifdescrs = get_configured_interface_list(true);
5819

    
5820
	foreach ($ifdescrs as $if => $ifname) {
5821
		if ($if == $interface || $ifname['if'] == $interface) {
5822
			return $if;
5823
		}
5824

    
5825
		if (get_real_interface($if) == $interface) {
5826
			return $if;
5827
		}
5828

    
5829
		if ($checkparent == false) {
5830
			continue;
5831
		}
5832

    
5833
		$int = get_parent_interface($if, true);
5834
		if (is_array($int)) {
5835
			foreach ($int as $iface) {
5836
				if ($iface == $interface) {
5837
					return $if;
5838
				}
5839
			}
5840
		}
5841
	}
5842

    
5843
	if ($interface == "enc0") {
5844
		return 'IPsec';
5845
	}
5846
}
5847

    
5848
/* attempt to resolve interface to friendly descr */
5849
function convert_friendly_interface_to_friendly_descr($interface) {
5850
	global $config;
5851

    
5852
	switch ($interface) {
5853
		case "l2tp":
5854
			$ifdesc = "L2TP";
5855
			break;
5856
		case "pptp":
5857
			$ifdesc = "PPTP";
5858
			break;
5859
		case "pppoe":
5860
			$ifdesc = "PPPoE";
5861
			break;
5862
		case "openvpn":
5863
			$ifdesc = "OpenVPN";
5864
			break;
5865
		case "lo0":
5866
			$ifdesc = "Loopback";
5867
			break;
5868
		case "enc0":
5869
		case "ipsec":
5870
		case "IPsec":
5871
			$ifdesc = "IPsec";
5872
			break;
5873
		default:
5874
			if (isset($config['interfaces'][$interface])) {
5875
				if (empty($config['interfaces'][$interface]['descr'])) {
5876
					$ifdesc = strtoupper($interface);
5877
				} else {
5878
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5879
				}
5880
				break;
5881
			} elseif (substr($interface, 0, 4) == '_vip') {
5882
				if (is_array($config['virtualip']['vip'])) {
5883
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5884
						if ($vip['mode'] == "carp") {
5885
							if ($interface == "_vip{$vip['uniqid']}") {
5886
								$descr = $vip['subnet'];
5887
								$descr .= " (vhid {$vip['vhid']})";
5888
								if (!empty($vip['descr'])) {
5889
									$descr .= " - " .$vip['descr'];
5890
								}
5891
								return $descr;
5892
							}
5893
						}
5894
					}
5895
				}
5896
			} elseif (substr($interface, 0, 5) == '_lloc') {
5897
				return get_interface_linklocal($interface);
5898
			} else {
5899
				if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5900
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5901
						if ($ifgen['ifname'] === $interface) {
5902
							return $ifgen['ifname'];
5903
						}
5904
					}
5905
				}
5906

    
5907
				/* if list */
5908
				$ifdescrs = get_configured_interface_with_descr(true);
5909
				foreach ($ifdescrs as $if => $ifname) {
5910
					if ($if == $interface || $ifname == $interface) {
5911
						return $ifname;
5912
					}
5913
				}
5914
			}
5915
			break;
5916
	}
5917

    
5918
	return $ifdesc;
5919
}
5920

    
5921
function convert_real_interface_to_friendly_descr($interface) {
5922

    
5923
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5924

    
5925
	if (!empty($ifdesc)) {
5926
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5927
	}
5928

    
5929
	return $interface;
5930
}
5931

    
5932
/*
5933
 *  get_parent_interface($interface):
5934
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5935
 *				or virtual interface (i.e. vlan)
5936
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5937
 *			-- returns $interface passed in if $interface parent is not found
5938
 *			-- returns empty array if an invalid interface is passed
5939
 *	(Only handles ppps and vlans now.)
5940
 */
5941
function get_parent_interface($interface, $avoidrecurse = false) {
5942
	global $config;
5943

    
5944
	$parents = array();
5945
	//Check that we got a valid interface passed
5946
	$realif = get_real_interface($interface);
5947
	if ($realif == NULL) {
5948
		return $parents;
5949
	}
5950

    
5951
	// If we got a real interface, find it's friendly assigned name
5952
	if ($interface == $realif && $avoidrecurse == false) {
5953
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5954
	}
5955

    
5956
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5957
		$ifcfg = $config['interfaces'][$interface];
5958
		switch ($ifcfg['ipaddr']) {
5959
			case "ppp":
5960
			case "pppoe":
5961
			case "pptp":
5962
			case "l2tp":
5963
				if (empty($parents)) {
5964
					if (is_array($config['ppps']['ppp'])) {
5965
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5966
							if ($ifcfg['if'] == $ppp['if']) {
5967
								$ports = explode(',', $ppp['ports']);
5968
								foreach ($ports as $pid => $parent_if) {
5969
									$parents[$pid] = get_real_interface($parent_if);
5970
								}
5971
								break;
5972
							}
5973
						}
5974
					}
5975
				}
5976
				break;
5977
			case "dhcp":
5978
			case "static":
5979
			default:
5980
				// Handle _vlans
5981
				$vlan = interface_is_vlan($ifcfg['if']);
5982
				if ($vlan != NULL) {
5983
					$parents[0] = $vlan['if'];
5984
				}
5985
				break;
5986
		}
5987
	}
5988

    
5989
	if (empty($parents)) {
5990
		// Handle _vlans not assigned to an interface
5991
		$vlan = interface_is_vlan($realif);
5992
		if ($vlan != NULL) {
5993
			$parents[0] = $vlan['if'];
5994
		}
5995
	}
5996

    
5997
	if (empty($parents)) {
5998
		/* Handle LAGGs. */
5999
		$lagg = interface_is_type($realif, 'lagg');
6000
		if ($lagg != NULL && isset($lagg['members'])) {
6001
			$parents = explode(",", $lagg['members']);
6002
		}
6003
	}
6004

    
6005
	if (empty($parents)) {
6006
		$parents[0] = $realif;
6007
	}
6008

    
6009
	return $parents;
6010
}
6011

    
6012
/*
6013
 *  get_parent_physical_interface($interface):
6014
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
6015
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
6016
 */
6017
function get_parent_physical_interface($interface) {
6018
	global $config;
6019

    
6020
	$realif = get_parent_interface($interface);
6021

    
6022
	if (substr($realif[0], 0, 4) == "lagg") {
6023
		foreach ($config['laggs']['lagg'] as $lagg) {
6024
			if ($realif[0] == $lagg['laggif']) {
6025
				return explode(",", $lagg['members']);
6026
			}
6027
		}
6028
	} else {
6029
		return $realif;
6030
	}
6031
}
6032

    
6033
function interface_is_wireless_clone($wlif) {
6034
	if (!stristr($wlif, "_wlan")) {
6035
		return false;
6036
	} else {
6037
		return true;
6038
	}
6039
}
6040

    
6041
function interface_get_wireless_base($wlif) {
6042
	if (!stristr($wlif, "_wlan")) {
6043
		return $wlif;
6044
	} else {
6045
		return substr($wlif, 0, stripos($wlif, "_wlan"));
6046
	}
6047
}
6048

    
6049
function interface_get_wireless_clone($wlif) {
6050
	if (!stristr($wlif, "_wlan")) {
6051
		return $wlif . "_wlan0";
6052
	} else {
6053
		return $wlif;
6054
	}
6055
}
6056

    
6057
function interface_list_wireless() {
6058
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
6059

    
6060
	$result = array();
6061
	foreach ($portlist as $port) {
6062
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
6063
			continue;
6064
		}
6065

    
6066
		$desc = $port . " ( " . get_single_sysctl(
6067
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
6068

    
6069
		$result[] = array(
6070
		    "if" => $port,
6071
		    "descr" => $desc
6072
		);
6073
	}
6074

    
6075
	return $result;
6076
}
6077

    
6078
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
6079
	global $config, $g;
6080

    
6081
	$wanif = NULL;
6082

    
6083
	switch ($interface) {
6084
		case "l2tp":
6085
			$wanif = "l2tp";
6086
			break;
6087
		case "pptp":
6088
			$wanif = "pptp";
6089
			break;
6090
		case "pppoe":
6091
			$wanif = "pppoe";
6092
			break;
6093
		case "openvpn":
6094
			$wanif = "openvpn";
6095
			break;
6096
		case "IPsec":
6097
		case "ipsec":
6098
		case "enc0":
6099
			$wanif = "enc0";
6100
			break;
6101
		case "ppp":
6102
			$wanif = "ppp";
6103
			break;
6104
		default:
6105
			if (substr($interface, 0, 4) == '_vip') {
6106
				$wanif = get_configured_vip_interface($interface);
6107
				if (!empty($wanif)) {
6108
					$wanif = get_real_interface($wanif);
6109
				}
6110
				break;
6111
			} elseif (substr($interface, 0, 5) == '_lloc') {
6112
				$interface = substr($interface, 5);
6113
			} elseif (interface_is_vlan($interface) != NULL ||
6114
			    does_interface_exist($interface, $flush)) {
6115
				/*
6116
				 * If a real interface was already passed simply
6117
				 * pass the real interface back.  This encourages
6118
				 * the usage of this function in more cases so that
6119
				 * we can combine logic for more flexibility.
6120
				 */
6121
				$wanif = $interface;
6122
				break;
6123
			}
6124

    
6125
			if (empty($config['interfaces'][$interface])) {
6126
				break;
6127
			}
6128

    
6129
			$cfg = &$config['interfaces'][$interface];
6130

    
6131
			if ($family == "inet6") {
6132
				switch ($cfg['ipaddrv6']) {
6133
					case "6rd":
6134
					case "6to4":
6135
						$wanif = "{$interface}_stf";
6136
						break;
6137
					case 'pppoe':
6138
					case 'ppp':
6139
					case 'l2tp':
6140
					case 'pptp':
6141
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6142
							$wanif = interface_get_wireless_clone($cfg['if']);
6143
						} else {
6144
							$wanif = $cfg['if'];
6145
						}
6146
						break;
6147
					default:
6148
						switch ($cfg['ipaddr']) {
6149
							case 'pppoe':
6150
							case 'ppp':
6151
							case 'l2tp':
6152
							case 'pptp':
6153
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
6154
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) ||
6155
								    isset($cfg['ipv6usev4iface']) || isset($cfg['slaacusev4iface'])) {
6156
									$wanif = $cfg['if'];
6157
								} else {
6158
									$parents = get_parent_interface($interface);
6159
									if (!empty($parents[0])) {
6160
										$wanif = $parents[0];
6161
									} else {
6162
										$wanif = $cfg['if'];
6163
									}
6164
								}
6165
								break;
6166
							default:
6167
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6168
									$wanif = interface_get_wireless_clone($cfg['if']);
6169
								} else {
6170
									$wanif = $cfg['if'];
6171
								}
6172
								break;
6173
						}
6174
						break;
6175
				}
6176
			} else {
6177
				// Wireless cloned NIC support (FreeBSD 8+)
6178
				// interface name format: $parentnic_wlanparentnic#
6179
				// example: ath0_wlan0
6180
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6181
					$wanif = interface_get_wireless_clone($cfg['if']);
6182
				} else {
6183
					$wanif = $cfg['if'];
6184
				}
6185
			}
6186
			break;
6187
	}
6188

    
6189
	return $wanif;
6190
}
6191

    
6192
/* Guess the physical interface by providing a IP address */
6193
function guess_interface_from_ip($ipaddress) {
6194

    
6195
	if (!is_ipaddr($ipaddress)) {
6196
		return false;
6197
	}
6198

    
6199
	$route = route_get($ipaddress);
6200
	if (empty($route)) {
6201
		return false;
6202
	}
6203

    
6204
	if (!empty($route[0]['interface-name'])) {
6205
		return $route[0]['interface-name'];
6206
	}
6207

    
6208
	return false;
6209
}
6210

    
6211
/*
6212
 * find_ip_interface($ip): return the interface where an ip is defined
6213
 *   (or if $bits is specified, where an IP within the subnet is defined)
6214
 */
6215
function find_ip_interface($ip, $bits = null) {
6216
	if (!is_ipaddr($ip)) {
6217
		return false;
6218
	}
6219

    
6220
	$isv6ip = is_ipaddrv6($ip);
6221

    
6222
	/* if list */
6223
	$ifdescrs = get_configured_interface_list();
6224

    
6225
	foreach ($ifdescrs as $ifdescr => $ifname) {
6226
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
6227
		if (is_null($ifip)) {
6228
			continue;
6229
		}
6230
		if (is_null($bits)) {
6231
			if ($ip == $ifip) {
6232
				$int = get_real_interface($ifname);
6233
				return $int;
6234
			}
6235
		} else {
6236
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
6237
				$int = get_real_interface($ifname);
6238
				return $int;
6239
			}
6240
		}
6241
	}
6242

    
6243
	return false;
6244
}
6245

    
6246
/*
6247
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6248
 *   (or if $bits is specified, where an IP within the subnet is found)
6249
 */
6250
function find_virtual_ip_alias($ip, $bits = null) {
6251
	global $config;
6252

    
6253
	if (!is_array($config['virtualip']['vip'])) {
6254
		return false;
6255
	}
6256
	if (!is_ipaddr($ip)) {
6257
		return false;
6258
	}
6259

    
6260
	$isv6ip = is_ipaddrv6($ip);
6261

    
6262
	foreach ($config['virtualip']['vip'] as $vip) {
6263
		if ($vip['mode'] === "ipalias") {
6264
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
6265
				continue;
6266
			}
6267
			if (is_null($bits)) {
6268
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
6269
					return $vip;
6270
				}
6271
			} else {
6272
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
6273
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
6274
					return $vip;
6275
				}
6276
			}
6277
		}
6278
	}
6279
	return false;
6280
}
6281

    
6282
function link_interface_to_track6($int, $action = "") {
6283
	global $config;
6284

    
6285
	if (empty($int)) {
6286
		return;
6287
	}
6288

    
6289
	if (is_array($config['interfaces'])) {
6290
		$list = array();
6291
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
6292
			if (!isset($ifcfg['enable'])) {
6293
				continue;
6294
			}
6295
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
6296
				if ($action == "update") {
6297
					interface_track6_configure($ifname, $ifcfg);
6298
				} elseif ($action == "") {
6299
					$list[$ifname] = $ifcfg;
6300
				}
6301
			}
6302
		}
6303
		return $list;
6304
	}
6305
}
6306

    
6307
function interface_find_child_cfgmtu($realiface) {
6308
	global $config;
6309

    
6310
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6311
	$vlans = link_interface_to_vlans($realiface);
6312
	$qinqs = link_interface_to_qinqs($realiface);
6313
	$bridge = link_interface_to_bridge($realiface);
6314
	if (!empty($interface)) {
6315
		$gifs = link_interface_to_tunnelif($interface, 'gif');
6316
		$gres = link_interface_to_tunnelif($interface, 'gre');
6317
		$vxlans = link_interface_to_tunnelif($interface, 'vxlan');
6318
	} else {
6319
		$gifs = array();
6320
		$gres = array();
6321
		$vxlans = array();
6322
	}
6323

    
6324
	$mtu = 0;
6325
	if (is_array($vlans)) {
6326
		foreach ($vlans as $vlan) {
6327
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
6328
			if (empty($ifass)) {
6329
				continue;
6330
			}
6331
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6332
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6333
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6334
				}
6335
			}
6336
		}
6337
	}
6338
	if (is_array($qinqs)) {
6339
		foreach ($qinqs as $qinq) {
6340
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
6341
			if (empty($ifass)) {
6342
				continue;
6343
			}
6344
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6345
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6346
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6347
				}
6348
			}
6349
		}
6350
	}
6351
	if (is_array($gifs)) {
6352
		foreach ($gifs as $gif) {
6353
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
6354
			if (empty($ifass)) {
6355
				continue;
6356
			}
6357
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6358
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6359
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6360
				}
6361
			}
6362
		}
6363
	}
6364
	if (is_array($gres)) {
6365
		foreach ($gres as $gre) {
6366
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
6367
			if (empty($ifass)) {
6368
				continue;
6369
			}
6370
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6371
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6372
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6373
				}
6374
			}
6375
		}
6376
	}
6377
	if (is_array($vxlans)) {
6378
		foreach ($vxlans as $vxlan) {
6379
			$ifass = convert_real_interface_to_friendly_interface_name($vxlan['vxlanif']);
6380
			if (empty($ifass)) {
6381
				continue;
6382
			}
6383
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6384
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6385
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6386
				}
6387
			}
6388
		}
6389
	}
6390
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
6391
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
6392
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6393
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
6394
		}
6395
	}
6396
	unset($vlans, $bridge, $gifs, $gres, $vxlans, $ifass, $vlan);
6397

    
6398
	return $mtu;
6399
}
6400

    
6401
function link_interface_to_vlans($int, $action = "") {
6402
	global $config;
6403

    
6404
	if (empty($int)) {
6405
		return;
6406
	}
6407

    
6408
	if (is_array($config['vlans']['vlan'])) {
6409
		$ifaces = array();
6410
		foreach ($config['vlans']['vlan'] as $vlan) {
6411
			if ($int == $vlan['if']) {
6412
				if ($action == "update") {
6413
					interfaces_bring_up($int);
6414
				} else {
6415
					$ifaces[$vlan['tag']] = $vlan;
6416
				}
6417
			}
6418
		}
6419
		if (!empty($ifaces)) {
6420
			return $ifaces;
6421
		}
6422
	}
6423
}
6424

    
6425
function link_interface_to_qinqs($int, $action = "") {
6426
	global $config;
6427

    
6428
	if (empty($int)) {
6429
		return;
6430
	}
6431

    
6432
	if (is_array($config['qinqs']['qinqentry'])) {
6433
		$ifaces = array();
6434
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
6435
			if ($int == $qinq['if']) {
6436
				if ($action == "update") {
6437
					interfaces_bring_up($int);
6438
				} else {
6439
					$ifaces[$qinq['tag']] = $qinq;
6440
				}
6441
			}
6442
		}
6443
		if (!empty($ifaces)) {
6444
			return $ifaces;
6445
		}
6446
	}
6447
}
6448

    
6449
function link_interface_to_vips($int, $action = "", $vhid = '') {
6450
	global $config;
6451

    
6452
	$updatevips = false;
6453
	if (is_array($config['virtualip']['vip'])) {
6454
		$result = array();
6455
		foreach ($config['virtualip']['vip'] as $vip) {
6456
			if (substr($vip['interface'], 0, 4) == "_vip") {
6457
				$iface = get_configured_vip_interface($vip['interface']);
6458
			} else {
6459
				$iface = $vip['interface'];
6460
			}
6461
			if ($int != $iface) {
6462
				continue;
6463
			}
6464
			if ($action == "update") {
6465
				$updatevips = true;
6466
			} else {
6467
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
6468
				    substr($vip['interface'], 0, 4) == "_vip") {
6469
					$result[] = $vip;
6470
				}
6471
			}
6472
		}
6473
		if ($updatevips === true) {
6474
			interfaces_vips_configure($int);
6475
		}
6476
		return $result;
6477
	}
6478

    
6479
	return NULL;
6480
}
6481

    
6482
/****f* interfaces/link_interface_to_bridge
6483
 * NAME
6484
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6485
 * INPUTS
6486
 *   $ip
6487
 * RESULT
6488
 *   bridge[0-99]
6489
 ******/
6490
function link_interface_to_bridge($int) {
6491
	global $config;
6492

    
6493
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6494
		foreach ($config['bridges']['bridged'] as $bridge) {
6495
			if (in_array($int, explode(',', $bridge['members']))) {
6496
				return "{$bridge['bridgeif']}";
6497
			}
6498
		}
6499
	}
6500
}
6501

    
6502
function link_interface_to_lagg($int) {
6503
	global $config;
6504

    
6505
	if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
6506
		foreach ($config['laggs']['lagg'] as $lagg) {
6507
			if (in_array($int, explode(',', $lagg['members']))) {
6508
				return "{$lagg['laggif']}";
6509
			}
6510
		}
6511
	}
6512
}
6513

    
6514
function link_interface_to_group($int) {
6515
	global $config;
6516

    
6517
	$result = array();
6518

    
6519
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6520
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6521
			if (in_array($int, explode(" ", $group['members']))) {
6522
				$result[$group['ifname']] = $int;
6523
			}
6524
		}
6525
	}
6526

    
6527
	return $result;
6528
}
6529

    
6530
function link_interface_to_tunnelif($interface, $type) {
6531
	global $config;
6532

    
6533
	if (!in_array($type, array('gre', 'gif', 'vxlan'))) {
6534
		return;
6535
	}
6536

    
6537
	$result = array();
6538

    
6539
	if (is_array($config["{$type}s"][$type])) {
6540
		foreach ($config["{$type}s"][$type] as $tunnel) {
6541
			if ($tunnel['if'] == $interface) {
6542
				$result[] = $tunnel;
6543
			}
6544
		}
6545
	}
6546

    
6547
	return $result;
6548
}
6549

    
6550
/*
6551
 * find_interface_ip($interface): return the interface ip (first found)
6552
 */
6553
function find_interface_ip($interface, $flush = false) {
6554
	global $interface_ip_arr_cache;
6555
	global $interface_sn_arr_cache;
6556

    
6557
	$interface = str_replace("\n", "", $interface);
6558

    
6559
	if (!does_interface_exist($interface)) {
6560
		return;
6561
	}
6562

    
6563
	/* Setup IP cache */
6564
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6565
		if (file_exists("/var/db/${interface}_ip")) {
6566
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6567
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6568
			foreach ($ifaddrs as $ifaddr) {
6569
				list($ip, $mask) = explode("/", $ifaddr);
6570
				if ($ip == $ifip) {
6571
					$interface_ip_arr_cache[$interface] = $ip;
6572
					$interface_sn_arr_cache[$interface] = $mask;
6573
					break;
6574
				}
6575
			}
6576
		}
6577
		if (!isset($interface_ip_arr_cache[$interface])) {
6578
			$ifinfo = pfSense_get_interface_addresses($interface);
6579
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6580
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6581
		}
6582
	}
6583

    
6584
	return $interface_ip_arr_cache[$interface];
6585
}
6586

    
6587
/*
6588
 * find_interface_ipv6($interface): return the interface ip (first found)
6589
 */
6590
function find_interface_ipv6($interface, $flush = false) {
6591
	global $interface_ipv6_arr_cache;
6592
	global $interface_snv6_arr_cache;
6593
	global $config;
6594

    
6595
	$interface = trim($interface);
6596
	$interface = get_real_interface($interface);
6597

    
6598
	if (!does_interface_exist($interface)) {
6599
		return;
6600
	}
6601

    
6602
	/* Setup IP cache */
6603
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6604
		$ifinfo = pfSense_get_interface_addresses($interface);
6605
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6606
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6607
	}
6608

    
6609
	return $interface_ipv6_arr_cache[$interface];
6610
}
6611

    
6612
/*
6613
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6614
 */
6615
function find_interface_ipv6_ll($interface, $flush = false) {
6616
	global $interface_llv6_arr_cache;
6617
	global $config;
6618

    
6619
	$interface = str_replace("\n", "", $interface);
6620

    
6621
	if (!does_interface_exist($interface)) {
6622
		return;
6623
	}
6624

    
6625
	/* Setup IP cache */
6626
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6627
		$ifinfo = pfSense_getall_interface_addresses($interface);
6628
		foreach ($ifinfo as $line) {
6629
			if (strstr($line, ":")) {
6630
				$parts = explode("/", $line);
6631
				if (is_linklocal($parts[0])) {
6632
					$ifinfo['linklocal'] = $parts[0];
6633
				}
6634
			}
6635
		}
6636
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6637
	}
6638
	return $interface_llv6_arr_cache[$interface];
6639
}
6640

    
6641
function find_interface_subnet($interface, $flush = false) {
6642
	global $interface_sn_arr_cache;
6643
	global $interface_ip_arr_cache;
6644

    
6645
	$interface = str_replace("\n", "", $interface);
6646
	if (does_interface_exist($interface) == false) {
6647
		return;
6648
	}
6649

    
6650
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6651
		$ifinfo = pfSense_get_interface_addresses($interface);
6652
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6653
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6654
	}
6655

    
6656
	return $interface_sn_arr_cache[$interface];
6657
}
6658

    
6659
function find_interface_subnetv6($interface, $flush = false) {
6660
	global $interface_snv6_arr_cache;
6661
	global $interface_ipv6_arr_cache;
6662

    
6663
	$interface = str_replace("\n", "", $interface);
6664
	if (does_interface_exist($interface) == false) {
6665
		return;
6666
	}
6667

    
6668
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6669
		$ifinfo = pfSense_get_interface_addresses($interface);
6670
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6671
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6672
	}
6673

    
6674
	return $interface_snv6_arr_cache[$interface];
6675
}
6676

    
6677
function ip_in_interface_alias_subnet($interface, $ipalias) {
6678
	global $config;
6679

    
6680
	if (empty($interface) || !is_ipaddr($ipalias)) {
6681
		return false;
6682
	}
6683
	if (is_array($config['virtualip']['vip'])) {
6684
		foreach ($config['virtualip']['vip'] as $vip) {
6685
			switch ($vip['mode']) {
6686
				case "ipalias":
6687
					if ($vip['interface'] <> $interface) {
6688
						break;
6689
					}
6690
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6691
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6692
						return true;
6693
					}
6694
					break;
6695
			}
6696
		}
6697
	}
6698

    
6699
	return false;
6700
}
6701

    
6702
function get_possible_listen_ips($include_ipv6_link_local=false) {
6703

    
6704
	$interfaces = get_configured_interface_with_descr();
6705
	foreach ($interfaces as $iface => $ifacename) {
6706
		if ($include_ipv6_link_local) {
6707
			/* This is to avoid going though added ll below */
6708
			if (substr($iface, 0, 5) == '_lloc') {
6709
				continue;
6710
			}
6711
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6712
			if (!empty($llip)) {
6713
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6714
			}
6715
		}
6716
	}
6717
	$viplist = get_configured_vip_list();
6718
	foreach ($viplist as $vip => $address) {
6719
		$interfaces[$vip] = $address;
6720
		if (get_vip_descr($address)) {
6721
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6722
		}
6723
	}
6724

    
6725
	$interfaces['lo0'] = 'Localhost';
6726

    
6727
	return $interfaces;
6728
}
6729

    
6730
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6731
	global $config;
6732

    
6733
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6734
	foreach (array('server', 'client') as $mode) {
6735
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6736
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6737
				if (!isset($setting['disable'])) {
6738
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6739
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6740
				}
6741
			}
6742
		}
6743
	}
6744
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
6745
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
6746
			if ($ph1ent['disabled']) {
6747
				continue;
6748
			}
6749
			if (ipsec_vti($ph1ent)) {
6750
				$sourceips_key = "ipsec{$ph1ent['ikeid']}";
6751
				$sourceips[$sourceips_key] = gettext("IPsec VTI") . ": " . htmlspecialchars($ph1ent['descr']);
6752
			}
6753
		}
6754
	}
6755
	return $sourceips;
6756
}
6757

    
6758
function get_interface_ip($interface = "wan") {
6759
	global $config;
6760

    
6761
	if (substr($interface, 0, 4) == '_vip') {
6762
		return get_configured_vip_ipv4($interface);
6763
	} elseif (substr($interface, 0, 5) == '_lloc') {
6764
		/* No link-local address for v4. */
6765
		return null;
6766
	}
6767

    
6768
	$realif = get_failover_interface($interface, 'inet');
6769
	if (!$realif) {
6770
		return null;
6771
	}
6772

    
6773
	if (substr($realif, 0, 4) == '_vip') {
6774
		return get_configured_vip_ipv4($realif);
6775
	} elseif (substr($realif, 0, 5) == '_lloc') {
6776
		/* No link-local address for v4. */
6777
		return null;
6778
	}
6779

    
6780
	if (is_array($config['interfaces'][$interface]) &&
6781
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6782
		return ($config['interfaces'][$interface]['ipaddr']);
6783
	}
6784

    
6785
	/*
6786
	 * Beaware that find_interface_ip() is our last option, it will
6787
	 * return the first IP it find on interface, not necessarily the
6788
	 * main IP address.
6789
	 */
6790
	$curip = find_interface_ip($realif);
6791
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6792
		return $curip;
6793
	} else {
6794
		return null;
6795
	}
6796
}
6797

    
6798
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6799
	global $config;
6800

    
6801
	if (substr($interface, 0, 4) == '_vip') {
6802
		return get_configured_vip_ipv6($interface);
6803
	} elseif (substr($interface, 0, 5) == '_lloc') {
6804
		return get_interface_linklocal($interface);
6805
	}
6806

    
6807
	$realif = get_failover_interface($interface, 'inet6');
6808
	if (!$realif) {
6809
		return null;
6810
	}
6811

    
6812
	if (substr($realif, 0, 4) == '_vip') {
6813
		return get_configured_vip_ipv6($realif);
6814
	} elseif (substr($realif, 0, 5) == '_lloc') {
6815
		return get_interface_linklocal($realif);
6816
	}
6817

    
6818
	if (is_array($config['interfaces'][$interface])) {
6819
		switch ($config['interfaces'][$interface]['ipaddr']) {
6820
			case 'pppoe':
6821
			case 'l2tp':
6822
			case 'pptp':
6823
			case 'ppp':
6824
				if (($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') ||
6825
				    ($config['interfaces'][$interface]['ipaddrv6'] == 'slaac')) {
6826
					$realif = get_real_interface($interface, 'inet6', false);
6827
				}
6828
				break;
6829
		}
6830
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6831
			return ($config['interfaces'][$interface]['ipaddrv6']);
6832
		}
6833
	}
6834

    
6835
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6836
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6837
		$curip = get_interface_track6ip($interface);
6838
		if ($curip) {
6839
			return $curip[0];
6840
		}
6841
	}
6842

    
6843
	/*
6844
	 * Beaware that find_interface_ip() is our last option, it will
6845
	 * return the first IP it find on interface, not necessarily the
6846
	 * main IP address.
6847
	 */
6848
	$curip = find_interface_ipv6($realif, $flush);
6849
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6850
		return $curip;
6851
	} else {
6852
		/*
6853
		 * NOTE: On the case when only the prefix is requested,
6854
		 * the communication on WAN will be done over link-local.
6855
		 */
6856
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6857
			$curip = find_interface_ipv6_ll($realif, $flush);
6858
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6859
				return $curip;
6860
			}
6861
		}
6862
	}
6863
	return null;
6864
}
6865

    
6866
function get_interface_linklocal($interface = "wan") {
6867

    
6868
	$realif = get_failover_interface($interface, 'inet6');
6869
	if (!$realif) {
6870
		return null;
6871
	}
6872

    
6873
	if (substr($interface, 0, 4) == '_vip') {
6874
		$realif = get_real_interface($interface);
6875
	} elseif (substr($interface, 0, 5) == '_lloc') {
6876
		$realif = get_real_interface(substr($interface, 5));
6877
	}
6878

    
6879
	$curip = find_interface_ipv6_ll($realif);
6880
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6881
		return $curip;
6882
	} else {
6883
		return null;
6884
	}
6885
}
6886

    
6887
function get_interface_track6ip($interface = "wan") {
6888
	$realif = get_real_interface($interface);
6889
	$vips = get_configured_vip_list('inet6');
6890

    
6891
	foreach (pfSense_getall_interface_addresses($realif) as $ifaddr) {
6892
		list($ip, $bits) = explode("/", $ifaddr);
6893
		$ip = text_to_compressed_ip6($ip);
6894
		if (is_ipaddrv6($ip) && !is_linklocal($ip)) {
6895
			if (is_array($vips) && !empty($vips)) {
6896
				foreach ($vips as $vip) {
6897
					if ($ip != text_to_compressed_ip6($vip)) {
6898
						return array($ip, $bits);
6899
					}
6900
				}
6901
			} else {
6902
				return array($ip, $bits);
6903
			}
6904
		}
6905
	}
6906
	return false;
6907
}
6908

    
6909
function get_interface_subnet($interface = "wan") {
6910
	global $config;
6911

    
6912
	if (substr($interface, 0, 4) == '_vip') {
6913
		return (get_configured_vip_subnetv4($interface));
6914
	}
6915

    
6916
	if (is_array($config['interfaces'][$interface]) &&
6917
	    !empty($config['interfaces'][$interface]['subnet']) &&
6918
	    is_ipaddrv4($config['interfaces'][$interface]['ipaddr'])) {
6919
		return ($config['interfaces'][$interface]['subnet']);
6920
	}
6921

    
6922
	$realif = get_real_interface($interface);
6923
	if (!$realif) {
6924
		return (NULL);
6925
	}
6926

    
6927
	$cursn = find_interface_subnet($realif);
6928
	if (!empty($cursn)) {
6929
		return ($cursn);
6930
	}
6931

    
6932
	return (NULL);
6933
}
6934

    
6935
function get_interface_subnetv6($interface = "wan") {
6936
	global $config;
6937

    
6938
	if (substr($interface, 0, 4) == '_vip') {
6939
		return (get_configured_vip_subnetv6($interface));
6940
	} elseif (substr($interface, 0, 5) == '_lloc') {
6941
		$interface = substr($interface, 5);
6942
	}
6943

    
6944
	if (is_array($config['interfaces'][$interface]) &&
6945
	    !empty($config['interfaces'][$interface]['subnetv6']) &&
6946
	    is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6947
		return ($config['interfaces'][$interface]['subnetv6']);
6948
	}
6949

    
6950
	$realif = get_real_interface($interface, 'inet6');
6951
	if (!$realif) {
6952
		return (NULL);
6953
	}
6954

    
6955
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6956
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6957
		$curip = get_interface_track6ip($interface);
6958
		if ($curip) {
6959
			return $curip[1];
6960
		}
6961
	}
6962

    
6963
	$cursn = find_interface_subnetv6($realif);
6964
	if (!empty($cursn)) {
6965
		return ($cursn);
6966
	}
6967

    
6968
	return (NULL);
6969
}
6970

    
6971
/* return outside interfaces with a gateway */
6972
function get_interfaces_with_gateway() {
6973
	global $config;
6974

    
6975
	$ints = array();
6976

    
6977
	/* loop interfaces, check config for outbound */
6978
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6979
		switch ($ifname['ipaddr']) {
6980
			case "dhcp":
6981
			case "pppoe":
6982
			case "pptp":
6983
			case "l2tp":
6984
			case "ppp":
6985
				$ints[$ifdescr] = $ifdescr;
6986
				break;
6987
			default:
6988
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6989
				    !empty($ifname['gateway'])) {
6990
					$ints[$ifdescr] = $ifdescr;
6991
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6992
				    !empty($ifname['gateway'])) {
6993
					$ints[$ifdescr] = $ifdescr;
6994
				}
6995

    
6996
				break;
6997
		}
6998
	}
6999
	return $ints;
7000
}
7001

    
7002
/* return true if interface has a gateway */
7003
function interface_has_gateway($friendly) {
7004
	global $config;
7005

    
7006
	if (!empty($config['interfaces'][$friendly])) {
7007
		$ifname = &$config['interfaces'][$friendly];
7008
		switch ($ifname['ipaddr']) {
7009
			case "dhcp":
7010
			case "pppoe":
7011
			case "pptp":
7012
			case "l2tp":
7013
			case "ppp":
7014
				return true;
7015
			break;
7016
			default:
7017
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
7018
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
7019
					return true;
7020
				}
7021
				$tunnelif = substr($ifname['if'], 0, 3);
7022
				if ($tunnelif == "gif" || $tunnelif == "gre") {
7023
					if (find_interface_ip($ifname['if'])) {
7024
						return true;
7025
					}
7026
				}
7027
				if (!empty($ifname['gateway'])) {
7028
					return true;
7029
				}
7030
			break;
7031
		}
7032
	}
7033

    
7034
	return false;
7035
}
7036

    
7037
/* return true if interface has a gateway */
7038
function interface_has_gatewayv6($friendly) {
7039
	global $config;
7040

    
7041
	if (!empty($config['interfaces'][$friendly])) {
7042
		$ifname = &$config['interfaces'][$friendly];
7043
		switch ($ifname['ipaddrv6']) {
7044
			case "slaac":
7045
			case "dhcp6":
7046
			case "6to4":
7047
			case "6rd":
7048
				return true;
7049
				break;
7050
			default:
7051
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
7052
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
7053
					return true;
7054
				}
7055
				$tunnelif = substr($ifname['if'], 0, 3);
7056
				if ($tunnelif == "gif" || $tunnelif == "gre") {
7057
					if (find_interface_ipv6($ifname['if'])) {
7058
						return true;
7059
					}
7060
				}
7061
				if (!empty($ifname['gatewayv6'])) {
7062
					return true;
7063
				}
7064
				break;
7065
		}
7066
	}
7067

    
7068
	return false;
7069
}
7070

    
7071
/****f* interfaces/is_altq_capable
7072
 * NAME
7073
 *   is_altq_capable - Test if interface is capable of using ALTQ
7074
 * INPUTS
7075
 *   $int            - string containing interface name
7076
 * RESULT
7077
 *   boolean         - true or false
7078
 ******/
7079

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

    
7095
	$int_family = remove_ifindex($int);
7096

    
7097
	if (in_array($int_family, $capable)) {
7098
		return true;
7099
	} elseif (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
7100
		return true;
7101
	} elseif (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
7102
		return true;
7103
	} elseif (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
7104
		return true;
7105
	} else {
7106
		return false;
7107
	}
7108
}
7109

    
7110
/****f* interfaces/is_interface_wireless
7111
 * NAME
7112
 *   is_interface_wireless - Returns if an interface is wireless
7113
 * RESULT
7114
 *   $tmp       - Returns if an interface is wireless
7115
 ******/
7116
function is_interface_wireless($interface) {
7117
	global $config, $g;
7118

    
7119
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
7120
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
7121
		if (preg_match($g['wireless_regex'], $interface)) {
7122
			if (isset($config['interfaces'][$friendly])) {
7123
				$config['interfaces'][$friendly]['wireless'] = array();
7124
			}
7125
			return true;
7126
		}
7127
		return false;
7128
	} else {
7129
		return true;
7130
	}
7131
}
7132

    
7133
function get_wireless_modes($interface) {
7134
	/* return wireless modes and channels */
7135
	$wireless_modes = array();
7136

    
7137
	$cloned_interface = get_real_interface($interface);
7138

    
7139
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7140
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
7141
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
7142
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
7143

    
7144
		$interface_channels = "";
7145
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
7146
		$interface_channel_count = count($interface_channels);
7147

    
7148
		$c = 0;
7149
		while ($c < $interface_channel_count) {
7150
			$channel_line = explode(",", $interface_channels["$c"]);
7151
			$wireless_mode = trim($channel_line[0]);
7152
			$wireless_channel = trim($channel_line[1]);
7153
			if (trim($wireless_mode) != "") {
7154
				/* if we only have 11g also set 11b channels */
7155
				if ($wireless_mode == "11g") {
7156
					if (!isset($wireless_modes["11b"])) {
7157
						$wireless_modes["11b"] = array();
7158
					}
7159
				} elseif ($wireless_mode == "11g ht") {
7160
					if (!isset($wireless_modes["11b"])) {
7161
						$wireless_modes["11b"] = array();
7162
					}
7163
					if (!isset($wireless_modes["11g"])) {
7164
						$wireless_modes["11g"] = array();
7165
					}
7166
					$wireless_mode = "11ng";
7167
				} elseif ($wireless_mode == "11a ht") {
7168
					if (!isset($wireless_modes["11a"])) {
7169
						$wireless_modes["11a"] = array();
7170
					}
7171
					$wireless_mode = "11na";
7172
				}
7173
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
7174
			}
7175
			$c++;
7176
		}
7177
	}
7178
	return($wireless_modes);
7179
}
7180

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

    
7186
		$interface_channels = "";
7187
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7188
		return $interface_channels;
7189
}
7190

    
7191
/* return wireless HT modes */
7192
function get_wireless_ht_modes($interface) {
7193
	$wireless_hts_supported = array(0 => gettext('Auto'));
7194

    
7195
	$cloned_interface = get_real_interface($interface);
7196

    
7197
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7198
		$interface_channels = get_wireless_channels($cloned_interface);
7199

    
7200
		foreach ($interface_channels as $channel) {
7201
			$channel_line = explode(",", $channel);
7202
			$wireless_ht = trim($channel_line[1]);
7203
			if (!empty($wireless_ht)) {
7204
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
7205
			}
7206
		}
7207
	}
7208
	return($wireless_hts_supported);
7209
}
7210

    
7211
/* return wireless HT by channel/standard */
7212
function get_wireless_ht_list($interface) {
7213
	$wireless_hts = array();
7214

    
7215
	$cloned_interface = get_real_interface($interface);
7216

    
7217
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7218
		$interface_channels = get_wireless_channels($cloned_interface);
7219
		$interface_channel_count = count($interface_channels);
7220

    
7221
		$c = 0;
7222
		while ($c < $interface_channel_count) {
7223
			$channel_line = explode(",", $interface_channels["$c"]);
7224
			$wireless_mode = trim($channel_line[0]);
7225
			$wireless_ht = trim($channel_line[1]);
7226
			$wireless_channel = trim($channel_line[2]);
7227
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
7228
				if ($wireless_mode == "11g") {
7229
					if (!isset($wireless_modes["11g"])) {
7230
						$wireless_hts["11g"] = array();
7231
					}
7232
					$wireless_mode = "11ng";
7233
				} elseif ($wireless_mode == "11a") {
7234
					if (!isset($wireless_modes["11a"])) {
7235
						$wireless_hts["11a"] = array();
7236
					}
7237
					$wireless_mode = "11na";
7238
				}
7239
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
7240
			}
7241
			$c++;
7242
		}
7243
	}
7244
	return($wireless_hts);
7245
}
7246

    
7247
/* return channel numbers, frequency, max txpower, and max regulation txpower */
7248
function get_wireless_channel_info($interface) {
7249
	$wireless_channels = array();
7250

    
7251
	$cloned_interface = get_real_interface($interface);
7252

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

    
7258
		$interface_channels = "";
7259
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7260

    
7261
		foreach ($interface_channels as $channel_line) {
7262
			$channel_line = explode(",", $channel_line);
7263
			if (!isset($wireless_channels[$channel_line[0]])) {
7264
				$wireless_channels[$channel_line[0]] = $channel_line;
7265
			}
7266
		}
7267
	}
7268
	return($wireless_channels);
7269
}
7270

    
7271
function set_interface_mtu($interface, $mtu) {
7272

    
7273
	/* LAGG interface must be destroyed and re-created to change MTU */
7274
	if ((substr($interface, 0, 4) == 'lagg') &&
7275
	    (!strstr($interface, "."))) {
7276
		if (isset($config['laggs']['lagg']) &&
7277
		    is_array($config['laggs']['lagg'])) {
7278
			foreach ($config['laggs']['lagg'] as $lagg) {
7279
				if ($lagg['laggif'] == $interface) {
7280
					interface_lagg_configure($lagg);
7281
					break;
7282
				}
7283
			}
7284
		}
7285
	} else {
7286
		pfSense_interface_mtu($interface, $mtu);
7287
		set_ipv6routes_mtu($interface, $mtu);
7288
	}
7289
}
7290

    
7291
/****f* interfaces/get_interface_mtu
7292
 * NAME
7293
 *   get_interface_mtu - Return the mtu of an interface
7294
 * RESULT
7295
 *   $tmp       - Returns the mtu of an interface
7296
 ******/
7297
function get_interface_mtu($interface) {
7298
	$mtu = pfSense_interface_getmtu($interface);
7299
	return $mtu['mtu'];
7300
}
7301

    
7302
function get_interface_mac($interface) {
7303
	$macinfo = pfSense_get_interface_addresses($interface);
7304
	return $macinfo["macaddr"];
7305
}
7306

    
7307
function get_interface_vendor_mac($interface) {
7308
	global $config, $g;
7309

    
7310
	$macinfo = pfSense_get_interface_addresses($interface);
7311
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7312
	    "00:00:00:00:00:00") {
7313
		return ($macinfo["hwaddr"]);
7314
	}
7315

    
7316
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7317
	if (file_exists($hwaddr_file)) {
7318
		$macaddr = trim(file_get_contents($hwaddr_file));
7319
		if (is_macaddr($macaddr)) {
7320
			return ($macaddr);
7321
		}
7322
	} elseif (is_macaddr($macinfo['macaddr'])) {
7323
		/* Save original macaddress to be restored when necessary */
7324
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7325
	}
7326

    
7327
	return (NULL);
7328
}
7329

    
7330
/****f* pfsense-utils/generate_random_mac_address
7331
 * NAME
7332
 *   generate_random_mac - generates a random mac address
7333
 * INPUTS
7334
 *   none
7335
 * RESULT
7336
 *   $mac - a random mac address
7337
 ******/
7338
function generate_random_mac_address() {
7339
	$mac = "02";
7340
	for ($x = 0; $x < 5; $x++) {
7341
		$mac .= ":" . dechex(rand(16, 255));
7342
	}
7343
	return $mac;
7344
}
7345

    
7346
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7347
	global $g;
7348

    
7349
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7350

    
7351
	if (!empty($iface) && !empty($pppif)) {
7352
		$cron_cmd = <<<EOD
7353
#!/bin/sh
7354
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7355
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7356

    
7357
EOD;
7358

    
7359
		@file_put_contents($cron_file, $cron_cmd);
7360
		chmod($cron_file, 0755);
7361
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7362
	} else {
7363
		unlink_if_exists($cron_file);
7364
	}
7365
}
7366

    
7367
function get_interface_default_mtu($type = "ethernet") {
7368
	switch ($type) {
7369
		case "gre":
7370
			return 1476;
7371
			break;
7372
		case "gif":
7373
			return 1280;
7374
			break;
7375
		case "tun":
7376
		case "vlan":
7377
		case "tap":
7378
		case "ethernet":
7379
		default:
7380
			return 1500;
7381
			break;
7382
	}
7383

    
7384
	/* Never reached */
7385
	return 1500;
7386
}
7387

    
7388
function get_vip_descr($ipaddress) {
7389
	global $config;
7390

    
7391
	foreach ($config['virtualip']['vip'] as $vip) {
7392
		if ($vip['subnet'] == $ipaddress) {
7393
			return ($vip['descr']);
7394
		}
7395
	}
7396
	return "";
7397
}
7398

    
7399
function interfaces_staticarp_configure($if) {
7400
	global $config, $g;
7401
	if (isset($config['system']['developerspew'])) {
7402
		$mt = microtime();
7403
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7404
	}
7405

    
7406
	$ifcfg = $config['interfaces'][$if];
7407

    
7408
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
7409
		return 0;
7410
	}
7411

    
7412
	/* Enable staticarp, if enabled */
7413
	if (isset($config['dhcpd'][$if]['staticarp'])) {
7414
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7415
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7416
	} else {
7417
		/*
7418
		 * Interfaces do not have staticarp enabled by default
7419
		 * Let's not disable staticarp on freshly created interfaces
7420
		 */
7421
		if (!platform_booting()) {
7422
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7423
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7424
		}
7425
	}
7426

    
7427
	/* Enable static arp entries */
7428
	if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
7429
		foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
7430
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7431
				continue;
7432
			}
7433
			if (isset($config['dhcpd'][$if]['staticarp']) || isset($arpent['arp_table_static_entry'])) {
7434
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7435
			}
7436
		}
7437
	}
7438

    
7439
	return 0;
7440
}
7441

    
7442
function get_failover_interface($interface, $family = "all") {
7443
	global $config;
7444

    
7445
	/* shortcut to get_real_interface if we find it in the config */
7446
	if (is_array($config['interfaces'][$interface])) {
7447
		return get_real_interface($interface, $family);
7448
	}
7449

    
7450
	/* compare against gateway groups */
7451
	$a_groups = return_gateway_groups_array(true);
7452
	if (is_array($a_groups[$interface])) {
7453
		/* we found a gateway group, fetch the interface or vip */
7454
		if (!empty($a_groups[$interface][0]['vip'])) {
7455
			return $a_groups[$interface][0]['vip'];
7456
		} else {
7457
			return $a_groups[$interface][0]['int'];
7458
		}
7459
	}
7460
	/* fall through to get_real_interface */
7461
	/* XXX: Really needed? */
7462
	return get_real_interface($interface, $family);
7463
}
7464

    
7465
/****f* interfaces/interface_has_dhcp
7466
 * NAME
7467
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7468
 * INPUTS
7469
 *   interface or gateway group name
7470
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7471
 * RESULT
7472
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7473
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7474
 ******/
7475
function interface_has_dhcp($interface, $family = 4) {
7476
	global $config;
7477

    
7478
	if ($config['interfaces'][$interface]) {
7479
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
7480
			return true;
7481
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
7482
			return true;
7483
		} else {
7484
			return false;
7485
		}
7486
	}
7487

    
7488
	if (!is_array($config['gateways']['gateway_group'])) {
7489
		return false;
7490
	}
7491

    
7492
	if ($family == 6) {
7493
		$dhcp_string = "_DHCP6";
7494
	} else {
7495
		$dhcp_string = "_DHCP";
7496
	}
7497

    
7498
	foreach ($config['gateways']['gateway_group'] as $group) {
7499
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7500
			continue;
7501
		}
7502
		foreach ($group['item'] as $item) {
7503
			$item_data = explode("|", $item);
7504
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7505
				return true;
7506
			}
7507
		}
7508
	}
7509

    
7510
	return false;
7511
}
7512

    
7513
function remove_ifindex($ifname) {
7514
	return preg_replace("/[0-9]+$/", "", $ifname);
7515
}
7516

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

    
7520
	$viplist = get_configured_vip_list($family, $type);
7521
	foreach ($viplist as $vip => $address) {
7522
		$interfaces[$vip] = $address;
7523
		if ($type = VIP_CARP) {
7524
			$vip = get_configured_vip($vipid);
7525
			if (isset($vip) && is_array($vip) ) {
7526
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7527
			}
7528
		}
7529
		if (get_vip_descr($address)) {
7530
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
7531
		}
7532
	}
7533
	return $interfaces;
7534
}
7535

    
7536
function return_gateway_groups_array_with_descr() {
7537
	$interfaces = array();
7538
	$grouplist = return_gateway_groups_array();
7539
	foreach ($grouplist as $name => $group) {
7540
		if ($group[0]['vip'] != "") {
7541
			$vipif = $group[0]['vip'];
7542
		} else {
7543
			$vipif = $group[0]['int'];
7544
		}
7545

    
7546
		$interfaces[$name] = "GW Group {$name}";
7547
	}
7548
	return $interfaces;
7549
}
7550

    
7551
function get_serial_ports() {
7552
	$linklist = array();
7553
	if (!is_dir("/var/spool/lock")) {
7554
		mwexec("/bin/mkdir -p /var/spool/lock");
7555
	}
7556
	$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);
7557
	foreach ($serialports as $port) {
7558
		$linklist[$port] = trim($port);
7559
	}
7560
	return $linklist;
7561
}
7562

    
7563
function get_interface_ports() {
7564
	global $config;
7565
	$linklist = array();
7566
	$portlist = get_interface_list();
7567
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7568
		foreach ($config['vlans']['vlan'] as $vlan) {
7569
			$portlist[$vlan['vlanif']] = $vlan;
7570
		}
7571
	}
7572

    
7573
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7574
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7575
			$members = explode(" ", $qinq['members']);
7576
			foreach ($members as $mem) {
7577
				$qentry = $qinq['vlanif'] . "." . $mem;
7578
				$portlist[$qentry] = $qentry;
7579
			}
7580
		}
7581
	}
7582

    
7583
	foreach ($portlist as $ifn => $ifinfo) {
7584
		$string = "";
7585
		if (is_array($ifinfo)) {
7586
			$string .= $ifn;
7587
			if ($ifinfo['mac']) {
7588
				$string .= " ({$ifinfo['mac']})";
7589
			}
7590
			if ($ifinfo['friendly']) {
7591
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7592
			} elseif ($ifinfo['descr']) {
7593
				$string .= " - {$ifinfo['descr']}";
7594
			}
7595
		} else {
7596
			$string .= $ifinfo;
7597
		}
7598

    
7599
		$linklist[$ifn] = $string;
7600
	}
7601
	return $linklist;
7602
}
7603

    
7604
function build_ppps_link_list() {
7605
	global $pconfig;
7606

    
7607
	$linklist = array('list' => array(), 'selected' => array());
7608

    
7609
	if ($pconfig['type'] == 'ppp') {
7610
		$linklist['list'] = get_serial_ports();
7611
	} else {
7612
		$iflist = get_interface_ports();
7613

    
7614
		$viplist = array();
7615
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7616
		foreach ($carplist as $vid => $vaddr) {
7617
			$vip = get_configured_vip($vid);
7618
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7619
		}
7620

    
7621
		$linklist['list'] = array_merge($iflist, $viplist);
7622

    
7623
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7624
		$lagglist = get_lagg_interface_list();
7625
		foreach ($lagglist as $laggif => $lagg) {
7626
			/* LAGG members cannot be assigned */
7627
			$laggmembers = explode(',', $lagg['members']);
7628
			foreach ($laggmembers as $lagm) {
7629
				if (isset($linklist['list'][$lagm])) {
7630
					unset($linklist['list'][$lagm]);
7631
				}
7632
			}
7633
		}
7634
	}
7635

    
7636
	$selected_ports = array();
7637
	if (is_array($pconfig['interfaces'])) {
7638
		$selected_ports = $pconfig['interfaces'];
7639
	} elseif (!empty($pconfig['interfaces'])) {
7640
		$selected_ports = explode(',', $pconfig['interfaces']);
7641
	}
7642
	foreach ($selected_ports as $port) {
7643
		if (isset($linklist['list'][$port])) {
7644
			array_push($linklist['selected'], $port);
7645
		}
7646
	}
7647
	return($linklist);
7648
}
7649

    
7650
function create_interface_list() {
7651
	global $config;
7652

    
7653
	$iflist = array();
7654

    
7655
	// add group interfaces
7656
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7657
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7658
			if (have_ruleint_access($ifgen['ifname'])) {
7659
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7660
			}
7661
		}
7662
	}
7663

    
7664
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7665
		if (have_ruleint_access($ifent)) {
7666
			$iflist[$ifent] = $ifdesc;
7667
		}
7668
	}
7669

    
7670
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
7671
		$iflist['l2tp'] = gettext('L2TP VPN');
7672
	}
7673

    
7674
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
7675
		$iflist['pppoe'] = gettext("PPPoE Server");
7676
	}
7677

    
7678
	// add ipsec interfaces
7679
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
7680
		$iflist["enc0"] = gettext("IPsec");
7681
	}
7682

    
7683
	// add openvpn/tun interfaces
7684
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7685
		$iflist["openvpn"] = gettext("OpenVPN");
7686
	}
7687

    
7688
	return($iflist);
7689
}
7690

    
7691
function is_pseudo_interface($inf, $tap=true) {
7692
	global $config;
7693
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe', 'vxlan');
7694
	foreach ($psifs as $pif) {
7695
		if (substr($inf, 0, strlen($pif)) == $pif) {
7696
			if (($pif == 'ovpn') && $tap) {
7697
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7698
				$type = ($m[1] == 'c') ? 'client' : 'server';
7699
				foreach ($config['openvpn']['openvpn-'.$type] as $ovpn) {
7700
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7701
						return false;
7702
					} elseif ($ovpn['vpnid'] == $m[2]) {
7703
						return true;
7704
					}
7705
				}
7706
			} else {
7707
				return true;
7708
			}
7709
		}
7710
	}
7711
	return false;
7712
}
7713

    
7714
function is_stf_interface($inf) {
7715
	global $config;
7716

    
7717
	if (is_array($config['interfaces'][$inf]) &&
7718
	    (($config['interfaces'][$inf]['ipaddrv6'] == '6rd') ||
7719
	    ($config['interfaces'][$inf]['ipaddrv6'] == '6to4'))) {
7720
	    return true;
7721
	}
7722

    
7723
	return false;
7724
}
7725

    
7726
?>
(22-22/61)