Project

General

Profile

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

    
26
/* include all configuration functions */
27
require_once("globals.inc");
28
require_once("util.inc");
29
require_once("gwlb.inc");
30

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

    
40
/*
41
 * Validate comma-separated list of IPv4 addresses
42
 */
43
function validate_ipv4_list($value) {
44
	$value = trim($value);
45

    
46
	if (empty($value)) {
47
		return false;
48
	}
49

    
50
	$list = explode(',', $value);
51

    
52
	foreach ($list as $ip) {
53
		if (!is_ipaddrv4($ip)) {
54
			return false;
55
		}
56
	}
57

    
58
	return true;
59
}
60

    
61
/*
62
 * Return the interface array
63
 */
64
function get_interface_arr($flush = false) {
65
	global $interface_arr_cache;
66

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

    
72
	return $interface_arr_cache;
73
}
74

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

    
82
	if (!$interface) {
83
		return false;
84
	}
85

    
86
	$ints = get_interface_arr($flush);
87
	if (in_array($interface, $ints)) {
88
		return true;
89
	} else {
90
		return false;
91
	}
92
}
93

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

    
101
	if (!$vip) {
102
		return false;
103
	}
104

    
105

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

    
121
	$ifacedata = pfSense_getall_interface_addresses($realif);
122
	foreach ($ifacedata as $vipips) {
123
		if ($vipips == "{$vip['subnet']}/{$vip['subnet_bits']}") {
124
			return true;
125
		}
126
	}
127

    
128
	return false;
129
}
130

    
131
function interface_netgraph_needed($interface = "wan") {
132
	global $config;
133

    
134
	$found = false;
135
	if (!empty($config['l2tp']) &&
136
	    $config['l2tp']['mode'] == "server") {
137
		$found = true;
138
	}
139
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
140
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
141
			if ($pppoe['mode'] != "server") {
142
				continue;
143
			}
144
			if ($pppoe['interface'] == $interface) {
145
				$found = true;
146
				break;
147
			}
148
		}
149
	}
150
	if ($found == false) {
151
		$found = interface_isppp_type($interface);
152
	}
153

    
154
	if ($found == false) {
155
		$realif = get_real_interface($interface);
156
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
157
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
158
				$ports = explode(',', $ppp['ports']);
159
				foreach ($ports as $pid => $port) {
160
					$port = get_real_interface($port);
161
					if ($realif == $port) {
162
						$found = true;
163
						break;
164
					}
165
					/* Find the parent interfaces of the vlans in the MLPPP configs
166
					* there should be only one element in the array here
167
					* -- this could be better . . . */
168
					$parent_if = get_parent_interface($port);
169
					if ($realif == $parent_if[0]) {
170
						$found = true;
171
						break;
172
					}
173
				}
174
			}
175
		}
176
	}
177

    
178
	if ($found == false) {
179
		$realif = get_real_interface($interface);
180
		pfSense_ngctl_detach("{$realif}:", $realif);
181
	}
182
	/* NOTE: We make sure for this on interface_ppps_configure()
183
	 *	no need to do it here again.
184
	 *	else
185
	 *		pfSense_ngctl_attach(".", $realif);
186
	 */
187
}
188

    
189
function interfaces_loopback_configure() {
190
	global $g;
191

    
192
	if (platform_booting()) {
193
		echo gettext("Configuring loopback interface...");
194
	}
195
	pfSense_interface_setaddress("lo0", "127.0.0.1");
196
	interfaces_bring_up("lo0");
197
	if (platform_booting()) {
198
		echo gettext("done.") . "\n";
199
	}
200
	return 0;
201
}
202

    
203
function vlan_valid_tag($tag = NULL) {
204

    
205
	if ($tag == NULL || empty($tag) ||
206
	    !is_numericint($tag) || intval($tag) < 1 || intval($tag) > 4094) {
207
		return (false);
208
	}
209
	return (true);
210
}
211

    
212
function qinq_inuse($qinq = NULL, $inqtag = NULL) {
213
        global $config;
214

    
215
	if ($qinq == NULL || $inqtag == NULL ||
216
	    !is_array($qinq) || !vlan_valid_tag($inqtag)) {
217
		return (false);
218
	}
219

    
220
        $iflist = get_configured_interface_list(true);
221
        foreach ($iflist as $if) {
222
                if ($config['interfaces'][$if]['if'] == qinq_interface($qinq, $inqtag)) {
223
                        return (true);
224
                }
225
        }
226

    
227
        return (false);
228
}
229

    
230
function qinq_interface($qinq = NULL, $inqtag = NULL) {
231

    
232
	if ($qinq == NULL || $inqtag == NULL || !is_array($qinq) ||
233
	    !isset($qinq['if']) || !isset($qinq['tag']) ||
234
	    !vlan_valid_tag($qinq['tag']) || !vlan_valid_tag($inqtag)) {
235
		return (NULL);
236
	}
237
	return ("{$qinq['if']}.{$qinq['tag']}.{$inqtag}");
238
}
239

    
240
function interface_is_qinq($if = NULL) {
241
	global $config;
242

    
243
	if ($if == NULL || empty($if) || !is_array($config['qinqs']['qinqentry'])) {
244
		return (NULL);
245
	}
246

    
247
	/* Check basic format. */
248
	list($qinqif, $vlantag, $inqtag) = explode(".", $if);
249
	if (empty($qinqif) || empty($vlantag) || empty($inqtag) ||
250
	    !vlan_valid_tag($vlantag) || !vlan_valid_tag($inqtag)) {
251
		return (NULL);
252
	}
253

    
254
	foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
255
		if ("{$qinqif}.{$vlantag}" != $qinq['vlanif']) {
256
			continue;
257
		}
258
		if (empty($qinq['members'])) {
259
			continue;
260
		}
261
		foreach (explode(" ", $qinq['members']) as $tag) {
262
			if ($if == qinq_interface($qinq, $tag)) {
263
				return ($qinq);
264
			}
265
		}
266
	}
267

    
268
	return (NULL);
269
}
270

    
271
function interface_is_lagg($if = NULL) {
272
	global $config;
273

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

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

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

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

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

    
300
	return (false);
301
}
302

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

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

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

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

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

    
334
	return (NULL);
335
}
336

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

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

    
350
	$current_mac = get_interface_mac($interface);
351

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

    
364
function interfaces_vlan_configure($realif = "") {
365
	global $config, $g;
366
	if (platform_booting()) {
367
		echo gettext("Configuring VLAN interfaces...");
368
	}
369
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
370
		foreach ($config['vlans']['vlan'] as $vlan) {
371
			if (empty($vlan['vlanif'])) {
372
				$vlan['vlanif'] = vlan_interface($vlan);
373
			}
374
			if (!empty($realif) && $realif != $vlan['vlanif']) {
375
				continue;
376
			}
377

    
378
			/* XXX: Maybe we should report any errors?! */
379
			interface_vlan_configure($vlan);
380
		}
381
	}
382
	if (platform_booting()) {
383
		echo gettext("done.") . "\n";
384
	}
385
}
386

    
387
function interface_vlan_configure(&$vlan) {
388
	global $config, $g;
389

    
390
	if (!is_array($vlan)) {
391
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
392
		return(NULL);
393
	}
394
	$if = $vlan['if'];
395
	if (empty($if)) {
396
		log_error(gettext("interface_vlan_configure called with if undefined."));
397
		return(NULL);
398
	}
399

    
400
	$vlanif = empty($vlan['vlanif']) ? vlan_interface($vlan) : $vlan['vlanif'];
401
	if ($vlanif == NULL) {
402
		log_error(gettext("vlan_interface called with if undefined var."));
403
		return(NULL);
404
	}
405
	$tag = $vlan['tag'];
406
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
407

    
408
	/* make sure the parent interface is up */
409
	interfaces_bring_up($if);
410
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
411
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
412

    
413
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
414
		pfSense_interface_destroy($vlanif);
415
	}
416

    
417
	$tmpvlanif = pfSense_interface_create("vlan");
418
	pfSense_interface_rename($tmpvlanif, $vlanif);
419
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
420

    
421
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
422

    
423
	interfaces_bring_up($vlanif);
424

    
425
	/* invalidate interface cache */
426
	get_interface_arr(true);
427

    
428
	/* configure interface if assigned */
429
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
430
	if ($assignedif) {
431
		if (isset($config['interfaces'][$assignedif]['enable'])) {
432
			interface_configure($assignedif, true);
433
		}
434
	}
435

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

    
439
	return $vlanif;
440
}
441

    
442
function interface_qinq_configure(&$qinq, $fd = NULL) {
443
	global $config, $g;
444

    
445
	if (!is_array($qinq)) {
446
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
447
		return;
448
	}
449

    
450
	$qinqif = $qinq['if'];
451
	$tag = $qinq['tag'];
452
	if (empty($qinqif)) {
453
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
454
		return;
455
	}
456

    
457
	if (!does_interface_exist($qinqif)) {
458
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
459
		return;
460
	}
461

    
462
	$vlanif = interface_vlan_configure($qinq);
463
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
464
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
465
		return;
466
	}
467

    
468
	if ($fd == NULL) {
469
		$exec = true;
470
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
471
	} else {
472
		$exec = false;
473
	}
474
	/* make sure the parent is converted to ng_vlan(4) and is up */
475
	interfaces_bring_up($qinqif);
476

    
477
	pfSense_ngctl_attach(".", $qinqif);
478
	$ngif = str_replace(".", "_", $vlanif);
479
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
480
		exec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1");
481
		exec("/usr/sbin/ngctl msg {$ngif}qinq: gettable > /dev/null 2>&1", $result);
482
		if (empty($result)) {
483
			fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
484
			fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
485
			fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
486
		}
487
	} else {
488
		fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
489
		fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
490
		fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
491
	}
492

    
493
	/* invalidate interface cache */
494
	get_interface_arr(true);
495

    
496
	if (interface_is_vlan($qinqif) == NULL) {
497
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
498
	}
499

    
500
	$macaddr = get_interface_mac($qinqif);
501
	if (!empty($qinq['members'])) {
502
		$qinqcmdbuf = "";
503
		$members = explode(" ", $qinq['members']);
504
		foreach ($members as $qtag) {
505
			$qinq2 = array();
506
			$qinq2['tag'] = $qtag;
507
			$qinq2['if'] = $vlanif;
508
			interface_qinq2_configure($qinq2, $qinqcmdbuf, $macaddr);
509
			unset($qinq2);
510
		}
511
		if (strlen($qinqcmdbuf) > 0) {
512
			fwrite($fd, $qinqcmdbuf);
513
		}
514
	}
515
	if ($exec == true) {
516
		fclose($fd);
517
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd > /dev/null 2>&1");
518
	}
519

    
520
	interfaces_bring_up($qinqif);
521
	if (!empty($qinq['members'])) {
522
		$members = explode(" ", $qinq['members']);
523
		foreach ($members as $qtag) {
524
			interfaces_bring_up(qinq_interface($qinq, $qtag));
525
		}
526
	}
527

    
528
	return $vlanif;
529
}
530

    
531
function interfaces_qinq_configure() {
532
	global $config, $g;
533
	if (platform_booting()) {
534
		echo gettext("Configuring QinQ interfaces...");
535
	}
536
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
537
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
538
			/* XXX: Maybe we should report any errors?! */
539
			interface_qinq_configure($qinq);
540
		}
541
	}
542
	if (platform_booting()) {
543
		echo gettext("done.") . "\n";
544
	}
545
}
546

    
547
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr) {
548
	global $config, $g;
549

    
550
	if (!is_array($qinq)) {
551
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
552
		return;
553
	}
554

    
555
	$if = $qinq['if'];
556
	if (empty($if)) {
557
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
558
		return;
559
	}
560
	$tag = $qinq['tag'];
561
	$vlanif = "{$if}.{$tag}";
562
	$ngif = str_replace(".", "_", $if);
563
	if (strlen($vlanif) > IF_NAMESIZE) {
564
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
565
		    $vlanif, IF_NAMESIZE, "\n"));
566
		return;
567
	}
568

    
569
	exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1");
570
	$cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n";
571
	$cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n";
572
	$cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n";
573
	$cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n";
574
	$cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n";
575

    
576
	/* invalidate interface cache */
577
	get_interface_arr(true);
578

    
579
	return $vlanif;
580
}
581

    
582
function interfaces_create_wireless_clones() {
583
	global $config, $g;
584

    
585
	if (platform_booting()) {
586
		echo gettext("Creating wireless clone interfaces...");
587
	}
588

    
589
	$iflist = get_configured_interface_list();
590

    
591
	foreach ($iflist as $if) {
592
		$realif = $config['interfaces'][$if]['if'];
593
		if (is_interface_wireless($realif)) {
594
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
595
		}
596
	}
597

    
598
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
599
		foreach ($config['wireless']['clone'] as $clone) {
600
			if (empty($clone['cloneif'])) {
601
				continue;
602
			}
603
			if (does_interface_exist($clone['cloneif'])) {
604
				continue;
605
			}
606
			/* XXX: Maybe we should report any errors?! */
607
			interface_wireless_clone($clone['cloneif'], $clone);
608
		}
609
	}
610
	if (platform_booting()) {
611
		echo gettext("done.") . "\n";
612
	}
613

    
614
}
615

    
616
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
617
	global $config;
618

    
619
	$i = 0;
620
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
621
		foreach ($config['bridges']['bridged'] as $bridge) {
622
			if (empty($bridge['bridgeif'])) {
623
				$bridge['bridgeif'] = "bridge{$i}";
624
			}
625
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
626
				continue;
627
			}
628

    
629
			if ($checkmember == 1) {
630
				/* XXX: It should not be possible no? */
631
				if (strstr($bridge['if'], '_vip')) {
632
					continue;
633
				}
634
				$members = explode(',', $bridge['members']);
635
				foreach ($members as $member) {
636
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6") {
637
						continue 2;
638
					}
639
				}
640
			}
641
			else if ($checkmember == 2) {
642
				$members = explode(',', $bridge['members']);
643
				foreach ($members as $member) {
644
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6") {
645
						continue 2;
646
					}
647
				}
648
			}
649
			/* XXX: Maybe we should report any errors?! */
650
			interface_bridge_configure($bridge, $checkmember);
651
			$i++;
652
		}
653
	}
654
}
655

    
656
function interface_bridge_configure(&$bridge, $checkmember = 0) {
657
	global $config, $g;
658

    
659
	if (!is_array($bridge)) {
660
		return;
661
	}
662

    
663
	if (empty($bridge['members'])) {
664
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
665
		return;
666
	}
667

    
668
	$members = explode(',', $bridge['members']);
669
	if (!count($members)) {
670
		return;
671
	}
672

    
673
	/* Calculate smaller mtu and enforce it */
674
	$smallermtu = 0;
675
	$foundgif = false;
676
	foreach ($members as $member) {
677
		$realif = get_real_interface($member);
678
		$mtu = get_interface_mtu($realif);
679
		if (substr($realif, 0, 3) == "gif") {
680
			$foundgif = true;
681
			if ($checkmember == 1) {
682
				return;
683
			}
684
			if ($mtu <= 1500) {
685
				continue;
686
			}
687
		}
688
		if ($smallermtu == 0 && !empty($mtu)) {
689
			$smallermtu = $mtu;
690
		} else if (!empty($mtu) && $mtu < $smallermtu) {
691
			$smallermtu = $mtu;
692
		}
693
	}
694
	if ($foundgif == false && $checkmember == 2) {
695
		return;
696
	}
697

    
698
	/* Just in case anything is not working well */
699
	if ($smallermtu == 0) {
700
		$smallermtu = 1500;
701
	}
702

    
703
	if (!empty($bridge['bridgeif'])) {
704
		pfSense_interface_destroy($bridge['bridgeif']);
705
		pfSense_interface_create($bridge['bridgeif']);
706
		$bridgeif = escapeshellarg($bridge['bridgeif']);
707
	} else {
708
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
709
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
710
		$bridgeif = pfSense_interface_create("bridge");
711
		$bridge['bridgeif'] = $bridgeif;
712
	}
713

    
714
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
715
	if ($bridgemtu > $smallermtu) {
716
		$smallermtu = $bridgemtu;
717
	}
718

    
719
	$checklist = get_configured_interface_list();
720

    
721
	/* Add interfaces to bridge */
722
	foreach ($members as $member) {
723
		if (empty($checklist[$member])) {
724
			continue;
725
		}
726
		$realif = get_real_interface($member);
727
		if (!$realif) {
728
			log_error(gettext("realif not defined in interfaces bridge - up"));
729
			continue;
730
		}
731
		/* make sure the parent interface is up */
732
		pfSense_interface_mtu($realif, $smallermtu);
733
		interfaces_bring_up($realif);
734
		enable_hardware_offloading($member);
735
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
736
	}
737

    
738
	if (isset($bridge['enablestp'])) {
739
		interface_bridge_configure_stp($bridge);
740
	}
741

    
742
	interface_bridge_configure_advanced($bridge);
743

    
744
	interface_bridge_configure_ip6linklocal($bridge);
745

    
746
	if ($bridge['bridgeif']) {
747
		interfaces_bring_up($bridge['bridgeif']);
748
	} else {
749
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
750
	}
751
}
752

    
753
function interface_bridge_configure_stp($bridge) {
754
	if (isset($bridge['enablestp'])) {
755
		$bridgeif = trim($bridge['bridgeif']);
756
		/* configure spanning tree proto */
757
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
758

    
759
		if (!empty($bridge['stp'])) {
760
			$stpifs = explode(',', $bridge['stp']);
761
			foreach ($stpifs as $stpif) {
762
				$realif = get_real_interface($stpif);
763
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
764
			}
765
		}
766
		if (!empty($bridge['maxage'])) {
767
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
768
		}
769
		if (!empty($bridge['fwdelay'])) {
770
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
771
		}
772
		if (!empty($bridge['hellotime'])) {
773
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
774
		}
775
		if (!empty($bridge['priority'])) {
776
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
777
		}
778
		if (!empty($bridge['holdcnt'])) {
779
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
780
		}
781
		if (!empty($bridge['ifpriority'])) {
782
			$pconfig = explode(",", $bridge['ifpriority']);
783
			$ifpriority = array();
784
			foreach ($pconfig as $cfg) {
785
				$embcfg = explode_assoc(":", $cfg);
786
				foreach ($embcfg as $key => $value) {
787
					$ifpriority[$key] = $value;
788
				}
789
			}
790
			foreach ($ifpriority as $key => $value) {
791
				$realif = get_real_interface($key);
792
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
793
			}
794
		}
795
		if (!empty($bridge['ifpathcost'])) {
796
			$pconfig = explode(",", $bridge['ifpathcost']);
797
			$ifpathcost = array();
798
			foreach ($pconfig as $cfg) {
799
				$embcfg = explode_assoc(":", $cfg);
800
				foreach ($embcfg as $key => $value) {
801
					$ifpathcost[$key] = $value;
802
				}
803
			}
804
			foreach ($ifpathcost as $key => $value) {
805
				$realif = get_real_interface($key);
806
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
807
			}
808
		}
809
	}
810
}
811

    
812
function interface_bridge_configure_advanced($bridge) {
813
	$bridgeif = trim($bridge['bridgeif']);
814

    
815
	if ($bridge['maxaddr'] <> "") {
816
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
817
	}
818
	if ($bridge['timeout'] <> "") {
819
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
820
	}
821
	if (!empty($bridge['span'])) {
822
		$spanifs = explode(",", $bridge['span']);
823
		foreach ($spanifs as $spanif) {
824
			$realif = get_real_interface($spanif);
825
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
826
		}
827
	}
828
	if (!empty($bridge['edge'])) {
829
		$edgeifs = explode(',', $bridge['edge']);
830
		foreach ($edgeifs as $edgeif) {
831
			$realif = get_real_interface($edgeif);
832
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
833
		}
834
	}
835
	if (!empty($bridge['autoedge'])) {
836
		$edgeifs = explode(',', $bridge['autoedge']);
837
		foreach ($edgeifs as $edgeif) {
838
			$realif = get_real_interface($edgeif);
839
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
840
		}
841
	}
842
	if (!empty($bridge['ptp'])) {
843
		$ptpifs = explode(',', $bridge['ptp']);
844
		foreach ($ptpifs as $ptpif) {
845
			$realif = get_real_interface($ptpif);
846
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
847
		}
848
	}
849
	if (!empty($bridge['autoptp'])) {
850
		$ptpifs = explode(',', $bridge['autoptp']);
851
		foreach ($ptpifs as $ptpif) {
852
			$realif = get_real_interface($ptpif);
853
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
854
		}
855
	}
856
	if (!empty($bridge['static'])) {
857
		$stickyifs = explode(',', $bridge['static']);
858
		foreach ($stickyifs as $stickyif) {
859
			$realif = get_real_interface($stickyif);
860
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
861
		}
862
	}
863
	if (!empty($bridge['private'])) {
864
		$privateifs = explode(',', $bridge['private']);
865
		foreach ($privateifs as $privateif) {
866
			$realif = get_real_interface($privateif);
867
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
868
		}
869
	}
870
}
871

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

    
875
	$members = explode(',', $bridge['members']);
876
	if (!count($members)) {
877
		return;
878
	}
879

    
880
	$auto_linklocal = isset($bridge['ip6linklocal']);
881
	$bridgeop = $auto_linklocal ? '' : '-';
882
	$memberop = $auto_linklocal ? '-' : '';
883

    
884
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
885
	foreach ($members as $member) {
886
		$realif = get_real_interface($member);
887
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
888
	}
889
}
890

    
891
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
892
	global $config;
893

    
894
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
895
		return;
896
	}
897

    
898
	if ($flagsapplied == false) {
899
		$mtu = get_interface_mtu($bridgeif);
900
		$mtum = get_interface_mtu($interface);
901
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
902
			pfSense_interface_mtu($interface, $mtu);
903
		}
904

    
905
		hardware_offloading_applyflags($interface);
906
		interfaces_bring_up($interface);
907
	}
908

    
909
	pfSense_bridge_add_member($bridgeif, $interface);
910
	if (is_array($config['bridges']['bridged'])) {
911
		foreach ($config['bridges']['bridged'] as $bridge) {
912
			if ($bridgeif == $bridge['bridgeif']) {
913
				interface_bridge_configure_stp($bridge);
914
				interface_bridge_configure_advanced($bridge);
915
			}
916
		}
917
	}
918
}
919

    
920
function interfaces_lagg_configure($realif = "") {
921
	global $config, $g;
922
	if (platform_booting()) {
923
		echo gettext("Configuring LAGG interfaces...");
924
	}
925
	$i = 0;
926
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
927
		foreach ($config['laggs']['lagg'] as $lagg) {
928
			if (empty($lagg['laggif'])) {
929
				$lagg['laggif'] = "lagg{$i}";
930
			}
931
			if (!empty($realif) && $realif != $lagg['laggif']) {
932
				continue;
933
			}
934
			/* XXX: Maybe we should report any errors?! */
935
			interface_lagg_configure($lagg);
936
			$i++;
937
		}
938
	}
939
	if (platform_booting()) {
940
		echo gettext("done.") . "\n";
941
	}
942
}
943

    
944
function interface_lagg_configure($lagg) {
945
	global $config, $g;
946

    
947
	if (!is_array($lagg)) {
948
		return -1;
949
	}
950

    
951
	$members = explode(',', $lagg['members']);
952
	if (!count($members)) {
953
		return -1;
954
	}
955

    
956
	if (platform_booting() || !(empty($lagg['laggif']))) {
957
		pfSense_interface_destroy($lagg['laggif']);
958
		pfSense_interface_create($lagg['laggif']);
959
		$laggif = $lagg['laggif'];
960
	} else {
961
		$laggif = pfSense_interface_create("lagg");
962
	}
963

    
964
	/* Check if MTU was defined for this lagg interface */
965
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
966
	if ($lagg_mtu == 0 &&
967
	    is_array($config['interfaces'])) {
968
		foreach ($config['interfaces'] as $tmpinterface) {
969
			if ($tmpinterface['if'] == $lagg['laggif'] &&
970
			    !empty($tmpinterface['mtu'])) {
971
				$lagg_mtu = $tmpinterface['mtu'];
972
				break;
973
			}
974
		}
975
	}
976

    
977
	/* Just in case anything is not working well */
978
	if ($lagg_mtu == 0) {
979
		$lagg_mtu = 1500;
980
	}
981

    
982
	foreach ($members as $member) {
983
		if (!does_interface_exist($member)) {
984
			continue;
985
		}
986

    
987
		/* make sure the parent interface is up */
988
		pfSense_interface_mtu($member, $lagg_mtu);
989
		interfaces_bring_up($member);
990
		hardware_offloading_applyflags($member);
991

    
992
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
993
		$laggif = str_replace("\0", "", $laggif);
994
		$member = str_replace("\0", "", $member);
995
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
996
	}
997

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

    
1000
	interfaces_bring_up($laggif);
1001

    
1002
	return $laggif;
1003
}
1004

    
1005
function interfaces_gre_configure($checkparent = 0, $realif = "") {
1006
	global $config;
1007

    
1008
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
1009
		foreach ($config['gres']['gre'] as $i => $gre) {
1010
			if (empty($gre['greif'])) {
1011
				$gre['greif'] = "gre{$i}";
1012
			}
1013
			if (!empty($realif) && $realif != $gre['greif']) {
1014
				continue;
1015
			}
1016

    
1017
			if ($checkparent == 1) {
1018
				if (substr($gre['if'], 0, 4) == '_vip') {
1019
					continue;
1020
				}
1021
				if (substr($gre['if'], 0, 5) == '_lloc') {
1022
					continue;
1023
				}
1024
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6") {
1025
					continue;
1026
				}
1027
			} else if ($checkparent == 2) {
1028
				if ((substr($gre['if'], 0, 4) != '_vip' && substr($gre['if'], 0, 5) != '_lloc') &&
1029
				    (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")) {
1030
					continue;
1031
				}
1032
			}
1033
			/* XXX: Maybe we should report any errors?! */
1034
			interface_gre_configure($gre);
1035
		}
1036
	}
1037
}
1038

    
1039
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
1040
function interface_gre_configure(&$gre, $grekey = "") {
1041
	global $config, $g;
1042

    
1043
	if (!is_array($gre)) {
1044
		return -1;
1045
	}
1046

    
1047
	$realif = get_real_interface($gre['if']);
1048
	$realifip = get_interface_ip($gre['if']);
1049
	$realifip6 = get_interface_ipv6($gre['if']);
1050

    
1051
	/* make sure the parent interface is up */
1052
	interfaces_bring_up($realif);
1053

    
1054
	if (platform_booting() || !(empty($gre['greif']))) {
1055
		pfSense_interface_destroy($gre['greif']);
1056
		pfSense_interface_create($gre['greif']);
1057
		$greif = $gre['greif'];
1058
	} else {
1059
		$greif = pfSense_interface_create("gre");
1060
	}
1061

    
1062
	/* Do not change the order here for more see gre(4) NOTES section. */
1063
	if (is_ipaddrv6($gre['remote-addr'])) {
1064
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1065
	} else {
1066
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1067
	}
1068
	if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
1069
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1070
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
1071
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
1072
	} else {
1073
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1074
	}
1075

    
1076
	if ($greif) {
1077
		interfaces_bring_up($greif);
1078
	} else {
1079
		log_error(gettext("Could not bring greif up -- variable not defined."));
1080
	}
1081

    
1082
	if (isset($gre['link1']) && $gre['link1']) {
1083
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1084
	}
1085
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
1086
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1087
	}
1088
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
1089
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
1090
	}
1091

    
1092
	interfaces_bring_up($greif);
1093

    
1094
	return $greif;
1095
}
1096

    
1097
function interfaces_gif_configure($checkparent = 0, $realif = "") {
1098
	global $config;
1099

    
1100
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
1101
		foreach ($config['gifs']['gif'] as $i => $gif) {
1102
			if (empty($gif['gifif'])) {
1103
				$gre['gifif'] = "gif{$i}";
1104
			}
1105
			if (!empty($realif) && $realif != $gif['gifif']) {
1106
				continue;
1107
			}
1108

    
1109
			if ($checkparent == 1) {
1110
				if (substr($gif['if'], 0, 4) == '_vip') {
1111
					continue;
1112
				}
1113
				if (substr($gif['if'], 0, 5) == '_lloc') {
1114
					continue;
1115
				}
1116
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
1117
					continue;
1118
				}
1119
			}
1120
			else if ($checkparent == 2) {
1121
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
1122
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
1123
					continue;
1124
				}
1125
			}
1126
			/* XXX: Maybe we should report any errors?! */
1127
			interface_gif_configure($gif);
1128
		}
1129
	}
1130
}
1131

    
1132
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1133
function interface_gif_configure(&$gif, $gifkey = "") {
1134
	global $config, $g;
1135

    
1136
	if (!is_array($gif)) {
1137
		return -1;
1138
	}
1139

    
1140
	$realif = get_real_interface($gif['if']);
1141
	$ipaddr = get_interface_ip($gif['if']);
1142

    
1143
	if (is_ipaddrv4($gif['remote-addr'])) {
1144
		if (is_ipaddrv4($ipaddr)) {
1145
			$realifip = $ipaddr;
1146
		} else {
1147
			$realifip = get_interface_ip($gif['if']);
1148
		}
1149
		$realifgw = get_interface_gateway($gif['if']);
1150
	} else if (is_ipaddrv6($gif['remote-addr'])) {
1151
		if (is_ipaddrv6($ipaddr)) {
1152
			$realifip = $ipaddr;
1153
		} else {
1154
			$realifip = get_interface_ipv6($gif['if']);
1155
		}
1156
		$realifgw = get_interface_gateway_v6($gif['if']);
1157
	}
1158
	/* make sure the parent interface is up */
1159
	if ($realif) {
1160
		interfaces_bring_up($realif);
1161
	} else {
1162
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
1163
	}
1164

    
1165
	if (platform_booting() || !(empty($gif['gifif']))) {
1166
		pfSense_interface_destroy($gif['gifif']);
1167
		pfSense_interface_create($gif['gifif']);
1168
		$gifif = $gif['gifif'];
1169
	} else {
1170
		$gifif = pfSense_interface_create("gif");
1171
	}
1172

    
1173
	/* Do not change the order here for more see gif(4) NOTES section. */
1174
	if (is_ipaddrv6($gif['remote-addr'])) {
1175
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1176
	} else {
1177
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1178
	}
1179
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1180
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1181
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1182
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1183
	} else {
1184
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1185
	}
1186
	if (isset($gif['link1'])) {
1187
		pfSense_interface_flags($gifif, IFF_LINK1);
1188
	}
1189
	if (isset($gif['link2'])) {
1190
		pfSense_interface_flags($gifif, IFF_LINK2);
1191
	}
1192
	if ($gifif) {
1193
		interfaces_bring_up($gifif);
1194
		$gifmtu = "";
1195
		$currentgifmtu = get_interface_mtu($gifif);
1196
		foreach ($config['interfaces'] as $tmpinterface) {
1197
			if ($tmpinterface['if'] == $gifif) {
1198
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1199
					$gifmtu = $tmpinterface['mtu'];
1200
				}
1201
			}
1202
		}
1203
		if (is_numericint($gifmtu)) {
1204
			if ($gifmtu != $currentgifmtu) {
1205
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1206
			}
1207
		}
1208
	} else {
1209
		log_error(gettext("could not bring gifif up -- variable not defined"));
1210
	}
1211

    
1212
	if (!platform_booting()) {
1213
		$iflist = get_configured_interface_list();
1214
		foreach ($iflist as $ifname) {
1215
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1216
				if (get_interface_gateway($ifname)) {
1217
					system_routing_configure($ifname);
1218
					break;
1219
				}
1220
				if (get_interface_gateway_v6($ifname)) {
1221
					system_routing_configure($ifname);
1222
					break;
1223
				}
1224
			}
1225
		}
1226
	}
1227

    
1228

    
1229
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1230
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1231
	}
1232
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1233
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1234
	}
1235

    
1236
	if (is_ipaddrv4($realifgw)) {
1237
		route_add_or_change("-host {$gif['remote-addr']} {$realifgw}");
1238
	}
1239
	if (is_ipaddrv6($realifgw)) {
1240
		route_add_or_change("-host -inet6 {$gif['remote-addr']} {$realifgw}");
1241
	}
1242

    
1243
	interfaces_bring_up($gifif);
1244

    
1245
	return $gifif;
1246
}
1247

    
1248
/* Build a list of IPsec interfaces */
1249
function interface_ipsec_vti_list_p1($ph1ent) {
1250
	global $config;
1251
	$iface_list = array();
1252

    
1253
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1254
		return $iface_list;
1255
	}
1256

    
1257
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1258
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1259
		return $iface_list;
1260
	}
1261

    
1262
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1263
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1264
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1265
			$iface_list["ipsec{$ph1ent['ikeid']}00{$idx}"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1266
		}
1267
	} else {
1268
		/* For IKEv2, only create one interface with additional addresses as aliases */
1269
		$iface_list["ipsec{$ph1ent['ikeid']}000"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1270
	}
1271
	return $iface_list;
1272
}
1273
function interface_ipsec_vti_list_all() {
1274
	global $config;
1275
	$iface_list = array();
1276
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1277
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1278
			if ($ph1ent['disabled']) {
1279
				continue;
1280
			}
1281
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1282
		}
1283
	}
1284
	return $iface_list;
1285
}
1286

    
1287
function is_interface_ipsec_vti_assigned($phase2) {
1288
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1289
	$vti_interface = null;
1290
	$vtisubnet_spec = ipsec_vti($phase1, true);
1291
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1292
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1293
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1294
			foreach ($vtisubnet_spec as $idx => $vtisub) {
1295
				/* Is this for this P2? */
1296
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1297
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1298
					$vti_interface = "ipsec{$phase1['ikeid']}00{$idx}";
1299
				}
1300
			}
1301
		} else {
1302
			$vti_interface = "ipsec{$phase1['ikeid']}000";
1303
		}
1304
	}
1305
	/* Check if this interface is assigned */
1306
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1307
}
1308
function interface_ipsec_vti_configure($ph1ent) {
1309
	global $config;
1310

    
1311
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1312
		return false;
1313
	}
1314

    
1315
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1316
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1317
		return false;
1318
	}
1319

    
1320
	$left_spec = ipsec_get_phase1_src($ph1ent);
1321
	$right_spec = $ph1ent['remote-gateway'];
1322

    
1323
	$iface_addrs = array();
1324

    
1325
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1326
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1327
		/* Form a single interface for each P2 entry */
1328
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1329
			$ipsecifnum = "{$ph1ent['ikeid']}00{$idx}";
1330
			if (!is_array($iface_addrs[$ipsecifnum])) {
1331
				$iface_addrs[$ipsecifnum] = array();
1332
			}
1333
			$vtisub['alias'] = "";
1334
			$iface_addrs[$ipsecifnum][] = $vtisub;
1335
		}
1336
	} else {
1337
		/* For IKEv2, only create one interface with additional addresses as aliases */
1338
		$ipsecifnum = "{$ph1ent['ikeid']}000";
1339
		if (!is_array($iface_addrs[$ipsecifnum])) {
1340
			$iface_addrs[$ipsecifnum] = array();
1341
		}
1342
		$have_v4 = false;
1343
		$have_v6 = false;
1344
		foreach ($vtisubnet_spec as $vtisub) {
1345
			// Alias stuff
1346
			$vtisub['alias'] = "";
1347
			if (is_ipaddrv6($vtisub['left'])) {
1348
				if ($have_v6) {
1349
					$vtisub['alias'] = " alias";
1350
				}
1351
				$have_v6 = true;
1352
			} else {
1353
				if ($have_v4) {
1354
					$vtisub['alias'] = " alias";
1355
				}
1356
				$have_v4 = true;
1357
			}
1358
			$iface_addrs[$ipsecifnum][] = $vtisub;
1359
		}
1360
	}
1361

    
1362
	foreach ($iface_addrs as $ipsecifnum => $addrs) {
1363
		$ipsecif = "ipsec{$ipsecifnum}";
1364
		if (!is_array($addrs)) {
1365
			continue;
1366
		}
1367
		// Create IPsec interface
1368
		if (platform_booting() || !does_interface_exist($ipsecif)) {
1369
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy", false);
1370
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1371
		} else {
1372
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1373
		}
1374

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

    
1379
		/* Loop through all of the addresses for this interface and apply them as needed */
1380
		foreach ($addrs as $addr) {
1381
			// apply interface addresses
1382
			if (is_ipaddrv6($addr['left'])) {
1383
				$inet = "inet6";
1384
				$gwtype = "v6";
1385
			} else {
1386
				$inet = "inet";
1387
				$gwtype = "";
1388
			}
1389

    
1390
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . escapeshellarg($addr['right']) . $addr['alias'], false);
1391
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1392
			if (empty($addr['alias'])) {
1393
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1394
			}
1395
		}
1396
		if (!platform_booting()) {
1397
			system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1398
		}
1399
	}
1400
}
1401

    
1402
function interfaces_ipsec_vti_configure() {
1403
	global $config;
1404
	if (platform_booting()) {
1405
		echo gettext("Configuring IPsec VTI interfaces...");
1406
	}
1407
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1408
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1409
			if ($ph1ent['disabled']) {
1410
				continue;
1411
			}
1412
			interface_ipsec_vti_configure($ph1ent);
1413
		}
1414
	}
1415
	if (platform_booting()) {
1416
		echo gettext("done.") . "\n";
1417
	}
1418
}
1419

    
1420
function interfaces_configure() {
1421
	global $config, $g;
1422

    
1423
	/* Set up our loopback interface */
1424
	interfaces_loopback_configure();
1425

    
1426
	/* create the unconfigured wireless clones */
1427
	interfaces_create_wireless_clones();
1428

    
1429
	/* set up LAGG virtual interfaces */
1430
	interfaces_lagg_configure();
1431

    
1432
	/* set up VLAN virtual interfaces */
1433
	interfaces_vlan_configure();
1434

    
1435
	interfaces_qinq_configure();
1436

    
1437
	/* set up IPsec VTI interfaces */
1438
	interfaces_ipsec_vti_configure();
1439

    
1440
	$iflist = get_configured_interface_with_descr();
1441
	$delayed_list = array();
1442
	$bridge_list = array();
1443
	$track6_list = array();
1444

    
1445
	/* This is needed to speedup interfaces on bootup. */
1446
	$reload = false;
1447
	if (!platform_booting()) {
1448
		$reload = true;
1449
	}
1450

    
1451
	foreach ($iflist as $if => $ifname) {
1452
		$realif = $config['interfaces'][$if]['if'];
1453
		if (strstr($realif, "bridge")) {
1454
			$bridge_list[$if] = $ifname;
1455
		} else if (strstr($realif, "gre")) {
1456
			$delayed_list[$if] = $ifname;
1457
		} else if (strstr($realif, "gif")) {
1458
			$delayed_list[$if] = $ifname;
1459
		} else if (strstr($realif, "ovpn")) {
1460
			//echo "Delaying OpenVPN interface configuration...done.\n";
1461
			continue;
1462
		} else if (strstr($realif, "ipsec")) {
1463
			continue;
1464
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1465
			$track6_list[$if] = $ifname;
1466
		} else {
1467
			if (platform_booting()) {
1468
				printf(gettext("Configuring %s interface..."), $ifname);
1469
			}
1470

    
1471
			if ($g['debug']) {
1472
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1473
			}
1474
			interface_configure($if, $reload);
1475
			if (platform_booting()) {
1476
				echo gettext("done.") . "\n";
1477
			}
1478
		}
1479
	}
1480

    
1481
	/*
1482
	 * NOTE: The following function parameter consists of
1483
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1484
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1485
	 */
1486

    
1487
	/* set up GRE virtual interfaces */
1488
	interfaces_gre_configure(1);
1489

    
1490
	/* set up GIF virtual interfaces */
1491
	interfaces_gif_configure(1);
1492

    
1493
	/* set up BRIDGe virtual interfaces */
1494
	interfaces_bridge_configure(1);
1495

    
1496
	foreach ($track6_list as $if => $ifname) {
1497
		if (platform_booting()) {
1498
			printf(gettext("Configuring %s interface..."), $ifname);
1499
		}
1500
		if ($g['debug']) {
1501
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1502
		}
1503

    
1504
		interface_configure($if, $reload);
1505

    
1506
		if (platform_booting()) {
1507
			echo gettext("done.") . "\n";
1508
		}
1509
	}
1510

    
1511
	/* bring up vip interfaces */
1512
	interfaces_vips_configure();
1513

    
1514
	/* set up GRE virtual interfaces */
1515
	interfaces_gre_configure(2);
1516

    
1517
	/* set up GIF virtual interfaces */
1518
	interfaces_gif_configure(2);
1519

    
1520
	foreach ($delayed_list as $if => $ifname) {
1521
		if (platform_booting()) {
1522
			printf(gettext("Configuring %s interface..."), $ifname);
1523
		}
1524
		if ($g['debug']) {
1525
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1526
		}
1527

    
1528
		interface_configure($if, $reload);
1529

    
1530
		if (platform_booting()) {
1531
			echo gettext("done.") . "\n";
1532
		}
1533
	}
1534

    
1535
	/* set up BRIDGe virtual interfaces */
1536
	interfaces_bridge_configure(2);
1537

    
1538
	foreach ($bridge_list as $if => $ifname) {
1539
		if (platform_booting()) {
1540
			printf(gettext("Configuring %s interface..."), $ifname);
1541
		}
1542
		if ($g['debug']) {
1543
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1544
		}
1545

    
1546
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1547
		// redmine #3997
1548
		interface_reconfigure($if, $reload);
1549
		interfaces_vips_configure($if);
1550

    
1551
		if (platform_booting()) {
1552
			echo gettext("done.") . "\n";
1553
		}
1554
	}
1555

    
1556
	/* configure interface groups */
1557
	interfaces_group_setup();
1558

    
1559
	if (!platform_booting()) {
1560
		/* reconfigure static routes (kernel may have deleted them) */
1561
		system_routing_configure();
1562

    
1563
		/* reload IPsec tunnels */
1564
		vpn_ipsec_configure();
1565

    
1566
		/* restart dns servers (defering dhcpd reload) */
1567
		if (isset($config['dnsmasq']['enable'])) {
1568
			services_dnsmasq_configure(false);
1569
		}
1570
		if (isset($config['unbound']['enable'])) {
1571
			services_unbound_configure(false);
1572
		}
1573

    
1574
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1575
		services_dhcpd_configure();
1576
	}
1577

    
1578
	return 0;
1579
}
1580

    
1581
function interface_reconfigure($interface = "wan", $reloadall = false) {
1582
	interface_bring_down($interface);
1583
	interface_configure($interface, $reloadall);
1584
}
1585

    
1586
function interface_vip_bring_down($vip) {
1587
	global $g;
1588

    
1589
	$vipif = get_real_interface($vip['interface']);
1590
	switch ($vip['mode']) {
1591
		case "proxyarp":
1592
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1593
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1594
			}
1595
			break;
1596
		case "ipalias":
1597
			if (does_interface_exist($vipif)) {
1598
				if (is_ipaddrv6($vip['subnet'])) {
1599
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1600
				} else {
1601
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1602
				}
1603
			}
1604
			break;
1605
		case "carp":
1606
			/* XXX: Is enough to delete ip address? */
1607
			if (does_interface_exist($vipif)) {
1608
				if (is_ipaddrv6($vip['subnet'])) {
1609
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1610
				} else {
1611
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1612
				}
1613
			}
1614
			break;
1615
	}
1616
}
1617

    
1618
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1619
	global $config, $g;
1620

    
1621
	if (!isset($config['interfaces'][$interface])) {
1622
		return;
1623
	}
1624

    
1625
	if ($g['debug']) {
1626
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1627
	}
1628

    
1629
	/*
1630
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1631
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1632
	 * Keep this in mind while doing changes here!
1633
	 */
1634
	if ($ifacecfg === false) {
1635
		$ifcfg = $config['interfaces'][$interface];
1636
		$ppps = $config['ppps']['ppp'];
1637
		$realif = get_real_interface($interface);
1638
		$realifv6 = get_real_interface($interface, "inet6", true);
1639
	} elseif (!is_array($ifacecfg)) {
1640
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1641
		$ifcfg = $config['interfaces'][$interface];
1642
		$ppps = $config['ppps']['ppp'];
1643
		$realif = get_real_interface($interface);
1644
		$realifv6 = get_real_interface($interface, "inet6", true);
1645
	} else {
1646
		$ifcfg = $ifacecfg['ifcfg'];
1647
		$ppps = $ifacecfg['ppps'];
1648
		if (isset($ifacecfg['ifcfg']['realif'])) {
1649
			$realif = $ifacecfg['ifcfg']['realif'];
1650
			/* XXX: Any better way? */
1651
			$realifv6 = $realif;
1652
		} else {
1653
			$realif = get_real_interface($interface);
1654
			$realifv6 = get_real_interface($interface, "inet6", true);
1655
		}
1656
	}
1657

    
1658
	switch ($ifcfg['ipaddr']) {
1659
		case "ppp":
1660
		case "pppoe":
1661
		case "pptp":
1662
		case "l2tp":
1663
			if (is_array($ppps) && count($ppps)) {
1664
				foreach ($ppps as $pppid => $ppp) {
1665
					if ($realif == $ppp['if']) {
1666
						if (isset($ppp['ondemand']) && !$destroy) {
1667
							send_event("interface reconfigure {$interface}");
1668
							break;
1669
						}
1670
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1671
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1672
							sleep(2);
1673
						}
1674
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1675
						break;
1676
					}
1677
				}
1678
			}
1679
			break;
1680
		case "dhcp":
1681
			kill_dhclient_process($realif);
1682
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1683
			if (does_interface_exist("$realif")) {
1684
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1685
				interface_vip_cleanup($interface, "inet4");
1686
				if ($destroy == true) {
1687
					pfSense_interface_flags($realif, -IFF_UP);
1688
				}
1689
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1690
			}
1691
			break;
1692
		default:
1693
			if (does_interface_exist("$realif")) {
1694
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1695
				interface_vip_cleanup($interface, "inet4");
1696
				if ($destroy == true) {
1697
					pfSense_interface_flags($realif, -IFF_UP);
1698
				}
1699
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1700
			}
1701
			break;
1702
	}
1703

    
1704
	$track6 = array();
1705
	switch ($ifcfg['ipaddrv6']) {
1706
		case "slaac":
1707
		case "dhcp6":
1708
			kill_dhcp6client_process($realif, $destroy, false);
1709
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1710
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1711
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1712
			if (does_interface_exist($realifv6)) {
1713
				$ip6 = find_interface_ipv6($realifv6);
1714
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1715
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1716
				}
1717
				interface_vip_cleanup($interface, "inet6");
1718
				if ($destroy == true) {
1719
					pfSense_interface_flags($realif, -IFF_UP);
1720
				}
1721
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1722
			}
1723
			$track6 = link_interface_to_track6($interface);
1724
			break;
1725
		case "6rd":
1726
		case "6to4":
1727
			$realif = "{$interface}_stf";
1728
			if (does_interface_exist("$realif")) {
1729
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1730
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1731
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1732
					$destroy = true;
1733
				} else {
1734
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1735
					$ip6 = get_interface_ipv6($interface);
1736
					if (is_ipaddrv6($ip6)) {
1737
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1738
					}
1739
				}
1740
				interface_vip_cleanup($interface, "inet6");
1741
				if ($destroy == true) {
1742
					pfSense_interface_flags($realif, -IFF_UP);
1743
				}
1744
			}
1745
			$track6 = link_interface_to_track6($interface);
1746
			break;
1747
		default:
1748
			if (does_interface_exist("$realif")) {
1749
				$ip6 = get_interface_ipv6($interface);
1750
				if (is_ipaddrv6($ip6)) {
1751
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1752
				}
1753
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1754
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1755
				}
1756
				interface_vip_cleanup($interface, "inet6");
1757
				if ($destroy == true) {
1758
					pfSense_interface_flags($realif, -IFF_UP);
1759
				}
1760
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1761
			}
1762
			$track6 = link_interface_to_track6($interface);
1763
			break;
1764
	}
1765

    
1766
	if (!empty($track6) && is_array($track6)) {
1767
		if (!function_exists('services_dhcpd_configure')) {
1768
			require_once('services.inc');
1769
		}
1770
		/* Bring down radvd and dhcp6 on these interfaces */
1771
		services_dhcpd_configure('inet6', $track6);
1772
	}
1773

    
1774
	$old_router = '';
1775
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1776
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1777
	}
1778

    
1779
	/* remove interface up file if it exists */
1780
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1781
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1782
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1783
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1784
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1785
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1786
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1787

    
1788
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1789
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1790
	if (is_array($ifcfg['wireless'])) {
1791
		kill_hostapd($realif);
1792
		mwexec(kill_wpasupplicant($realif));
1793
	}
1794

    
1795
	if ($destroy == true) {
1796
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^ipsec|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1797
			pfSense_interface_destroy($realif);
1798
		}
1799
	}
1800

    
1801
	return;
1802
}
1803

    
1804
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1805
	global $config;
1806
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1807
		unset($config["virtualip_carp_maintenancemode"]);
1808
		write_config("Leave CARP maintenance mode");
1809
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1810
		$config["virtualip_carp_maintenancemode"] = true;
1811
		write_config(gettext("Enter CARP maintenance mode"));
1812
	}
1813

    
1814
	$viparr = &$config['virtualip']['vip'];
1815

    
1816
	if (is_array($viparr)) {
1817
		foreach ($viparr as $vip) {
1818
			if ($vip['mode'] == "carp") {
1819
				interface_carp_configure($vip);
1820
			}
1821
		}
1822
	}
1823
}
1824

    
1825
function interface_wait_tentative($interface, $timeout = 10) {
1826
	if (!does_interface_exist($interface)) {
1827
		return false;
1828
	}
1829

    
1830
	$time = 0;
1831
	while ($time <= $timeout) {
1832
		$if = pfSense_get_interface_addresses($interface);
1833
		if (!isset($if['tentative'])) {
1834
			return true;
1835
		}
1836
		sleep(1);
1837
		$time++;
1838
	}
1839

    
1840
	return false;
1841
}
1842

    
1843
function interface_isppp_type($interface) {
1844
	global $config;
1845

    
1846
	if (!is_array($config['interfaces'][$interface])) {
1847
		return false;
1848
	}
1849

    
1850
	switch ($config['interfaces'][$interface]['ipaddr']) {
1851
		case 'pptp':
1852
		case 'l2tp':
1853
		case 'pppoe':
1854
		case 'ppp':
1855
			return true;
1856
			break;
1857
		default:
1858
			return false;
1859
			break;
1860
	}
1861
}
1862

    
1863
function interfaces_ptpid_used($ptpid) {
1864
	global $config;
1865

    
1866
	if (is_array($config['ppps']['ppp'])) {
1867
		foreach ($config['ppps']['ppp'] as & $settings) {
1868
			if ($ptpid == $settings['ptpid']) {
1869
				return true;
1870
			}
1871
		}
1872
	}
1873

    
1874
	return false;
1875
}
1876

    
1877
function interfaces_ptpid_next() {
1878

    
1879
	$ptpid = 0;
1880
	while (interfaces_ptpid_used($ptpid)) {
1881
		$ptpid++;
1882
	}
1883

    
1884
	return $ptpid;
1885
}
1886

    
1887
function getMPDCRONSettings($pppif) {
1888
	global $config;
1889

    
1890
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1891
	if (is_array($config['cron']['item'])) {
1892
		foreach ($config['cron']['item'] as $i => $item) {
1893
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1894
				return array("ID" => $i, "ITEM" => $item);
1895
			}
1896
		}
1897
	}
1898

    
1899
	return NULL;
1900
}
1901

    
1902
function handle_pppoe_reset($post_array) {
1903
	global $config, $g;
1904

    
1905
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1906
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1907

    
1908
	if (!is_array($config['cron']['item'])) {
1909
		$config['cron']['item'] = array();
1910
	}
1911

    
1912
	$itemhash = getMPDCRONSettings($pppif);
1913

    
1914
	// reset cron items if necessary and return
1915
	if (empty($post_array['pppoe-reset-type'])) {
1916
		if (isset($itemhash)) {
1917
			unset($config['cron']['item'][$itemhash['ID']]);
1918
		}
1919
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1920
		return;
1921
	}
1922

    
1923
	if (empty($itemhash)) {
1924
		$itemhash = array();
1925
	}
1926
	$item = array();
1927
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1928
		$item['minute'] = $post_array['pppoe_resetminute'];
1929
		$item['hour'] = $post_array['pppoe_resethour'];
1930
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1931
			$date = explode("/", $post_array['pppoe_resetdate']);
1932
			$item['mday'] = $date[1];
1933
			$item['month'] = $date[0];
1934
		} else {
1935
			$item['mday'] = "*";
1936
			$item['month'] = "*";
1937
		}
1938
		$item['wday'] = "*";
1939
		$item['who'] = "root";
1940
		$item['command'] = $cron_cmd_file;
1941
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1942
		switch ($post_array['pppoe_pr_preset_val']) {
1943
			case "monthly":
1944
				$item['minute'] = "0";
1945
				$item['hour'] = "0";
1946
				$item['mday'] = "1";
1947
				$item['month'] = "*";
1948
				$item['wday'] = "*";
1949
				break;
1950
			case "weekly":
1951
				$item['minute'] = "0";
1952
				$item['hour'] = "0";
1953
				$item['mday'] = "*";
1954
				$item['month'] = "*";
1955
				$item['wday'] = "0";
1956
				break;
1957
			case "daily":
1958
				$item['minute'] = "0";
1959
				$item['hour'] = "0";
1960
				$item['mday'] = "*";
1961
				$item['month'] = "*";
1962
				$item['wday'] = "*";
1963
				break;
1964
			case "hourly":
1965
				$item['minute'] = "0";
1966
				$item['hour'] = "*";
1967
				$item['mday'] = "*";
1968
				$item['month'] = "*";
1969
				$item['wday'] = "*";
1970
				break;
1971
		} // end switch
1972
		$item['who'] = "root";
1973
		$item['command'] = $cron_cmd_file;
1974
	}
1975
	if (empty($item)) {
1976
		return;
1977
	}
1978
	if (isset($itemhash['ID'])) {
1979
		$config['cron']['item'][$itemhash['ID']] = $item;
1980
	} else {
1981
		$config['cron']['item'][] = $item;
1982
	}
1983
}
1984

    
1985
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
1986
	global $config;
1987
	$ppp_list = array();
1988
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1989
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1990
			$ports = explode(",", $ppp['ports']);
1991
			foreach($ports as $port) {
1992
				foreach($triggerinterfaces as $vip) {
1993
					if ($port == "_vip{$vip['uniqid']}") {
1994
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
1995
						$ppp_list[$if] = 1;
1996
					}
1997
				}
1998
			}
1999
		}
2000
	}
2001
	foreach($ppp_list as $pppif => $dummy) {
2002
		interface_ppps_configure($pppif);
2003
	}
2004
}
2005

    
2006
/*
2007
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2008
 * It writes the mpd config file to /var/etc every time the link is opened.
2009
 */
2010
function interface_ppps_configure($interface) {
2011
	global $config, $g;
2012

    
2013
	/* Return for unassigned interfaces. This is a minimum requirement. */
2014
	if (empty($config['interfaces'][$interface])) {
2015
		return 0;
2016
	}
2017
	$ifcfg = $config['interfaces'][$interface];
2018
	if (!isset($ifcfg['enable'])) {
2019
		return 0;
2020
	}
2021

    
2022
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2023
	if (!is_dir("/var/spool/lock")) {
2024
		mkdir("/var/spool/lock", 0777, true);
2025
	}
2026
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2027
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2028
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2029
	}
2030

    
2031
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2032
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2033
			if ($ifcfg['if'] == $ppp['if']) {
2034
				break;
2035
			}
2036
		}
2037
	}
2038
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2039
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2040
		return 0;
2041
	}
2042
	$pppif = $ifcfg['if'];
2043
	if ($ppp['type'] == "ppp") {
2044
		$type = "modem";
2045
	} else {
2046
		$type = $ppp['type'];
2047
	}
2048
	$upper_type = strtoupper($ppp['type']);
2049

    
2050
	/* XXX: This does not make sense and may create trouble
2051
	 * comment it for now to be removed later on.
2052
	if (platform_booting()) {
2053
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
2054
		echo "starting {$pppif} link...";
2055
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
2056
			return 0;
2057
	}
2058
	*/
2059
	$confports = explode(',', $ppp['ports']);
2060
	if ($type == "modem") {
2061
		$ports = $confports;
2062
	} else {
2063
		$ports = array();
2064
		foreach ($confports as $pid => $port) {
2065
			if (strstr($port, "_vip")) {
2066
				if (get_carp_interface_status($port) != "MASTER") {
2067
					continue;
2068
				}
2069
			}
2070
			$ports[$pid] = get_real_interface($port);
2071
			if (empty($ports[$pid])) {
2072
				return 0;
2073
			}
2074
		}
2075
	}
2076
	$localips = explode(',', $ppp['localip']);
2077
	$gateways = explode(',', $ppp['gateway']);
2078
	$subnets = explode(',', $ppp['subnet']);
2079

    
2080
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2081
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2082
	 */
2083
	foreach ($ports as $pid => $port) {
2084
		switch ($ppp['type']) {
2085
			case "pppoe":
2086
				/* Bring the parent interface up */
2087
				interfaces_bring_up($port);
2088
				pfSense_ngctl_attach(".", $port);
2089
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2090
				$ngif = str_replace(".", "_", $port);
2091
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2092
				break;
2093
			case "pptp":
2094
			case "l2tp":
2095
				/* configure interface */
2096
				if (is_ipaddr($localips[$pid])) {
2097
					// Manually configure interface IP/subnet
2098
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2099
					interfaces_bring_up($port);
2100
				} else if (empty($localips[$pid])) {
2101
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2102
				}
2103

    
2104
				if (!is_ipaddr($localips[$pid])) {
2105
					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));
2106
					$localips[$pid] = "0.0.0.0";
2107
				}
2108
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2109
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2110
				}
2111
				if (!is_ipaddr($gateways[$pid])) {
2112
					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));
2113
					return 0;
2114
				}
2115
				pfSense_ngctl_attach(".", $port);
2116
				break;
2117
			case "ppp":
2118
				if (!file_exists("{$port}")) {
2119
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2120
					return 0;
2121
				}
2122
				break;
2123
			default:
2124
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2125
				break;
2126
		}
2127
	}
2128

    
2129
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2130
	    (is_array($ports) && count($ports) > 1)) {
2131
		$multilink = "enable";
2132
	} else {
2133
		$multilink = "disable";
2134
	}
2135

    
2136
	if ($type == "modem") {
2137
		if (is_ipaddr($ppp['localip'])) {
2138
			$localip = $ppp['localip'];
2139
		} else {
2140
			$localip = '0.0.0.0';
2141
		}
2142

    
2143
		if (is_ipaddr($ppp['gateway'])) {
2144
			$gateway = $ppp['gateway'];
2145
		} else {
2146
			$gateway = "10.64.64.{$pppid}";
2147
		}
2148
		$ranges = "{$localip}/0 {$gateway}/0";
2149

    
2150
		if (empty($ppp['apnum'])) {
2151
			$ppp['apnum'] = 1;
2152
		}
2153
	} else {
2154
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2155
	}
2156

    
2157
	if (isset($ppp['ondemand'])) {
2158
		$ondemand = "enable";
2159
	} else {
2160
		$ondemand = "disable";
2161
	}
2162
	if (!isset($ppp['idletimeout'])) {
2163
		$ppp['idletimeout'] = 0;
2164
	}
2165

    
2166
	if (empty($ppp['username']) && $type == "modem") {
2167
		$ppp['username'] = "user";
2168
		$ppp['password'] = "none";
2169
	}
2170
	if (empty($ppp['password']) && $type == "modem") {
2171
		$passwd = "none";
2172
	} else {
2173
		$passwd = base64_decode($ppp['password']);
2174
	}
2175

    
2176
	$bandwidths = explode(',', $ppp['bandwidth']);
2177
	$defaultmtu = "1492";
2178
	if (!empty($ifcfg['mtu'])) {
2179
		$defaultmtu = intval($ifcfg['mtu']);
2180
	}
2181
	if (isset($ppp['mtu'])) {
2182
		$mtus = explode(',', $ppp['mtu']);
2183
	}
2184
	if (isset($ppp['mru'])) {
2185
		$mrus = explode(',', $ppp['mru']);
2186
	}
2187
	if (isset($ppp['mrru'])) {
2188
		$mrrus = explode(',', $ppp['mrru']);
2189
	}
2190

    
2191
	// Construct the mpd.conf file
2192
	$mpdconf = <<<EOD
2193
startup:
2194
	# configure the console
2195
	set console close
2196
	# configure the web server
2197
	set web close
2198

    
2199
default:
2200
{$ppp['type']}client:
2201
	create bundle static {$interface}
2202
	set bundle enable ipv6cp
2203
	set iface name {$pppif}
2204

    
2205
EOD;
2206
	$setdefaultgw = false;
2207
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2208
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2209
	if ($defgw4['interface'] == $interface) {
2210
		$setdefaultgw = true;
2211
	}
2212

    
2213
/* Omit this, we maintain the default route by other means, and it causes problems with
2214
 * default gateway switching. See redmine #1837 for original issue
2215
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2216
 * edge case. redmine #6495 open to address.
2217
 */
2218
	if ($setdefaultgw == true) {
2219
		$mpdconf .= <<<EOD
2220
	set iface route default
2221

    
2222
EOD;
2223
	}
2224

    
2225
	$mpdconf .= <<<EOD
2226
	set iface {$ondemand} on-demand
2227
	set iface idle {$ppp['idletimeout']}
2228

    
2229
EOD;
2230

    
2231
	if (isset($ppp['ondemand'])) {
2232
		$mpdconf .= <<<EOD
2233
	set iface addrs 10.10.1.1 10.10.1.2
2234

    
2235
EOD;
2236
	}
2237

    
2238
	if (isset($ppp['mtu-override']) &&
2239
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2240
		/* Find the smaller MTU set on ports */
2241
		$mtu = $defaultmtu;
2242
		foreach ($ports as $pid => $port) {
2243
			if (empty($mtus[$pid])) {
2244
				$mtus[$pid] = $defaultmtu;
2245
			}
2246
			if ($type == "pppoe") {
2247
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2248
					$mtus[$pid] = get_interface_mtu($port) - 8;
2249
				}
2250
			}
2251
			if ($mtu > $mtus[$pid]) {
2252
				$mtu = $mtus[$pid];
2253
			}
2254
		}
2255
		$mpdconf .= <<<EOD
2256
	set iface mtu {$mtu} override
2257

    
2258
EOD;
2259
	}
2260

    
2261
	if (isset($ppp['tcpmssfix'])) {
2262
		$tcpmss = "disable";
2263
	} else {
2264
		$tcpmss = "enable";
2265
	}
2266
	$mpdconf .= <<<EOD
2267
	set iface {$tcpmss} tcpmssfix
2268

    
2269
EOD;
2270

    
2271
	$mpdconf .= <<<EOD
2272
	set iface up-script /usr/local/sbin/ppp-linkup
2273
	set iface down-script /usr/local/sbin/ppp-linkdown
2274
	set ipcp ranges {$ranges}
2275

    
2276
EOD;
2277
	if (isset($ppp['vjcomp'])) {
2278
		$mpdconf .= <<<EOD
2279
	set ipcp no vjcomp
2280

    
2281
EOD;
2282
	}
2283

    
2284
	if (isset($config['system']['dnsallowoverride'])) {
2285
		$mpdconf .= <<<EOD
2286
	set ipcp enable req-pri-dns
2287
	set ipcp enable req-sec-dns
2288

    
2289
EOD;
2290
	}
2291

    
2292
	if (!isset($ppp['verbose_log'])) {
2293
		$mpdconf .= <<<EOD
2294
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2295

    
2296
EOD;
2297
	}
2298

    
2299
	foreach ($ports as $pid => $port) {
2300
		$port = get_real_interface($port);
2301
		$mpdconf .= <<<EOD
2302

    
2303
	create link static {$interface}_link{$pid} {$type}
2304
	set link action bundle {$interface}
2305
	set link {$multilink} multilink
2306
	set link keep-alive 10 60
2307
	set link max-redial 0
2308

    
2309
EOD;
2310
		if (isset($ppp['shortseq'])) {
2311
			$mpdconf .= <<<EOD
2312
	set link no shortseq
2313

    
2314
EOD;
2315
		}
2316

    
2317
		if (isset($ppp['acfcomp'])) {
2318
			$mpdconf .= <<<EOD
2319
	set link no acfcomp
2320

    
2321
EOD;
2322
		}
2323

    
2324
		if (isset($ppp['protocomp'])) {
2325
			$mpdconf .= <<<EOD
2326
	set link no protocomp
2327

    
2328
EOD;
2329
		}
2330

    
2331
		$mpdconf .= <<<EOD
2332
	set link disable chap pap
2333
	set link accept chap pap eap
2334
	set link disable incoming
2335

    
2336
EOD;
2337

    
2338

    
2339
		if (!empty($bandwidths[$pid])) {
2340
			$mpdconf .= <<<EOD
2341
	set link bandwidth {$bandwidths[$pid]}
2342

    
2343
EOD;
2344
		}
2345

    
2346
		if (empty($mtus[$pid])) {
2347
			$mtus[$pid] = $defaultmtu;
2348
		}
2349
		if ($type == "pppoe") {
2350
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2351
				$mtus[$pid] = get_interface_mtu($port) - 8;
2352
			}
2353
		}
2354
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2355
		    !isset($ppp['mtu-override']) &&
2356
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2357
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2358
			$mpdconf .= <<<EOD
2359
	set link mtu {$mtus[$pid]}
2360

    
2361
EOD;
2362
		}
2363

    
2364
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2365
		    !isset($ppp['mtu-override']) &&
2366
		    !empty($mrus[$pid])) {
2367
			$mpdconf .= <<<EOD
2368
	set link mru {$mrus[$pid]}
2369

    
2370
EOD;
2371
		}
2372

    
2373
		if (!empty($mrrus[$pid])) {
2374
			$mpdconf .= <<<EOD
2375
	set link mrru {$mrrus[$pid]}
2376

    
2377
EOD;
2378
		}
2379

    
2380
		$mpdconf .= <<<EOD
2381
	set auth authname "{$ppp['username']}"
2382
	set auth password {$passwd}
2383

    
2384
EOD;
2385
		if ($type == "modem") {
2386
			$mpdconf .= <<<EOD
2387
	set modem device {$ppp['ports']}
2388
	set modem script DialPeer
2389
	set modem idle-script Ringback
2390
	set modem watch -cd
2391
	set modem var \$DialPrefix "DT"
2392
	set modem var \$Telephone "{$ppp['phone']}"
2393

    
2394
EOD;
2395
		}
2396
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2397
			$mpdconf .= <<<EOD
2398
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2399

    
2400
EOD;
2401
		}
2402
		if (isset($ppp['initstr']) && $type == "modem") {
2403
			$initstr = base64_decode($ppp['initstr']);
2404
			$mpdconf .= <<<EOD
2405
	set modem var \$InitString "{$initstr}"
2406

    
2407
EOD;
2408
		}
2409
		if (isset($ppp['simpin']) && $type == "modem") {
2410
			if ($ppp['pin-wait'] == "") {
2411
				$ppp['pin-wait'] = 0;
2412
			}
2413
			$mpdconf .= <<<EOD
2414
	set modem var \$SimPin "{$ppp['simpin']}"
2415
	set modem var \$PinWait "{$ppp['pin-wait']}"
2416

    
2417
EOD;
2418
		}
2419
		if (isset($ppp['apn']) && $type == "modem") {
2420
			$mpdconf .= <<<EOD
2421
	set modem var \$APN "{$ppp['apn']}"
2422
	set modem var \$APNum "{$ppp['apnum']}"
2423

    
2424
EOD;
2425
		}
2426
		if ($type == "pppoe") {
2427
			// Send a null service name if none is set.
2428
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2429
			$mpdconf .= <<<EOD
2430
	set pppoe service "{$provider}"
2431

    
2432
EOD;
2433
		}
2434
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
2435
			$mpdconf .= <<<EOD
2436
	set pppoe max-payload {$mtus[$pid]}
2437

    
2438
EOD;
2439
		}
2440
		if ($type == "pppoe") {
2441
			$mpdconf .= <<<EOD
2442
	set pppoe iface {$port}
2443

    
2444
EOD;
2445
		}
2446

    
2447
		if ($type == "pptp" || $type == "l2tp") {
2448
			$mpdconf .= <<<EOD
2449
	set {$type} self {$localips[$pid]}
2450
	set {$type} peer {$gateways[$pid]}
2451

    
2452
EOD;
2453
		}
2454

    
2455
		$mpdconf .= "\topen\n";
2456
	} //end foreach ($port)
2457

    
2458

    
2459
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2460
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2461
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2462
	} else {
2463
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2464
		if (!$fd) {
2465
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2466
			return 0;
2467
		}
2468
		// Write out mpd_ppp.conf
2469
		fwrite($fd, $mpdconf);
2470
		fclose($fd);
2471
		unset($mpdconf);
2472
	}
2473

    
2474
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2475
	if (isset($ppp['uptime'])) {
2476
		if (!file_exists("/conf/{$pppif}.log")) {
2477
			file_put_contents("/conf/{$pppif}.log", '');
2478
		}
2479
	} else {
2480
		if (file_exists("/conf/{$pppif}.log")) {
2481
			@unlink("/conf/{$pppif}.log");
2482
		}
2483
	}
2484

    
2485
	/* clean up old lock files */
2486
	foreach ($ports as $port) {
2487
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2488
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2489
		}
2490
	}
2491

    
2492
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2493
	/* random IPv6 interface identifier during boot. More details at */
2494
	/* https://forum.pfsense.org/index.php?topic=101967.msg570519#msg570519 */
2495
	if (platform_booting() && is_array($config['interfaces'])) {
2496
		$count = 0;
2497
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2498
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2499
				$tempaddr[$count]['if'] = $tempiface['if'];
2500
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2501
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2502
				$count++;
2503
			}
2504
			// Maximum /31 is is x.y.z.254/31
2505
			if ($count > 122) {
2506
				break;
2507
			}
2508
		}
2509
		unset($count);
2510
	}
2511

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

    
2517
	// Check for PPPoE periodic reset request
2518
	if ($type == "pppoe") {
2519
		if (!empty($ppp['pppoe-reset-type'])) {
2520
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2521
		} else {
2522
			interface_setup_pppoe_reset_file($ppp['if']);
2523
		}
2524
	}
2525
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2526
	$i = 0;
2527
	while ($i < 10) {
2528
		if (does_interface_exist($ppp['if'], true)) {
2529
			break;
2530
		}
2531
		sleep(3);
2532
		$i++;
2533
	}
2534

    
2535
	/* Remove all temporary bogon IPv4 addresses */
2536
	if (is_array($tempaddr)) {
2537
		foreach ($tempaddr as $tempiface) {
2538
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2539
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2540
			}
2541
		}
2542
		unset ($tempaddr);
2543
	}
2544

    
2545
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2546
	/* We should be able to launch the right version for each modem */
2547
	/* We can also guess the mondev from the manufacturer */
2548
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2549
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2550
	foreach ($ports as $port) {
2551
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2552
			$mondev = substr(basename($port), 0, -1);
2553
			$devlist = glob("/dev/{$mondev}?");
2554
			$mondev = basename(end($devlist));
2555
		}
2556
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2557
			$mondev = substr(basename($port), 0, -1) . "1";
2558
		}
2559
		if ($mondev != '') {
2560
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2561
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2562
		}
2563
	}
2564

    
2565
	return 1;
2566
}
2567

    
2568
function interfaces_sync_setup() {
2569
	global $g, $config;
2570

    
2571
	if (isset($config['system']['developerspew'])) {
2572
		$mt = microtime();
2573
		echo "interfaces_sync_setup() being called $mt\n";
2574
	}
2575

    
2576
	if (platform_booting()) {
2577
		echo gettext("Configuring CARP settings...");
2578
		mute_kernel_msgs();
2579
	}
2580

    
2581
	/* suck in configuration items */
2582
	if ($config['hasync']) {
2583
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2584
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2585
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2586
	} else {
2587
		unset($pfsyncinterface);
2588
		unset($pfsyncenabled);
2589
	}
2590

    
2591
	set_sysctl(array(
2592
		"net.inet.carp.preempt" => "1",
2593
		"net.inet.carp.log" => "1")
2594
	);
2595

    
2596
	if (!empty($pfsyncinterface)) {
2597
		$carp_sync_int = get_real_interface($pfsyncinterface);
2598
	} else {
2599
		unset($carp_sync_int);
2600
	}
2601

    
2602
	/* setup pfsync interface */
2603
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2604
		if (is_ipaddr($pfsyncpeerip)) {
2605
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2606
		} else {
2607
			$syncpeer = "-syncpeer";
2608
		}
2609

    
2610
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2611
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2612

    
2613
		sleep(1);
2614

    
2615
		/* XXX: Handle an issue with pfsync(4) and carp(4). In a cluster carp will come up before pfsync(4) has updated and so will cause issues
2616
		 * for existing sessions.
2617
		 */
2618
		log_error(gettext("waiting for pfsync..."));
2619
		$i = 0;
2620
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2621
			$i++;
2622
			sleep(1);
2623
		}
2624
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2625
		log_error(gettext("Configuring CARP settings finalize..."));
2626
	} else {
2627
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2628
	}
2629

    
2630
	$carplist = get_configured_vip_list('all', VIP_CARP);
2631
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2632
		set_single_sysctl("net.inet.carp.allow", "1");
2633
	} else {
2634
		set_single_sysctl("net.inet.carp.allow", "0");
2635
	}
2636

    
2637
	if (platform_booting()) {
2638
		unmute_kernel_msgs();
2639
		echo gettext("done.") . "\n";
2640
	}
2641
}
2642

    
2643
function interface_proxyarp_configure($interface = "") {
2644
	global $config, $g;
2645
	if (isset($config['system']['developerspew'])) {
2646
		$mt = microtime();
2647
		echo "interface_proxyarp_configure() being called $mt\n";
2648
	}
2649

    
2650
	/* kill any running choparp */
2651
	if (empty($interface)) {
2652
		killbyname("choparp");
2653
	} else {
2654
		$vipif = get_real_interface($interface);
2655
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2656
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2657
		}
2658
	}
2659

    
2660
	$paa = array();
2661
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2662

    
2663
		/* group by interface */
2664
		foreach ($config['virtualip']['vip'] as $vipent) {
2665
			if ($vipent['mode'] === "proxyarp") {
2666
				if ($vipent['interface']) {
2667
					$proxyif = $vipent['interface'];
2668
				} else {
2669
					$proxyif = "wan";
2670
				}
2671

    
2672
				if (!empty($interface) && $interface != $proxyif) {
2673
					continue;
2674
				}
2675

    
2676
				if (!is_array($paa[$proxyif])) {
2677
					$paa[$proxyif] = array();
2678
				}
2679

    
2680
				$paa[$proxyif][] = $vipent;
2681
			}
2682
		}
2683
	}
2684

    
2685
	if (!empty($interface)) {
2686
		if (is_array($paa[$interface])) {
2687
			$paaifip = get_interface_ip($interface);
2688
			if (!is_ipaddr($paaifip)) {
2689
				return;
2690
			}
2691
			$vipif = get_real_interface($interface);
2692
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2693
			$args .= $vipif . " auto";
2694
			foreach ($paa[$interface] as $paent) {
2695
				if (isset($paent['subnet'])) {
2696
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2697
				} else if (isset($paent['range'])) {
2698
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2699
				}
2700
			}
2701
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2702
		}
2703
	} else if (count($paa) > 0) {
2704
		foreach ($paa as $paif => $paents) {
2705
			$paaifip = get_interface_ip($paif);
2706
			if (!is_ipaddr($paaifip)) {
2707
				continue;
2708
			}
2709
			$vipif = get_real_interface($paif);
2710
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2711
			$args .= $vipif . " auto";
2712
			foreach ($paents as $paent) {
2713
				if (isset($paent['subnet'])) {
2714
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2715
				} else if (isset($paent['range'])) {
2716
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2717
				}
2718
			}
2719
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2720
		}
2721
	}
2722
}
2723

    
2724
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2725
	global $g, $config;
2726

    
2727
	if (is_array($config['virtualip']['vip'])) {
2728
		foreach ($config['virtualip']['vip'] as $vip) {
2729

    
2730
			$iface = $vip['interface'];
2731
			if (substr($iface, 0, 4) == "_vip")
2732
				$iface = get_configured_vip_interface($vip['interface']);
2733
			if ($iface != $interface)
2734
				continue;
2735
			if ($type == VIP_CARP) {
2736
				if ($vip['mode'] != "carp")
2737
					continue;
2738
			} elseif ($type == VIP_IPALIAS) {
2739
				if ($vip['mode'] != "ipalias")
2740
					continue;
2741
			} else {
2742
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2743
					continue;
2744
			}
2745

    
2746
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2747
				interface_vip_bring_down($vip);
2748
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2749
				interface_vip_bring_down($vip);
2750
			else if ($inet == "all")
2751
				interface_vip_bring_down($vip);
2752
		}
2753
	}
2754
}
2755

    
2756
function interfaces_vips_configure($interface = "") {
2757
	global $g, $config;
2758
	if (isset($config['system']['developerspew'])) {
2759
		$mt = microtime();
2760
		echo "interfaces_vips_configure() being called $mt\n";
2761
	}
2762
	$paa = array();
2763
	if (is_array($config['virtualip']['vip'])) {
2764
		$carp_setuped = false;
2765
		$anyproxyarp = false;
2766
		foreach ($config['virtualip']['vip'] as $vip) {
2767
			if ($interface <> "" && get_root_interface($vip['interface']) <> $interface) {
2768
				continue;
2769
			}
2770
			switch ($vip['mode']) {
2771
				case "proxyarp":
2772
					/* nothing it is handled on interface_proxyarp_configure() */
2773
					$anyproxyarp = true;
2774
					break;
2775
				case "ipalias":
2776
					interface_ipalias_configure($vip);
2777
					break;
2778
				case "carp":
2779
					if ($carp_setuped == false) {
2780
						$carp_setuped = true;
2781
					}
2782
					interface_carp_configure($vip);
2783
					break;
2784
			}
2785
		}
2786
		if ($carp_setuped == true) {
2787
			interfaces_sync_setup();
2788
		}
2789
		if ($anyproxyarp == true) {
2790
			interface_proxyarp_configure();
2791
		}
2792
	}
2793
}
2794

    
2795
function interface_ipalias_configure(&$vip) {
2796
	global $config;
2797

    
2798
	if ($vip['mode'] != 'ipalias') {
2799
		return;
2800
	}
2801

    
2802
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2803
	if ($realif != "lo0") {
2804
		$if = convert_real_interface_to_friendly_interface_name($realif);
2805
		if (!isset($config['interfaces'][$if]) ||
2806
		    !isset($config['interfaces'][$if]['enable'])) {
2807
			return;
2808
		}
2809
	}
2810

    
2811
	$af = 'inet';
2812
	if (is_ipaddrv6($vip['subnet'])) {
2813
		$af = 'inet6';
2814
	}
2815
	$iface = $vip['interface'];
2816
	$vhid = '';
2817
	if (substr($vip['interface'], 0, 4) == "_vip") {
2818
		$carpvip = get_configured_vip($vip['interface']);
2819
		$iface = $carpvip['interface'];
2820
		$vhid = "vhid {$carpvip['vhid']}";
2821
	}
2822
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2823
	unset($iface, $af, $realif, $carpvip, $vhid);
2824
}
2825

    
2826
function interface_carp_configure(&$vip) {
2827
	global $config, $g;
2828
	if (isset($config['system']['developerspew'])) {
2829
		$mt = microtime();
2830
		echo "interface_carp_configure() being called $mt\n";
2831
	}
2832

    
2833
	if ($vip['mode'] != "carp") {
2834
		return;
2835
	}
2836

    
2837
	$realif = get_real_interface($vip['interface']);
2838
	if (!does_interface_exist($realif)) {
2839
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2840
		return;
2841
	}
2842
	if ($realif != "lo0") {
2843
		if (!isset($config['interfaces'][$vip['interface']]) ||
2844
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
2845
			return;
2846
		}
2847
	}
2848

    
2849
	$vip_password = $vip['password'];
2850
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2851
	if ($vip['password'] != "") {
2852
		$password = " pass {$vip_password}";
2853
	}
2854

    
2855
	$advbase = "";
2856
	if (!empty($vip['advbase'])) {
2857
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2858
	}
2859

    
2860
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2861
	if ($carp_maintenancemode) {
2862
		$advskew = "advskew 254";
2863
	} else {
2864
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2865
	}
2866

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

    
2869
	if (is_ipaddrv4($vip['subnet'])) {
2870
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2871
	} else if (is_ipaddrv6($vip['subnet'])) {
2872
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2873
	}
2874

    
2875
	return $realif;
2876
}
2877

    
2878
function interface_wireless_clone($realif, $wlcfg) {
2879
	global $config, $g;
2880
	/*   Check to see if interface has been cloned as of yet.
2881
	 *   If it has not been cloned then go ahead and clone it.
2882
	 */
2883
	$needs_clone = false;
2884
	if (is_array($wlcfg['wireless'])) {
2885
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2886
	} else {
2887
		$wlcfg_mode = $wlcfg['mode'];
2888
	}
2889
	switch ($wlcfg_mode) {
2890
		case "hostap":
2891
			$mode = "wlanmode hostap";
2892
			break;
2893
		case "adhoc":
2894
			$mode = "wlanmode adhoc";
2895
			break;
2896
		default:
2897
			$mode = "";
2898
			break;
2899
	}
2900
	$baseif = interface_get_wireless_base($wlcfg['if']);
2901
	if (does_interface_exist($realif)) {
2902
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2903
		$ifconfig_str = implode($output);
2904
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2905
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2906
			$needs_clone = true;
2907
		}
2908
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2909
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2910
			$needs_clone = true;
2911
		}
2912
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2913
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2914
			$needs_clone = true;
2915
		}
2916
	} else {
2917
		$needs_clone = true;
2918
	}
2919

    
2920
	if ($needs_clone == true) {
2921
		/* remove previous instance if it exists */
2922
		if (does_interface_exist($realif)) {
2923
			pfSense_interface_destroy($realif);
2924
		}
2925

    
2926
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2927
		// Create the new wlan interface. FreeBSD returns the new interface name.
2928
		// example:  wlan2
2929
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2930
		if ($ret <> 0) {
2931
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2932
			return false;
2933
		}
2934
		$newif = trim($out[0]);
2935
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2936
		pfSense_interface_rename($newif, $realif);
2937
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2938
	}
2939
	return true;
2940
}
2941

    
2942
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2943
	global $config, $g;
2944

    
2945
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2946
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2947
				 'regdomain', 'regcountry', 'reglocation');
2948

    
2949
	if (!is_interface_wireless($ifcfg['if'])) {
2950
		return;
2951
	}
2952

    
2953
	$baseif = interface_get_wireless_base($ifcfg['if']);
2954

    
2955
	// Sync shared settings for assigned clones
2956
	$iflist = get_configured_interface_list(true);
2957
	foreach ($iflist as $if) {
2958
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2959
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2960
				foreach ($shared_settings as $setting) {
2961
					if ($sync_changes) {
2962
						if (isset($ifcfg['wireless'][$setting])) {
2963
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2964
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2965
							unset($config['interfaces'][$if]['wireless'][$setting]);
2966
						}
2967
					} else {
2968
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2969
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2970
						} else if (isset($ifcfg['wireless'][$setting])) {
2971
							unset($ifcfg['wireless'][$setting]);
2972
						}
2973
					}
2974
				}
2975
				if (!$sync_changes) {
2976
					break;
2977
				}
2978
			}
2979
		}
2980
	}
2981

    
2982
	// Read or write settings at shared area
2983
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2984
		foreach ($shared_settings as $setting) {
2985
			if ($sync_changes) {
2986
				if (isset($ifcfg['wireless'][$setting])) {
2987
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2988
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2989
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2990
				}
2991
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2992
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2993
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2994
				} else if (isset($ifcfg['wireless'][$setting])) {
2995
					unset($ifcfg['wireless'][$setting]);
2996
				}
2997
			}
2998
		}
2999
	}
3000

    
3001
	// Sync the mode on the clone creation page with the configured mode on the interface
3002
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3003
		foreach ($config['wireless']['clone'] as &$clone) {
3004
			if ($clone['cloneif'] == $ifcfg['if']) {
3005
				if ($sync_changes) {
3006
					$clone['mode'] = $ifcfg['wireless']['mode'];
3007
				} else {
3008
					$ifcfg['wireless']['mode'] = $clone['mode'];
3009
				}
3010
				break;
3011
			}
3012
		}
3013
		unset($clone);
3014
	}
3015
}
3016

    
3017
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3018
	global $config, $g;
3019

    
3020
	/*    open up a shell script that will be used to output the commands.
3021
	 *    since wireless is changing a lot, these series of commands are fragile
3022
	 *    and will sometimes need to be verified by a operator by executing the command
3023
	 *    and returning the output of the command to the developers for inspection.  please
3024
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3025
	 */
3026

    
3027
	// Remove script file
3028
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3029

    
3030
	// Clone wireless nic if needed.
3031
	interface_wireless_clone($if, $wl);
3032

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

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

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

    
3042
	/* set values for /path/program */
3043
	if (file_exists("/usr/local/sbin/hostapd")) {
3044
		$hostapd = "/usr/local/sbin/hostapd";
3045
	} else {
3046
		$hostapd = "/usr/sbin/hostapd";
3047
	}
3048
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3049
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3050
	} else {
3051
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3052
	}
3053
	$ifconfig = "/sbin/ifconfig";
3054
	$sysctl = "/sbin/sysctl";
3055
	$sysctl_args = "-q";
3056
	$killall = "/usr/bin/killall";
3057

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

    
3060
	$wlcmd = array();
3061
	$wl_sysctl = array();
3062
	/* Set a/b/g standard */
3063
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3064
	/* skip mode entirely for "auto" */
3065
	if ($wlcfg['standard'] != "auto") {
3066
		$wlcmd[] = "mode " . escapeshellarg($standard);
3067
	}
3068

    
3069
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3070
	 * to prevent massive packet loss under certain conditions. */
3071
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3072
		$wlcmd[] = "-ampdu";
3073
	}
3074

    
3075
	/* Set ssid */
3076
	if ($wlcfg['ssid']) {
3077
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3078
	}
3079

    
3080
	/* Set 802.11g protection mode */
3081
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3082

    
3083
	/* set wireless channel value */
3084
	if (isset($wlcfg['channel'])) {
3085
		if ($wlcfg['channel'] == "0") {
3086
			$wlcmd[] = "channel any";
3087
		} else {
3088
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
3089
		}
3090
	}
3091

    
3092
	/* Set antenna diversity value */
3093
	if (isset($wlcfg['diversity'])) {
3094
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3095
	}
3096

    
3097
	/* Set txantenna value */
3098
	if (isset($wlcfg['txantenna'])) {
3099
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3100
	}
3101

    
3102
	/* Set rxantenna value */
3103
	if (isset($wlcfg['rxantenna'])) {
3104
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3105
	}
3106

    
3107
	/* set Distance value */
3108
	if ($wlcfg['distance']) {
3109
		$distance = escapeshellarg($wlcfg['distance']);
3110
	}
3111

    
3112
	/* Set wireless hostap mode */
3113
	if ($wlcfg['mode'] == "hostap") {
3114
		$wlcmd[] = "mediaopt hostap";
3115
	} else {
3116
		$wlcmd[] = "-mediaopt hostap";
3117
	}
3118

    
3119
	/* Set wireless adhoc mode */
3120
	if ($wlcfg['mode'] == "adhoc") {
3121
		$wlcmd[] = "mediaopt adhoc";
3122
	} else {
3123
		$wlcmd[] = "-mediaopt adhoc";
3124
	}
3125

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

    
3128
	/* handle hide ssid option */
3129
	if (isset($wlcfg['hidessid']['enable'])) {
3130
		$wlcmd[] = "hidessid";
3131
	} else {
3132
		$wlcmd[] = "-hidessid";
3133
	}
3134

    
3135
	/* handle pureg (802.11g) only option */
3136
	if (isset($wlcfg['pureg']['enable'])) {
3137
		$wlcmd[] = "mode 11g pureg";
3138
	} else {
3139
		$wlcmd[] = "-pureg";
3140
	}
3141

    
3142
	/* handle puren (802.11n) only option */
3143
	if (isset($wlcfg['puren']['enable'])) {
3144
		$wlcmd[] = "puren";
3145
	} else {
3146
		$wlcmd[] = "-puren";
3147
	}
3148

    
3149
	/* enable apbridge option */
3150
	if (isset($wlcfg['apbridge']['enable'])) {
3151
		$wlcmd[] = "apbridge";
3152
	} else {
3153
		$wlcmd[] = "-apbridge";
3154
	}
3155

    
3156
	/* handle turbo option */
3157
	if (isset($wlcfg['turbo']['enable'])) {
3158
		$wlcmd[] = "mediaopt turbo";
3159
	} else {
3160
		$wlcmd[] = "-mediaopt turbo";
3161
	}
3162

    
3163
	/* handle txpower setting */
3164
	// or don't. this has issues at the moment.
3165
	/*
3166
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3167
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3168
	}*/
3169

    
3170
	/* handle wme option */
3171
	if (isset($wlcfg['wme']['enable'])) {
3172
		$wlcmd[] = "wme";
3173
	} else {
3174
		$wlcmd[] = "-wme";
3175
	}
3176

    
3177
	/* Enable wpa if it's configured. No WEP support anymore. */
3178
	if (isset($wlcfg['wpa']['enable'])) {
3179
		$wlcmd[] = "authmode wpa wepmode off ";
3180
	} else {
3181
		$wlcmd[] = "authmode open wepmode off ";
3182
	}
3183

    
3184
	kill_hostapd($if);
3185
	mwexec(kill_wpasupplicant("{$if}"));
3186

    
3187
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3188

    
3189
	switch ($wlcfg['mode']) {
3190
		case 'bss':
3191
			if (isset($wlcfg['wpa']['enable'])) {
3192
				$wpa .= <<<EOD
3193
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3194
ctrl_interface_group=0
3195
ap_scan=1
3196
#fast_reauth=1
3197
network={
3198
ssid="{$wlcfg['ssid']}"
3199
scan_ssid=1
3200
priority=5
3201
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3202
psk="{$wlcfg['wpa']['passphrase']}"
3203
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3204
group={$wlcfg['wpa']['wpa_pairwise']}
3205
}
3206
EOD;
3207

    
3208
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
3209
				unset($wpa);
3210
			}
3211
			break;
3212
		case 'hostap':
3213
			if (!empty($wlcfg['wpa']['passphrase'])) {
3214
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3215
			} else {
3216
				$wpa_passphrase = "";
3217
			}
3218
			if (isset($wlcfg['wpa']['enable'])) {
3219
				$wpa .= <<<EOD
3220
interface={$if}
3221
driver=bsd
3222
logger_syslog=-1
3223
logger_syslog_level=0
3224
logger_stdout=-1
3225
logger_stdout_level=0
3226
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3227
ctrl_interface={$g['varrun_path']}/hostapd
3228
ctrl_interface_group=wheel
3229
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3230
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3231
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3232
ssid={$wlcfg['ssid']}
3233
debug={$wlcfg['wpa']['debug_mode']}
3234
wpa={$wlcfg['wpa']['wpa_mode']}
3235
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3236
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3237
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3238
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3239
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3240
{$wpa_passphrase}
3241

    
3242
EOD;
3243

    
3244
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3245
					$wpa .= <<<EOD
3246
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3247
rsn_preauth=1
3248
rsn_preauth_interfaces={$if}
3249

    
3250
EOD;
3251
				}
3252
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3253
					$wpa .= "ieee8021x=1\n";
3254

    
3255
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3256
						$auth_server_port = "1812";
3257
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3258
							$auth_server_port = intval($wlcfg['auth_server_port']);
3259
						}
3260
						$wpa .= <<<EOD
3261

    
3262
auth_server_addr={$wlcfg['auth_server_addr']}
3263
auth_server_port={$auth_server_port}
3264
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3265

    
3266
EOD;
3267
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3268
							$auth_server_port2 = "1812";
3269
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3270
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3271
							}
3272

    
3273
							$wpa .= <<<EOD
3274
auth_server_addr={$wlcfg['auth_server_addr2']}
3275
auth_server_port={$auth_server_port2}
3276
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3277

    
3278
EOD;
3279
						}
3280
					}
3281
				}
3282

    
3283
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3284
				unset($wpa);
3285
			}
3286
			break;
3287
	}
3288

    
3289
	/*
3290
	 *    all variables are set, lets start up everything
3291
	 */
3292

    
3293
	$baseif = interface_get_wireless_base($if);
3294
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3295
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3296

    
3297
	/* set sysctls for the wireless interface */
3298
	if (!empty($wl_sysctl)) {
3299
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3300
		foreach ($wl_sysctl as $wl_sysctl_line) {
3301
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3302
		}
3303
	}
3304

    
3305
	/* set ack timers according to users preference (if he/she has any) */
3306
	if ($distance) {
3307
		fwrite($fd_set, "# Enable ATH distance settings\n");
3308
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3309
	}
3310

    
3311
	if (isset($wlcfg['wpa']['enable'])) {
3312
		if ($wlcfg['mode'] == "bss") {
3313
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3314
		}
3315
		if ($wlcfg['mode'] == "hostap") {
3316
			/* add line to script to restore old mac to make hostapd happy */
3317
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3318
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3319
				$if_curmac = get_interface_mac($if);
3320
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3321
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3322
						" link " . escapeshellarg($if_oldmac) . "\n");
3323
				}
3324
			}
3325

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

    
3328
			/* add line to script to restore spoofed mac after running hostapd */
3329
			if ($wl['spoofmac']) {
3330
				$if_curmac = get_interface_mac($if);
3331
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3332
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3333
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3334
				}
3335
			}
3336
		}
3337
	}
3338

    
3339
	fclose($fd_set);
3340

    
3341
	/* Making sure regulatory settings have actually changed
3342
	 * before applying, because changing them requires bringing
3343
	 * down all wireless networks on the interface. */
3344
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3345
	$ifconfig_str = implode($output);
3346
	unset($output);
3347
	$reg_changing = false;
3348

    
3349
	/* special case for the debug country code */
3350
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3351
		$reg_changing = true;
3352
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3353
		$reg_changing = true;
3354
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3355
		$reg_changing = true;
3356
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3357
		$reg_changing = true;
3358
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3359
		$reg_changing = true;
3360
	}
3361

    
3362
	if ($reg_changing) {
3363
		/* set regulatory domain */
3364
		if ($wlcfg['regdomain']) {
3365
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3366
		}
3367

    
3368
		/* set country */
3369
		if ($wlcfg['regcountry']) {
3370
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3371
		}
3372

    
3373
		/* set location */
3374
		if ($wlcfg['reglocation']) {
3375
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3376
		}
3377

    
3378
		$wlregcmd_args = implode(" ", $wlregcmd);
3379

    
3380
		/* build a complete list of the wireless clones for this interface */
3381
		$clone_list = array();
3382
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3383
			$clone_list[] = interface_get_wireless_clone($baseif);
3384
		}
3385
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3386
			foreach ($config['wireless']['clone'] as $clone) {
3387
				if ($clone['if'] == $baseif) {
3388
					$clone_list[] = $clone['cloneif'];
3389
				}
3390
			}
3391
		}
3392

    
3393
		/* find which clones are up and bring them down */
3394
		$clones_up = array();
3395
		foreach ($clone_list as $clone_if) {
3396
			$clone_status = pfSense_get_interface_addresses($clone_if);
3397
			if ($clone_status['status'] == 'up') {
3398
				$clones_up[] = $clone_if;
3399
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3400
			}
3401
		}
3402

    
3403
		/* apply the regulatory settings */
3404
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3405
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3406

    
3407
		/* bring the clones back up that were previously up */
3408
		foreach ($clones_up as $clone_if) {
3409
			interfaces_bring_up($clone_if);
3410

    
3411
			/*
3412
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3413
			 * is in infrastructure mode, and WPA is enabled.
3414
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3415
			 */
3416
			if ($clone_if != $if) {
3417
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3418
				if ((!empty($friendly_if)) &&
3419
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3420
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3421
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3422
				}
3423
			}
3424
		}
3425
	}
3426

    
3427
	/* The mode must be specified in a separate command before ifconfig
3428
	 * will allow the mode and channel at the same time in the next.
3429
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3430
	 */
3431
	if ($wlcfg['mode'] == "hostap") {
3432
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3433
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3434
	}
3435

    
3436
	/* configure wireless */
3437
	$wlcmd_args = implode(" ", $wlcmd);
3438
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3439
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3440
	/* Bring the interface up only after setting up all the other parameters. */
3441
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3442
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3443
	fclose($wlan_setup_log);
3444

    
3445
	unset($wlcmd_args, $wlcmd);
3446

    
3447

    
3448
	sleep(1);
3449
	/* execute hostapd and wpa_supplicant if required in shell */
3450
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3451

    
3452
	return 0;
3453

    
3454
}
3455

    
3456
function kill_hostapd($interface) {
3457
	global $g;
3458

    
3459
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3460
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3461
	}
3462
}
3463

    
3464
function kill_wpasupplicant($interface) {
3465
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3466
}
3467

    
3468
function find_dhclient_process($interface) {
3469
	if ($interface) {
3470
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3471
	} else {
3472
		$pid = 0;
3473
	}
3474

    
3475
	return intval($pid);
3476
}
3477

    
3478
function kill_dhclient_process($interface) {
3479
	if (empty($interface) || !does_interface_exist($interface)) {
3480
		return;
3481
	}
3482

    
3483
	$i = 0;
3484
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3485
		/* 3rd time make it die for sure */
3486
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3487
		posix_kill($pid, $sig);
3488
		sleep(1);
3489
		$i++;
3490
	}
3491
	unset($i);
3492
}
3493

    
3494
function find_dhcp6c_process($interface) {
3495
	global $g;
3496

    
3497
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3498
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3499
	} else {
3500
		return(false);
3501
	}
3502

    
3503
	return intval($pid);
3504
}
3505

    
3506
function kill_dhcp6client_process($interface, $force, $release = false) {
3507
	global $g;
3508

    
3509
	$i = 0;
3510

    
3511
	/*
3512
	Beware of the following: Reason, the interface may be down, but
3513
	dhcp6c may still be running, it just complains it cannot send
3514
	and carries on. Commented out as will stop the call to kill.
3515

    
3516
	if (empty($interface) || !does_interface_exist($interface)) {
3517
		return;
3518
	}
3519
	*/
3520

    
3521
	/*********** Notes on signals for dhcp6c and this function *************
3522

    
3523
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3524
	a release and waiting for the response that never comes.
3525
	So we need to tell it that the interface is down and to just die quickly
3526
	otherwise a new client may launch and we have duplicate proceses.
3527
	In this case use SIGUSR1.
3528

    
3529
	If we want to exit normally obeying the no release flag then use SIGTERM.
3530
	If we want to exit with a release overiding the no release flag then
3531
	use SIGUSR2.
3532

    
3533
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3534
	exit quickly without sending release signals.
3535

    
3536
	If $Force is set to false and $release is also set to false dhcp6c will
3537
	follow the no-release flag.
3538

    
3539
	If $Force is set to false and $release is true then dhcp6c will send a
3540
	release regardless of the no-release flag.
3541
	***********************************************************************/
3542

    
3543
	if ($force == true) {
3544
		$psig=SIGUSR1;
3545
	} else if ($release == false) {
3546
		$psig=SIGTERM;
3547
	} else {
3548
		$psig=SIGUSR2;
3549
	}
3550

    
3551
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3552
		/* 3rd time make it die for sure */
3553
		$sig = ($i == 2 ? SIGKILL : $psig);
3554
		posix_kill($pid, $sig);
3555
		sleep(1);
3556
		$i++;
3557
	}
3558
	/* Clear the RTSOLD script created lock & tidy up */
3559
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3560
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
3561
}
3562
function reset_dhcp6client_process($interface) {
3563

    
3564
	$pid = find_dhcp6c_process($interface);
3565

    
3566
	if($pid != 0) {
3567
		posix_kill($pid, SIGHUP);
3568
	}
3569
}
3570

    
3571
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3572
	global $g;
3573

    
3574
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3575
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3576

    
3577
	/*
3578
	 * Only run this if the lock does not exist. In theory the lock being
3579
	 * there in this mode means the user has selected dhcp6withoutRA while
3580
	 * a session is active in the other mode.
3581
	 *
3582
	 * It should not happen as the process should have been killed and the
3583
	 * lock deleted.
3584
	 */
3585

    
3586
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
3587
		kill_dhcp6client_process($interface, true);
3588
		/* Lock it to avoid multiple runs */
3589
		touch("/tmp/dhcp6c_{$interface}_lock");
3590
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3591
		    "{$noreleaseOption} " .
3592
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
3593
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
3594
		    $interface);
3595
		log_error(sprintf(gettext(
3596
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
3597
		    $interface));
3598
	}
3599
}
3600

    
3601
function interface_virtual_create($interface) {
3602
	global $config;
3603

    
3604
	if (interface_is_vlan($interface) != NULL) {
3605
		interfaces_vlan_configure($interface);
3606
	} else if (substr($interface, 0, 3) == "gre") {
3607
		interfaces_gre_configure(0, $interface);
3608
	} else if (substr($interface, 0, 3) == "gif") {
3609
		interfaces_gif_configure(0, $interface);
3610
	} else if (substr($interface, 0, 5) == "ovpns") {
3611
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3612
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3613
				if ($interface == "ovpns{$server['vpnid']}") {
3614
					if (!function_exists('openvpn_resync')) {
3615
						require_once('openvpn.inc');
3616
					}
3617
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3618
					openvpn_resync('server', $server);
3619
				}
3620
			}
3621
			unset($server);
3622
		}
3623
	} else if (substr($interface, 0, 5) == "ovpnc") {
3624
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3625
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3626
				if ($interface == "ovpnc{$client['vpnid']}") {
3627
					if (!function_exists('openvpn_resync')) {
3628
						require_once('openvpn.inc');
3629
					}
3630
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3631
					openvpn_resync('client', $client);
3632
				}
3633
			}
3634
			unset($client);
3635
		}
3636
	} else if (substr($interface, 0, 5) == "ipsec") {
3637
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
3638
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
3639
				if ($ph1ent['disabled']) {
3640
					continue;
3641
				}
3642
				if ($interface == "ipsec{$ph1ent['ikeid']}") {
3643
					interface_ipsec_vti_configure($ph1ent);
3644
				}
3645
			}
3646
		}
3647
	} else if (substr($interface, 0, 4) == "lagg") {
3648
		interfaces_lagg_configure($interface);
3649
	} else if (substr($interface, 0, 6) == "bridge") {
3650
		interfaces_bridge_configure(0, $interface);
3651
	}
3652
}
3653

    
3654
function interface_vlan_mtu_configured($iface) {
3655
	global $config;
3656

    
3657
	$mtu = 0;
3658
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3659
		foreach ($config['vlans']['vlan'] as $vlan) {
3660

    
3661
			if ($vlan['vlanif'] != $iface)
3662
				continue;
3663

    
3664
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3665
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3666
				/* VLAN MTU */
3667
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3668
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3669
				/* Parent MTU */
3670
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3671
			}
3672
		}
3673
	}
3674

    
3675
	return $mtu;
3676
}
3677

    
3678
function interface_mtu_wanted_for_pppoe($realif) {
3679
	global $config;
3680

    
3681
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3682
		return 0;
3683

    
3684
	$mtu = 0;
3685
	foreach ($config['ppps']['ppp'] as $ppp) {
3686
		if ($ppp['type'] != "pppoe") {
3687
			continue;
3688
		}
3689

    
3690
		$mtus = array();
3691
		if (!empty($ppp['mtu'])) {
3692
			$mtus = explode(',', $ppp['mtu']);
3693
		}
3694
		$ports = explode(',', $ppp['ports']);
3695

    
3696
		foreach ($ports as $pid => $port) {
3697
			$parentifa = get_parent_interface($port);
3698
			$parentif = $parentifa[0];
3699
			if ($parentif != $realif)
3700
				continue;
3701

    
3702
			// there is an MTU configured on the port in question
3703
			if (!empty($mtus[$pid])) {
3704
				$mtu = intval($mtus[$pid]) + 8;
3705
			// or use the MTU configured on the interface ...
3706
			} elseif (is_array($config['interfaces'])) {
3707
				foreach ($config['interfaces'] as $interface) {
3708
					if ($interface['if'] == $ppp['if'] &&
3709
					    !empty($interface['mtu'])) {
3710
						$mtu = intval($interface['mtu']) + 8;
3711
						break;
3712
					}
3713
				}
3714
			}
3715
		}
3716
	}
3717

    
3718
	return $mtu;
3719
}
3720

    
3721
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3722
	global $config, $g;
3723
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3724
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3725

    
3726
	$wancfg = $config['interfaces'][$interface];
3727

    
3728
	if (!isset($wancfg['enable'])) {
3729
		return;
3730
	}
3731

    
3732
	$realif = get_real_interface($interface);
3733
	$realhwif_array = get_parent_interface($interface);
3734
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3735
	$realhwif = $realhwif_array[0];
3736

    
3737
	$mac_if_cfg = $wancfg;
3738
	if (interface_is_vlan($realif)) {
3739
		$mac_if = convert_real_interface_to_friendly_interface_name(
3740
		    $realhwif);
3741
		if (is_array($config['interfaces'][$mac_if])) {
3742
			$mac_if_cfg = $config['interfaces'][$mac_if];
3743
		} else {
3744
			$mac_if = $interface;
3745
		}
3746
	}
3747

    
3748
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn") && !(substr($realif, 0, 5) == "ipsec")) {
3749
		/* remove all IPv4 and IPv6 addresses */
3750
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3751
		if (is_array($tmpifaces)) {
3752
			foreach ($tmpifaces as $tmpiface) {
3753
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3754
					if (!is_linklocal($tmpiface)) {
3755
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3756
					}
3757
				} else {
3758
					if (is_subnetv4($tmpiface)) {
3759
						$tmpip = explode('/', $tmpiface);
3760
						$tmpip = $tmpip[0];
3761
					} else {
3762
						$tmpip = $tmpiface;
3763
					}
3764
					pfSense_interface_deladdress($realif, $tmpip);
3765
				}
3766
			}
3767
		}
3768

    
3769
		/* only bring down the interface when both v4 and v6 are set to NONE */
3770
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3771
			interface_bring_down($interface);
3772
		}
3773
	}
3774

    
3775
	$interface_to_check = $realif;
3776
	if (interface_isppp_type($interface)) {
3777
		$interface_to_check = $realhwif;
3778
	}
3779

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

    
3785
	/* Disable Accepting router advertisements unless specifically requested */
3786
	if ($g['debug']) {
3787
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3788
	}
3789
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
3790
	{
3791
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3792
	}
3793
	/* wireless configuration? */
3794
	if (is_array($wancfg['wireless']) && !$linkupevent) {
3795
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3796
	}
3797

    
3798
	$current_mac = get_interface_mac($realhwif);
3799
	$vendor_mac = get_interface_vendor_mac($realhwif);
3800

    
3801
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
3802
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
3803

    
3804
		interface_set_macaddr($realhwif, $mac_addr);
3805
	} else {
3806
		/*
3807
		 * this is not a valid mac address.  generate a
3808
		 * temporary mac address so the machine can get online.
3809
		 */
3810
		echo gettext("Generating new MAC address.");
3811
		$random_mac = generate_random_mac_address();
3812
		interface_set_macaddr($realhwif, $random_mac);
3813
		$config['interfaces'][$mac_if]['spoofmac'] = $random_mac;
3814
		write_config(sprintf(gettext('The invalid MAC address ' .
3815
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
3816
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
3817
		file_notice("MAC Address altered", sprintf(gettext('The ' .
3818
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
3819
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
3820
		    $random_mac), "Interfaces");
3821
	}
3822

    
3823
	/* media */
3824
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3825
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3826
		if ($wancfg['media']) {
3827
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3828
		}
3829
		if ($wancfg['mediaopt']) {
3830
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3831
		}
3832
		mwexec($cmd);
3833
	}
3834

    
3835
	/* Apply hw offloading policies as configured */
3836
	enable_hardware_offloading($interface);
3837

    
3838
	/* invalidate interface/ip/sn cache */
3839
	get_interface_arr(true);
3840
	unset($interface_ip_arr_cache[$realif]);
3841
	unset($interface_sn_arr_cache[$realif]);
3842
	unset($interface_ipv6_arr_cache[$realif]);
3843
	unset($interface_snv6_arr_cache[$realif]);
3844

    
3845
	$tunnelif = substr($realif, 0, 3);
3846

    
3847
	$mtuif = $realif;
3848
	$mtuhwif = $realhwif;
3849

    
3850
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3851
	if (interface_isppp_type($interface)) {
3852
		$mtuif = $realhwif;
3853
		$mtuhwif_array = get_parent_interface($mtuif);
3854
		$mtuhwif = $mtuhwif_array[0];
3855
	}
3856

    
3857
	$wantedmtu = 0;
3858
	if (is_array($config['interfaces'])) {
3859
		foreach ($config['interfaces'] as $tmpinterface) {
3860
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3861
				$wantedmtu = $tmpinterface['mtu'];
3862
				break;
3863
			}
3864
		}
3865
	}
3866

    
3867
	/* MTU is not specified for interface, try the pppoe settings. */
3868
	if ($wantedmtu == 0) {
3869
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3870
	}
3871
	if ($wantedmtu == 0 && interface_is_vlan($mtuif) != NULL && interface_isppp_type($interface)) {
3872
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3873
	}
3874

    
3875
	/* Set the MTU to 1500 if no explicit MTU configured. */
3876
	if ($wantedmtu == 0) {
3877
		$wantedmtu = 1500; /* Default */
3878
	}
3879

    
3880
	if (interface_is_vlan($mtuif) != NULL) {
3881
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3882
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3883
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3884
			if ($wancfg['mtu'] > $parentmtu) {
3885
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3886
			}
3887
		}
3888

    
3889
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3890

    
3891
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3892
			$configuredmtu = $parentmtu;
3893
		if ($configuredmtu != 0)
3894
			$mtu = $configuredmtu;
3895
		else
3896
			$mtu = $wantedmtu;
3897

    
3898
		/* Set the parent MTU. */
3899
		if (get_interface_mtu($mtuhwif) < $mtu)
3900
			set_interface_mtu($mtuhwif, $mtu);
3901
		/* Set the VLAN MTU. */
3902
		if (get_interface_mtu($mtuif) != $mtu)
3903
			set_interface_mtu($mtuif, $mtu);
3904
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3905
		/* LAGG interface must be destroyed and re-created to change MTU */
3906
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3907
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3908
				foreach ($config['laggs']['lagg'] as $lagg) {
3909
					if ($lagg['laggif'] == $mtuif) {
3910
						interface_lagg_configure($lagg);
3911
						break;
3912
					}
3913
				}
3914
			}
3915
		}
3916
	} else {
3917
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3918
			pfSense_interface_mtu($mtuif, $wantedmtu);
3919
		}
3920
	}
3921
	/* XXX: What about gre/gif/.. ? */
3922

    
3923
	if (does_interface_exist($wancfg['if'])) {
3924
		interfaces_bring_up($wancfg['if']);
3925
	}
3926

    
3927
	switch ($wancfg['ipaddr']) {
3928
		case 'dhcp':
3929
			interface_dhcp_configure($interface);
3930
			break;
3931
		case 'pppoe':
3932
		case 'l2tp':
3933
		case 'pptp':
3934
		case 'ppp':
3935
			interface_ppps_configure($interface);
3936
			break;
3937
		default:
3938
			/* XXX: Kludge for now related to #3280 */
3939
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
3940
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3941
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3942
				}
3943
			}
3944
			break;
3945
	}
3946

    
3947
	switch ($wancfg['ipaddrv6']) {
3948
		case 'slaac':
3949
		case 'dhcp6':
3950
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
3951
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
3952
			// handles all non-PPP connections with 'dhcp6usev4iface' set
3953
			/* Remove the check file. Should not be there but just in case */
3954
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
3955
			log_error(gettext("calling interface_dhcpv6_configure."));
3956
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
3957
				interface_dhcpv6_configure($interface, $wancfg);
3958
			}
3959
			break;
3960
		case '6rd':
3961
			interface_6rd_configure($interface, $wancfg);
3962
			break;
3963
		case '6to4':
3964
			interface_6to4_configure($interface, $wancfg);
3965
			break;
3966
		case 'track6':
3967
			interface_track6_configure($interface, $wancfg, $linkupevent);
3968
			break;
3969
		default:
3970
			/* XXX: Kludge for now related to #3280 */
3971
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
3972
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3973
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3974
					// FIXME: Add IPv6 Support to the pfSense module
3975
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3976
				}
3977
			}
3978
			break;
3979
	}
3980

    
3981
	interface_netgraph_needed($interface);
3982

    
3983
	if (!platform_booting()) {
3984
		link_interface_to_vips($interface, "update");
3985

    
3986
		if ($tunnelif != 'gre') {
3987
			unset($gre);
3988
			$gre = link_interface_to_gre($interface);
3989
			if (!empty($gre)) {
3990
				array_walk($gre, 'interface_gre_configure');
3991
			}
3992
		}
3993

    
3994
		if ($tunnelif != 'gif') {
3995
			unset($gif);
3996
			$gif = link_interface_to_gif ($interface);
3997
			if (!empty($gif)) {
3998
				array_walk($gif, 'interface_gif_configure');
3999
			}
4000
		}
4001

    
4002
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4003
			unset($bridgetmp);
4004
			$bridgetmp = link_interface_to_bridge($interface);
4005
			if (!empty($bridgetmp)) {
4006
				interface_bridge_add_member($bridgetmp, $realif);
4007
			}
4008
		}
4009

    
4010
		$grouptmp = link_interface_to_group($interface);
4011
		if (!empty($grouptmp)) {
4012
			array_walk($grouptmp, 'interface_group_add_member');
4013
		}
4014

    
4015
		if ($interface == "lan") {
4016
			/* make new hosts file */
4017
			system_hosts_generate();
4018
		}
4019

    
4020
		if ($reloadall == true) {
4021

    
4022
			/* reconfigure static routes (kernel may have deleted them) */
4023
			system_routing_configure($interface);
4024

    
4025
			/* reload ipsec tunnels */
4026
			send_event("service reload ipsecdns");
4027

    
4028
			if (isset($config['dnsmasq']['enable'])) {
4029
				services_dnsmasq_configure();
4030
			}
4031

    
4032
			if (isset($config['unbound']['enable'])) {
4033
				services_unbound_configure();
4034
			}
4035

    
4036
			/* update dyndns */
4037
			send_event("service reload dyndns {$interface}");
4038

    
4039
			/* reload captive portal */
4040
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4041
				require_once('captiveportal.inc');
4042
			}
4043
			captiveportal_init_rules_byinterface($interface);
4044
		}
4045
	}
4046

    
4047
	interfaces_staticarp_configure($interface);
4048
	return 0;
4049
}
4050

    
4051
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4052
	global $config, $g;
4053

    
4054
	if (!is_array($wancfg)) {
4055
		return;
4056
	}
4057

    
4058
	if (!isset($wancfg['enable'])) {
4059
		return;
4060
	}
4061

    
4062
	/* If the interface is not configured via another, exit */
4063
	if (empty($wancfg['track6-interface'])) {
4064
		return;
4065
	}
4066

    
4067
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4068
	$realif = get_real_interface($interface);
4069
	$linklocal = find_interface_ipv6_ll($realif, true);
4070
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4071
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
4072
	}
4073
	/* XXX: This might break for good on a carp installation using link-local as network ips */
4074
	/* XXX: Probably should remove? */
4075
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
4076

    
4077
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4078
	if (!isset($trackcfg['enable'])) {
4079
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4080
		return;
4081
	}
4082

    
4083
	switch ($trackcfg['ipaddrv6']) {
4084
		case "6to4":
4085
			if ($g['debug']) {
4086
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4087
			}
4088
			interface_track6_6to4_configure($interface, $wancfg);
4089
			break;
4090
		case "6rd":
4091
			if ($g['debug']) {
4092
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4093
			}
4094
			interface_track6_6rd_configure($interface, $wancfg);
4095
			break;
4096
		case "dhcp6":
4097
			if ($linkupevent == true) {
4098
				/*
4099
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4100
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4101
				 *
4102
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4103
				 */
4104
				$parentrealif = get_real_interface($wancfg['track6-interface']);
4105
				$pidv6 = find_dhcp6c_process($parentrealif);
4106
				if ($pidv6) {
4107
					posix_kill($pidv6, SIGHUP);
4108
				}
4109
			}
4110
			break;
4111
	}
4112

    
4113
	if ($linkupevent == false && !platform_booting()) {
4114
		if (!function_exists('services_dhcpd_configure')) {
4115
			require_once("services.inc");
4116
		}
4117

    
4118
		/* restart dns servers (defering dhcpd reload) */
4119
		if (isset($config['unbound']['enable'])) {
4120
			services_unbound_configure(false);
4121
		}
4122
		if (isset($config['dnsmasq']['enable'])) {
4123
			services_dnsmasq_configure(false);
4124
		}
4125

    
4126
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4127
		services_dhcpd_configure("inet6");
4128
	}
4129

    
4130
	return 0;
4131
}
4132

    
4133
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4134
	global $config, $g;
4135
	global $interface_ipv6_arr_cache;
4136
	global $interface_snv6_arr_cache;
4137

    
4138
	if (!is_array($lancfg)) {
4139
		return;
4140
	}
4141

    
4142
	/* If the interface is not configured via another, exit */
4143
	if (empty($lancfg['track6-interface'])) {
4144
		return;
4145
	}
4146

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

    
4153
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4154
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4155
		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']));
4156
		return;
4157
	}
4158
	$hexwanv4 = return_hex_ipv4($ip4address);
4159

    
4160
	/* create the long prefix notation for math, save the prefix length */
4161
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4162
	$rd6prefixlen = $rd6prefix[1];
4163
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4164

    
4165
	/* binary presentation of the prefix for all 128 bits. */
4166
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4167

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

    
4173
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4174
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4175
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4176
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4177
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4178
	/* fill the rest out with zeros */
4179
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4180

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

    
4184
	$lanif = get_real_interface($interface);
4185
	$oip = find_interface_ipv6($lanif);
4186
	if (is_ipaddrv6($oip)) {
4187
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4188
	}
4189
	unset($interface_ipv6_arr_cache[$lanif]);
4190
	unset($interface_snv6_arr_cache[$lanif]);
4191
	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));
4192
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4193

    
4194
	return 0;
4195
}
4196

    
4197
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4198
	global $config, $g;
4199
	global $interface_ipv6_arr_cache;
4200
	global $interface_snv6_arr_cache;
4201

    
4202
	if (!is_array($lancfg)) {
4203
		return;
4204
	}
4205

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

    
4211
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4212
	if (empty($wancfg)) {
4213
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4214
		return;
4215
	}
4216

    
4217
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4218
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4219
		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']));
4220
		return;
4221
	}
4222
	$hexwanv4 = return_hex_ipv4($ip4address);
4223

    
4224
	/* create the long prefix notation for math, save the prefix length */
4225
	$sixto4prefix = "2002::";
4226
	$sixto4prefixlen = 16;
4227
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4228

    
4229
	/* binary presentation of the prefix for all 128 bits. */
4230
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4231

    
4232
	/* just save the left prefix length bits */
4233
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4234
	/* add the v4 address */
4235
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4236
	/* add the custom prefix id */
4237
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4238
	/* fill the rest out with zeros */
4239
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4240

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

    
4244
	$lanif = get_real_interface($interface);
4245
	$oip = find_interface_ipv6($lanif);
4246
	if (is_ipaddrv6($oip)) {
4247
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4248
	}
4249
	unset($interface_ipv6_arr_cache[$lanif]);
4250
	unset($interface_snv6_arr_cache[$lanif]);
4251
	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));
4252
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4253

    
4254
	return 0;
4255
}
4256

    
4257
function interface_6rd_configure($interface = "wan", $wancfg) {
4258
	global $config, $g;
4259

    
4260
	/* because this is a tunnel interface we can only function
4261
	 *	with a public IPv4 address on the interface */
4262

    
4263
	if (!is_array($wancfg)) {
4264
		return;
4265
	}
4266

    
4267
	if (!is_module_loaded('if_stf.ko')) {
4268
		mwexec('/sbin/kldload if_stf.ko');
4269
	}
4270

    
4271
	$wanif = get_real_interface($interface);
4272
	$ip4address = find_interface_ip($wanif);
4273
	if (!is_ipaddrv4($ip4address)) {
4274
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4275
		return false;
4276
	}
4277
	$hexwanv4 = return_hex_ipv4($ip4address);
4278

    
4279
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4280
		$wancfg['prefix-6rd-v4plen'] = 0;
4281
	}
4282

    
4283
	/* create the long prefix notation for math, save the prefix length */
4284
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4285
	$rd6prefixlen = $rd6prefix[1];
4286
	$brgw = explode('.', $wancfg['gateway-6rd']);
4287
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4288
	$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);
4289
	if (strlen($rd6brgw) < 128) {
4290
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4291
	}
4292
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4293
	unset($brgw);
4294
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4295

    
4296
	/* binary presentation of the prefix for all 128 bits. */
4297
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4298

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

    
4306
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4307
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4308

    
4309

    
4310
	/* XXX: need to extend to support variable prefix size for v4 */
4311
	$stfiface = "{$interface}_stf";
4312
	if (does_interface_exist($stfiface)) {
4313
		pfSense_interface_destroy($stfiface);
4314
	}
4315
	$tmpstfiface = pfSense_interface_create("stf");
4316
	pfSense_interface_rename($tmpstfiface, $stfiface);
4317
	pfSense_interface_flags($stfiface, IFF_LINK2);
4318
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4319
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4320
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4321
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4322
	}
4323
	if ($g['debug']) {
4324
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4325
	}
4326

    
4327
	/* write out a default router file */
4328
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4329
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4330

    
4331
	$ip4gateway = get_interface_gateway($interface);
4332
	if (is_ipaddrv4($ip4gateway)) {
4333
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
4334
	}
4335

    
4336
	/* configure dependent interfaces */
4337
	if (!platform_booting()) {
4338
		link_interface_to_track6($interface, "update");
4339
	}
4340

    
4341
	return 0;
4342
}
4343

    
4344
function interface_6to4_configure($interface = "wan", $wancfg) {
4345
	global $config, $g;
4346

    
4347
	/* because this is a tunnel interface we can only function
4348
	 *	with a public IPv4 address on the interface */
4349

    
4350
	if (!is_array($wancfg)) {
4351
		return;
4352
	}
4353

    
4354
	$wanif = get_real_interface($interface);
4355
	$ip4address = find_interface_ip($wanif);
4356
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4357
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4358
		return false;
4359
	}
4360

    
4361
	/* create the long prefix notation for math, save the prefix length */
4362
	$stfprefixlen = 16;
4363
	$stfprefix = Net_IPv6::uncompress("2002::");
4364
	$stfarr = explode(":", $stfprefix);
4365
	$v4prefixlen = "0";
4366

    
4367
	/* we need the hex form of the interface IPv4 address */
4368
	$ip4arr = explode(".", $ip4address);
4369
	$hexwanv4 = "";
4370
	foreach ($ip4arr as $octet) {
4371
		$hexwanv4 .= sprintf("%02x", $octet);
4372
	}
4373

    
4374
	/* we need the hex form of the broker IPv4 address */
4375
	$ip4arr = explode(".", "192.88.99.1");
4376
	$hexbrv4 = "";
4377
	foreach ($ip4arr as $octet) {
4378
		$hexbrv4 .= sprintf("%02x", $octet);
4379
	}
4380

    
4381
	/* binary presentation of the prefix for all 128 bits. */
4382
	$stfprefixbin = "";
4383
	foreach ($stfarr as $element) {
4384
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4385
	}
4386
	/* just save the left prefix length bits */
4387
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4388

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

    
4393
	/* for the local subnet too. */
4394
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4395
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4396

    
4397
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4398
	$stfbrarr = array();
4399
	$stfbrbinarr = array();
4400
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4401
	foreach ($stfbrbinarr as $bin) {
4402
		$stfbrarr[] = dechex(bindec($bin));
4403
	}
4404
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4405

    
4406
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4407
	$stflanarr = array();
4408
	$stflanbinarr = array();
4409
	$stflanbinarr = str_split($stflanbin, 16);
4410
	foreach ($stflanbinarr as $bin) {
4411
		$stflanarr[] = dechex(bindec($bin));
4412
	}
4413
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4414
	$stflanarr[7] = 1;
4415
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4416

    
4417
	/* setup the stf interface */
4418
	if (!is_module_loaded("if_stf")) {
4419
		mwexec("/sbin/kldload if_stf.ko");
4420
	}
4421
	$stfiface = "{$interface}_stf";
4422
	if (does_interface_exist($stfiface)) {
4423
		pfSense_interface_destroy($stfiface);
4424
	}
4425
	$tmpstfiface = pfSense_interface_create("stf");
4426
	pfSense_interface_rename($tmpstfiface, $stfiface);
4427
	pfSense_interface_flags($stfiface, IFF_LINK2);
4428
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4429

    
4430
	if ($g['debug']) {
4431
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4432
	}
4433

    
4434
	/* write out a default router file */
4435
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4436
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4437

    
4438
	$ip4gateway = get_interface_gateway($interface);
4439
	if (is_ipaddrv4($ip4gateway)) {
4440
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
4441
	}
4442

    
4443
	if (!platform_booting()) {
4444
		link_interface_to_track6($interface, "update");
4445
	}
4446

    
4447
	return 0;
4448
}
4449

    
4450
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4451
	global $config, $g;
4452

    
4453
	if (!is_array($wancfg)) {
4454
		return;
4455
	}
4456

    
4457
	$wanif = get_real_interface($interface, "inet6");
4458
	$dhcp6cconf = "";
4459

    
4460
	if (!empty($config['system']['global-v6duid'])) {
4461
		// Write the DUID file
4462
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4463
		    log_error(gettext("Failed to write user DUID file!"));
4464
		}
4465
	}
4466

    
4467
	/* accept router advertisements for this interface                 */
4468
	/* Moved to early in the function as sometimes interface not ready */
4469
	/* RTSOLD fails as interface does not accept .....                 */
4470

    
4471
	log_error("Accept router advertisements on interface {$wanif} ");
4472
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4473

    
4474
	if ($wancfg['adv_dhcp6_config_file_override']) {
4475
		// DHCP6 Config File Override
4476
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4477
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4478
		// DHCP6 Config File Advanced
4479
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4480
	} else {
4481
		// DHCP6 Config File Basic
4482
		$dhcp6cconf .= "interface {$wanif} {\n";
4483

    
4484
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4485
		if ($wancfg['ipaddrv6'] == "slaac") {
4486
			$dhcp6cconf .= "\tinformation-only;\n";
4487
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4488
			$dhcp6cconf .= "\trequest domain-name;\n";
4489
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4490
			$dhcp6cconf .= "};\n";
4491
		} else {
4492
			$trackiflist = array();
4493
			$iflist = link_interface_to_track6($interface);
4494
			foreach ($iflist as $ifname => $ifcfg) {
4495
				if (is_numeric($ifcfg['track6-prefix-id'])) {
4496
					$trackiflist[$ifname] = $ifcfg;
4497
				}
4498
			}
4499

    
4500
			/* skip address request if this is set */
4501
			if (!isset($wancfg['dhcp6prefixonly'])) {
4502
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4503
			}
4504
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4505
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4506
			}
4507

    
4508
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4509
			$dhcp6cconf .= "\trequest domain-name;\n";
4510

    
4511
			/*
4512
			 * dhcp6c will run different scripts depending on
4513
			 * whether dhcpwithoutra is set or unset.
4514
			 */
4515
			if (isset($wancfg['dhcp6withoutra'])) {
4516
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4517
			} else {
4518
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4519
			}
4520
			$dhcp6cconf .= "};\n";
4521

    
4522
			if (!isset($wancfg['dhcp6prefixonly'])) {
4523
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4524
			}
4525

    
4526
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4527
				/* Setup the prefix delegation */
4528
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4529
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4530
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4531
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4532
				}
4533
				foreach ($trackiflist as $friendly => $ifcfg) {
4534
					if ($g['debug']) {
4535
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4536
					}
4537
					$realif = get_real_interface($friendly);
4538
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4539
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4540
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4541
					$dhcp6cconf .= "\t};\n";
4542
				}
4543
				unset($preflen, $iflist, $ifcfg, $ifname);
4544
				$dhcp6cconf .= "};\n";
4545
			}
4546
			unset($trackiflist);
4547
		}
4548
	}
4549

    
4550
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4551
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4552

    
4553
	/* wide-dhcp6c works for now. */
4554
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4555
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4556
		unset($dhcp6cconf);
4557
		return 1;
4558
	}
4559
	unset($dhcp6cconf);
4560

    
4561
	/*************** Script Debug Logging ***************************
4562
	Both dhcp6 scripts now have a logging message built in.
4563
	These logging messages ONLY appear if dhcp6c debug logging is set.
4564
	The logging messages appear in the dhcp section of the logs,
4565
	not in system.
4566

    
4567
	These scripts now also take advantage of the REASON= env vars
4568
	supplied by dhcp6c.
4569
	****************************************************************/
4570

    
4571
	/* Script create for dhcp6withoutRA mode */
4572
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4573
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4574
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4575
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4576
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4577
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4578
	// Need to pass params to  the final script
4579
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4580
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4581
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4582
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4583
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
4584
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
4585
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4586
	if ($debugOption == '-D') {
4587
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4588
	}
4589
	$dhcp6cscriptwithoutra .= ";;\n";
4590
	$dhcp6cscriptwithoutra .= "REBIND)\n";
4591
	if ($debugOption == '-D') {
4592
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4593
	}
4594
	$dhcp6cscriptwithoutra .= ";;\n";
4595
	if (isset($wancfg['dhcp6norelease'])) {
4596
		$dhcp6cscriptwithoutra .= "EXIT)\n";
4597
	} else {
4598
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
4599
	}
4600
	if ($debugOption == '-D') {
4601
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4602
	}
4603
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4604
	$dhcp6cscriptwithoutra .= ";;\n";
4605
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
4606
	if ($debugOption == '-D') {
4607
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4608
	}
4609
	$dhcp6cscriptwithoutra .= "esac\n";
4610
	if (!@file_put_contents(
4611
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4612
	    $dhcp6cscriptwithoutra)) {
4613
		printf("Error: cannot open " .
4614
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4615
		    "interface_dhcpv6_configure() for writing.\n");
4616
		unset($dhcp6cscriptwithoutra);
4617
		return 1;
4618
	}
4619

    
4620
	unset($dhcp6cscriptwithoutra);
4621
	@chmod(
4622
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4623
	    0755);
4624

    
4625
	/*
4626
	 * Dual mode wan_dhcp6c script with variations depending on node
4627
	 * dhcp6 will run the wan ipv6 configure
4628
	 */
4629
	$dhcp6cscript  = "#!/bin/sh\n";
4630
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4631
	if (!isset($wancfg['dhcp6withoutra'])) {
4632
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4633
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4634
		$dhcp6cscript .= "case \$REASON in\n";
4635
		$dhcp6cscript .= "REQUEST)\n";
4636
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4637
		if ($debugOption == '-D') {
4638
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4639
		}
4640
		$dhcp6cscript .= ";;\n";
4641
		$dhcp6cscript .= "REBIND)\n";
4642
		if ($debugOption == '-D') {
4643
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4644
		}
4645
		$dhcp6cscript .= ";;\n";
4646
		if (isset($wancfg['dhcp6norelease'])) {
4647
			$dhcp6cscript .= "EXIT)\n";
4648
		} else {
4649
			$dhcp6cscript .= "RELEASE)\n";
4650
		}
4651
		if ($debugOption == '-D') {
4652
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4653
		}
4654
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4655
		$dhcp6cscript .= ";;\n";
4656
		$dhcp6cscript .= "RENEW|INFO)\n";
4657
		if ($debugOption == '-D') {
4658
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4659
		}
4660
		$dhcp6cscript .= "esac\n";
4661
	} else {
4662
		// Need to get the parameters from the dhcp6cwithoutRA run
4663
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
4664
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
4665
		$dhcp6cscript .= "/bin/sleep 1\n";
4666
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4667
	}
4668

    
4669
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4670
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4671
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4672
		unset($dhcp6cscript);
4673
		return 1;
4674
	}
4675
	unset($dhcp6cscript);
4676
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4677

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

    
4684
	/* non ipoe Process */
4685
	if (!isset($wancfg['dhcp6withoutra'])) {
4686
		/*
4687
		 * We only want this script to run once, and if it runs twice
4688
		 * then do not launch dhcp6c again, this only happens if
4689
		 * dhcpwithoutra is not set.
4690
		 *
4691
		 * Check for a lock file, trying to prevent multiple instances
4692
		 * of dhcp6c being launched
4693
		 */
4694
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
4695
		/*
4696
		 * Create the lock file, trying to prevent multiple instances
4697
		 * of dhcp6c being launched
4698
		 */
4699
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
4700
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
4701
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4702
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4703
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
4704
		$rtsoldscript .= "\tfi\n";
4705
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
4706
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
4707
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4708
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4709
		$rtsoldscript .= "else\n";
4710
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
4711
		$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c_{$wanif}.pid\")\n";
4712
		$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
4713
		$rtsoldscript .= "fi\n";
4714
	} else {
4715
		/*
4716
		 * The script needs to run in dhcp6withoutra mode as RA may
4717
		 * not have been received, or there can be a delay with
4718
		 * certain ISPs
4719
		 */
4720
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
4721
		$rtsoldscript .= "/bin/sleep 1\n";
4722
	}
4723
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4724
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4725
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4726
		unset($rtsoldscript);
4727
		return 1;
4728
	}
4729
	unset($rtsoldscript);
4730
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4731

    
4732
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4733
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4734
		log_error("Killing running rtsold process");
4735
		sleep(2);
4736
	}
4737

    
4738
	if (isset($wancfg['dhcp6withoutra'])) {
4739
		/*
4740
		 * Start dhcp6c here if we don't want to wait for ra - calls
4741
		 * seperate function
4742
		 *
4743
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
4744
		 * will then run the configure on receipt of the RA.
4745
		 *
4746
		 * Already started. interface_dhcpv6_configure() appears to get
4747
		 * called multiple times.
4748
		 *
4749
		 * Taking the interface down or releasing will kill the client.
4750
		 */
4751
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
4752
		{
4753
			/*
4754
			 * If the interface is being brought up, wait for the
4755
			 * interface to configure accept RA before launching.
4756
			 * Otherwise it is not ready to accept and will fail.
4757
			 */
4758
			sleep(3);
4759
			run_dhcp6client_process($wanif,$interface,$wancfg);
4760
		}
4761
	} else {
4762
		/*
4763
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
4764
		 * ( it does not background, it exits! ) It will launch dhcp6c
4765
		 * if dhcpwihtoutra is not set
4766
		 */
4767
		log_error("Starting rtsold process");
4768
		sleep(2);
4769
		mwexec("/usr/sbin/rtsold -1 " .
4770
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
4771
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
4772
		    $wanif);
4773
	}
4774
	/*
4775
	 * NOTE: will be called from rtsold invoked script
4776
	 * link_interface_to_track6($interface, "update");
4777
	 */
4778

    
4779
	return 0;
4780
}
4781

    
4782
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4783
	global $g;
4784

    
4785
	$send_options = "";
4786
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4787
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4788
		foreach ($options as $option) {
4789
			$send_options .= "\tsend " . trim($option) . ";\n";
4790
		}
4791
	}
4792

    
4793
	$request_options = "";
4794
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4795
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4796
		foreach ($options as $option) {
4797
			$request_options .= "\trequest " . trim($option) . ";\n";
4798
		}
4799
	}
4800

    
4801
	$information_only = "";
4802
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4803
		$information_only = "\tinformation-only;\n";
4804
	}
4805

    
4806
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4807
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4808
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4809
	}
4810

    
4811
	$interface_statement  = "interface";
4812
	$interface_statement .= " {$wanif}";
4813
	$interface_statement .= " {\n";
4814
	$interface_statement .= "$send_options";
4815
	$interface_statement .= "$request_options";
4816
	$interface_statement .= "$information_only";
4817
	$interface_statement .= "$script";
4818
	$interface_statement .= "};\n";
4819

    
4820
	$id_assoc_statement_address = "";
4821
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4822
		$id_assoc_statement_address .= "id-assoc";
4823
		$id_assoc_statement_address .= " na";
4824
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4825
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4826
		}
4827
		$id_assoc_statement_address .= " { ";
4828

    
4829
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4830
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4831
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4832
			$id_assoc_statement_address .= "\n\taddress";
4833
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4834
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4835
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4836
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4837
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4838
			}
4839
			$id_assoc_statement_address .= ";\n";
4840
		}
4841

    
4842
		$id_assoc_statement_address .= "};\n";
4843
	}
4844

    
4845
	$id_assoc_statement_prefix = "";
4846
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4847
		$id_assoc_statement_prefix .= "id-assoc";
4848
		$id_assoc_statement_prefix .= " pd";
4849
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4850
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4851
		}
4852
		$id_assoc_statement_prefix .= " { ";
4853

    
4854
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4855
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4856
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4857
			$id_assoc_statement_prefix .= "\n\tprefix";
4858
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4859
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4860
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4861
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4862
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4863
			}
4864
			$id_assoc_statement_prefix .= ";";
4865
		}
4866

    
4867
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
4868
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4869
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4870
			$id_assoc_statement_prefix .= " {$realif}";
4871
			$id_assoc_statement_prefix .= " {\n";
4872
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4873
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4874
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4875
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4876
			}
4877
			$id_assoc_statement_prefix .= "\t};";
4878
		}
4879

    
4880
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4881
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4882
			$id_assoc_statement_prefix .= "\n";
4883
		}
4884

    
4885
		$id_assoc_statement_prefix .= "};\n";
4886
	}
4887

    
4888
	$authentication_statement = "";
4889
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4890
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4891
		$authentication_statement .= "authentication";
4892
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4893
		$authentication_statement .= " {\n";
4894
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4895
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4896
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4897
		}
4898
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4899
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4900
		}
4901
		$authentication_statement .= "};\n";
4902
	}
4903

    
4904
	$key_info_statement = "";
4905
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4906
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4907
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4908
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4909
		$key_info_statement .= "keyinfo";
4910
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4911
		$key_info_statement .= " {\n";
4912
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4913
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4914
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4915
		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'])) {
4916
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4917
		}
4918
		$key_info_statement .= "};\n";
4919
	}
4920

    
4921
	$dhcp6cconf  = $interface_statement;
4922
	$dhcp6cconf .= $id_assoc_statement_address;
4923
	$dhcp6cconf .= $id_assoc_statement_prefix;
4924
	$dhcp6cconf .= $authentication_statement;
4925
	$dhcp6cconf .= $key_info_statement;
4926

    
4927
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4928

    
4929
	return $dhcp6cconf;
4930
}
4931

    
4932

    
4933
function DHCP6_Config_File_Override($wancfg, $wanif) {
4934

    
4935
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4936

    
4937
	if ($dhcp6cconf === false) {
4938
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4939
		return '';
4940
	} else {
4941
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4942
	}
4943
}
4944

    
4945

    
4946
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4947

    
4948
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4949

    
4950
	return $dhcp6cconf;
4951
}
4952

    
4953

    
4954
function interface_dhcp_configure($interface = "wan") {
4955
	global $config, $g, $vlanprio_values;
4956

    
4957
	$ifcfg = $config['interfaces'][$interface];
4958
	if (empty($ifcfg)) {
4959
		$ifcfg = array();
4960
	}
4961

    
4962
	$dhclientconf_vlantag = "";
4963
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
4964
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
4965
	}
4966

    
4967
	/* generate dhclient_wan.conf */
4968
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4969
	if (!$fd) {
4970
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4971
		return 1;
4972
	}
4973

    
4974
	if ($ifcfg['dhcphostname']) {
4975
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
4976
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
4977
	} else {
4978
		$dhclientconf_hostname = "";
4979
	}
4980

    
4981
	$realif = get_real_interface($interface);
4982
	if (empty($realif)) {
4983
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4984
		return 0;
4985
	}
4986
	$dhclientconf = "";
4987

    
4988
	$dhclientconf .= <<<EOD
4989
interface "{$realif}" {
4990
	supersede interface-mtu 0;
4991
	timeout 60;
4992
	retry 15;
4993
	select-timeout 0;
4994
	initial-interval 1;
4995
	{$dhclientconf_vlantag}
4996
	{$dhclientconf_hostname}
4997
	script "/usr/local/sbin/pfSense-dhclient-script";
4998
EOD;
4999

    
5000
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5001
		$dhclientconf .= <<<EOD
5002

    
5003
	reject {$ifcfg['dhcprejectfrom']};
5004
EOD;
5005
	}
5006
	$dhclientconf .= <<<EOD
5007

    
5008
}
5009

    
5010
EOD;
5011

    
5012
	// DHCP Config File Advanced
5013
	if ($ifcfg['adv_dhcp_config_advanced']) {
5014
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5015
	}
5016

    
5017
	if (is_ipaddr($ifcfg['alias-address'])) {
5018
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5019
		$dhclientconf .= <<<EOD
5020
alias {
5021
	interface "{$realif}";
5022
	fixed-address {$ifcfg['alias-address']};
5023
	option subnet-mask {$subnetmask};
5024
}
5025

    
5026
EOD;
5027
	}
5028

    
5029
	// DHCP Config File Override
5030
	if ($ifcfg['adv_dhcp_config_file_override']) {
5031
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5032
	}
5033

    
5034
	fwrite($fd, $dhclientconf);
5035
	fclose($fd);
5036

    
5037
	/* bring wan interface up before starting dhclient */
5038
	if ($realif) {
5039
		interfaces_bring_up($realif);
5040
	}
5041

    
5042
	/* Make sure dhclient is not running */
5043
	kill_dhclient_process($realif);
5044

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

    
5048
	return 0;
5049
}
5050

    
5051
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5052

    
5053
	$hostname = "";
5054
	if ($ifcfg['dhcphostname'] != '') {
5055
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5056
	}
5057

    
5058
	/* DHCP Protocol Timings */
5059
	$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");
5060
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5061
		$pt_variable = "{$Protocol_Timing}";
5062
		${$pt_variable} = "";
5063
		if ($ifcfg[$Protocol_Timing] != "") {
5064
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5065
		}
5066
	}
5067

    
5068
	$send_options = "";
5069
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5070
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5071
		foreach ($options as $option) {
5072
			$send_options .= "\tsend " . trim($option) . ";\n";
5073
		}
5074
	}
5075

    
5076
	$request_options = "";
5077
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5078
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5079
	}
5080

    
5081
	$required_options = "";
5082
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5083
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5084
	}
5085

    
5086
	$option_modifiers = "";
5087
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5088
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5089
		foreach ($modifiers as $modifier) {
5090
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5091
		}
5092
	}
5093

    
5094
	$dhclientconf  = "interface \"{$realif}\" {\n";
5095
	$dhclientconf .= "\n";
5096
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5097
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5098
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5099
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5100
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5101
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5102
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5103
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5104
	$dhclientconf .= "\n";
5105
	$dhclientconf .= "# DHCP Protocol Options\n";
5106
	$dhclientconf .= "{$hostname}";
5107
	$dhclientconf .= "{$send_options}";
5108
	$dhclientconf .= "{$request_options}";
5109
	$dhclientconf .= "{$required_options}";
5110
	$dhclientconf .= "{$option_modifiers}";
5111
	$dhclientconf .= "\n";
5112
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5113
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5114
	}
5115
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5116
	$dhclientconf .= "}\n";
5117

    
5118
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5119

    
5120
	return $dhclientconf;
5121
}
5122

    
5123
function DHCP_Config_Option_Split($option_string) {
5124
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5125
	return $matches ? $matches[0] : [];
5126
}
5127

    
5128
function DHCP_Config_File_Override($ifcfg, $realif) {
5129

    
5130
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5131

    
5132
	if ($dhclientconf === false) {
5133
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5134
		return '';
5135
	} else {
5136
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5137
	}
5138
}
5139

    
5140

    
5141
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5142

    
5143
	/* Apply Interface Substitutions */
5144
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5145

    
5146
	/* Apply Hostname Substitutions */
5147
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5148

    
5149
	/* Arrays of MAC Address Types, Cases, Delimiters */
5150
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5151
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5152
	$various_mac_cases      = array("U", "L");
5153
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5154

    
5155
	/* Apply MAC Address Substitutions */
5156
	foreach ($various_mac_types as $various_mac_type) {
5157
		foreach ($various_mac_cases as $various_mac_case) {
5158
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5159

    
5160
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5161
				if ($res !== false) {
5162

    
5163
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5164
					if ("$various_mac_case" == "U") {
5165
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5166
					}
5167
					if ("$various_mac_case" == "L") {
5168
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5169
					}
5170

    
5171
					if ("$various_mac_type" == "mac_addr_hex") {
5172
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5173
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5174
						$dhcpclientconf_mac_hex = "";
5175
						$delimiter = "";
5176
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5177
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5178
							$delimiter = ":";
5179
						}
5180
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5181
					}
5182

    
5183
					/* MAC Address Delimiter Substitutions */
5184
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5185

    
5186
					/* Apply MAC Address Substitutions */
5187
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5188
				}
5189
			}
5190
		}
5191
	}
5192

    
5193
	return $dhclientconf;
5194
}
5195

    
5196
function interfaces_group_setup() {
5197
	global $config;
5198

    
5199
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
5200
		return;
5201
	}
5202

    
5203
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5204
		interface_group_setup($groupar);
5205
	}
5206

    
5207
	return;
5208
}
5209

    
5210
function interface_group_setup(&$groupname /* The parameter is an array */) {
5211
	global $config;
5212

    
5213
	if (!is_array($groupname)) {
5214
		return;
5215
	}
5216
	$members = explode(" ", $groupname['members']);
5217
	foreach ($members as $ifs) {
5218
		$realif = get_real_interface($ifs);
5219
		if ($realif && does_interface_exist($realif)) {
5220
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5221
		}
5222
	}
5223

    
5224
	return;
5225
}
5226

    
5227
function is_interface_group($if) {
5228
	global $config;
5229

    
5230
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5231
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5232
			if ($groupentry['ifname'] === $if) {
5233
				return true;
5234
			}
5235
		}
5236
	}
5237

    
5238
	return false;
5239
}
5240

    
5241
function interface_group_add_member($interface, $groupname) {
5242
	$interface = get_real_interface($interface);
5243
	if (does_interface_exist($interface)) {
5244
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5245
	}
5246
}
5247

    
5248
/* COMPAT Function */
5249
function convert_friendly_interface_to_real_interface_name($interface) {
5250
	return get_real_interface($interface);
5251
}
5252

    
5253
/* COMPAT Function */
5254
function get_real_wan_interface($interface = "wan") {
5255
	return get_real_interface($interface);
5256
}
5257

    
5258
/* COMPAT Function */
5259
function get_current_wan_address($interface = "wan") {
5260
	return get_interface_ip($interface);
5261
}
5262

    
5263
/*
5264
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5265
 */
5266
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5267
	global $config;
5268

    
5269
	/* XXX: For speed reasons reference directly the interface array */
5270
	$ifdescrs = &$config['interfaces'];
5271
	//$ifdescrs = get_configured_interface_list(true);
5272

    
5273
	foreach ($ifdescrs as $if => $ifname) {
5274
		if ($if == $interface || $ifname['if'] == $interface) {
5275
			return $if;
5276
		}
5277

    
5278
		if (get_real_interface($if) == $interface) {
5279
			return $if;
5280
		}
5281

    
5282
		if ($checkparent == false) {
5283
			continue;
5284
		}
5285

    
5286
		$int = get_parent_interface($if, true);
5287
		if (is_array($int)) {
5288
			foreach ($int as $iface) {
5289
				if ($iface == $interface) {
5290
					return $if;
5291
				}
5292
			}
5293
		}
5294
	}
5295

    
5296
	if ($interface == "enc0") {
5297
		return 'IPsec';
5298
	}
5299
}
5300

    
5301
/* attempt to resolve interface to friendly descr */
5302
function convert_friendly_interface_to_friendly_descr($interface) {
5303
	global $config;
5304

    
5305
	switch ($interface) {
5306
		case "l2tp":
5307
			$ifdesc = "L2TP";
5308
			break;
5309
		case "pptp":
5310
			$ifdesc = "PPTP";
5311
			break;
5312
		case "pppoe":
5313
			$ifdesc = "PPPoE";
5314
			break;
5315
		case "openvpn":
5316
			$ifdesc = "OpenVPN";
5317
			break;
5318
		case "lo0":
5319
			$ifdesc = "Loopback";
5320
			break;
5321
		case "enc0":
5322
		case "ipsec":
5323
		case "IPsec":
5324
			$ifdesc = "IPsec";
5325
			break;
5326
		default:
5327
			if (isset($config['interfaces'][$interface])) {
5328
				if (empty($config['interfaces'][$interface]['descr'])) {
5329
					$ifdesc = strtoupper($interface);
5330
				} else {
5331
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5332
				}
5333
				break;
5334
			} else if (substr($interface, 0, 4) == '_vip') {
5335
				if (is_array($config['virtualip']['vip'])) {
5336
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5337
						if ($vip['mode'] == "carp") {
5338
							if ($interface == "_vip{$vip['uniqid']}") {
5339
								$descr = $vip['subnet'];
5340
								$descr .= " (vhid {$vip['vhid']})";
5341
								if (!empty($vip['descr'])) {
5342
									$descr .= " - " .$vip['descr'];
5343
								}
5344
								return $descr;
5345
							}
5346
						}
5347
					}
5348
				}
5349
			} else if (substr($interface, 0, 5) == '_lloc') {
5350
				return get_interface_linklocal($interface);
5351
			} else {
5352
				if (is_array($config['ifgroups']['ifgroupentry'])) {
5353
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5354
						if ($ifgen['ifname'] === $interface) {
5355
							return $ifgen['ifname'];
5356
						}
5357
					}
5358
				}
5359

    
5360
				/* if list */
5361
				$ifdescrs = get_configured_interface_with_descr(true);
5362
				foreach ($ifdescrs as $if => $ifname) {
5363
					if ($if == $interface || $ifname == $interface) {
5364
						return $ifname;
5365
					}
5366
				}
5367
			}
5368
			break;
5369
	}
5370

    
5371
	return $ifdesc;
5372
}
5373

    
5374
function convert_real_interface_to_friendly_descr($interface) {
5375

    
5376
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5377

    
5378
	if (!empty($ifdesc)) {
5379
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5380
	}
5381

    
5382
	return $interface;
5383
}
5384

    
5385
/*
5386
 *  get_parent_interface($interface):
5387
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5388
 *				or virtual interface (i.e. vlan)
5389
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5390
 *			-- returns $interface passed in if $interface parent is not found
5391
 *			-- returns empty array if an invalid interface is passed
5392
 *	(Only handles ppps and vlans now.)
5393
 */
5394
function get_parent_interface($interface, $avoidrecurse = false) {
5395
	global $config;
5396

    
5397
	$parents = array();
5398
	//Check that we got a valid interface passed
5399
	$realif = get_real_interface($interface);
5400
	if ($realif == NULL) {
5401
		return $parents;
5402
	}
5403

    
5404
	// If we got a real interface, find it's friendly assigned name
5405
	if ($interface == $realif && $avoidrecurse == false) {
5406
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5407
	}
5408

    
5409
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5410
		$ifcfg = $config['interfaces'][$interface];
5411
		switch ($ifcfg['ipaddr']) {
5412
			case "ppp":
5413
			case "pppoe":
5414
			case "pptp":
5415
			case "l2tp":
5416
				if (empty($parents)) {
5417
					if (is_array($config['ppps']['ppp'])) {
5418
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5419
							if ($ifcfg['if'] == $ppp['if']) {
5420
								$ports = explode(',', $ppp['ports']);
5421
								foreach ($ports as $pid => $parent_if) {
5422
									$parents[$pid] = get_real_interface($parent_if);
5423
								}
5424
								break;
5425
							}
5426
						}
5427
					}
5428
				}
5429
				break;
5430
			case "dhcp":
5431
			case "static":
5432
			default:
5433
				// Handle _vlans
5434
				$vlan = interface_is_vlan($ifcfg['if']);
5435
				if ($vlan != NULL) {
5436
					$parents[0] = $vlan['if'];
5437
				}
5438
				break;
5439
		}
5440
	}
5441

    
5442
	if (empty($parents)) {
5443
		// Handle _vlans not assigned to an interface
5444
		$vlan = interface_is_vlan($realif);
5445
		if ($vlan != NULL) {
5446
			$parents[0] = $vlan['if'];
5447
		}
5448
	}
5449

    
5450
	if (empty($parents)) {
5451
		/* Handle LAGGs. */
5452
		$lagg = interface_is_lagg($realif);
5453
		if ($lagg != NULL && isset($lagg['members'])) {
5454
			$parents = explode(",", $lagg['members']);
5455
		}
5456
	}
5457

    
5458
	if (empty($parents)) {
5459
		$parents[0] = $realif;
5460
	}
5461

    
5462
	return $parents;
5463
}
5464

    
5465
/*
5466
 *  get_parent_physical_interface($interface):
5467
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5468
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5469
 */
5470
function get_parent_physical_interface($interface) {
5471
	global $config;
5472

    
5473
	$realif = get_parent_interface($interface);
5474

    
5475
	if (substr($realif[0], 0, 4) == "lagg") {
5476
		foreach ($config['laggs']['lagg'] as $lagg) {
5477
			if ($realif[0] == $lagg['laggif']) {
5478
				return explode(",", $lagg['members']);
5479
			}
5480
		}
5481
	} else {
5482
		return $realif;
5483
	}
5484
}
5485

    
5486
function interface_is_wireless_clone($wlif) {
5487
	if (!stristr($wlif, "_wlan")) {
5488
		return false;
5489
	} else {
5490
		return true;
5491
	}
5492
}
5493

    
5494
function interface_get_wireless_base($wlif) {
5495
	if (!stristr($wlif, "_wlan")) {
5496
		return $wlif;
5497
	} else {
5498
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5499
	}
5500
}
5501

    
5502
function interface_get_wireless_clone($wlif) {
5503
	if (!stristr($wlif, "_wlan")) {
5504
		return $wlif . "_wlan0";
5505
	} else {
5506
		return $wlif;
5507
	}
5508
}
5509

    
5510
function interface_list_wireless() {
5511
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5512

    
5513
	$result = array();
5514
	foreach ($portlist as $port) {
5515
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5516
			continue;
5517
		}
5518

    
5519
		$desc = $port . " ( " . get_single_sysctl(
5520
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5521

    
5522
		$result[] = array(
5523
		    "if" => $port,
5524
		    "descr" => $desc
5525
		);
5526
	}
5527

    
5528
	return $result;
5529
}
5530

    
5531
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
5532
	global $config, $g;
5533

    
5534
	$wanif = NULL;
5535

    
5536
	switch ($interface) {
5537
		case "l2tp":
5538
			$wanif = "l2tp";
5539
			break;
5540
		case "pptp":
5541
			$wanif = "pptp";
5542
			break;
5543
		case "pppoe":
5544
			$wanif = "pppoe";
5545
			break;
5546
		case "openvpn":
5547
			$wanif = "openvpn";
5548
			break;
5549
		case "IPsec":
5550
		case "ipsec":
5551
		case "enc0":
5552
			$wanif = "enc0";
5553
			break;
5554
		case "ppp":
5555
			$wanif = "ppp";
5556
			break;
5557
		default:
5558
			if (substr($interface, 0, 4) == '_vip') {
5559
				$wanif = get_configured_vip_interface($interface);
5560
				if (!empty($wanif)) {
5561
					$wanif = get_real_interface($wanif);
5562
				}
5563
				break;
5564
			} else if (substr($interface, 0, 5) == '_lloc') {
5565
				$interface = substr($interface, 5);
5566
			} else if (interface_is_vlan($interface) != NULL ||
5567
			    does_interface_exist($interface, $flush)) {
5568
				/*
5569
				 * If a real interface was already passed simply
5570
				 * pass the real interface back.  This encourages
5571
				 * the usage of this function in more cases so that
5572
				 * we can combine logic for more flexibility.
5573
				 */
5574
				$wanif = $interface;
5575
				break;
5576
			}
5577

    
5578
			if (empty($config['interfaces'][$interface])) {
5579
				break;
5580
			}
5581

    
5582
			$cfg = &$config['interfaces'][$interface];
5583

    
5584
			if ($family == "inet6") {
5585
				switch ($cfg['ipaddrv6']) {
5586
					case "6rd":
5587
					case "6to4":
5588
						$wanif = "{$interface}_stf";
5589
						break;
5590
					case 'pppoe':
5591
					case 'ppp':
5592
					case 'l2tp':
5593
					case 'pptp':
5594
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5595
							$wanif = interface_get_wireless_clone($cfg['if']);
5596
						} else {
5597
							$wanif = $cfg['if'];
5598
						}
5599
						break;
5600
					default:
5601
						switch ($cfg['ipaddr']) {
5602
							case 'pppoe':
5603
							case 'ppp':
5604
							case 'l2tp':
5605
							case 'pptp':
5606
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
5607
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) || isset($cfg['ipv6usev4iface'])) {
5608
									$wanif = $cfg['if'];
5609
								} else {
5610
									$parents = get_parent_interface($interface);
5611
									if (!empty($parents[0])) {
5612
										$wanif = $parents[0];
5613
									} else {
5614
										$wanif = $cfg['if'];
5615
									}
5616
								}
5617
								break;
5618
							default:
5619
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5620
									$wanif = interface_get_wireless_clone($cfg['if']);
5621
								} else {
5622
									$wanif = $cfg['if'];
5623
								}
5624
								break;
5625
						}
5626
						break;
5627
				}
5628
			} else {
5629
				// Wireless cloned NIC support (FreeBSD 8+)
5630
				// interface name format: $parentnic_wlanparentnic#
5631
				// example: ath0_wlan0
5632
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5633
					$wanif = interface_get_wireless_clone($cfg['if']);
5634
				} else {
5635
					$wanif = $cfg['if'];
5636
				}
5637
			}
5638
			break;
5639
	}
5640

    
5641
	return $wanif;
5642
}
5643

    
5644
/* Guess the physical interface by providing a IP address */
5645
function guess_interface_from_ip($ipaddress) {
5646

    
5647
	$family = '';
5648
	if (is_ipaddrv4($ipaddress)) {
5649
		$family = 'inet';
5650
	}
5651
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5652
		$family = 'inet6';
5653
	}
5654

    
5655
	if (empty($family)) {
5656
		return false;
5657
	}
5658

    
5659
	/* create a route table we can search */
5660
	$output = '';
5661
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
5662
	$output[0] = trim($output[0], " \n");
5663
	if (!empty($output[0])) {
5664
		return $output[0];
5665
	}
5666

    
5667
	return false;
5668
}
5669

    
5670
/*
5671
 * find_ip_interface($ip): return the interface where an ip is defined
5672
 *   (or if $bits is specified, where an IP within the subnet is defined)
5673
 */
5674
function find_ip_interface($ip, $bits = null) {
5675
	if (!is_ipaddr($ip)) {
5676
		return false;
5677
	}
5678

    
5679
	$isv6ip = is_ipaddrv6($ip);
5680

    
5681
	/* if list */
5682
	$ifdescrs = get_configured_interface_list();
5683

    
5684
	foreach ($ifdescrs as $ifdescr => $ifname) {
5685
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
5686
		if (is_null($ifip)) {
5687
			continue;
5688
		}
5689
		if (is_null($bits)) {
5690
			if ($ip == $ifip) {
5691
				$int = get_real_interface($ifname);
5692
				return $int;
5693
			}
5694
		} else {
5695
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
5696
				$int = get_real_interface($ifname);
5697
				return $int;
5698
			}
5699
		}
5700
	}
5701

    
5702
	return false;
5703
}
5704

    
5705
/*
5706
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5707
 *   (or if $bits is specified, where an IP within the subnet is found)
5708
 */
5709
function find_virtual_ip_alias($ip, $bits = null) {
5710
	global $config;
5711

    
5712
	if (!is_array($config['virtualip']['vip'])) {
5713
		return false;
5714
	}
5715
	if (!is_ipaddr($ip)) {
5716
		return false;
5717
	}
5718

    
5719
	$isv6ip = is_ipaddrv6($ip);
5720

    
5721
	foreach ($config['virtualip']['vip'] as $vip) {
5722
		if ($vip['mode'] === "ipalias") {
5723
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
5724
				continue;
5725
			}
5726
			if (is_null($bits)) {
5727
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
5728
					return $vip;
5729
				}
5730
			} else {
5731
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5732
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5733
					return $vip;
5734
				}
5735
			}
5736
		}
5737
	}
5738
	return false;
5739
}
5740

    
5741
function link_interface_to_track6($int, $action = "") {
5742
	global $config;
5743

    
5744
	if (empty($int)) {
5745
		return;
5746
	}
5747

    
5748
	if (is_array($config['interfaces'])) {
5749
		$list = array();
5750
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5751
			if (!isset($ifcfg['enable'])) {
5752
				continue;
5753
			}
5754
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5755
				if ($action == "update") {
5756
					interface_track6_configure($ifname, $ifcfg);
5757
				} else if ($action == "") {
5758
					$list[$ifname] = $ifcfg;
5759
				}
5760
			}
5761
		}
5762
		return $list;
5763
	}
5764
}
5765

    
5766
function interface_find_child_cfgmtu($realiface) {
5767
	global $config;
5768

    
5769
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5770
	$vlans = link_interface_to_vlans($realiface);
5771
	$qinqs = link_interface_to_qinqs($realiface);
5772
	$bridge = link_interface_to_bridge($realiface);
5773
	if (!empty($interface)) {
5774
		$gifs = link_interface_to_gif($interface);
5775
		$gres = link_interface_to_gre($interface);
5776
	} else {
5777
		$gifs = array();
5778
		$gres = array();
5779
	}
5780

    
5781
	$mtu = 0;
5782
	if (is_array($vlans)) {
5783
		foreach ($vlans as $vlan) {
5784
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5785
			if (empty($ifass)) {
5786
				continue;
5787
			}
5788
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5789
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5790
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5791
				}
5792
			}
5793
		}
5794
	}
5795
	if (is_array($qinqs)) {
5796
		foreach ($qinqs as $qinq) {
5797
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5798
			if (empty($ifass)) {
5799
				continue;
5800
			}
5801
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5802
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5803
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5804
				}
5805
			}
5806
		}
5807
	}
5808
	if (is_array($gifs)) {
5809
		foreach ($gifs as $gif) {
5810
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5811
			if (empty($ifass)) {
5812
				continue;
5813
			}
5814
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5815
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5816
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5817
				}
5818
			}
5819
		}
5820
	}
5821
	if (is_array($gres)) {
5822
		foreach ($gres as $gre) {
5823
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5824
			if (empty($ifass)) {
5825
				continue;
5826
			}
5827
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5828
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5829
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5830
				}
5831
			}
5832
		}
5833
	}
5834
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5835
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5836
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5837
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5838
		}
5839
	}
5840
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5841

    
5842
	return $mtu;
5843
}
5844

    
5845
function link_interface_to_vlans($int, $action = "") {
5846
	global $config;
5847

    
5848
	if (empty($int)) {
5849
		return;
5850
	}
5851

    
5852
	if (is_array($config['vlans']['vlan'])) {
5853
		$ifaces = array();
5854
		foreach ($config['vlans']['vlan'] as $vlan) {
5855
			if ($int == $vlan['if']) {
5856
				if ($action == "update") {
5857
					interfaces_bring_up($int);
5858
				} else {
5859
					$ifaces[$vlan['tag']] = $vlan;
5860
				}
5861
			}
5862
		}
5863
		if (!empty($ifaces)) {
5864
			return $ifaces;
5865
		}
5866
	}
5867
}
5868

    
5869
function link_interface_to_qinqs($int, $action = "") {
5870
	global $config;
5871

    
5872
	if (empty($int)) {
5873
		return;
5874
	}
5875

    
5876
	if (is_array($config['qinqs']['qinqentry'])) {
5877
		$ifaces = array();
5878
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5879
			if ($int == $qinq['if']) {
5880
				if ($action == "update") {
5881
					interfaces_bring_up($int);
5882
				} else {
5883
					$ifaces[$qinq['tag']] = $qinq;
5884
				}
5885
			}
5886
		}
5887
		if (!empty($ifaces)) {
5888
			return $ifaces;
5889
		}
5890
	}
5891
}
5892

    
5893
function link_interface_to_vips($int, $action = "", $vhid = '') {
5894
	global $config;
5895

    
5896
	$updatevips = false;
5897
	if (is_array($config['virtualip']['vip'])) {
5898
		$result = array();
5899
		foreach ($config['virtualip']['vip'] as $vip) {
5900
			if (substr($vip['interface'], 0, 4) == "_vip") {
5901
				$iface = get_configured_vip_interface($vip['interface']);
5902
			} else {
5903
				$iface = $vip['interface'];
5904
			}
5905
			if ($int != $iface) {
5906
				continue;
5907
			}
5908
			if ($action == "update") {
5909
				$updatevips = true;
5910
			} else {
5911
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5912
				    substr($vip['interface'], 0, 4) == "_vip") {
5913
					$result[] = $vip;
5914
				}
5915
			}
5916
		}
5917
		if ($updatevips === true) {
5918
			interfaces_vips_configure($int);
5919
		}
5920
		return $result;
5921
	}
5922

    
5923
	return NULL;
5924
}
5925

    
5926
/****f* interfaces/link_interface_to_bridge
5927
 * NAME
5928
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5929
 * INPUTS
5930
 *   $ip
5931
 * RESULT
5932
 *   bridge[0-99]
5933
 ******/
5934
function link_interface_to_bridge($int) {
5935
	global $config;
5936

    
5937
	if (is_array($config['bridges']['bridged'])) {
5938
		foreach ($config['bridges']['bridged'] as $bridge) {
5939
			if (in_array($int, explode(',', $bridge['members']))) {
5940
				return "{$bridge['bridgeif']}";
5941
			}
5942
		}
5943
	}
5944
}
5945

    
5946
function link_interface_to_group($int) {
5947
	global $config;
5948

    
5949
	$result = array();
5950

    
5951
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5952
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5953
			if (in_array($int, explode(" ", $group['members']))) {
5954
				$result[$group['ifname']] = $int;
5955
			}
5956
		}
5957
	}
5958

    
5959
	return $result;
5960
}
5961

    
5962
function link_interface_to_gre($interface) {
5963
	global $config;
5964

    
5965
	$result = array();
5966

    
5967
	if (is_array($config['gres']['gre'])) {
5968
		foreach ($config['gres']['gre'] as $gre) {
5969
			if ($gre['if'] == $interface) {
5970
				$result[] = $gre;
5971
			}
5972
		}
5973
	}
5974

    
5975
	return $result;
5976
}
5977

    
5978
function link_interface_to_gif($interface) {
5979
	global $config;
5980

    
5981
	$result = array();
5982

    
5983
	if (is_array($config['gifs']['gif'])) {
5984
		foreach ($config['gifs']['gif'] as $gif) {
5985
			if ($gif['if'] == $interface) {
5986
				$result[] = $gif;
5987
			}
5988
		}
5989
	}
5990

    
5991
	return $result;
5992
}
5993

    
5994
/*
5995
 * find_interface_ip($interface): return the interface ip (first found)
5996
 */
5997
function find_interface_ip($interface, $flush = false) {
5998
	global $interface_ip_arr_cache;
5999
	global $interface_sn_arr_cache;
6000

    
6001
	$interface = str_replace("\n", "", $interface);
6002

    
6003
	if (!does_interface_exist($interface)) {
6004
		return;
6005
	}
6006

    
6007
	/* Setup IP cache */
6008
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6009
		if (file_exists("/var/db/${interface}_ip")) {
6010
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6011
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6012
			foreach ($ifaddrs as $ifaddr) {
6013
				list($ip, $mask) = explode("/", $ifaddr);
6014
				if ($ip == $ifip) {
6015
					$interface_ip_arr_cache[$interface] = $ip;
6016
					$interface_sn_arr_cache[$interface] = $mask;
6017
					break;
6018
				}
6019
			}
6020
		}
6021
		if (!isset($interface_ip_arr_cache[$interface])) {
6022
			$ifinfo = pfSense_get_interface_addresses($interface);
6023
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6024
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6025
		}
6026
	}
6027

    
6028
	return $interface_ip_arr_cache[$interface];
6029
}
6030

    
6031
/*
6032
 * find_interface_ipv6($interface): return the interface ip (first found)
6033
 */
6034
function find_interface_ipv6($interface, $flush = false) {
6035
	global $interface_ipv6_arr_cache;
6036
	global $interface_snv6_arr_cache;
6037
	global $config;
6038

    
6039
	$interface = trim($interface);
6040
	$interface = get_real_interface($interface);
6041

    
6042
	if (!does_interface_exist($interface)) {
6043
		return;
6044
	}
6045

    
6046
	/* Setup IP cache */
6047
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6048
		$ifinfo = pfSense_get_interface_addresses($interface);
6049
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6050
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6051
	}
6052

    
6053
	return $interface_ipv6_arr_cache[$interface];
6054
}
6055

    
6056
/*
6057
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6058
 */
6059
function find_interface_ipv6_ll($interface, $flush = false) {
6060
	global $interface_llv6_arr_cache;
6061
	global $config;
6062

    
6063
	$interface = str_replace("\n", "", $interface);
6064

    
6065
	if (!does_interface_exist($interface)) {
6066
		return;
6067
	}
6068

    
6069
	/* Setup IP cache */
6070
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6071
		$ifinfo = pfSense_getall_interface_addresses($interface);
6072
		foreach ($ifinfo as $line) {
6073
			if (strstr($line, ":")) {
6074
				$parts = explode("/", $line);
6075
				if (is_linklocal($parts[0])) {
6076
					$ifinfo['linklocal'] = $parts[0];
6077
				}
6078
			}
6079
		}
6080
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6081
	}
6082
	return $interface_llv6_arr_cache[$interface];
6083
}
6084

    
6085
function find_interface_subnet($interface, $flush = false) {
6086
	global $interface_sn_arr_cache;
6087
	global $interface_ip_arr_cache;
6088

    
6089
	$interface = str_replace("\n", "", $interface);
6090
	if (does_interface_exist($interface) == false) {
6091
		return;
6092
	}
6093

    
6094
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6095
		$ifinfo = pfSense_get_interface_addresses($interface);
6096
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6097
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6098
	}
6099

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

    
6103
function find_interface_subnetv6($interface, $flush = false) {
6104
	global $interface_snv6_arr_cache;
6105
	global $interface_ipv6_arr_cache;
6106

    
6107
	$interface = str_replace("\n", "", $interface);
6108
	if (does_interface_exist($interface) == false) {
6109
		return;
6110
	}
6111

    
6112
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6113
		$ifinfo = pfSense_get_interface_addresses($interface);
6114
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6115
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6116
	}
6117

    
6118
	return $interface_snv6_arr_cache[$interface];
6119
}
6120

    
6121
function ip_in_interface_alias_subnet($interface, $ipalias) {
6122
	global $config;
6123

    
6124
	if (empty($interface) || !is_ipaddr($ipalias)) {
6125
		return false;
6126
	}
6127
	if (is_array($config['virtualip']['vip'])) {
6128
		foreach ($config['virtualip']['vip'] as $vip) {
6129
			switch ($vip['mode']) {
6130
				case "ipalias":
6131
					if ($vip['interface'] <> $interface) {
6132
						break;
6133
					}
6134
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6135
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6136
						return true;
6137
					}
6138
					break;
6139
			}
6140
		}
6141
	}
6142

    
6143
	return false;
6144
}
6145

    
6146
function get_possible_listen_ips($include_ipv6_link_local=false) {
6147

    
6148
	$interfaces = get_configured_interface_with_descr();
6149
	foreach ($interfaces as $iface => $ifacename) {
6150
		if ($include_ipv6_link_local) {
6151
			/* This is to avoid going though added ll below */
6152
			if (substr($iface, 0, 5) == '_lloc') {
6153
				continue;
6154
			}
6155
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6156
			if (!empty($llip)) {
6157
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6158
			}
6159
		}
6160
	}
6161
	$viplist = get_configured_vip_list();
6162
	foreach ($viplist as $vip => $address) {
6163
		$interfaces[$vip] = $address;
6164
		if (get_vip_descr($address)) {
6165
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6166
		}
6167
	}
6168

    
6169
	$interfaces['lo0'] = 'Localhost';
6170

    
6171
	return $interfaces;
6172
}
6173

    
6174
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6175
	global $config;
6176

    
6177
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6178
	foreach (array('server', 'client') as $mode) {
6179
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6180
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6181
				if (!isset($setting['disable'])) {
6182
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6183
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6184
				}
6185
			}
6186
		}
6187
	}
6188
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
6189
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
6190
			if ($ph1ent['disabled']) {
6191
				continue;
6192
			}
6193
			if (ipsec_vti($ph1ent)) {
6194
				$sourceips_key = "ipsec{$ph1ent['ikeid']}";
6195
				$sourceips[$sourceips_key] = gettext("IPsec VTI") . ": " . htmlspecialchars($ph1ent['descr']);
6196
			}
6197
		}
6198
	}
6199
	return $sourceips;
6200
}
6201

    
6202
function get_interface_ip($interface = "wan") {
6203
	global $config;
6204

    
6205
	if (substr($interface, 0, 4) == '_vip') {
6206
		return get_configured_vip_ipv4($interface);
6207
	} else if (substr($interface, 0, 5) == '_lloc') {
6208
		/* No link-local address for v4. */
6209
		return null;
6210
	}
6211

    
6212
	$realif = get_failover_interface($interface, 'inet');
6213
	if (!$realif) {
6214
		return null;
6215
	}
6216

    
6217
	if (substr($realif, 0, 4) == '_vip') {
6218
		return get_configured_vip_ipv4($realif);
6219
	} else if (substr($realif, 0, 5) == '_lloc') {
6220
		/* No link-local address for v4. */
6221
		return null;
6222
	}
6223

    
6224
	if (is_array($config['interfaces'][$interface]) &&
6225
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6226
		return ($config['interfaces'][$interface]['ipaddr']);
6227
	}
6228

    
6229
	/*
6230
	 * Beaware that find_interface_ip() is our last option, it will
6231
	 * return the first IP it find on interface, not necessarily the
6232
	 * main IP address.
6233
	 */
6234
	$curip = find_interface_ip($realif);
6235
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6236
		return $curip;
6237
	} else {
6238
		return null;
6239
	}
6240
}
6241

    
6242
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6243
	global $config;
6244

    
6245
	if (substr($interface, 0, 4) == '_vip') {
6246
		return get_configured_vip_ipv6($interface);
6247
	} else if (substr($interface, 0, 5) == '_lloc') {
6248
		return get_interface_linklocal($interface);
6249
	}
6250

    
6251
	$realif = get_failover_interface($interface, 'inet6');
6252
	if (!$realif) {
6253
		return null;
6254
	}
6255

    
6256
	if (substr($realif, 0, 4) == '_vip') {
6257
		return get_configured_vip_ipv6($realif);
6258
	} else if (substr($realif, 0, 5) == '_lloc') {
6259
		return get_interface_linklocal($realif);
6260
	}
6261

    
6262
	if (is_array($config['interfaces'][$interface])) {
6263
		switch ($config['interfaces'][$interface]['ipaddr']) {
6264
			case 'pppoe':
6265
			case 'l2tp':
6266
			case 'pptp':
6267
			case 'ppp':
6268
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
6269
					$realif = get_real_interface($interface, 'inet6', false);
6270
				}
6271
				break;
6272
		}
6273
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6274
			return ($config['interfaces'][$interface]['ipaddrv6']);
6275
		}
6276
	}
6277

    
6278
	/*
6279
	 * Beaware that find_interface_ip() is our last option, it will
6280
	 * return the first IP it find on interface, not necessarily the
6281
	 * main IP address.
6282
	 */
6283
	$curip = find_interface_ipv6($realif, $flush);
6284
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6285
		return $curip;
6286
	} else {
6287
		/*
6288
		 * NOTE: On the case when only the prefix is requested,
6289
		 * the communication on WAN will be done over link-local.
6290
		 */
6291
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6292
			$curip = find_interface_ipv6_ll($realif, $flush);
6293
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6294
				return $curip;
6295
			}
6296
		}
6297
	}
6298
	return null;
6299
}
6300

    
6301
function get_interface_linklocal($interface = "wan") {
6302

    
6303
	$realif = get_failover_interface($interface, 'inet6');
6304
	if (!$realif) {
6305
		return null;
6306
	}
6307

    
6308
	if (substr($interface, 0, 4) == '_vip') {
6309
		$realif = get_real_interface($interface);
6310
	} else if (substr($interface, 0, 5) == '_lloc') {
6311
		$realif = get_real_interface(substr($interface, 5));
6312
	}
6313

    
6314
	$curip = find_interface_ipv6_ll($realif);
6315
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6316
		return $curip;
6317
	} else {
6318
		return null;
6319
	}
6320
}
6321

    
6322
function get_interface_subnet($interface = "wan") {
6323
	global $config;
6324

    
6325
	if (substr($interface, 0, 4) == '_vip') {
6326
		return (get_configured_vip_subnetv4($interface));
6327
	}
6328

    
6329
	if (is_array($config['interfaces'][$interface]) &&
6330
		!empty($config['interfaces'][$interface]['subnet'])) {
6331
		return ($config['interfaces'][$interface]['subnet']);
6332
	}
6333

    
6334
	$realif = get_real_interface($interface);
6335
	if (!$realif) {
6336
		return (NULL);
6337
	}
6338

    
6339
	$cursn = find_interface_subnet($realif);
6340
	if (!empty($cursn)) {
6341
		return ($cursn);
6342
	}
6343

    
6344
	return (NULL);
6345
}
6346

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

    
6350
	if (substr($interface, 0, 4) == '_vip') {
6351
		return (get_configured_vip_subnetv6($interface));
6352
	} else if (substr($interface, 0, 5) == '_lloc') {
6353
		$interface = substr($interface, 5);
6354
	}
6355

    
6356
	if (is_array($config['interfaces'][$interface]) &&
6357
		!empty($config['interfaces'][$interface]['subnetv6'])) {
6358
		return ($config['interfaces'][$interface]['subnetv6']);
6359
	}
6360

    
6361
	$realif = get_real_interface($interface, 'inet6');
6362
	if (!$realif) {
6363
		return (NULL);
6364
	}
6365

    
6366
	$cursn = find_interface_subnetv6($realif);
6367
	if (!empty($cursn)) {
6368
		return ($cursn);
6369
	}
6370

    
6371
	return (NULL);
6372
}
6373

    
6374
/* return outside interfaces with a gateway */
6375
function get_interfaces_with_gateway() {
6376
	global $config;
6377

    
6378
	$ints = array();
6379

    
6380
	/* loop interfaces, check config for outbound */
6381
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6382
		switch ($ifname['ipaddr']) {
6383
			case "dhcp":
6384
			case "pppoe":
6385
			case "pptp":
6386
			case "l2tp":
6387
			case "ppp":
6388
				$ints[$ifdescr] = $ifdescr;
6389
				break;
6390
			default:
6391
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6392
				    !empty($ifname['gateway'])) {
6393
					$ints[$ifdescr] = $ifdescr;
6394
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6395
				    !empty($ifname['gateway'])) {
6396
					$ints[$ifdescr] = $ifdescr;
6397
				}
6398

    
6399
				break;
6400
		}
6401
	}
6402
	return $ints;
6403
}
6404

    
6405
/* return true if interface has a gateway */
6406
function interface_has_gateway($friendly) {
6407
	global $config;
6408

    
6409
	if (!empty($config['interfaces'][$friendly])) {
6410
		$ifname = &$config['interfaces'][$friendly];
6411
		switch ($ifname['ipaddr']) {
6412
			case "dhcp":
6413
			case "pppoe":
6414
			case "pptp":
6415
			case "l2tp":
6416
			case "ppp":
6417
				return true;
6418
			break;
6419
			default:
6420
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6421
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6422
					return true;
6423
				}
6424
				$tunnelif = substr($ifname['if'], 0, 3);
6425
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6426
					if (find_interface_ip($ifname['if'])) {
6427
						return true;
6428
					}
6429
				}
6430
				if (!empty($ifname['gateway'])) {
6431
					return true;
6432
				}
6433
			break;
6434
		}
6435
	}
6436

    
6437
	return false;
6438
}
6439

    
6440
/* return true if interface has a gateway */
6441
function interface_has_gatewayv6($friendly) {
6442
	global $config;
6443

    
6444
	if (!empty($config['interfaces'][$friendly])) {
6445
		$ifname = &$config['interfaces'][$friendly];
6446
		switch ($ifname['ipaddrv6']) {
6447
			case "slaac":
6448
			case "dhcp6":
6449
			case "6to4":
6450
			case "6rd":
6451
				return true;
6452
				break;
6453
			default:
6454
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6455
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6456
					return true;
6457
				}
6458
				$tunnelif = substr($ifname['if'], 0, 3);
6459
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6460
					if (find_interface_ipv6($ifname['if'])) {
6461
						return true;
6462
					}
6463
				}
6464
				if (!empty($ifname['gatewayv6'])) {
6465
					return true;
6466
				}
6467
				break;
6468
		}
6469
	}
6470

    
6471
	return false;
6472
}
6473

    
6474
/****f* interfaces/is_altq_capable
6475
 * NAME
6476
 *   is_altq_capable - Test if interface is capable of using ALTQ
6477
 * INPUTS
6478
 *   $int            - string containing interface name
6479
 * RESULT
6480
 *   boolean         - true or false
6481
 ******/
6482

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

    
6498
	$int_family = remove_ifindex($int);
6499

    
6500
	if (in_array($int_family, $capable)) {
6501
		return true;
6502
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6503
		return true;
6504
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6505
		return true;
6506
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6507
		return true;
6508
	} else {
6509
		return false;
6510
	}
6511
}
6512

    
6513
/****f* interfaces/is_interface_wireless
6514
 * NAME
6515
 *   is_interface_wireless - Returns if an interface is wireless
6516
 * RESULT
6517
 *   $tmp       - Returns if an interface is wireless
6518
 ******/
6519
function is_interface_wireless($interface) {
6520
	global $config, $g;
6521

    
6522
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6523
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6524
		if (preg_match($g['wireless_regex'], $interface)) {
6525
			if (isset($config['interfaces'][$friendly])) {
6526
				$config['interfaces'][$friendly]['wireless'] = array();
6527
			}
6528
			return true;
6529
		}
6530
		return false;
6531
	} else {
6532
		return true;
6533
	}
6534
}
6535

    
6536
function get_wireless_modes($interface) {
6537
	/* return wireless modes and channels */
6538
	$wireless_modes = array();
6539

    
6540
	$cloned_interface = get_real_interface($interface);
6541

    
6542
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6543
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6544
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6545
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6546

    
6547
		$interface_channels = "";
6548
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6549
		$interface_channel_count = count($interface_channels);
6550

    
6551
		$c = 0;
6552
		while ($c < $interface_channel_count) {
6553
			$channel_line = explode(",", $interface_channels["$c"]);
6554
			$wireless_mode = trim($channel_line[0]);
6555
			$wireless_channel = trim($channel_line[1]);
6556
			if (trim($wireless_mode) != "") {
6557
				/* if we only have 11g also set 11b channels */
6558
				if ($wireless_mode == "11g") {
6559
					if (!isset($wireless_modes["11b"])) {
6560
						$wireless_modes["11b"] = array();
6561
					}
6562
				} else if ($wireless_mode == "11g ht") {
6563
					if (!isset($wireless_modes["11b"])) {
6564
						$wireless_modes["11b"] = array();
6565
					}
6566
					if (!isset($wireless_modes["11g"])) {
6567
						$wireless_modes["11g"] = array();
6568
					}
6569
					$wireless_mode = "11ng";
6570
				} else if ($wireless_mode == "11a ht") {
6571
					if (!isset($wireless_modes["11a"])) {
6572
						$wireless_modes["11a"] = array();
6573
					}
6574
					$wireless_mode = "11na";
6575
				}
6576
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6577
			}
6578
			$c++;
6579
		}
6580
	}
6581
	return($wireless_modes);
6582
}
6583

    
6584
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6585
function get_wireless_channel_info($interface) {
6586
	$wireless_channels = array();
6587

    
6588
	$cloned_interface = get_real_interface($interface);
6589

    
6590
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6591
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
6592
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6593
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
6594

    
6595
		$interface_channels = "";
6596
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6597

    
6598
		foreach ($interface_channels as $channel_line) {
6599
			$channel_line = explode(",", $channel_line);
6600
			if (!isset($wireless_channels[$channel_line[0]])) {
6601
				$wireless_channels[$channel_line[0]] = $channel_line;
6602
			}
6603
		}
6604
	}
6605
	return($wireless_channels);
6606
}
6607

    
6608
function set_interface_mtu($interface, $mtu) {
6609

    
6610
	/* LAGG interface must be destroyed and re-created to change MTU */
6611
	if (substr($interface, 0, 4) == 'lagg') {
6612
		if (isset($config['laggs']['lagg']) &&
6613
		    is_array($config['laggs']['lagg'])) {
6614
			foreach ($config['laggs']['lagg'] as $lagg) {
6615
				if ($lagg['laggif'] == $interface) {
6616
					interface_lagg_configure($lagg);
6617
					break;
6618
				}
6619
			}
6620
		}
6621
	} else {
6622
		pfSense_interface_mtu($interface, $mtu);
6623
	}
6624
}
6625

    
6626
/****f* interfaces/get_interface_mtu
6627
 * NAME
6628
 *   get_interface_mtu - Return the mtu of an interface
6629
 * RESULT
6630
 *   $tmp       - Returns the mtu of an interface
6631
 ******/
6632
function get_interface_mtu($interface) {
6633
	$mtu = pfSense_interface_getmtu($interface);
6634
	return $mtu['mtu'];
6635
}
6636

    
6637
function get_interface_mac($interface) {
6638
	$macinfo = pfSense_get_interface_addresses($interface);
6639
	return $macinfo["macaddr"];
6640
}
6641

    
6642
function get_interface_vendor_mac($interface) {
6643
	global $config, $g;
6644

    
6645
	$macinfo = pfSense_get_interface_addresses($interface);
6646
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
6647
	    "00:00:00:00:00:00") {
6648
		return ($macinfo["hwaddr"]);
6649
	}
6650

    
6651
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
6652
	if (file_exists($hwaddr_file)) {
6653
		$macaddr = trim(file_get_contents($hwaddr_file));
6654
		if (is_macaddr($macaddr)) {
6655
			return ($macaddr);
6656
		}
6657
	} elseif (is_macaddr($macinfo['macaddr'])) {
6658
		/* Save original macaddress to be restored when necessary */
6659
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
6660
	}
6661

    
6662
	return (NULL);
6663
}
6664

    
6665
/****f* pfsense-utils/generate_random_mac_address
6666
 * NAME
6667
 *   generate_random_mac - generates a random mac address
6668
 * INPUTS
6669
 *   none
6670
 * RESULT
6671
 *   $mac - a random mac address
6672
 ******/
6673
function generate_random_mac_address() {
6674
	$mac = "02";
6675
	for ($x = 0; $x < 5; $x++) {
6676
		$mac .= ":" . dechex(rand(16, 255));
6677
	}
6678
	return $mac;
6679
}
6680

    
6681
/****f* interfaces/is_jumbo_capable
6682
 * NAME
6683
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
6684
 * INPUTS
6685
 *   $int             - string containing interface name
6686
 * RESULT
6687
 *   boolean          - true or false
6688
 ******/
6689
function is_jumbo_capable($iface) {
6690
	$iface = trim($iface);
6691
	$capable = pfSense_get_interface_addresses($iface);
6692

    
6693
	if (isset($capable['caps']['vlanmtu'])) {
6694
		return true;
6695
	}
6696

    
6697
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
6698
	if (substr($iface, 0, 4) == "lagg") {
6699
		return true;
6700
	}
6701

    
6702
	return false;
6703
}
6704

    
6705
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6706
	global $g;
6707

    
6708
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6709

    
6710
	if (!empty($iface) && !empty($pppif)) {
6711
		$cron_cmd = <<<EOD
6712
#!/bin/sh
6713
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
6714
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
6715

    
6716
EOD;
6717

    
6718
		@file_put_contents($cron_file, $cron_cmd);
6719
		chmod($cron_file, 0755);
6720
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
6721
	} else {
6722
		unlink_if_exists($cron_file);
6723
	}
6724
}
6725

    
6726
function get_interface_default_mtu($type = "ethernet") {
6727
	switch ($type) {
6728
		case "gre":
6729
			return 1476;
6730
			break;
6731
		case "gif":
6732
			return 1280;
6733
			break;
6734
		case "tun":
6735
		case "vlan":
6736
		case "tap":
6737
		case "ethernet":
6738
		default:
6739
			return 1500;
6740
			break;
6741
	}
6742

    
6743
	/* Never reached */
6744
	return 1500;
6745
}
6746

    
6747
function get_vip_descr($ipaddress) {
6748
	global $config;
6749

    
6750
	foreach ($config['virtualip']['vip'] as $vip) {
6751
		if ($vip['subnet'] == $ipaddress) {
6752
			return ($vip['descr']);
6753
		}
6754
	}
6755
	return "";
6756
}
6757

    
6758
function interfaces_staticarp_configure($if) {
6759
	global $config, $g;
6760
	if (isset($config['system']['developerspew'])) {
6761
		$mt = microtime();
6762
		echo "interfaces_staticarp_configure($if) being called $mt\n";
6763
	}
6764

    
6765
	$ifcfg = $config['interfaces'][$if];
6766

    
6767
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
6768
		return 0;
6769
	}
6770

    
6771
	/* Enable staticarp, if enabled */
6772
	if (isset($config['dhcpd'][$if]['staticarp'])) {
6773
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
6774
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6775
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
6776
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6777
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6778
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6779
				}
6780
			}
6781
		}
6782
	} else {
6783
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
6784
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6785
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
6786
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6787
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6788
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6789
				}
6790
			}
6791
		}
6792
	}
6793

    
6794
	return 0;
6795
}
6796

    
6797
function get_failover_interface($interface, $family = "all") {
6798
	global $config;
6799

    
6800
	/* shortcut to get_real_interface if we find it in the config */
6801
	if (is_array($config['interfaces'][$interface])) {
6802
		return get_real_interface($interface, $family);
6803
	}
6804

    
6805
	/* compare against gateway groups */
6806
	$a_groups = return_gateway_groups_array(true);
6807
	if (is_array($a_groups[$interface])) {
6808
		/* we found a gateway group, fetch the interface or vip */
6809
		if (!empty($a_groups[$interface][0]['vip'])) {
6810
			return $a_groups[$interface][0]['vip'];
6811
		} else {
6812
			return $a_groups[$interface][0]['int'];
6813
		}
6814
	}
6815
	/* fall through to get_real_interface */
6816
	/* XXX: Really needed? */
6817
	return get_real_interface($interface, $family);
6818
}
6819

    
6820
/****f* interfaces/interface_has_dhcp
6821
 * NAME
6822
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6823
 * INPUTS
6824
 *   interface or gateway group name
6825
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6826
 * RESULT
6827
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6828
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6829
 ******/
6830
function interface_has_dhcp($interface, $family = 4) {
6831
	global $config;
6832

    
6833
	if ($config['interfaces'][$interface]) {
6834
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6835
			return true;
6836
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6837
			return true;
6838
		} else {
6839
			return false;
6840
		}
6841
	}
6842

    
6843
	if (!is_array($config['gateways']['gateway_group'])) {
6844
		return false;
6845
	}
6846

    
6847
	if ($family == 6) {
6848
		$dhcp_string = "_DHCP6";
6849
	} else {
6850
		$dhcp_string = "_DHCP";
6851
	}
6852

    
6853
	foreach ($config['gateways']['gateway_group'] as $group) {
6854
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6855
			continue;
6856
		}
6857
		foreach ($group['item'] as $item) {
6858
			$item_data = explode("|", $item);
6859
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6860
				return true;
6861
			}
6862
		}
6863
	}
6864

    
6865
	return false;
6866
}
6867

    
6868
function remove_ifindex($ifname) {
6869
	return preg_replace("/[0-9]+$/", "", $ifname);
6870
}
6871

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

    
6875
	$viplist = get_configured_vip_list($family, $type);
6876
	foreach ($viplist as $vip => $address) {
6877
		$interfaces[$vip] = $address;
6878
		if ($type = VIP_CARP) {
6879
			$vip = get_configured_vip($vipid);
6880
			if (isset($vip) && is_array($vip) ) {
6881
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
6882
			}
6883
		}
6884
		if (get_vip_descr($address)) {
6885
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
6886
		}
6887
	}
6888
	return $interfaces;
6889
}
6890

    
6891
function return_gateway_groups_array_with_descr() {
6892
	$interfaces = array();
6893
	$grouplist = return_gateway_groups_array();
6894
	foreach ($grouplist as $name => $group) {
6895
		if ($group[0]['vip'] != "") {
6896
			$vipif = $group[0]['vip'];
6897
		} else {
6898
			$vipif = $group[0]['int'];
6899
		}
6900

    
6901
		$interfaces[$name] = "GW Group {$name}";
6902
	}
6903
	return $interfaces;
6904
}
6905

    
6906
function get_serial_ports() {
6907
	$linklist = array();
6908
	if (!is_dir("/var/spool/lock")) {
6909
		mwexec("/bin/mkdir -p /var/spool/lock");
6910
	}
6911
	$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);
6912
	foreach ($serialports as $port) {
6913
		$linklist[$port] = trim($port);
6914
	}
6915
	return $linklist;
6916
}
6917

    
6918
function get_interface_ports() {
6919
	global $config;
6920
	$linklist = array();
6921
	$portlist = get_interface_list();
6922
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
6923
		foreach ($config['vlans']['vlan'] as $vlan) {
6924
			$portlist[$vlan['vlanif']] = $vlan;
6925
		}
6926
	}
6927

    
6928
	foreach ($portlist as $ifn => $ifinfo) {
6929
		$string = "";
6930
		if (is_array($ifinfo)) {
6931
			$string .= $ifn;
6932
			if ($ifinfo['mac']) {
6933
				$string .= " ({$ifinfo['mac']})";
6934
			}
6935
			if ($ifinfo['friendly']) {
6936
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
6937
			} elseif ($ifinfo['descr']) {
6938
				$string .= " - {$ifinfo['descr']}";
6939
			}
6940
		} else {
6941
			$string .= $ifinfo;
6942
		}
6943

    
6944
		$linklist[$ifn] = $string;
6945
	}
6946
	return $linklist;
6947
}
6948

    
6949
function build_ppps_link_list() {
6950
	global $pconfig;
6951

    
6952
	$linklist = array('list' => array(), 'selected' => array());
6953

    
6954
	if ($pconfig['type'] == 'ppp') {
6955
		$linklist['list'] = get_serial_ports();
6956
	} else {
6957
		$iflist = get_interface_ports();
6958

    
6959
		$viplist = get_configured_vip_list_with_descr('all', VIP_CARP);
6960

    
6961
		$linklist['list'] = array_merge($iflist, $viplist);
6962

    
6963
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
6964
		$lagglist = get_lagg_interface_list();
6965
		foreach ($lagglist as $laggif => $lagg) {
6966
			/* LAGG members cannot be assigned */
6967
			$laggmembers = explode(',', $lagg['members']);
6968
			foreach ($laggmembers as $lagm) {
6969
				if (isset($linklist['list'][$lagm])) {
6970
					unset($linklist['list'][$lagm]);
6971
				}
6972
			}
6973
		}
6974
	}
6975

    
6976
	$selected_ports = array();
6977
	if (is_array($pconfig['interfaces'])) {
6978
		$selected_ports = $pconfig['interfaces'];
6979
	} elseif (!empty($pconfig['interfaces'])) {
6980
		$selected_ports = explode(',', $pconfig['interfaces']);
6981
	}
6982
	foreach ($selected_ports as $port) {
6983
		if (isset($linklist['list'][$port])) {
6984
			array_push($linklist['selected'], $port);
6985
		}
6986
	}
6987
	return($linklist);
6988
}
6989

    
6990
function create_interface_list() {
6991
	global $config;
6992

    
6993
	$iflist = array();
6994

    
6995
	// add group interfaces
6996
	if (is_array($config['ifgroups']['ifgroupentry'])) {
6997
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
6998
			if (have_ruleint_access($ifgen['ifname'])) {
6999
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7000
			}
7001
		}
7002
	}
7003

    
7004
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7005
		if (have_ruleint_access($ifent)) {
7006
			$iflist[$ifent] = $ifdesc;
7007
		}
7008
	}
7009

    
7010
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
7011
		$iflist['l2tp'] = gettext('L2TP VPN');
7012
	}
7013

    
7014
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
7015
		$iflist['pppoe'] = gettext("PPPoE Server");
7016
	}
7017

    
7018
	// add ipsec interfaces
7019
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
7020
		$iflist["enc0"] = gettext("IPsec");
7021
	}
7022

    
7023
	// add openvpn/tun interfaces
7024
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7025
		$iflist["openvpn"] = gettext("OpenVPN");
7026
	}
7027

    
7028
	return($iflist);
7029
}
7030

    
7031
?>
(23-23/60)