Project

General

Profile

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

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

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

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

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

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

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

    
60
	return true;
61
}
62

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

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

    
74
	return $interface_arr_cache;
75
}
76

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

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

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

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

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

    
107

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

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

    
130
	return false;
131
}
132

    
133
function interface_netgraph_needed($interface = "wan") {
134
	global $config;
135

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

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

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

    
191
function interfaces_loopback_configure() {
192
	global $g;
193

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

    
205
function vlan_valid_tag($tag = NULL) {
206

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

    
214
function qinq_inuse($qinq = NULL, $inqtag = NULL) {
215
        global $config;
216

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

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

    
229
        return (false);
230
}
231

    
232
function qinq_interface($qinq = NULL, $inqtag = NULL) {
233

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

    
242
function interface_is_qinq($if = NULL) {
243
	global $config;
244

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

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

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

    
270
	return (NULL);
271
}
272

    
273
function interface_is_lagg($if = NULL) {
274
	global $config;
275

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

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

    
288
function vlan_inuse($vlan) {
289
	global $config;
290

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

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

    
302
	return (false);
303
}
304

    
305
function interface_is_vlan($if = NULL) {
306
	global $config;
307

    
308
	if ($if == NULL || empty($if) || is_array($if)) {
309
		return (NULL);
310
	}
311

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

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

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

    
336
	return (NULL);
337
}
338

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

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

    
352
	$current_mac = get_interface_mac($interface);
353

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

    
366
function interface_is_parent($if, $parent_check) {
367

    
368
	$parent_array = get_parent_interface($if);
369
	if (count($parent_array) > 1) {
370
		$parent = $parent_array;
371
	} else {
372
		$parent = $parent_array[0];
373
	}
374
	if (is_array($parent)) {
375
		foreach ($parent as $parentif) {
376
			if (strcasecmp($parent_check, $parentif) == 0) {
377
				return (TRUE);
378
			}
379
		}
380
	} else {
381
		$realif = get_real_interface($parent);
382
		if (strcasecmp($parent_check, $realif) == 0) {
383
			return (TRUE);
384
		}
385
	}
386
	return (FALSE);
387
}
388

    
389
function interface_has_clones($if) {
390
	global $config;
391

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

    
423
	return (FALSE);
424
}
425

    
426
function interfaces_vlan_configure($realif = "") {
427
	global $config, $g;
428
	if (platform_booting()) {
429
		echo gettext("Configuring VLAN interfaces...");
430
	}
431
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
432
		foreach ($config['vlans']['vlan'] as $vlan) {
433
			if (empty($vlan['vlanif'])) {
434
				$vlan['vlanif'] = vlan_interface($vlan);
435
			}
436
			if (!empty($realif) && $realif != $vlan['vlanif']) {
437
				continue;
438
			}
439

    
440
			/* XXX: Maybe we should report any errors?! */
441
			interface_vlan_configure($vlan);
442
		}
443
	}
444
	if (platform_booting()) {
445
		echo gettext("done.") . "\n";
446
	}
447
}
448

    
449
function interface_vlan_configure(&$vlan) {
450
	global $config, $g;
451

    
452
	if (!is_array($vlan)) {
453
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
454
		return(NULL);
455
	}
456
	$if = $vlan['if'];
457
	if (empty($if)) {
458
		log_error(gettext("interface_vlan_configure called with if undefined."));
459
		return(NULL);
460
	}
461

    
462
	$vlanif = empty($vlan['vlanif']) ? vlan_interface($vlan) : $vlan['vlanif'];
463
	if ($vlanif == NULL) {
464
		log_error(gettext("vlan_interface called with if undefined var."));
465
		return(NULL);
466
	}
467
	$tag = $vlan['tag'];
468
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
469

    
470
	/* make sure the parent interface is up */
471
	interfaces_bring_up($if);
472
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
473
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
474

    
475
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
476
		pfSense_interface_destroy($vlanif);
477
	}
478

    
479
	$tmpvlanif = pfSense_interface_create("vlan");
480
	pfSense_interface_rename($tmpvlanif, $vlanif);
481
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
482

    
483
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
484

    
485
	interfaces_bring_up($vlanif);
486

    
487
	/* invalidate interface cache */
488
	get_interface_arr(true);
489

    
490
	/* configure interface if assigned */
491
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
492
	if ($assignedif) {
493
		if (isset($config['interfaces'][$assignedif]['enable'])) {
494
			interface_configure($assignedif, true);
495
		}
496
	}
497

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

    
501
	return $vlanif;
502
}
503

    
504
function interface_qinq_configure(&$qinq, $fd = NULL) {
505
	global $config, $g;
506

    
507
	if (!is_array($qinq)) {
508
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
509
		return;
510
	}
511

    
512
	$qinqif = $qinq['if'];
513
	$tag = $qinq['tag'];
514
	if (empty($qinqif)) {
515
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
516
		return;
517
	}
518

    
519
	if (!does_interface_exist($qinqif)) {
520
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
521
		return;
522
	}
523

    
524
	$vlanif = interface_vlan_configure($qinq);
525
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
526
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
527
		return;
528
	}
529

    
530
	if ($fd == NULL) {
531
		$exec = true;
532
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
533
	} else {
534
		$exec = false;
535
	}
536
	/* make sure the parent is converted to ng_vlan(4) and is up */
537
	interfaces_bring_up($qinqif);
538

    
539
	pfSense_ngctl_attach(".", $qinqif);
540
	$ngif = str_replace(".", "_", $vlanif);
541
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
542
		exec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1");
543
		exec("/usr/sbin/ngctl msg {$ngif}qinq: gettable > /dev/null 2>&1", $result);
544
		if (empty($result)) {
545
			fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
546
			fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
547
			fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
548
		}
549
	} else {
550
		fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
551
		fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
552
		fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
553
	}
554

    
555
	/* invalidate interface cache */
556
	get_interface_arr(true);
557

    
558
	if (interface_is_vlan($qinqif) == NULL) {
559
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
560
	}
561

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

    
582
	interfaces_bring_up($qinqif);
583
	if (!empty($qinq['members'])) {
584
		$members = explode(" ", $qinq['members']);
585
		foreach ($members as $qtag) {
586
			interfaces_bring_up(qinq_interface($qinq, $qtag));
587
		}
588
	}
589

    
590
	return $vlanif;
591
}
592

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

    
609
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr) {
610
	global $config, $g;
611

    
612
	if (!is_array($qinq)) {
613
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
614
		return;
615
	}
616

    
617
	$if = $qinq['if'];
618
	if (empty($if)) {
619
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
620
		return;
621
	}
622
	$tag = $qinq['tag'];
623
	$vlanif = "{$if}.{$tag}";
624
	$ngif = str_replace(".", "_", $if);
625
	if (strlen($vlanif) > IF_NAMESIZE) {
626
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
627
		    $vlanif, IF_NAMESIZE, "\n"));
628
		return;
629
	}
630

    
631
	exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1");
632
	$cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n";
633
	$cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n";
634
	$cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n";
635
	$cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n";
636
	$cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n";
637

    
638
	/* invalidate interface cache */
639
	get_interface_arr(true);
640

    
641
	return $vlanif;
642
}
643

    
644
function interfaces_create_wireless_clones() {
645
	global $config, $g;
646

    
647
	if (platform_booting()) {
648
		echo gettext("Creating wireless clone interfaces...");
649
	}
650

    
651
	$iflist = get_configured_interface_list();
652

    
653
	foreach ($iflist as $if) {
654
		$realif = $config['interfaces'][$if]['if'];
655
		if (is_interface_wireless($realif)) {
656
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
657
		}
658
	}
659

    
660
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
661
		foreach ($config['wireless']['clone'] as $clone) {
662
			if (empty($clone['cloneif'])) {
663
				continue;
664
			}
665
			if (does_interface_exist($clone['cloneif'])) {
666
				continue;
667
			}
668
			/* XXX: Maybe we should report any errors?! */
669
			interface_wireless_clone($clone['cloneif'], $clone);
670
		}
671
	}
672
	if (platform_booting()) {
673
		echo gettext("done.") . "\n";
674
	}
675

    
676
}
677

    
678
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
679
	global $config;
680

    
681
	$i = 0;
682
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
683
		foreach ($config['bridges']['bridged'] as $bridge) {
684
			if (empty($bridge['bridgeif'])) {
685
				$bridge['bridgeif'] = "bridge{$i}";
686
			}
687
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
688
				continue;
689
			}
690

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

    
718
function interface_bridge_configure(&$bridge, $checkmember = 0) {
719
	global $config, $g;
720

    
721
	if (!is_array($bridge)) {
722
		return;
723
	}
724

    
725
	if (empty($bridge['members'])) {
726
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
727
		return;
728
	}
729

    
730
	$members = explode(',', $bridge['members']);
731
	if (!count($members)) {
732
		return;
733
	}
734

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

    
760
	/* Just in case anything is not working well */
761
	if ($smallermtu == 0) {
762
		$smallermtu = 1500;
763
	}
764

    
765
	if (!empty($bridge['bridgeif'])) {
766
		pfSense_interface_destroy($bridge['bridgeif']);
767
		pfSense_interface_create($bridge['bridgeif']);
768
		$bridgeif = escapeshellarg($bridge['bridgeif']);
769
	} else {
770
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
771
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
772
		$bridgeif = pfSense_interface_create("bridge");
773
		$bridge['bridgeif'] = $bridgeif;
774
	}
775

    
776
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
777
	if ($bridgemtu > $smallermtu) {
778
		$smallermtu = $bridgemtu;
779
	}
780

    
781
	$checklist = get_configured_interface_list();
782

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

    
800
	if (isset($bridge['enablestp'])) {
801
		interface_bridge_configure_stp($bridge);
802
	}
803

    
804
	interface_bridge_configure_advanced($bridge);
805

    
806
	interface_bridge_configure_ip6linklocal($bridge);
807

    
808
	if ($bridge['bridgeif']) {
809
		interfaces_bring_up($bridge['bridgeif']);
810
	} else {
811
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
812
	}
813
}
814

    
815
function interface_bridge_configure_stp($bridge) {
816
	if (isset($bridge['enablestp'])) {
817
		$bridgeif = trim($bridge['bridgeif']);
818
		/* configure spanning tree proto */
819
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
820

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

    
874
function interface_bridge_configure_advanced($bridge) {
875
	$bridgeif = trim($bridge['bridgeif']);
876

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

    
934
function interface_bridge_configure_ip6linklocal($bridge) {
935
	$bridgeif = trim($bridge['bridgeif']);
936

    
937
	$members = explode(',', $bridge['members']);
938
	if (!count($members)) {
939
		return;
940
	}
941

    
942
	$auto_linklocal = isset($bridge['ip6linklocal']);
943
	$bridgeop = $auto_linklocal ? '' : '-';
944
	$memberop = $auto_linklocal ? '-' : '';
945

    
946
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
947
	foreach ($members as $member) {
948
		$realif = get_real_interface($member);
949
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
950
	}
951
}
952

    
953
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
954
	global $config;
955

    
956
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
957
		return;
958
	}
959

    
960
	if ($flagsapplied == false) {
961
		$mtu = get_interface_mtu($bridgeif);
962
		$mtum = get_interface_mtu($interface);
963
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
964
			pfSense_interface_mtu($interface, $mtu);
965
		}
966

    
967
		hardware_offloading_applyflags($interface);
968
		interfaces_bring_up($interface);
969
	}
970

    
971
	pfSense_bridge_add_member($bridgeif, $interface);
972
	if (is_array($config['bridges']['bridged'])) {
973
		foreach ($config['bridges']['bridged'] as $bridge) {
974
			if ($bridgeif == $bridge['bridgeif']) {
975
				interface_bridge_configure_stp($bridge);
976
				interface_bridge_configure_advanced($bridge);
977
			}
978
		}
979
	}
980
}
981

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

    
1006
function interface_lagg_configure($lagg) {
1007
	global $config, $g;
1008

    
1009
	if (!is_array($lagg)) {
1010
		return -1;
1011
	}
1012

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

    
1018
	if (platform_booting() || !(empty($lagg['laggif']))) {
1019
		pfSense_interface_destroy($lagg['laggif']);
1020
		pfSense_interface_create($lagg['laggif']);
1021
		$laggif = $lagg['laggif'];
1022
	} else {
1023
		$laggif = pfSense_interface_create("lagg");
1024
	}
1025

    
1026
	/* Check if MTU was defined for this lagg interface */
1027
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
1028
	if ($lagg_mtu == 0 &&
1029
	    is_array($config['interfaces'])) {
1030
		foreach ($config['interfaces'] as $tmpinterface) {
1031
			if ($tmpinterface['if'] == $lagg['laggif'] &&
1032
			    !empty($tmpinterface['mtu'])) {
1033
				$lagg_mtu = $tmpinterface['mtu'];
1034
				break;
1035
			}
1036
		}
1037
	}
1038

    
1039
	/* Just in case anything is not working well */
1040
	if ($lagg_mtu == 0) {
1041
		$lagg_mtu = 1500;
1042
	}
1043

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

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

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

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

    
1062
	interfaces_bring_up($laggif);
1063

    
1064
	return $laggif;
1065
}
1066

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

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

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

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

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

    
1109
	$realif = get_real_interface($gre['if']);
1110
	$realifip = get_interface_ip($gre['if']);
1111
	$realifip6 = get_interface_ipv6($gre['if']);
1112

    
1113
	/* make sure the parent interface is up */
1114
	interfaces_bring_up($realif);
1115

    
1116
	if (platform_booting() || !(empty($gre['greif']))) {
1117
		pfSense_interface_destroy($gre['greif']);
1118
		pfSense_interface_create($gre['greif']);
1119
		$greif = $gre['greif'];
1120
	} else {
1121
		$greif = pfSense_interface_create("gre");
1122
	}
1123

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

    
1138
	if ($greif) {
1139
		interfaces_bring_up($greif);
1140
	} else {
1141
		log_error(gettext("Could not bring greif up -- variable not defined."));
1142
	}
1143

    
1144
	if (isset($gre['link1']) && $gre['link1']) {
1145
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1146
	}
1147
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
1148
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1149
	}
1150
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
1151
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
1152
	}
1153

    
1154
	interfaces_bring_up($greif);
1155

    
1156
	return $greif;
1157
}
1158

    
1159
function interfaces_gif_configure($checkparent = 0, $realif = "") {
1160
	global $config;
1161

    
1162
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
1163
		foreach ($config['gifs']['gif'] as $i => $gif) {
1164
			if (empty($gif['gifif'])) {
1165
				$gre['gifif'] = "gif{$i}";
1166
			}
1167
			if (!empty($realif) && $realif != $gif['gifif']) {
1168
				continue;
1169
			}
1170

    
1171
			if ($checkparent == 1) {
1172
				if (substr($gif['if'], 0, 4) == '_vip') {
1173
					continue;
1174
				}
1175
				if (substr($gif['if'], 0, 5) == '_lloc') {
1176
					continue;
1177
				}
1178
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
1179
					continue;
1180
				}
1181
			}
1182
			else if ($checkparent == 2) {
1183
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
1184
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
1185
					continue;
1186
				}
1187
			}
1188
			/* XXX: Maybe we should report any errors?! */
1189
			interface_gif_configure($gif);
1190
		}
1191
	}
1192
}
1193

    
1194
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1195
function interface_gif_configure(&$gif, $gifkey = "") {
1196
	global $config, $g;
1197

    
1198
	if (!is_array($gif)) {
1199
		return -1;
1200
	}
1201

    
1202
	$realif = get_real_interface($gif['if']);
1203
	$ipaddr = get_interface_ip($gif['if']);
1204

    
1205
	if (is_ipaddrv4($gif['remote-addr'])) {
1206
		if (is_ipaddrv4($ipaddr)) {
1207
			$realifip = $ipaddr;
1208
		} else {
1209
			$realifip = get_interface_ip($gif['if']);
1210
		}
1211
		$realifgw = get_interface_gateway($gif['if']);
1212
	} else if (is_ipaddrv6($gif['remote-addr'])) {
1213
		if (is_ipaddrv6($ipaddr)) {
1214
			$realifip = $ipaddr;
1215
		} else {
1216
			$realifip = get_interface_ipv6($gif['if']);
1217
		}
1218
		$realifgw = get_interface_gateway_v6($gif['if']);
1219
	}
1220
	/* make sure the parent interface is up */
1221
	if ($realif) {
1222
		interfaces_bring_up($realif);
1223
	} else {
1224
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
1225
	}
1226

    
1227
	if (platform_booting() || !(empty($gif['gifif']))) {
1228
		pfSense_interface_destroy($gif['gifif']);
1229
		pfSense_interface_create($gif['gifif']);
1230
		$gifif = $gif['gifif'];
1231
	} else {
1232
		$gifif = pfSense_interface_create("gif");
1233
	}
1234

    
1235
	/* Do not change the order here for more see gif(4) NOTES section. */
1236
	if (is_ipaddrv6($gif['remote-addr'])) {
1237
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1238
	} else {
1239
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1240
	}
1241
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1242
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1243
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1244
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1245
	} else {
1246
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1247
	}
1248
	if (isset($gif['link1'])) {
1249
		pfSense_interface_flags($gifif, IFF_LINK1);
1250
	}
1251
	if (isset($gif['link2'])) {
1252
		pfSense_interface_flags($gifif, IFF_LINK2);
1253
	}
1254
	if ($gifif) {
1255
		interfaces_bring_up($gifif);
1256
		$gifmtu = "";
1257
		$currentgifmtu = get_interface_mtu($gifif);
1258
		foreach ($config['interfaces'] as $tmpinterface) {
1259
			if ($tmpinterface['if'] == $gifif) {
1260
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1261
					$gifmtu = $tmpinterface['mtu'];
1262
				}
1263
			}
1264
		}
1265
		if (is_numericint($gifmtu)) {
1266
			if ($gifmtu != $currentgifmtu) {
1267
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1268
			}
1269
		}
1270
	} else {
1271
		log_error(gettext("could not bring gifif up -- variable not defined"));
1272
	}
1273

    
1274
	if (!platform_booting()) {
1275
		$iflist = get_configured_interface_list();
1276
		foreach ($iflist as $ifname) {
1277
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1278
				if (get_interface_gateway($ifname)) {
1279
					system_routing_configure($ifname);
1280
					break;
1281
				}
1282
				if (get_interface_gateway_v6($ifname)) {
1283
					system_routing_configure($ifname);
1284
					break;
1285
				}
1286
			}
1287
		}
1288
	}
1289

    
1290

    
1291
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1292
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1293
	}
1294
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1295
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1296
	}
1297

    
1298
	if (is_ipaddrv4($realifgw)) {
1299
		route_add_or_change("-host {$gif['remote-addr']} {$realifgw}");
1300
	}
1301
	if (is_ipaddrv6($realifgw)) {
1302
		route_add_or_change("-host -inet6 {$gif['remote-addr']} {$realifgw}");
1303
	}
1304

    
1305
	interfaces_bring_up($gifif);
1306

    
1307
	return $gifif;
1308
}
1309

    
1310
/* Build a list of IPsec interfaces */
1311
function interface_ipsec_vti_list_p1($ph1ent) {
1312
	global $config;
1313
	$iface_list = array();
1314

    
1315
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1316
		return $iface_list;
1317
	}
1318

    
1319
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1320
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1321
		return $iface_list;
1322
	}
1323

    
1324
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1325
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1326
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1327
			$iface_list["ipsec{$ph1ent['ikeid']}00{$idx}"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1328
		}
1329
	} else {
1330
		/* For IKEv2, only create one interface with additional addresses as aliases */
1331
		$iface_list["ipsec{$ph1ent['ikeid']}000"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1332
	}
1333
	return $iface_list;
1334
}
1335
function interface_ipsec_vti_list_all() {
1336
	global $config;
1337
	$iface_list = array();
1338
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1339
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1340
			if ($ph1ent['disabled']) {
1341
				continue;
1342
			}
1343
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1344
		}
1345
	}
1346
	return $iface_list;
1347
}
1348

    
1349
function is_interface_ipsec_vti_assigned($phase2) {
1350
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1351
	$vti_interface = null;
1352
	$vtisubnet_spec = ipsec_vti($phase1, true);
1353
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1354
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1355
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1356
			foreach ($vtisubnet_spec as $idx => $vtisub) {
1357
				/* Is this for this P2? */
1358
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1359
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1360
					$vti_interface = "ipsec{$phase1['ikeid']}00{$idx}";
1361
				}
1362
			}
1363
		} else {
1364
			$vti_interface = "ipsec{$phase1['ikeid']}000";
1365
		}
1366
	}
1367
	/* Check if this interface is assigned */
1368
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1369
}
1370
function interface_ipsec_vti_configure($ph1ent) {
1371
	global $config;
1372

    
1373
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1374
		return false;
1375
	}
1376

    
1377
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1378
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1379
		return false;
1380
	}
1381

    
1382
	$left_spec = ipsec_get_phase1_src($ph1ent);
1383
	$right_spec = $ph1ent['remote-gateway'];
1384

    
1385
	$iface_addrs = array();
1386

    
1387
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1388
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1389
		/* Form a single interface for each P2 entry */
1390
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1391
			$ipsecifnum = "{$ph1ent['ikeid']}00{$idx}";
1392
			if (!is_array($iface_addrs[$ipsecifnum])) {
1393
				$iface_addrs[$ipsecifnum] = array();
1394
			}
1395
			$vtisub['alias'] = "";
1396
			$iface_addrs[$ipsecifnum][] = $vtisub;
1397
		}
1398
	} else {
1399
		/* For IKEv2, only create one interface with additional addresses as aliases */
1400
		$ipsecifnum = "{$ph1ent['ikeid']}000";
1401
		if (!is_array($iface_addrs[$ipsecifnum])) {
1402
			$iface_addrs[$ipsecifnum] = array();
1403
		}
1404
		$have_v4 = false;
1405
		$have_v6 = false;
1406
		foreach ($vtisubnet_spec as $vtisub) {
1407
			// Alias stuff
1408
			$vtisub['alias'] = "";
1409
			if (is_ipaddrv6($vtisub['left'])) {
1410
				if ($have_v6) {
1411
					$vtisub['alias'] = " alias";
1412
				}
1413
				$have_v6 = true;
1414
			} else {
1415
				if ($have_v4) {
1416
					$vtisub['alias'] = " alias";
1417
				}
1418
				$have_v4 = true;
1419
			}
1420
			$iface_addrs[$ipsecifnum][] = $vtisub;
1421
		}
1422
	}
1423

    
1424
	foreach ($iface_addrs as $ipsecifnum => $addrs) {
1425
		$ipsecif = "ipsec{$ipsecifnum}";
1426
		if (!is_array($addrs)) {
1427
			continue;
1428
		}
1429
		// Create IPsec interface
1430
		if (platform_booting() || !does_interface_exist($ipsecif)) {
1431
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy", false);
1432
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1433
		} else {
1434
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1435
		}
1436

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

    
1441
		/* Loop through all of the addresses for this interface and apply them as needed */
1442
		foreach ($addrs as $addr) {
1443
			// apply interface addresses
1444
			if (is_ipaddrv6($addr['left'])) {
1445
				$inet = "inet6";
1446
				$gwtype = "v6";
1447
			} else {
1448
				$inet = "inet";
1449
				$gwtype = "";
1450
			}
1451

    
1452
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . escapeshellarg($addr['right']) . $addr['alias'], false);
1453
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1454
			if (empty($addr['alias'])) {
1455
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1456
			}
1457
		}
1458
		/* Check/set the MTU if the user configured a custom value.
1459
		 * https://redmine.pfsense.org/issues/9111 */
1460
		$currentvtimtu = get_interface_mtu($ipsecif);
1461
		foreach ($config['interfaces'] as $tmpinterface) {
1462
			if ($tmpinterface['if'] == $ipsecif) {
1463
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1464
					$vtimtu = $tmpinterface['mtu'];
1465
				}
1466
			}
1467
		}
1468
		if (is_numericint($vtimtu)) {
1469
			if ($vtimtu != $currentvtimtu) {
1470
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1471
			}
1472
		}
1473
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1474
	}
1475
}
1476

    
1477
function interfaces_ipsec_vti_configure() {
1478
	global $config;
1479
	if (platform_booting()) {
1480
		echo gettext("Configuring IPsec VTI interfaces...");
1481
	}
1482
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1483
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1484
			if ($ph1ent['disabled']) {
1485
				continue;
1486
			}
1487
			interface_ipsec_vti_configure($ph1ent);
1488
		}
1489
	}
1490
	if (platform_booting()) {
1491
		echo gettext("done.") . "\n";
1492
	}
1493
}
1494

    
1495
function interfaces_configure() {
1496
	global $config, $g;
1497

    
1498
	/* Set up our loopback interface */
1499
	interfaces_loopback_configure();
1500

    
1501
	/* create the unconfigured wireless clones */
1502
	interfaces_create_wireless_clones();
1503

    
1504
	/* set up LAGG virtual interfaces */
1505
	interfaces_lagg_configure();
1506

    
1507
	/* set up VLAN virtual interfaces */
1508
	interfaces_vlan_configure();
1509

    
1510
	interfaces_qinq_configure();
1511

    
1512
	/* set up IPsec VTI interfaces */
1513
	interfaces_ipsec_vti_configure();
1514

    
1515
	$iflist = get_configured_interface_with_descr();
1516
	$delayed_list = array();
1517
	$bridge_list = array();
1518
	$track6_list = array();
1519

    
1520
	/* This is needed to speedup interfaces on bootup. */
1521
	$reload = false;
1522
	if (!platform_booting()) {
1523
		$reload = true;
1524
	}
1525

    
1526
	foreach ($iflist as $if => $ifname) {
1527
		$realif = $config['interfaces'][$if]['if'];
1528
		if (strstr($realif, "bridge")) {
1529
			$bridge_list[$if] = $ifname;
1530
		} else if (strstr($realif, "gre")) {
1531
			$delayed_list[$if] = $ifname;
1532
		} else if (strstr($realif, "gif")) {
1533
			$delayed_list[$if] = $ifname;
1534
		} else if (strstr($realif, "ovpn")) {
1535
			//echo "Delaying OpenVPN interface configuration...done.\n";
1536
			continue;
1537
		} else if (strstr($realif, "ipsec")) {
1538
			continue;
1539
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1540
			$track6_list[$if] = $ifname;
1541
		} else {
1542
			if (platform_booting()) {
1543
				printf(gettext("Configuring %s interface..."), $ifname);
1544
			}
1545

    
1546
			if ($g['debug']) {
1547
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1548
			}
1549
			interface_configure($if, $reload);
1550
			if (platform_booting()) {
1551
				echo gettext("done.") . "\n";
1552
			}
1553
		}
1554
	}
1555

    
1556
	/*
1557
	 * NOTE: The following function parameter consists of
1558
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1559
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1560
	 */
1561

    
1562
	/* set up GRE virtual interfaces */
1563
	interfaces_gre_configure(1);
1564

    
1565
	/* set up GIF virtual interfaces */
1566
	interfaces_gif_configure(1);
1567

    
1568
	/* set up BRIDGe virtual interfaces */
1569
	interfaces_bridge_configure(1);
1570

    
1571
	foreach ($track6_list as $if => $ifname) {
1572
		if (platform_booting()) {
1573
			printf(gettext("Configuring %s interface..."), $ifname);
1574
		}
1575
		if ($g['debug']) {
1576
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1577
		}
1578

    
1579
		interface_configure($if, $reload);
1580

    
1581
		if (platform_booting()) {
1582
			echo gettext("done.") . "\n";
1583
		}
1584
	}
1585

    
1586
	/* bring up vip interfaces */
1587
	interfaces_vips_configure();
1588

    
1589
	/* set up GRE virtual interfaces */
1590
	interfaces_gre_configure(2);
1591

    
1592
	/* set up GIF virtual interfaces */
1593
	interfaces_gif_configure(2);
1594

    
1595
	foreach ($delayed_list as $if => $ifname) {
1596
		if (platform_booting()) {
1597
			printf(gettext("Configuring %s interface..."), $ifname);
1598
		}
1599
		if ($g['debug']) {
1600
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1601
		}
1602

    
1603
		interface_configure($if, $reload);
1604

    
1605
		if (platform_booting()) {
1606
			echo gettext("done.") . "\n";
1607
		}
1608
	}
1609

    
1610
	/* set up BRIDGe virtual interfaces */
1611
	interfaces_bridge_configure(2);
1612

    
1613
	foreach ($bridge_list as $if => $ifname) {
1614
		if (platform_booting()) {
1615
			printf(gettext("Configuring %s interface..."), $ifname);
1616
		}
1617
		if ($g['debug']) {
1618
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1619
		}
1620

    
1621
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1622
		// redmine #3997
1623
		interface_reconfigure($if, $reload);
1624
		interfaces_vips_configure($if);
1625

    
1626
		if (platform_booting()) {
1627
			echo gettext("done.") . "\n";
1628
		}
1629
	}
1630

    
1631
	/* configure interface groups */
1632
	interfaces_group_setup();
1633

    
1634
	if (!platform_booting()) {
1635
		/* reconfigure static routes (kernel may have deleted them) */
1636
		system_routing_configure();
1637

    
1638
		/* reload IPsec tunnels */
1639
		vpn_ipsec_configure();
1640

    
1641
		/* restart dns servers (defering dhcpd reload) */
1642
		if (isset($config['dnsmasq']['enable'])) {
1643
			services_dnsmasq_configure(false);
1644
		}
1645
		if (isset($config['unbound']['enable'])) {
1646
			services_unbound_configure(false);
1647
		}
1648

    
1649
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1650
		services_dhcpd_configure();
1651
	}
1652

    
1653
	return 0;
1654
}
1655

    
1656
function interface_reconfigure($interface = "wan", $reloadall = false) {
1657
	interface_bring_down($interface);
1658
	interface_configure($interface, $reloadall);
1659
}
1660

    
1661
function interface_vip_bring_down($vip) {
1662
	global $g;
1663

    
1664
	$vipif = get_real_interface($vip['interface']);
1665
	switch ($vip['mode']) {
1666
		case "proxyarp":
1667
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1668
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1669
			}
1670
			break;
1671
		case "ipalias":
1672
			if (does_interface_exist($vipif)) {
1673
				if (is_ipaddrv6($vip['subnet'])) {
1674
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1675
				} else {
1676
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1677
				}
1678
			}
1679
			break;
1680
		case "carp":
1681
			/* XXX: Is enough to delete ip address? */
1682
			if (does_interface_exist($vipif)) {
1683
				if (is_ipaddrv6($vip['subnet'])) {
1684
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1685
				} else {
1686
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1687
				}
1688
			}
1689
			break;
1690
	}
1691
}
1692

    
1693
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1694
	global $config, $g;
1695

    
1696
	if (!isset($config['interfaces'][$interface])) {
1697
		return;
1698
	}
1699

    
1700
	if ($g['debug']) {
1701
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1702
	}
1703

    
1704
	/*
1705
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1706
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1707
	 * Keep this in mind while doing changes here!
1708
	 */
1709
	if ($ifacecfg === false) {
1710
		$ifcfg = $config['interfaces'][$interface];
1711
		$ppps = $config['ppps']['ppp'];
1712
		$realif = get_real_interface($interface);
1713
		$realifv6 = get_real_interface($interface, "inet6", true);
1714
	} elseif (!is_array($ifacecfg)) {
1715
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1716
		$ifcfg = $config['interfaces'][$interface];
1717
		$ppps = $config['ppps']['ppp'];
1718
		$realif = get_real_interface($interface);
1719
		$realifv6 = get_real_interface($interface, "inet6", true);
1720
	} else {
1721
		$ifcfg = $ifacecfg['ifcfg'];
1722
		$ppps = $ifacecfg['ppps'];
1723
		if (isset($ifacecfg['ifcfg']['realif'])) {
1724
			$realif = $ifacecfg['ifcfg']['realif'];
1725
			/* XXX: Any better way? */
1726
			$realifv6 = $realif;
1727
		} else {
1728
			$realif = get_real_interface($interface);
1729
			$realifv6 = get_real_interface($interface, "inet6", true);
1730
		}
1731
	}
1732

    
1733
	switch ($ifcfg['ipaddr']) {
1734
		case "ppp":
1735
		case "pppoe":
1736
		case "pptp":
1737
		case "l2tp":
1738
			if (is_array($ppps) && count($ppps)) {
1739
				foreach ($ppps as $pppid => $ppp) {
1740
					if ($realif == $ppp['if']) {
1741
						if (isset($ppp['ondemand']) && !$destroy) {
1742
							send_event("interface reconfigure {$interface}");
1743
							break;
1744
						}
1745
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1746
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1747
							sleep(2);
1748
						}
1749
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1750
						break;
1751
					}
1752
				}
1753
			}
1754
			break;
1755
		case "dhcp":
1756
			kill_dhclient_process($realif);
1757
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1758
			if (does_interface_exist("$realif")) {
1759
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1760
				interface_vip_cleanup($interface, "inet4");
1761
				if ($destroy == true) {
1762
					pfSense_interface_flags($realif, -IFF_UP);
1763
				}
1764
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1765
			}
1766
			break;
1767
		default:
1768
			if (does_interface_exist("$realif")) {
1769
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1770
				interface_vip_cleanup($interface, "inet4");
1771
				if ($destroy == true) {
1772
					pfSense_interface_flags($realif, -IFF_UP);
1773
				}
1774
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1775
			}
1776
			break;
1777
	}
1778

    
1779
	$track6 = array();
1780
	switch ($ifcfg['ipaddrv6']) {
1781
		case "slaac":
1782
		case "dhcp6":
1783
			kill_dhcp6client_process($realif, $destroy, false);
1784
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1785
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1786
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1787
			if (does_interface_exist($realifv6)) {
1788
				$ip6 = find_interface_ipv6($realifv6);
1789
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1790
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1791
				}
1792
				interface_vip_cleanup($interface, "inet6");
1793
				if ($destroy == true) {
1794
					pfSense_interface_flags($realif, -IFF_UP);
1795
				}
1796
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1797
			}
1798
			$track6 = link_interface_to_track6($interface);
1799
			break;
1800
		case "6rd":
1801
		case "6to4":
1802
			$realif = "{$interface}_stf";
1803
			if (does_interface_exist("$realif")) {
1804
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1805
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1806
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1807
					$destroy = true;
1808
				} else {
1809
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1810
					$ip6 = get_interface_ipv6($interface);
1811
					if (is_ipaddrv6($ip6)) {
1812
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1813
					}
1814
				}
1815
				interface_vip_cleanup($interface, "inet6");
1816
				if ($destroy == true) {
1817
					pfSense_interface_flags($realif, -IFF_UP);
1818
				}
1819
			}
1820
			$track6 = link_interface_to_track6($interface);
1821
			break;
1822
		default:
1823
			if (does_interface_exist("$realif")) {
1824
				$ip6 = get_interface_ipv6($interface);
1825
				if (is_ipaddrv6($ip6)) {
1826
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1827
				}
1828
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1829
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1830
				}
1831
				interface_vip_cleanup($interface, "inet6");
1832
				if ($destroy == true) {
1833
					pfSense_interface_flags($realif, -IFF_UP);
1834
				}
1835
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1836
			}
1837
			$track6 = link_interface_to_track6($interface);
1838
			break;
1839
	}
1840

    
1841
	if (!empty($track6) && is_array($track6)) {
1842
		if (!function_exists('services_dhcpd_configure')) {
1843
			require_once('services.inc');
1844
		}
1845
		/* Bring down radvd and dhcp6 on these interfaces */
1846
		services_dhcpd_configure('inet6', $track6);
1847
	}
1848

    
1849
	$old_router = '';
1850
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1851
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1852
	}
1853

    
1854
	/* remove interface up file if it exists */
1855
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1856
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1857
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1858
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1859
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1860
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1861
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1862

    
1863
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1864
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1865
	if (is_array($ifcfg['wireless'])) {
1866
		kill_hostapd($realif);
1867
		mwexec(kill_wpasupplicant($realif));
1868
	}
1869

    
1870
	if ($destroy == true) {
1871
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^ipsec|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1872
			pfSense_interface_destroy($realif);
1873
		}
1874
	}
1875

    
1876
	return;
1877
}
1878

    
1879
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1880
	global $config;
1881
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1882
		unset($config["virtualip_carp_maintenancemode"]);
1883
		write_config("Leave CARP maintenance mode");
1884
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1885
		$config["virtualip_carp_maintenancemode"] = true;
1886
		write_config(gettext("Enter CARP maintenance mode"));
1887
	}
1888
	init_config_arr(array('virtualip', 'vip'));
1889
	$viparr = &$config['virtualip']['vip'];
1890

    
1891
	if (is_array($viparr)) {
1892
		foreach ($viparr as $vip) {
1893
			if ($vip['mode'] == "carp") {
1894
				interface_carp_configure($vip, true);
1895
			}
1896
		}
1897
	}
1898
}
1899

    
1900
function interface_wait_tentative($interface, $timeout = 10) {
1901
	if (!does_interface_exist($interface)) {
1902
		return false;
1903
	}
1904

    
1905
	$time = 0;
1906
	while ($time <= $timeout) {
1907
		$if = pfSense_get_interface_addresses($interface);
1908
		if (!isset($if['tentative'])) {
1909
			return true;
1910
		}
1911
		sleep(1);
1912
		$time++;
1913
	}
1914

    
1915
	return false;
1916
}
1917

    
1918
function interface_isppp_type($interface) {
1919
	global $config;
1920

    
1921
	if (!is_array($config['interfaces'][$interface])) {
1922
		return false;
1923
	}
1924

    
1925
	switch ($config['interfaces'][$interface]['ipaddr']) {
1926
		case 'pptp':
1927
		case 'l2tp':
1928
		case 'pppoe':
1929
		case 'ppp':
1930
			return true;
1931
			break;
1932
		default:
1933
			return false;
1934
			break;
1935
	}
1936
}
1937

    
1938
function interfaces_ptpid_used($ptpid) {
1939
	global $config;
1940

    
1941
	if (is_array($config['ppps']['ppp'])) {
1942
		foreach ($config['ppps']['ppp'] as & $settings) {
1943
			if ($ptpid == $settings['ptpid']) {
1944
				return true;
1945
			}
1946
		}
1947
	}
1948

    
1949
	return false;
1950
}
1951

    
1952
function interfaces_ptpid_next() {
1953

    
1954
	$ptpid = 0;
1955
	while (interfaces_ptpid_used($ptpid)) {
1956
		$ptpid++;
1957
	}
1958

    
1959
	return $ptpid;
1960
}
1961

    
1962
function getMPDCRONSettings($pppif) {
1963
	global $config;
1964

    
1965
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1966
	if (is_array($config['cron']['item'])) {
1967
		foreach ($config['cron']['item'] as $i => $item) {
1968
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1969
				return array("ID" => $i, "ITEM" => $item);
1970
			}
1971
		}
1972
	}
1973

    
1974
	return NULL;
1975
}
1976

    
1977
function handle_pppoe_reset($post_array) {
1978
	global $config, $g;
1979

    
1980
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1981
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1982

    
1983
	if (!is_array($config['cron']['item'])) {
1984
		$config['cron']['item'] = array();
1985
	}
1986

    
1987
	$itemhash = getMPDCRONSettings($pppif);
1988

    
1989
	// reset cron items if necessary and return
1990
	if (empty($post_array['pppoe-reset-type'])) {
1991
		if (isset($itemhash)) {
1992
			unset($config['cron']['item'][$itemhash['ID']]);
1993
		}
1994
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1995
		return;
1996
	}
1997

    
1998
	if (empty($itemhash)) {
1999
		$itemhash = array();
2000
	}
2001
	$item = array();
2002
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2003
		$item['minute'] = $post_array['pppoe_resetminute'];
2004
		$item['hour'] = $post_array['pppoe_resethour'];
2005
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2006
			$date = explode("/", $post_array['pppoe_resetdate']);
2007
			$item['mday'] = $date[1];
2008
			$item['month'] = $date[0];
2009
		} else {
2010
			$item['mday'] = "*";
2011
			$item['month'] = "*";
2012
		}
2013
		$item['wday'] = "*";
2014
		$item['who'] = "root";
2015
		$item['command'] = $cron_cmd_file;
2016
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2017
		switch ($post_array['pppoe_pr_preset_val']) {
2018
			case "monthly":
2019
				$item['minute'] = "0";
2020
				$item['hour'] = "0";
2021
				$item['mday'] = "1";
2022
				$item['month'] = "*";
2023
				$item['wday'] = "*";
2024
				break;
2025
			case "weekly":
2026
				$item['minute'] = "0";
2027
				$item['hour'] = "0";
2028
				$item['mday'] = "*";
2029
				$item['month'] = "*";
2030
				$item['wday'] = "0";
2031
				break;
2032
			case "daily":
2033
				$item['minute'] = "0";
2034
				$item['hour'] = "0";
2035
				$item['mday'] = "*";
2036
				$item['month'] = "*";
2037
				$item['wday'] = "*";
2038
				break;
2039
			case "hourly":
2040
				$item['minute'] = "0";
2041
				$item['hour'] = "*";
2042
				$item['mday'] = "*";
2043
				$item['month'] = "*";
2044
				$item['wday'] = "*";
2045
				break;
2046
		} // end switch
2047
		$item['who'] = "root";
2048
		$item['command'] = $cron_cmd_file;
2049
	}
2050
	if (empty($item)) {
2051
		return;
2052
	}
2053
	if (isset($itemhash['ID'])) {
2054
		$config['cron']['item'][$itemhash['ID']] = $item;
2055
	} else {
2056
		$config['cron']['item'][] = $item;
2057
	}
2058
}
2059

    
2060
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2061
	global $config;
2062
	$ppp_list = array();
2063
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2064
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2065
			$ports = explode(",", $ppp['ports']);
2066
			foreach($ports as $port) {
2067
				foreach($triggerinterfaces as $vip) {
2068
					if ($port == "_vip{$vip['uniqid']}") {
2069
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2070
						$ppp_list[$if] = 1;
2071
					}
2072
				}
2073
			}
2074
		}
2075
	}
2076
	foreach($ppp_list as $pppif => $dummy) {
2077
		interface_ppps_configure($pppif);
2078
	}
2079
}
2080

    
2081
/*
2082
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2083
 * It writes the mpd config file to /var/etc every time the link is opened.
2084
 */
2085
function interface_ppps_configure($interface) {
2086
	global $config, $g;
2087

    
2088
	/* Return for unassigned interfaces. This is a minimum requirement. */
2089
	if (empty($config['interfaces'][$interface])) {
2090
		return 0;
2091
	}
2092
	$ifcfg = $config['interfaces'][$interface];
2093
	if (!isset($ifcfg['enable'])) {
2094
		return 0;
2095
	}
2096

    
2097
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2098
	if (!is_dir("/var/spool/lock")) {
2099
		mkdir("/var/spool/lock", 0777, true);
2100
	}
2101
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2102
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2103
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2104
	}
2105

    
2106
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2107
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2108
			if ($ifcfg['if'] == $ppp['if']) {
2109
				break;
2110
			}
2111
		}
2112
	}
2113
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2114
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2115
		return 0;
2116
	}
2117
	$pppif = $ifcfg['if'];
2118
	if ($ppp['type'] == "ppp") {
2119
		$type = "modem";
2120
	} else {
2121
		$type = $ppp['type'];
2122
	}
2123
	$upper_type = strtoupper($ppp['type']);
2124

    
2125
	/* XXX: This does not make sense and may create trouble
2126
	 * comment it for now to be removed later on.
2127
	if (platform_booting()) {
2128
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
2129
		echo "starting {$pppif} link...";
2130
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
2131
			return 0;
2132
	}
2133
	*/
2134
	$confports = explode(',', $ppp['ports']);
2135
	if ($type == "modem") {
2136
		$ports = $confports;
2137
	} else {
2138
		$ports = array();
2139
		foreach ($confports as $pid => $port) {
2140
			if (strstr($port, "_vip")) {
2141
				if (get_carp_interface_status($port) != "MASTER") {
2142
					continue;
2143
				}
2144
			}
2145
			$ports[$pid] = get_real_interface($port);
2146
			if (empty($ports[$pid])) {
2147
				return 0;
2148
			}
2149
		}
2150
	}
2151
	$localips = explode(',', $ppp['localip']);
2152
	$gateways = explode(',', $ppp['gateway']);
2153
	$subnets = explode(',', $ppp['subnet']);
2154

    
2155
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2156
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2157
	 */
2158
	foreach ($ports as $pid => $port) {
2159
		switch ($ppp['type']) {
2160
			case "pppoe":
2161
				/* Bring the parent interface up */
2162
				interfaces_bring_up($port);
2163
				pfSense_ngctl_attach(".", $port);
2164
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2165
				$ngif = str_replace(".", "_", $port);
2166
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2167
				break;
2168
			case "pptp":
2169
			case "l2tp":
2170
				/* configure interface */
2171
				if (is_ipaddr($localips[$pid])) {
2172
					// Manually configure interface IP/subnet
2173
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2174
					interfaces_bring_up($port);
2175
				} else if (empty($localips[$pid])) {
2176
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2177
				}
2178

    
2179
				if (!is_ipaddr($localips[$pid])) {
2180
					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));
2181
					$localips[$pid] = "0.0.0.0";
2182
				}
2183
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2184
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2185
				}
2186
				if (!is_ipaddr($gateways[$pid])) {
2187
					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));
2188
					return 0;
2189
				}
2190
				pfSense_ngctl_attach(".", $port);
2191
				break;
2192
			case "ppp":
2193
				if (!file_exists("{$port}")) {
2194
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2195
					return 0;
2196
				}
2197
				break;
2198
			default:
2199
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2200
				break;
2201
		}
2202
	}
2203

    
2204
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2205
	    (is_array($ports) && count($ports) > 1)) {
2206
		$multilink = "enable";
2207
	} else {
2208
		$multilink = "disable";
2209
	}
2210

    
2211
	if ($type == "modem") {
2212
		if (is_ipaddr($ppp['localip'])) {
2213
			$localip = $ppp['localip'];
2214
		} else {
2215
			$localip = '0.0.0.0';
2216
		}
2217

    
2218
		if (is_ipaddr($ppp['gateway'])) {
2219
			$gateway = $ppp['gateway'];
2220
		} else {
2221
			$gateway = "10.64.64.{$pppid}";
2222
		}
2223
		$ranges = "{$localip}/0 {$gateway}/0";
2224

    
2225
		if (empty($ppp['apnum'])) {
2226
			$ppp['apnum'] = 1;
2227
		}
2228
	} else {
2229
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2230
	}
2231

    
2232
	if (isset($ppp['ondemand'])) {
2233
		$ondemand = "enable";
2234
	} else {
2235
		$ondemand = "disable";
2236
	}
2237
	if (!isset($ppp['idletimeout'])) {
2238
		$ppp['idletimeout'] = 0;
2239
	}
2240

    
2241
	if (empty($ppp['username']) && $type == "modem") {
2242
		$ppp['username'] = "user";
2243
		$ppp['password'] = "none";
2244
	}
2245
	if (empty($ppp['password']) && $type == "modem") {
2246
		$passwd = "none";
2247
	} else {
2248
		$passwd = base64_decode($ppp['password']);
2249
	}
2250

    
2251
	$bandwidths = explode(',', $ppp['bandwidth']);
2252
	$defaultmtu = "1492";
2253
	if (!empty($ifcfg['mtu'])) {
2254
		$defaultmtu = intval($ifcfg['mtu']);
2255
	}
2256
	if (isset($ppp['mtu'])) {
2257
		$mtus = explode(',', $ppp['mtu']);
2258
	}
2259
	if (isset($ppp['mru'])) {
2260
		$mrus = explode(',', $ppp['mru']);
2261
	}
2262
	if (isset($ppp['mrru'])) {
2263
		$mrrus = explode(',', $ppp['mrru']);
2264
	}
2265

    
2266
	// Construct the mpd.conf file
2267
	$mpdconf = <<<EOD
2268
startup:
2269
	# configure the console
2270
	set console close
2271
	# configure the web server
2272
	set web close
2273

    
2274
default:
2275
{$ppp['type']}client:
2276
	create bundle static {$interface}
2277
	set bundle enable ipv6cp
2278
	set iface name {$pppif}
2279

    
2280
EOD;
2281
	$setdefaultgw = false;
2282
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2283
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2284
	if ($defgw4['interface'] == $interface) {
2285
		$setdefaultgw = true;
2286
	}
2287

    
2288
/* Omit this, we maintain the default route by other means, and it causes problems with
2289
 * default gateway switching. See redmine #1837 for original issue
2290
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2291
 * edge case. redmine #6495 open to address.
2292
 */
2293
	if ($setdefaultgw == true) {
2294
		$mpdconf .= <<<EOD
2295
	set iface route default
2296

    
2297
EOD;
2298
	}
2299

    
2300
	$mpdconf .= <<<EOD
2301
	set iface {$ondemand} on-demand
2302
	set iface idle {$ppp['idletimeout']}
2303

    
2304
EOD;
2305

    
2306
	if (isset($ppp['ondemand'])) {
2307
		$mpdconf .= <<<EOD
2308
	set iface addrs 10.10.1.1 10.10.1.2
2309

    
2310
EOD;
2311
	}
2312

    
2313
	if (isset($ppp['mtu-override']) &&
2314
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2315
		/* Find the smaller MTU set on ports */
2316
		$mtu = $defaultmtu;
2317
		foreach ($ports as $pid => $port) {
2318
			if (empty($mtus[$pid])) {
2319
				$mtus[$pid] = $defaultmtu;
2320
			}
2321
			if ($type == "pppoe") {
2322
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2323
					$mtus[$pid] = get_interface_mtu($port) - 8;
2324
				}
2325
			}
2326
			if ($mtu > $mtus[$pid]) {
2327
				$mtu = $mtus[$pid];
2328
			}
2329
		}
2330
		$mpdconf .= <<<EOD
2331
	set iface mtu {$mtu} override
2332

    
2333
EOD;
2334
	}
2335

    
2336
	if (isset($ppp['tcpmssfix'])) {
2337
		$tcpmss = "disable";
2338
	} else {
2339
		$tcpmss = "enable";
2340
	}
2341
	$mpdconf .= <<<EOD
2342
	set iface {$tcpmss} tcpmssfix
2343

    
2344
EOD;
2345

    
2346
	$mpdconf .= <<<EOD
2347
	set iface up-script /usr/local/sbin/ppp-linkup
2348
	set iface down-script /usr/local/sbin/ppp-linkdown
2349
	set ipcp ranges {$ranges}
2350

    
2351
EOD;
2352
	if (isset($ppp['vjcomp'])) {
2353
		$mpdconf .= <<<EOD
2354
	set ipcp no vjcomp
2355

    
2356
EOD;
2357
	}
2358

    
2359
	if (isset($config['system']['dnsallowoverride'])) {
2360
		$mpdconf .= <<<EOD
2361
	set ipcp enable req-pri-dns
2362
	set ipcp enable req-sec-dns
2363

    
2364
EOD;
2365
	}
2366

    
2367
	if (!isset($ppp['verbose_log'])) {
2368
		$mpdconf .= <<<EOD
2369
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2370

    
2371
EOD;
2372
	}
2373

    
2374
	foreach ($ports as $pid => $port) {
2375
		$port = get_real_interface($port);
2376
		$mpdconf .= <<<EOD
2377

    
2378
	create link static {$interface}_link{$pid} {$type}
2379
	set link action bundle {$interface}
2380
	set link {$multilink} multilink
2381
	set link keep-alive 10 60
2382
	set link max-redial 0
2383

    
2384
EOD;
2385
		if (isset($ppp['shortseq'])) {
2386
			$mpdconf .= <<<EOD
2387
	set link no shortseq
2388

    
2389
EOD;
2390
		}
2391

    
2392
		if (isset($ppp['acfcomp'])) {
2393
			$mpdconf .= <<<EOD
2394
	set link no acfcomp
2395

    
2396
EOD;
2397
		}
2398

    
2399
		if (isset($ppp['protocomp'])) {
2400
			$mpdconf .= <<<EOD
2401
	set link no protocomp
2402

    
2403
EOD;
2404
		}
2405

    
2406
		$mpdconf .= <<<EOD
2407
	set link disable chap pap
2408
	set link accept chap pap eap
2409
	set link disable incoming
2410

    
2411
EOD;
2412

    
2413

    
2414
		if (!empty($bandwidths[$pid])) {
2415
			$mpdconf .= <<<EOD
2416
	set link bandwidth {$bandwidths[$pid]}
2417

    
2418
EOD;
2419
		}
2420

    
2421
		if (empty($mtus[$pid])) {
2422
			$mtus[$pid] = $defaultmtu;
2423
		}
2424
		if ($type == "pppoe") {
2425
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2426
				$mtus[$pid] = get_interface_mtu($port) - 8;
2427
			}
2428
		}
2429
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2430
		    !isset($ppp['mtu-override']) &&
2431
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2432
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2433
			$mpdconf .= <<<EOD
2434
	set link mtu {$mtus[$pid]}
2435

    
2436
EOD;
2437
		}
2438

    
2439
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2440
		    !isset($ppp['mtu-override']) &&
2441
		    !empty($mrus[$pid])) {
2442
			$mpdconf .= <<<EOD
2443
	set link mru {$mrus[$pid]}
2444

    
2445
EOD;
2446
		}
2447

    
2448
		if (!empty($mrrus[$pid])) {
2449
			$mpdconf .= <<<EOD
2450
	set link mrru {$mrrus[$pid]}
2451

    
2452
EOD;
2453
		}
2454

    
2455
		$mpdconf .= <<<EOD
2456
	set auth authname "{$ppp['username']}"
2457
	set auth password {$passwd}
2458

    
2459
EOD;
2460
		if ($type == "modem") {
2461
			$mpdconf .= <<<EOD
2462
	set modem device {$ppp['ports']}
2463
	set modem script DialPeer
2464
	set modem idle-script Ringback
2465
	set modem watch -cd
2466
	set modem var \$DialPrefix "DT"
2467
	set modem var \$Telephone "{$ppp['phone']}"
2468

    
2469
EOD;
2470
		}
2471
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2472
			$mpdconf .= <<<EOD
2473
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2474

    
2475
EOD;
2476
		}
2477
		if (isset($ppp['initstr']) && $type == "modem") {
2478
			$initstr = base64_decode($ppp['initstr']);
2479
			$mpdconf .= <<<EOD
2480
	set modem var \$InitString "{$initstr}"
2481

    
2482
EOD;
2483
		}
2484
		if (isset($ppp['simpin']) && $type == "modem") {
2485
			if ($ppp['pin-wait'] == "") {
2486
				$ppp['pin-wait'] = 0;
2487
			}
2488
			$mpdconf .= <<<EOD
2489
	set modem var \$SimPin "{$ppp['simpin']}"
2490
	set modem var \$PinWait "{$ppp['pin-wait']}"
2491

    
2492
EOD;
2493
		}
2494
		if (isset($ppp['apn']) && $type == "modem") {
2495
			$mpdconf .= <<<EOD
2496
	set modem var \$APN "{$ppp['apn']}"
2497
	set modem var \$APNum "{$ppp['apnum']}"
2498

    
2499
EOD;
2500
		}
2501
		if ($type == "pppoe") {
2502
			// Send a null service name if none is set.
2503
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2504
			$mpdconf .= <<<EOD
2505
	set pppoe service "{$provider}"
2506

    
2507
EOD;
2508
		}
2509
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
2510
			$mpdconf .= <<<EOD
2511
	set pppoe max-payload {$mtus[$pid]}
2512

    
2513
EOD;
2514
		}
2515
		if ($type == "pppoe") {
2516
			$mpdconf .= <<<EOD
2517
	set pppoe iface {$port}
2518

    
2519
EOD;
2520
		}
2521

    
2522
		if ($type == "pptp" || $type == "l2tp") {
2523
			$mpdconf .= <<<EOD
2524
	set {$type} self {$localips[$pid]}
2525
	set {$type} peer {$gateways[$pid]}
2526

    
2527
EOD;
2528
		}
2529

    
2530
		$mpdconf .= "\topen\n";
2531
	} //end foreach ($port)
2532

    
2533

    
2534
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2535
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2536
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2537
	} else {
2538
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2539
		if (!$fd) {
2540
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2541
			return 0;
2542
		}
2543
		// Write out mpd_ppp.conf
2544
		fwrite($fd, $mpdconf);
2545
		fclose($fd);
2546
		unset($mpdconf);
2547
	}
2548

    
2549
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2550
	if (isset($ppp['uptime'])) {
2551
		if (!file_exists("/conf/{$pppif}.log")) {
2552
			file_put_contents("/conf/{$pppif}.log", '');
2553
		}
2554
	} else {
2555
		if (file_exists("/conf/{$pppif}.log")) {
2556
			@unlink("/conf/{$pppif}.log");
2557
		}
2558
	}
2559

    
2560
	/* clean up old lock files */
2561
	foreach ($ports as $port) {
2562
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2563
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2564
		}
2565
	}
2566

    
2567
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2568
	/* random IPv6 interface identifier during boot. More details at */
2569
	/* https://forum.pfsense.org/index.php?topic=101967.msg570519#msg570519 */
2570
	if (platform_booting() && is_array($config['interfaces'])) {
2571
		$count = 0;
2572
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2573
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2574
				$tempaddr[$count]['if'] = $tempiface['if'];
2575
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2576
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2577
				$count++;
2578
			}
2579
			// Maximum /31 is is x.y.z.254/31
2580
			if ($count > 122) {
2581
				break;
2582
			}
2583
		}
2584
		unset($count);
2585
	}
2586

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

    
2592
	// Check for PPPoE periodic reset request
2593
	if ($type == "pppoe") {
2594
		if (!empty($ppp['pppoe-reset-type'])) {
2595
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2596
		} else {
2597
			interface_setup_pppoe_reset_file($ppp['if']);
2598
		}
2599
	}
2600
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2601
	$i = 0;
2602
	while ($i < 10) {
2603
		if (does_interface_exist($ppp['if'], true)) {
2604
			break;
2605
		}
2606
		sleep(3);
2607
		$i++;
2608
	}
2609

    
2610
	/* Remove all temporary bogon IPv4 addresses */
2611
	if (is_array($tempaddr)) {
2612
		foreach ($tempaddr as $tempiface) {
2613
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2614
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2615
			}
2616
		}
2617
		unset ($tempaddr);
2618
	}
2619

    
2620
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2621
	/* We should be able to launch the right version for each modem */
2622
	/* We can also guess the mondev from the manufacturer */
2623
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2624
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2625
	foreach ($ports as $port) {
2626
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2627
			$mondev = substr(basename($port), 0, -1);
2628
			$devlist = glob("/dev/{$mondev}?");
2629
			$mondev = basename(end($devlist));
2630
		}
2631
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2632
			$mondev = substr(basename($port), 0, -1) . "1";
2633
		}
2634
		if ($mondev != '') {
2635
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2636
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2637
		}
2638
	}
2639

    
2640
	return 1;
2641
}
2642

    
2643
function interfaces_sync_setup() {
2644
	global $g, $config;
2645

    
2646
	if (isset($config['system']['developerspew'])) {
2647
		$mt = microtime();
2648
		echo "interfaces_sync_setup() being called $mt\n";
2649
	}
2650

    
2651
	if (platform_booting()) {
2652
		echo gettext("Configuring CARP settings...");
2653
		mute_kernel_msgs();
2654
	}
2655

    
2656
	/* suck in configuration items */
2657
	if ($config['hasync']) {
2658
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2659
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2660
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2661
	} else {
2662
		unset($pfsyncinterface);
2663
		unset($pfsyncenabled);
2664
	}
2665

    
2666
	set_sysctl(array(
2667
		"net.inet.carp.preempt" => "1",
2668
		"net.inet.carp.log" => "1")
2669
	);
2670

    
2671
	if (!empty($pfsyncinterface)) {
2672
		$carp_sync_int = get_real_interface($pfsyncinterface);
2673
	} else {
2674
		unset($carp_sync_int);
2675
	}
2676

    
2677
	/* setup pfsync interface */
2678
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2679
		if (is_ipaddr($pfsyncpeerip)) {
2680
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2681
		} else {
2682
			$syncpeer = "-syncpeer";
2683
		}
2684

    
2685
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2686
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2687

    
2688
		sleep(1);
2689

    
2690
		/* 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
2691
		 * for existing sessions.
2692
		 */
2693
		log_error(gettext("waiting for pfsync..."));
2694
		$i = 0;
2695
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2696
			$i++;
2697
			sleep(1);
2698
		}
2699
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2700
		log_error(gettext("Configuring CARP settings finalize..."));
2701
	} else {
2702
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2703
	}
2704

    
2705
	$carplist = get_configured_vip_list('all', VIP_CARP);
2706
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2707
		set_single_sysctl("net.inet.carp.allow", "1");
2708
	} else {
2709
		set_single_sysctl("net.inet.carp.allow", "0");
2710
	}
2711

    
2712
	if (platform_booting()) {
2713
		unmute_kernel_msgs();
2714
		echo gettext("done.") . "\n";
2715
	}
2716
}
2717

    
2718
function interface_proxyarp_configure($interface = "") {
2719
	global $config, $g;
2720
	if (isset($config['system']['developerspew'])) {
2721
		$mt = microtime();
2722
		echo "interface_proxyarp_configure() being called $mt\n";
2723
	}
2724

    
2725
	/* kill any running choparp */
2726
	if (empty($interface)) {
2727
		killbyname("choparp");
2728
	} else {
2729
		$vipif = get_real_interface($interface);
2730
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2731
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2732
		}
2733
	}
2734

    
2735
	$paa = array();
2736
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2737

    
2738
		/* group by interface */
2739
		foreach ($config['virtualip']['vip'] as $vipent) {
2740
			if ($vipent['mode'] === "proxyarp") {
2741
				if ($vipent['interface']) {
2742
					$proxyif = $vipent['interface'];
2743
				} else {
2744
					$proxyif = "wan";
2745
				}
2746

    
2747
				if (!empty($interface) && $interface != $proxyif) {
2748
					continue;
2749
				}
2750

    
2751
				if (!is_array($paa[$proxyif])) {
2752
					$paa[$proxyif] = array();
2753
				}
2754

    
2755
				$paa[$proxyif][] = $vipent;
2756
			}
2757
		}
2758
	}
2759

    
2760
	if (!empty($interface)) {
2761
		if (is_array($paa[$interface])) {
2762
			$paaifip = get_interface_ip($interface);
2763
			if (!is_ipaddr($paaifip)) {
2764
				return;
2765
			}
2766
			$vipif = get_real_interface($interface);
2767
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2768
			$args .= $vipif . " auto";
2769
			foreach ($paa[$interface] as $paent) {
2770
				if (isset($paent['subnet'])) {
2771
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2772
				} else if (isset($paent['range'])) {
2773
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2774
				}
2775
			}
2776
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2777
		}
2778
	} else if (count($paa) > 0) {
2779
		foreach ($paa as $paif => $paents) {
2780
			$paaifip = get_interface_ip($paif);
2781
			if (!is_ipaddr($paaifip)) {
2782
				continue;
2783
			}
2784
			$vipif = get_real_interface($paif);
2785
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2786
			$args .= $vipif . " auto";
2787
			foreach ($paents as $paent) {
2788
				if (isset($paent['subnet'])) {
2789
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2790
				} else if (isset($paent['range'])) {
2791
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2792
				}
2793
			}
2794
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2795
		}
2796
	}
2797
}
2798

    
2799
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2800
	global $g, $config;
2801

    
2802
	if (is_array($config['virtualip']['vip'])) {
2803
		foreach ($config['virtualip']['vip'] as $vip) {
2804

    
2805
			$iface = $vip['interface'];
2806
			if (substr($iface, 0, 4) == "_vip")
2807
				$iface = get_configured_vip_interface($vip['interface']);
2808
			if ($iface != $interface)
2809
				continue;
2810
			if ($type == VIP_CARP) {
2811
				if ($vip['mode'] != "carp")
2812
					continue;
2813
			} elseif ($type == VIP_IPALIAS) {
2814
				if ($vip['mode'] != "ipalias")
2815
					continue;
2816
			} else {
2817
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2818
					continue;
2819
			}
2820

    
2821
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2822
				interface_vip_bring_down($vip);
2823
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2824
				interface_vip_bring_down($vip);
2825
			else if ($inet == "all")
2826
				interface_vip_bring_down($vip);
2827
		}
2828
	}
2829
}
2830

    
2831
function interfaces_vips_configure($interface = "") {
2832
	global $g, $config;
2833
	if (isset($config['system']['developerspew'])) {
2834
		$mt = microtime();
2835
		echo "interfaces_vips_configure() being called $mt\n";
2836
	}
2837
	$paa = array();
2838
	if (is_array($config['virtualip']['vip'])) {
2839
		$carp_setuped = false;
2840
		$anyproxyarp = false;
2841
		foreach ($config['virtualip']['vip'] as $vip) {
2842
			if ($interface <> "" && get_root_interface($vip['interface']) <> $interface) {
2843
				continue;
2844
			}
2845
			switch ($vip['mode']) {
2846
				case "proxyarp":
2847
					/* nothing it is handled on interface_proxyarp_configure() */
2848
					$anyproxyarp = true;
2849
					break;
2850
				case "ipalias":
2851
					interface_ipalias_configure($vip);
2852
					break;
2853
				case "carp":
2854
					if ($carp_setuped == false) {
2855
						$carp_setuped = true;
2856
					}
2857
					interface_carp_configure($vip);
2858
					break;
2859
			}
2860
		}
2861
		if ($carp_setuped == true) {
2862
			interfaces_sync_setup();
2863
		}
2864
		if ($anyproxyarp == true) {
2865
			interface_proxyarp_configure();
2866
		}
2867
	}
2868
}
2869

    
2870
function interface_ipalias_configure(&$vip) {
2871
	global $config;
2872

    
2873
	if ($vip['mode'] != 'ipalias') {
2874
		return;
2875
	}
2876

    
2877
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2878
	if ($realif != "lo0") {
2879
		$if = convert_real_interface_to_friendly_interface_name($realif);
2880
		if (!isset($config['interfaces'][$if]) ||
2881
		    !isset($config['interfaces'][$if]['enable'])) {
2882
			return;
2883
		}
2884
	}
2885

    
2886
	$af = 'inet';
2887
	if (is_ipaddrv6($vip['subnet'])) {
2888
		$af = 'inet6';
2889
	}
2890
	$iface = $vip['interface'];
2891
	$vhid = '';
2892
	if (substr($vip['interface'], 0, 4) == "_vip") {
2893
		$carpvip = get_configured_vip($vip['interface']);
2894
		$iface = $carpvip['interface'];
2895
		$vhid = "vhid {$carpvip['vhid']}";
2896
	}
2897
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2898
	unset($iface, $af, $realif, $carpvip, $vhid);
2899
}
2900

    
2901
function interface_carp_configure(&$vip, $maintenancemode_only = false) {
2902
	global $config, $g;
2903
	if (isset($config['system']['developerspew'])) {
2904
		$mt = microtime();
2905
		echo "interface_carp_configure() being called $mt\n";
2906
	}
2907

    
2908
	if ($vip['mode'] != "carp") {
2909
		return;
2910
	}
2911

    
2912
	$realif = get_real_interface($vip['interface']);
2913
	if (!does_interface_exist($realif)) {
2914
		file_notice("CARP", sprintf(gettext(
2915
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
2916
		    $vip['subnet']), "Firewall: Virtual IP", "");
2917
		return;
2918
	}
2919
	if ($realif != "lo0") {
2920
		if (!isset($config['interfaces'][$vip['interface']]) ||
2921
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
2922
			return;
2923
		}
2924
	}
2925

    
2926
	$vip_password = $vip['password'];
2927
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
2928
	    $vip_password)));
2929
	if ($vip['password'] != "") {
2930
		$password = " pass {$vip_password}";
2931
	}
2932

    
2933
	$advbase = "";
2934
	if (!empty($vip['advbase'])) {
2935
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2936
	}
2937

    
2938
	$carp_maintenancemode = isset(
2939
	    $config["virtualip_carp_maintenancemode"]);
2940
	if ($carp_maintenancemode) {
2941
		$advskew = "advskew 254";
2942
	} else {
2943
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2944
	}
2945

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

    
2949
	if (!$maintenancemode_only) {
2950
		if (is_ipaddrv4($vip['subnet'])) {
2951
			mwexec("/sbin/ifconfig {$realif} " .
2952
			    escapeshellarg($vip['subnet']) . "/" .
2953
			    escapeshellarg($vip['subnet_bits']) .
2954
			    " alias vhid " . escapeshellarg($vip['vhid']));
2955
		} else if (is_ipaddrv6($vip['subnet'])) {
2956
			mwexec("/sbin/ifconfig {$realif} inet6 " .
2957
			    escapeshellarg($vip['subnet']) . " prefixlen " .
2958
			    escapeshellarg($vip['subnet_bits']) .
2959
			    " alias vhid " . escapeshellarg($vip['vhid']));
2960
		}
2961
	}
2962

    
2963
	return $realif;
2964
}
2965

    
2966
function interface_wireless_clone($realif, $wlcfg) {
2967
	global $config, $g;
2968
	/*   Check to see if interface has been cloned as of yet.
2969
	 *   If it has not been cloned then go ahead and clone it.
2970
	 */
2971
	$needs_clone = false;
2972
	if (is_array($wlcfg['wireless'])) {
2973
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2974
	} else {
2975
		$wlcfg_mode = $wlcfg['mode'];
2976
	}
2977
	switch ($wlcfg_mode) {
2978
		case "hostap":
2979
			$mode = "wlanmode hostap";
2980
			break;
2981
		case "adhoc":
2982
			$mode = "wlanmode adhoc";
2983
			break;
2984
		default:
2985
			$mode = "";
2986
			break;
2987
	}
2988
	$baseif = interface_get_wireless_base($wlcfg['if']);
2989
	if (does_interface_exist($realif)) {
2990
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2991
		$ifconfig_str = implode($output);
2992
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2993
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2994
			$needs_clone = true;
2995
		}
2996
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2997
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2998
			$needs_clone = true;
2999
		}
3000
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3001
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3002
			$needs_clone = true;
3003
		}
3004
	} else {
3005
		$needs_clone = true;
3006
	}
3007

    
3008
	if ($needs_clone == true) {
3009
		/* remove previous instance if it exists */
3010
		if (does_interface_exist($realif)) {
3011
			pfSense_interface_destroy($realif);
3012
		}
3013

    
3014
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3015
		// Create the new wlan interface. FreeBSD returns the new interface name.
3016
		// example:  wlan2
3017
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3018
		if ($ret <> 0) {
3019
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3020
			return false;
3021
		}
3022
		$newif = trim($out[0]);
3023
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3024
		pfSense_interface_rename($newif, $realif);
3025
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3026
	}
3027
	return true;
3028
}
3029

    
3030
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3031
	global $config, $g;
3032

    
3033
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3034
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3035
				 'regdomain', 'regcountry', 'reglocation');
3036

    
3037
	if (!is_interface_wireless($ifcfg['if'])) {
3038
		return;
3039
	}
3040

    
3041
	$baseif = interface_get_wireless_base($ifcfg['if']);
3042

    
3043
	// Sync shared settings for assigned clones
3044
	$iflist = get_configured_interface_list(true);
3045
	foreach ($iflist as $if) {
3046
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
3047
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
3048
				foreach ($shared_settings as $setting) {
3049
					if ($sync_changes) {
3050
						if (isset($ifcfg['wireless'][$setting])) {
3051
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
3052
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3053
							unset($config['interfaces'][$if]['wireless'][$setting]);
3054
						}
3055
					} else {
3056
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3057
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
3058
						} else if (isset($ifcfg['wireless'][$setting])) {
3059
							unset($ifcfg['wireless'][$setting]);
3060
						}
3061
					}
3062
				}
3063
				if (!$sync_changes) {
3064
					break;
3065
				}
3066
			}
3067
		}
3068
	}
3069

    
3070
	// Read or write settings at shared area
3071
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3072
		foreach ($shared_settings as $setting) {
3073
			if ($sync_changes) {
3074
				if (isset($ifcfg['wireless'][$setting])) {
3075
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3076
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3077
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3078
				}
3079
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3080
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3081
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3082
				} else if (isset($ifcfg['wireless'][$setting])) {
3083
					unset($ifcfg['wireless'][$setting]);
3084
				}
3085
			}
3086
		}
3087
	}
3088

    
3089
	// Sync the mode on the clone creation page with the configured mode on the interface
3090
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3091
		foreach ($config['wireless']['clone'] as &$clone) {
3092
			if ($clone['cloneif'] == $ifcfg['if']) {
3093
				if ($sync_changes) {
3094
					$clone['mode'] = $ifcfg['wireless']['mode'];
3095
				} else {
3096
					$ifcfg['wireless']['mode'] = $clone['mode'];
3097
				}
3098
				break;
3099
			}
3100
		}
3101
		unset($clone);
3102
	}
3103
}
3104

    
3105
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3106
	global $config, $g;
3107

    
3108
	/*    open up a shell script that will be used to output the commands.
3109
	 *    since wireless is changing a lot, these series of commands are fragile
3110
	 *    and will sometimes need to be verified by a operator by executing the command
3111
	 *    and returning the output of the command to the developers for inspection.  please
3112
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3113
	 */
3114

    
3115
	// Remove script file
3116
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3117

    
3118
	// Clone wireless nic if needed.
3119
	interface_wireless_clone($if, $wl);
3120

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

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

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

    
3130
	/* set values for /path/program */
3131
	if (file_exists("/usr/local/sbin/hostapd")) {
3132
		$hostapd = "/usr/local/sbin/hostapd";
3133
	} else {
3134
		$hostapd = "/usr/sbin/hostapd";
3135
	}
3136
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3137
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3138
	} else {
3139
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3140
	}
3141
	$ifconfig = "/sbin/ifconfig";
3142
	$sysctl = "/sbin/sysctl";
3143
	$sysctl_args = "-q";
3144
	$killall = "/usr/bin/killall";
3145

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

    
3148
	$wlcmd = array();
3149
	$wl_sysctl = array();
3150
	/* Set a/b/g standard */
3151
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3152
	/* skip mode entirely for "auto" */
3153
	if ($wlcfg['standard'] != "auto") {
3154
		$wlcmd[] = "mode " . escapeshellarg($standard);
3155
	}
3156

    
3157
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3158
	 * to prevent massive packet loss under certain conditions. */
3159
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3160
		$wlcmd[] = "-ampdu";
3161
	}
3162

    
3163
	/* Set ssid */
3164
	if ($wlcfg['ssid']) {
3165
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3166
	}
3167

    
3168
	/* Set 802.11g protection mode */
3169
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3170

    
3171
	/* set wireless channel value */
3172
	if (isset($wlcfg['channel'])) {
3173
		if ($wlcfg['channel'] == "0") {
3174
			$wlcmd[] = "channel any";
3175
		} else {
3176
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
3177
		}
3178
	}
3179

    
3180
	/* Set antenna diversity value */
3181
	if (isset($wlcfg['diversity'])) {
3182
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3183
	}
3184

    
3185
	/* Set txantenna value */
3186
	if (isset($wlcfg['txantenna'])) {
3187
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3188
	}
3189

    
3190
	/* Set rxantenna value */
3191
	if (isset($wlcfg['rxantenna'])) {
3192
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3193
	}
3194

    
3195
	/* set Distance value */
3196
	if ($wlcfg['distance']) {
3197
		$distance = escapeshellarg($wlcfg['distance']);
3198
	}
3199

    
3200
	/* Set wireless hostap mode */
3201
	if ($wlcfg['mode'] == "hostap") {
3202
		$wlcmd[] = "mediaopt hostap";
3203
	} else {
3204
		$wlcmd[] = "-mediaopt hostap";
3205
	}
3206

    
3207
	/* Set wireless adhoc mode */
3208
	if ($wlcfg['mode'] == "adhoc") {
3209
		$wlcmd[] = "mediaopt adhoc";
3210
	} else {
3211
		$wlcmd[] = "-mediaopt adhoc";
3212
	}
3213

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

    
3216
	/* handle hide ssid option */
3217
	if (isset($wlcfg['hidessid']['enable'])) {
3218
		$wlcmd[] = "hidessid";
3219
	} else {
3220
		$wlcmd[] = "-hidessid";
3221
	}
3222

    
3223
	/* handle pureg (802.11g) only option */
3224
	if (isset($wlcfg['pureg']['enable'])) {
3225
		$wlcmd[] = "mode 11g pureg";
3226
	} else {
3227
		$wlcmd[] = "-pureg";
3228
	}
3229

    
3230
	/* handle puren (802.11n) only option */
3231
	if (isset($wlcfg['puren']['enable'])) {
3232
		$wlcmd[] = "puren";
3233
	} else {
3234
		$wlcmd[] = "-puren";
3235
	}
3236

    
3237
	/* enable apbridge option */
3238
	if (isset($wlcfg['apbridge']['enable'])) {
3239
		$wlcmd[] = "apbridge";
3240
	} else {
3241
		$wlcmd[] = "-apbridge";
3242
	}
3243

    
3244
	/* handle turbo option */
3245
	if (isset($wlcfg['turbo']['enable'])) {
3246
		$wlcmd[] = "mediaopt turbo";
3247
	} else {
3248
		$wlcmd[] = "-mediaopt turbo";
3249
	}
3250

    
3251
	/* handle txpower setting */
3252
	// or don't. this has issues at the moment.
3253
	/*
3254
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3255
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3256
	}*/
3257

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

    
3265
	/* Enable wpa if it's configured. No WEP support anymore. */
3266
	if (isset($wlcfg['wpa']['enable'])) {
3267
		$wlcmd[] = "authmode wpa wepmode off ";
3268
	} else {
3269
		$wlcmd[] = "authmode open wepmode off ";
3270
	}
3271

    
3272
	kill_hostapd($if);
3273
	mwexec(kill_wpasupplicant("{$if}"));
3274

    
3275
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3276

    
3277
	switch ($wlcfg['mode']) {
3278
		case 'bss':
3279
			if (isset($wlcfg['wpa']['enable'])) {
3280
				$wpa .= <<<EOD
3281
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3282
ctrl_interface_group=0
3283
ap_scan=1
3284
#fast_reauth=1
3285
network={
3286
ssid="{$wlcfg['ssid']}"
3287
scan_ssid=1
3288
priority=5
3289
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3290
psk="{$wlcfg['wpa']['passphrase']}"
3291
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3292
group={$wlcfg['wpa']['wpa_pairwise']}
3293
}
3294
EOD;
3295

    
3296
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
3297
				unset($wpa);
3298
			}
3299
			break;
3300
		case 'hostap':
3301
			if (!empty($wlcfg['wpa']['passphrase'])) {
3302
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3303
			} else {
3304
				$wpa_passphrase = "";
3305
			}
3306
			if (isset($wlcfg['wpa']['enable'])) {
3307
				$wpa .= <<<EOD
3308
interface={$if}
3309
driver=bsd
3310
logger_syslog=-1
3311
logger_syslog_level=0
3312
logger_stdout=-1
3313
logger_stdout_level=0
3314
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3315
ctrl_interface={$g['varrun_path']}/hostapd
3316
ctrl_interface_group=wheel
3317
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3318
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3319
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3320
ssid={$wlcfg['ssid']}
3321
debug={$wlcfg['wpa']['debug_mode']}
3322
wpa={$wlcfg['wpa']['wpa_mode']}
3323
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3324
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3325
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3326
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3327
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3328
{$wpa_passphrase}
3329

    
3330
EOD;
3331

    
3332
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3333
					$wpa .= <<<EOD
3334
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3335
rsn_preauth=1
3336
rsn_preauth_interfaces={$if}
3337

    
3338
EOD;
3339
				}
3340
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3341
					$wpa .= "ieee8021x=1\n";
3342

    
3343
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3344
						$auth_server_port = "1812";
3345
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3346
							$auth_server_port = intval($wlcfg['auth_server_port']);
3347
						}
3348
						$wpa .= <<<EOD
3349

    
3350
auth_server_addr={$wlcfg['auth_server_addr']}
3351
auth_server_port={$auth_server_port}
3352
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3353

    
3354
EOD;
3355
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3356
							$auth_server_port2 = "1812";
3357
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3358
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3359
							}
3360

    
3361
							$wpa .= <<<EOD
3362
auth_server_addr={$wlcfg['auth_server_addr2']}
3363
auth_server_port={$auth_server_port2}
3364
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3365

    
3366
EOD;
3367
						}
3368
					}
3369
				}
3370

    
3371
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3372
				unset($wpa);
3373
			}
3374
			break;
3375
	}
3376

    
3377
	/*
3378
	 *    all variables are set, lets start up everything
3379
	 */
3380

    
3381
	$baseif = interface_get_wireless_base($if);
3382
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3383
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3384

    
3385
	/* set sysctls for the wireless interface */
3386
	if (!empty($wl_sysctl)) {
3387
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3388
		foreach ($wl_sysctl as $wl_sysctl_line) {
3389
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3390
		}
3391
	}
3392

    
3393
	/* set ack timers according to users preference (if he/she has any) */
3394
	if ($distance) {
3395
		fwrite($fd_set, "# Enable ATH distance settings\n");
3396
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3397
	}
3398

    
3399
	if (isset($wlcfg['wpa']['enable'])) {
3400
		if ($wlcfg['mode'] == "bss") {
3401
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3402
		}
3403
		if ($wlcfg['mode'] == "hostap") {
3404
			/* add line to script to restore old mac to make hostapd happy */
3405
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3406
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3407
				$if_curmac = get_interface_mac($if);
3408
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3409
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3410
						" link " . escapeshellarg($if_oldmac) . "\n");
3411
				}
3412
			}
3413

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

    
3416
			/* add line to script to restore spoofed mac after running hostapd */
3417
			if ($wl['spoofmac']) {
3418
				$if_curmac = get_interface_mac($if);
3419
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3420
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3421
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3422
				}
3423
			}
3424
		}
3425
	}
3426

    
3427
	fclose($fd_set);
3428

    
3429
	/* Making sure regulatory settings have actually changed
3430
	 * before applying, because changing them requires bringing
3431
	 * down all wireless networks on the interface. */
3432
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3433
	$ifconfig_str = implode($output);
3434
	unset($output);
3435
	$reg_changing = false;
3436

    
3437
	/* special case for the debug country code */
3438
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3439
		$reg_changing = true;
3440
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3441
		$reg_changing = true;
3442
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3443
		$reg_changing = true;
3444
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3445
		$reg_changing = true;
3446
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3447
		$reg_changing = true;
3448
	}
3449

    
3450
	if ($reg_changing) {
3451
		/* set regulatory domain */
3452
		if ($wlcfg['regdomain']) {
3453
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3454
		}
3455

    
3456
		/* set country */
3457
		if ($wlcfg['regcountry']) {
3458
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3459
		}
3460

    
3461
		/* set location */
3462
		if ($wlcfg['reglocation']) {
3463
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3464
		}
3465

    
3466
		$wlregcmd_args = implode(" ", $wlregcmd);
3467

    
3468
		/* build a complete list of the wireless clones for this interface */
3469
		$clone_list = array();
3470
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3471
			$clone_list[] = interface_get_wireless_clone($baseif);
3472
		}
3473
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3474
			foreach ($config['wireless']['clone'] as $clone) {
3475
				if ($clone['if'] == $baseif) {
3476
					$clone_list[] = $clone['cloneif'];
3477
				}
3478
			}
3479
		}
3480

    
3481
		/* find which clones are up and bring them down */
3482
		$clones_up = array();
3483
		foreach ($clone_list as $clone_if) {
3484
			$clone_status = pfSense_get_interface_addresses($clone_if);
3485
			if ($clone_status['status'] == 'up') {
3486
				$clones_up[] = $clone_if;
3487
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3488
			}
3489
		}
3490

    
3491
		/* apply the regulatory settings */
3492
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3493
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3494

    
3495
		/* bring the clones back up that were previously up */
3496
		foreach ($clones_up as $clone_if) {
3497
			interfaces_bring_up($clone_if);
3498

    
3499
			/*
3500
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3501
			 * is in infrastructure mode, and WPA is enabled.
3502
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3503
			 */
3504
			if ($clone_if != $if) {
3505
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3506
				if ((!empty($friendly_if)) &&
3507
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3508
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3509
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3510
				}
3511
			}
3512
		}
3513
	}
3514

    
3515
	/* The mode must be specified in a separate command before ifconfig
3516
	 * will allow the mode and channel at the same time in the next.
3517
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3518
	 */
3519
	if ($wlcfg['mode'] == "hostap") {
3520
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3521
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3522
	}
3523

    
3524
	/* configure wireless */
3525
	$wlcmd_args = implode(" ", $wlcmd);
3526
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3527
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3528
	/* Bring the interface up only after setting up all the other parameters. */
3529
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3530
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3531
	fclose($wlan_setup_log);
3532

    
3533
	unset($wlcmd_args, $wlcmd);
3534

    
3535

    
3536
	sleep(1);
3537
	/* execute hostapd and wpa_supplicant if required in shell */
3538
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3539

    
3540
	return 0;
3541

    
3542
}
3543

    
3544
function kill_hostapd($interface) {
3545
	global $g;
3546

    
3547
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3548
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3549
	}
3550
}
3551

    
3552
function kill_wpasupplicant($interface) {
3553
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3554
}
3555

    
3556
function find_dhclient_process($interface) {
3557
	if ($interface) {
3558
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3559
	} else {
3560
		$pid = 0;
3561
	}
3562

    
3563
	return intval($pid);
3564
}
3565

    
3566
function kill_dhclient_process($interface) {
3567
	if (empty($interface) || !does_interface_exist($interface)) {
3568
		return;
3569
	}
3570

    
3571
	$i = 0;
3572
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3573
		/* 3rd time make it die for sure */
3574
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3575
		posix_kill($pid, $sig);
3576
		sleep(1);
3577
		$i++;
3578
	}
3579
	unset($i);
3580
}
3581

    
3582
function find_dhcp6c_process($interface) {
3583
	global $g;
3584

    
3585
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3586
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3587
	} else {
3588
		return(false);
3589
	}
3590

    
3591
	return intval($pid);
3592
}
3593

    
3594
function kill_dhcp6client_process($interface, $force, $release = false) {
3595
	global $g;
3596

    
3597
	$i = 0;
3598

    
3599
	/*
3600
	Beware of the following: Reason, the interface may be down, but
3601
	dhcp6c may still be running, it just complains it cannot send
3602
	and carries on. Commented out as will stop the call to kill.
3603

    
3604
	if (empty($interface) || !does_interface_exist($interface)) {
3605
		return;
3606
	}
3607
	*/
3608

    
3609
	/*********** Notes on signals for dhcp6c and this function *************
3610

    
3611
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3612
	a release and waiting for the response that never comes.
3613
	So we need to tell it that the interface is down and to just die quickly
3614
	otherwise a new client may launch and we have duplicate proceses.
3615
	In this case use SIGUSR1.
3616

    
3617
	If we want to exit normally obeying the no release flag then use SIGTERM.
3618
	If we want to exit with a release overiding the no release flag then
3619
	use SIGUSR2.
3620

    
3621
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3622
	exit quickly without sending release signals.
3623

    
3624
	If $Force is set to false and $release is also set to false dhcp6c will
3625
	follow the no-release flag.
3626

    
3627
	If $Force is set to false and $release is true then dhcp6c will send a
3628
	release regardless of the no-release flag.
3629
	***********************************************************************/
3630

    
3631
	if ($force == true) {
3632
		$psig=SIGUSR1;
3633
	} else if ($release == false) {
3634
		$psig=SIGTERM;
3635
	} else {
3636
		$psig=SIGUSR2;
3637
	}
3638

    
3639
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3640
		/* 3rd time make it die for sure */
3641
		$sig = ($i == 2 ? SIGKILL : $psig);
3642
		posix_kill($pid, $sig);
3643
		sleep(1);
3644
		$i++;
3645
	}
3646
	/* Clear the RTSOLD script created lock & tidy up */
3647
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3648
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
3649
}
3650
function reset_dhcp6client_process($interface) {
3651

    
3652
	$pid = find_dhcp6c_process($interface);
3653

    
3654
	if($pid != 0) {
3655
		posix_kill($pid, SIGHUP);
3656
	}
3657
}
3658

    
3659
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3660
	global $g;
3661

    
3662
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3663
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3664

    
3665
	/*
3666
	 * Only run this if the lock does not exist. In theory the lock being
3667
	 * there in this mode means the user has selected dhcp6withoutRA while
3668
	 * a session is active in the other mode.
3669
	 *
3670
	 * It should not happen as the process should have been killed and the
3671
	 * lock deleted.
3672
	 */
3673

    
3674
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
3675
		kill_dhcp6client_process($interface, true);
3676
		/* Lock it to avoid multiple runs */
3677
		touch("/tmp/dhcp6c_{$interface}_lock");
3678
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3679
		    "{$noreleaseOption} " .
3680
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
3681
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
3682
		    $interface);
3683
		log_error(sprintf(gettext(
3684
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
3685
		    $interface));
3686
	}
3687
}
3688

    
3689
function interface_virtual_create($interface) {
3690
	global $config;
3691

    
3692
	if (interface_is_vlan($interface) != NULL) {
3693
		interfaces_vlan_configure($interface);
3694
	} else if (substr($interface, 0, 3) == "gre") {
3695
		interfaces_gre_configure(0, $interface);
3696
	} else if (substr($interface, 0, 3) == "gif") {
3697
		interfaces_gif_configure(0, $interface);
3698
	} else if (substr($interface, 0, 5) == "ovpns") {
3699
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3700
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3701
				if ($interface == "ovpns{$server['vpnid']}") {
3702
					if (!function_exists('openvpn_resync')) {
3703
						require_once('openvpn.inc');
3704
					}
3705
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3706
					openvpn_resync('server', $server);
3707
				}
3708
			}
3709
			unset($server);
3710
		}
3711
	} else if (substr($interface, 0, 5) == "ovpnc") {
3712
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3713
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3714
				if ($interface == "ovpnc{$client['vpnid']}") {
3715
					if (!function_exists('openvpn_resync')) {
3716
						require_once('openvpn.inc');
3717
					}
3718
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3719
					openvpn_resync('client', $client);
3720
				}
3721
			}
3722
			unset($client);
3723
		}
3724
	} else if (substr($interface, 0, 5) == "ipsec") {
3725
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
3726
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
3727
				if ($ph1ent['disabled']) {
3728
					continue;
3729
				}
3730
				if ($interface == "ipsec{$ph1ent['ikeid']}") {
3731
					interface_ipsec_vti_configure($ph1ent);
3732
				}
3733
			}
3734
		}
3735
	} else if (substr($interface, 0, 4) == "lagg") {
3736
		interfaces_lagg_configure($interface);
3737
	} else if (substr($interface, 0, 6) == "bridge") {
3738
		interfaces_bridge_configure(0, $interface);
3739
	}
3740
}
3741

    
3742
function interface_vlan_mtu_configured($iface) {
3743
	global $config;
3744

    
3745
	$mtu = 0;
3746
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3747
		foreach ($config['vlans']['vlan'] as $vlan) {
3748

    
3749
			if ($vlan['vlanif'] != $iface)
3750
				continue;
3751

    
3752
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3753
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3754
				/* VLAN MTU */
3755
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3756
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3757
				/* Parent MTU */
3758
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3759
			}
3760
		}
3761
	}
3762

    
3763
	return $mtu;
3764
}
3765

    
3766
function interface_mtu_wanted_for_pppoe($realif) {
3767
	global $config;
3768

    
3769
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3770
		return 0;
3771

    
3772
	$mtu = 0;
3773
	foreach ($config['ppps']['ppp'] as $ppp) {
3774
		if ($ppp['type'] != "pppoe") {
3775
			continue;
3776
		}
3777

    
3778
		$mtus = array();
3779
		if (!empty($ppp['mtu'])) {
3780
			$mtus = explode(',', $ppp['mtu']);
3781
		}
3782
		$ports = explode(',', $ppp['ports']);
3783

    
3784
		foreach ($ports as $pid => $port) {
3785
			$parentifa = get_parent_interface($port);
3786
			$parentif = $parentifa[0];
3787
			if ($parentif != $realif)
3788
				continue;
3789

    
3790
			// there is an MTU configured on the port in question
3791
			if (!empty($mtus[$pid])) {
3792
				$mtu = intval($mtus[$pid]) + 8;
3793
			// or use the MTU configured on the interface ...
3794
			} elseif (is_array($config['interfaces'])) {
3795
				foreach ($config['interfaces'] as $interface) {
3796
					if ($interface['if'] == $ppp['if'] &&
3797
					    !empty($interface['mtu'])) {
3798
						$mtu = intval($interface['mtu']) + 8;
3799
						break;
3800
					}
3801
				}
3802
			}
3803
		}
3804
	}
3805

    
3806
	return $mtu;
3807
}
3808

    
3809
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3810
	global $config, $g;
3811
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3812
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3813

    
3814
	$wancfg = $config['interfaces'][$interface];
3815

    
3816
	if (!isset($wancfg['enable'])) {
3817
		return;
3818
	}
3819

    
3820
	$realif = get_real_interface($interface);
3821
	$realhwif_array = get_parent_interface($interface);
3822
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3823
	$realhwif = $realhwif_array[0];
3824

    
3825
	$mac_if_cfg = $wancfg;
3826
	if (interface_is_vlan($realif)) {
3827
		$mac_if = convert_real_interface_to_friendly_interface_name(
3828
		    $realhwif);
3829
		if (is_array($config['interfaces'][$mac_if])) {
3830
			$mac_if_cfg = $config['interfaces'][$mac_if];
3831
		} else {
3832
			$mac_if = $interface;
3833
		}
3834
	}
3835

    
3836
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn") && !(substr($realif, 0, 5) == "ipsec")) {
3837
		/* remove all IPv4 and IPv6 addresses */
3838
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3839
		if (is_array($tmpifaces)) {
3840
			foreach ($tmpifaces as $tmpiface) {
3841
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3842
					if (!is_linklocal($tmpiface)) {
3843
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3844
					}
3845
				} else {
3846
					if (is_subnetv4($tmpiface)) {
3847
						$tmpip = explode('/', $tmpiface);
3848
						$tmpip = $tmpip[0];
3849
					} else {
3850
						$tmpip = $tmpiface;
3851
					}
3852
					pfSense_interface_deladdress($realif, $tmpip);
3853
				}
3854
			}
3855
		}
3856

    
3857
		/* only bring down the interface when both v4 and v6 are set to NONE */
3858
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3859
			interface_bring_down($interface);
3860
		}
3861
	}
3862

    
3863
	$interface_to_check = $realif;
3864
	if (interface_isppp_type($interface)) {
3865
		$interface_to_check = $realhwif;
3866
	}
3867

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

    
3873
	/* Disable Accepting router advertisements unless specifically requested */
3874
	if ($g['debug']) {
3875
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3876
	}
3877
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
3878
	{
3879
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3880
	}
3881
	/* wireless configuration? */
3882
	if (is_array($wancfg['wireless']) && !$linkupevent) {
3883
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3884
	}
3885

    
3886
	$current_mac = get_interface_mac($realhwif);
3887
	$vendor_mac = get_interface_vendor_mac($realhwif);
3888

    
3889
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
3890
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
3891

    
3892
		interface_set_macaddr($realhwif, $mac_addr);
3893
	} else {
3894
		/*
3895
		 * this is not a valid mac address.  generate a
3896
		 * temporary mac address so the machine can get online.
3897
		 */
3898
		echo gettext("Generating new MAC address.");
3899
		$random_mac = generate_random_mac_address();
3900
		interface_set_macaddr($realhwif, $random_mac);
3901
		$config['interfaces'][$mac_if]['spoofmac'] = $random_mac;
3902
		write_config(sprintf(gettext('The invalid MAC address ' .
3903
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
3904
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
3905
		file_notice("MAC Address altered", sprintf(gettext('The ' .
3906
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
3907
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
3908
		    $random_mac), "Interfaces");
3909
	}
3910

    
3911
	/* media */
3912
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3913
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3914
		if ($wancfg['media']) {
3915
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3916
		}
3917
		if ($wancfg['mediaopt']) {
3918
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3919
		}
3920
		mwexec($cmd);
3921
	}
3922

    
3923
	/* Apply hw offloading policies as configured */
3924
	enable_hardware_offloading($interface);
3925

    
3926
	/* invalidate interface/ip/sn cache */
3927
	get_interface_arr(true);
3928
	unset($interface_ip_arr_cache[$realif]);
3929
	unset($interface_sn_arr_cache[$realif]);
3930
	unset($interface_ipv6_arr_cache[$realif]);
3931
	unset($interface_snv6_arr_cache[$realif]);
3932

    
3933
	$tunnelif = substr($realif, 0, 3);
3934

    
3935
	$mtuif = $realif;
3936
	$mtuhwif = $realhwif;
3937

    
3938
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3939
	if (interface_isppp_type($interface)) {
3940
		$mtuif = $realhwif;
3941
		$mtuhwif_array = get_parent_interface($mtuif);
3942
		$mtuhwif = $mtuhwif_array[0];
3943
	}
3944

    
3945
	$wantedmtu = 0;
3946
	if (is_array($config['interfaces'])) {
3947
		foreach ($config['interfaces'] as $tmpinterface) {
3948
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3949
				$wantedmtu = $tmpinterface['mtu'];
3950
				break;
3951
			}
3952
		}
3953
	}
3954

    
3955
	/* MTU is not specified for interface, try the pppoe settings. */
3956
	if ($wantedmtu == 0) {
3957
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3958
	}
3959
	if ($wantedmtu == 0 && interface_is_vlan($mtuif) != NULL && interface_isppp_type($interface)) {
3960
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3961
	}
3962

    
3963
	/* Set the MTU to 1500 if no explicit MTU configured. */
3964
	if ($wantedmtu == 0) {
3965
		$wantedmtu = 1500; /* Default */
3966
	}
3967

    
3968
	if (interface_is_vlan($mtuif) != NULL) {
3969
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3970
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3971
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3972
			if ($wancfg['mtu'] > $parentmtu) {
3973
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3974
			}
3975
		}
3976

    
3977
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3978

    
3979
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3980
			$configuredmtu = $parentmtu;
3981
		if ($configuredmtu != 0)
3982
			$mtu = $configuredmtu;
3983
		else
3984
			$mtu = $wantedmtu;
3985

    
3986
		/* Set the parent MTU. */
3987
		if (get_interface_mtu($mtuhwif) < $mtu)
3988
			set_interface_mtu($mtuhwif, $mtu);
3989
		/* Set the VLAN MTU. */
3990
		if (get_interface_mtu($mtuif) != $mtu)
3991
			set_interface_mtu($mtuif, $mtu);
3992
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3993
		/* LAGG interface must be destroyed and re-created to change MTU */
3994
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3995
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3996
				foreach ($config['laggs']['lagg'] as $lagg) {
3997
					if ($lagg['laggif'] == $mtuif) {
3998
						interface_lagg_configure($lagg);
3999
						break;
4000
					}
4001
				}
4002
			}
4003
		}
4004
	} else {
4005
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4006
			pfSense_interface_mtu($mtuif, $wantedmtu);
4007
		}
4008
	}
4009
	/* XXX: What about gre/gif/.. ? */
4010

    
4011
	if (does_interface_exist($wancfg['if'])) {
4012
		interfaces_bring_up($wancfg['if']);
4013
	}
4014

    
4015
	switch ($wancfg['ipaddr']) {
4016
		case 'dhcp':
4017
			interface_dhcp_configure($interface);
4018
			break;
4019
		case 'pppoe':
4020
		case 'l2tp':
4021
		case 'pptp':
4022
		case 'ppp':
4023
			interface_ppps_configure($interface);
4024
			break;
4025
		default:
4026
			/* XXX: Kludge for now related to #3280 */
4027
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4028
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4029
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4030
				}
4031
			}
4032
			break;
4033
	}
4034

    
4035
	switch ($wancfg['ipaddrv6']) {
4036
		case 'slaac':
4037
		case 'dhcp6':
4038
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4039
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4040
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4041
			/* Remove the check file. Should not be there but just in case */
4042
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
4043
			log_error(gettext("calling interface_dhcpv6_configure."));
4044
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
4045
				interface_dhcpv6_configure($interface, $wancfg);
4046
			}
4047
			break;
4048
		case '6rd':
4049
			interface_6rd_configure($interface, $wancfg);
4050
			break;
4051
		case '6to4':
4052
			interface_6to4_configure($interface, $wancfg);
4053
			break;
4054
		case 'track6':
4055
			interface_track6_configure($interface, $wancfg, $linkupevent);
4056
			break;
4057
		default:
4058
			/* XXX: Kludge for now related to #3280 */
4059
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4060
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4061
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4062
					// FIXME: Add IPv6 Support to the pfSense module
4063
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4064
				}
4065
			}
4066
			break;
4067
	}
4068

    
4069
	interface_netgraph_needed($interface);
4070

    
4071
	if (!platform_booting()) {
4072
		link_interface_to_vips($interface, "update");
4073

    
4074
		if ($tunnelif != 'gre') {
4075
			unset($gre);
4076
			$gre = link_interface_to_gre($interface);
4077
			if (!empty($gre)) {
4078
				array_walk($gre, 'interface_gre_configure');
4079
			}
4080
		}
4081

    
4082
		if ($tunnelif != 'gif') {
4083
			unset($gif);
4084
			$gif = link_interface_to_gif ($interface);
4085
			if (!empty($gif)) {
4086
				array_walk($gif, 'interface_gif_configure');
4087
			}
4088
		}
4089

    
4090
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4091
			unset($bridgetmp);
4092
			$bridgetmp = link_interface_to_bridge($interface);
4093
			if (!empty($bridgetmp)) {
4094
				interface_bridge_add_member($bridgetmp, $realif);
4095
			}
4096
		}
4097

    
4098
		$grouptmp = link_interface_to_group($interface);
4099
		if (!empty($grouptmp)) {
4100
			array_walk($grouptmp, 'interface_group_add_member');
4101
		}
4102

    
4103
		if ($interface == "lan") {
4104
			/* make new hosts file */
4105
			system_hosts_generate();
4106
		}
4107

    
4108
		if ($reloadall == true) {
4109

    
4110
			/* reconfigure static routes (kernel may have deleted them) */
4111
			system_routing_configure($interface);
4112

    
4113
			/* reload ipsec tunnels */
4114
			send_event("service reload ipsecdns");
4115

    
4116
			if (isset($config['dnsmasq']['enable'])) {
4117
				services_dnsmasq_configure();
4118
			}
4119

    
4120
			if (isset($config['unbound']['enable'])) {
4121
				services_unbound_configure();
4122
			}
4123

    
4124
			/* update dyndns */
4125
			send_event("service reload dyndns {$interface}");
4126

    
4127
			/* reload captive portal */
4128
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4129
				require_once('captiveportal.inc');
4130
			}
4131
			captiveportal_init_rules_byinterface($interface);
4132
		}
4133
	}
4134

    
4135
	interfaces_staticarp_configure($interface);
4136
	return 0;
4137
}
4138

    
4139
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4140
	global $config, $g;
4141

    
4142
	if (!is_array($wancfg)) {
4143
		return;
4144
	}
4145

    
4146
	if (!isset($wancfg['enable'])) {
4147
		return;
4148
	}
4149

    
4150
	/* If the interface is not configured via another, exit */
4151
	if (empty($wancfg['track6-interface'])) {
4152
		return;
4153
	}
4154

    
4155
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4156
	$realif = get_real_interface($interface);
4157
	$linklocal = find_interface_ipv6_ll($realif, true);
4158
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4159
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
4160
	}
4161
	/* XXX: This might break for good on a carp installation using link-local as network ips */
4162
	/* XXX: Probably should remove? */
4163
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
4164

    
4165
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4166
	if (!isset($trackcfg['enable'])) {
4167
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4168
		return;
4169
	}
4170

    
4171
	switch ($trackcfg['ipaddrv6']) {
4172
		case "6to4":
4173
			if ($g['debug']) {
4174
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4175
			}
4176
			interface_track6_6to4_configure($interface, $wancfg);
4177
			break;
4178
		case "6rd":
4179
			if ($g['debug']) {
4180
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4181
			}
4182
			interface_track6_6rd_configure($interface, $wancfg);
4183
			break;
4184
		case "dhcp6":
4185
			if ($linkupevent == true) {
4186
				/*
4187
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4188
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4189
				 *
4190
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4191
				 */
4192
				$parentrealif = get_real_interface($wancfg['track6-interface']);
4193
				$pidv6 = find_dhcp6c_process($parentrealif);
4194
				if ($pidv6) {
4195
					posix_kill($pidv6, SIGHUP);
4196
				}
4197
			}
4198
			break;
4199
	}
4200

    
4201
	if ($linkupevent == false && !platform_booting()) {
4202
		if (!function_exists('services_dhcpd_configure')) {
4203
			require_once("services.inc");
4204
		}
4205

    
4206
		/* restart dns servers (defering dhcpd reload) */
4207
		if (isset($config['unbound']['enable'])) {
4208
			services_unbound_configure(false);
4209
		}
4210
		if (isset($config['dnsmasq']['enable'])) {
4211
			services_dnsmasq_configure(false);
4212
		}
4213

    
4214
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4215
		services_dhcpd_configure("inet6");
4216
	}
4217

    
4218
	return 0;
4219
}
4220

    
4221
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4222
	global $config, $g;
4223
	global $interface_ipv6_arr_cache;
4224
	global $interface_snv6_arr_cache;
4225

    
4226
	if (!is_array($lancfg)) {
4227
		return;
4228
	}
4229

    
4230
	/* If the interface is not configured via another, exit */
4231
	if (empty($lancfg['track6-interface'])) {
4232
		return;
4233
	}
4234

    
4235
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4236
	if (empty($wancfg)) {
4237
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4238
		return;
4239
	}
4240

    
4241
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4242
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4243
		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']));
4244
		return;
4245
	}
4246
	$hexwanv4 = return_hex_ipv4($ip4address);
4247

    
4248
	/* create the long prefix notation for math, save the prefix length */
4249
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4250
	$rd6prefixlen = $rd6prefix[1];
4251
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4252

    
4253
	/* binary presentation of the prefix for all 128 bits. */
4254
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4255

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

    
4261
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4262
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4263
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4264
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4265
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4266
	/* fill the rest out with zeros */
4267
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4268

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

    
4272
	$lanif = get_real_interface($interface);
4273
	$oip = find_interface_ipv6($lanif);
4274
	if (is_ipaddrv6($oip)) {
4275
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4276
	}
4277
	unset($interface_ipv6_arr_cache[$lanif]);
4278
	unset($interface_snv6_arr_cache[$lanif]);
4279
	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));
4280
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4281

    
4282
	return 0;
4283
}
4284

    
4285
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4286
	global $config, $g;
4287
	global $interface_ipv6_arr_cache;
4288
	global $interface_snv6_arr_cache;
4289

    
4290
	if (!is_array($lancfg)) {
4291
		return;
4292
	}
4293

    
4294
	/* If the interface is not configured via another, exit */
4295
	if (empty($lancfg['track6-interface'])) {
4296
		return;
4297
	}
4298

    
4299
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4300
	if (empty($wancfg)) {
4301
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4302
		return;
4303
	}
4304

    
4305
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4306
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4307
		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']));
4308
		return;
4309
	}
4310
	$hexwanv4 = return_hex_ipv4($ip4address);
4311

    
4312
	/* create the long prefix notation for math, save the prefix length */
4313
	$sixto4prefix = "2002::";
4314
	$sixto4prefixlen = 16;
4315
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4316

    
4317
	/* binary presentation of the prefix for all 128 bits. */
4318
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4319

    
4320
	/* just save the left prefix length bits */
4321
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4322
	/* add the v4 address */
4323
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4324
	/* add the custom prefix id */
4325
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4326
	/* fill the rest out with zeros */
4327
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4328

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

    
4332
	$lanif = get_real_interface($interface);
4333
	$oip = find_interface_ipv6($lanif);
4334
	if (is_ipaddrv6($oip)) {
4335
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4336
	}
4337
	unset($interface_ipv6_arr_cache[$lanif]);
4338
	unset($interface_snv6_arr_cache[$lanif]);
4339
	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));
4340
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4341

    
4342
	return 0;
4343
}
4344

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

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

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

    
4355
	if (!is_module_loaded('if_stf.ko')) {
4356
		mwexec('/sbin/kldload if_stf.ko');
4357
	}
4358

    
4359
	$wanif = get_real_interface($interface);
4360
	$ip4address = find_interface_ip($wanif);
4361
	if (!is_ipaddrv4($ip4address)) {
4362
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4363
		return false;
4364
	}
4365
	$hexwanv4 = return_hex_ipv4($ip4address);
4366

    
4367
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4368
		$wancfg['prefix-6rd-v4plen'] = 0;
4369
	}
4370

    
4371
	/* create the long prefix notation for math, save the prefix length */
4372
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4373
	$rd6prefixlen = $rd6prefix[1];
4374
	$brgw = explode('.', $wancfg['gateway-6rd']);
4375
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4376
	$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);
4377
	if (strlen($rd6brgw) < 128) {
4378
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4379
	}
4380
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4381
	unset($brgw);
4382
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4383

    
4384
	/* binary presentation of the prefix for all 128 bits. */
4385
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4386

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

    
4394
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4395
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4396

    
4397

    
4398
	/* XXX: need to extend to support variable prefix size for v4 */
4399
	$stfiface = "{$interface}_stf";
4400
	if (does_interface_exist($stfiface)) {
4401
		pfSense_interface_destroy($stfiface);
4402
	}
4403
	$tmpstfiface = pfSense_interface_create("stf");
4404
	pfSense_interface_rename($tmpstfiface, $stfiface);
4405
	pfSense_interface_flags($stfiface, IFF_LINK2);
4406
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4407
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4408
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4409
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4410
	}
4411
	if ($g['debug']) {
4412
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4413
	}
4414

    
4415
	/* write out a default router file */
4416
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4417
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4418

    
4419
	$ip4gateway = get_interface_gateway($interface);
4420
	if (is_ipaddrv4($ip4gateway)) {
4421
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
4422
	}
4423

    
4424
	/* configure dependent interfaces */
4425
	if (!platform_booting()) {
4426
		link_interface_to_track6($interface, "update");
4427
	}
4428

    
4429
	return 0;
4430
}
4431

    
4432
function interface_6to4_configure($interface = "wan", $wancfg) {
4433
	global $config, $g;
4434

    
4435
	/* because this is a tunnel interface we can only function
4436
	 *	with a public IPv4 address on the interface */
4437

    
4438
	if (!is_array($wancfg)) {
4439
		return;
4440
	}
4441

    
4442
	$wanif = get_real_interface($interface);
4443
	$ip4address = find_interface_ip($wanif);
4444
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4445
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4446
		return false;
4447
	}
4448

    
4449
	/* create the long prefix notation for math, save the prefix length */
4450
	$stfprefixlen = 16;
4451
	$stfprefix = Net_IPv6::uncompress("2002::");
4452
	$stfarr = explode(":", $stfprefix);
4453
	$v4prefixlen = "0";
4454

    
4455
	/* we need the hex form of the interface IPv4 address */
4456
	$ip4arr = explode(".", $ip4address);
4457
	$hexwanv4 = "";
4458
	foreach ($ip4arr as $octet) {
4459
		$hexwanv4 .= sprintf("%02x", $octet);
4460
	}
4461

    
4462
	/* we need the hex form of the broker IPv4 address */
4463
	$ip4arr = explode(".", "192.88.99.1");
4464
	$hexbrv4 = "";
4465
	foreach ($ip4arr as $octet) {
4466
		$hexbrv4 .= sprintf("%02x", $octet);
4467
	}
4468

    
4469
	/* binary presentation of the prefix for all 128 bits. */
4470
	$stfprefixbin = "";
4471
	foreach ($stfarr as $element) {
4472
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4473
	}
4474
	/* just save the left prefix length bits */
4475
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4476

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

    
4481
	/* for the local subnet too. */
4482
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4483
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4484

    
4485
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4486
	$stfbrarr = array();
4487
	$stfbrbinarr = array();
4488
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4489
	foreach ($stfbrbinarr as $bin) {
4490
		$stfbrarr[] = dechex(bindec($bin));
4491
	}
4492
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4493

    
4494
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4495
	$stflanarr = array();
4496
	$stflanbinarr = array();
4497
	$stflanbinarr = str_split($stflanbin, 16);
4498
	foreach ($stflanbinarr as $bin) {
4499
		$stflanarr[] = dechex(bindec($bin));
4500
	}
4501
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4502
	$stflanarr[7] = 1;
4503
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4504

    
4505
	/* setup the stf interface */
4506
	if (!is_module_loaded("if_stf")) {
4507
		mwexec("/sbin/kldload if_stf.ko");
4508
	}
4509
	$stfiface = "{$interface}_stf";
4510
	if (does_interface_exist($stfiface)) {
4511
		pfSense_interface_destroy($stfiface);
4512
	}
4513
	$tmpstfiface = pfSense_interface_create("stf");
4514
	pfSense_interface_rename($tmpstfiface, $stfiface);
4515
	pfSense_interface_flags($stfiface, IFF_LINK2);
4516
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4517

    
4518
	if ($g['debug']) {
4519
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4520
	}
4521

    
4522
	/* write out a default router file */
4523
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4524
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4525

    
4526
	$ip4gateway = get_interface_gateway($interface);
4527
	if (is_ipaddrv4($ip4gateway)) {
4528
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
4529
	}
4530

    
4531
	if (!platform_booting()) {
4532
		link_interface_to_track6($interface, "update");
4533
	}
4534

    
4535
	return 0;
4536
}
4537

    
4538
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4539
	global $config, $g;
4540

    
4541
	if (!is_array($wancfg)) {
4542
		return;
4543
	}
4544

    
4545
	$wanif = get_real_interface($interface, "inet6");
4546
	$dhcp6cconf = "";
4547

    
4548
	if (!empty($config['system']['global-v6duid'])) {
4549
		// Write the DUID file
4550
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4551
		    log_error(gettext("Failed to write user DUID file!"));
4552
		}
4553
	}
4554

    
4555
	/* accept router advertisements for this interface                 */
4556
	/* Moved to early in the function as sometimes interface not ready */
4557
	/* RTSOLD fails as interface does not accept .....                 */
4558

    
4559
	log_error("Accept router advertisements on interface {$wanif} ");
4560
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4561

    
4562
	if ($wancfg['adv_dhcp6_config_file_override']) {
4563
		// DHCP6 Config File Override
4564
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4565
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4566
		// DHCP6 Config File Advanced
4567
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4568
	} else {
4569
		// DHCP6 Config File Basic
4570
		$dhcp6cconf .= "interface {$wanif} {\n";
4571

    
4572
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4573
		if ($wancfg['ipaddrv6'] == "slaac") {
4574
			$dhcp6cconf .= "\tinformation-only;\n";
4575
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4576
			$dhcp6cconf .= "\trequest domain-name;\n";
4577
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4578
			$dhcp6cconf .= "};\n";
4579
		} else {
4580
			$trackiflist = array();
4581
			$iflist = link_interface_to_track6($interface);
4582
			foreach ($iflist as $ifname => $ifcfg) {
4583
				if (is_numeric($ifcfg['track6-prefix-id'])) {
4584
					$trackiflist[$ifname] = $ifcfg;
4585
				}
4586
			}
4587

    
4588
			/* skip address request if this is set */
4589
			if (!isset($wancfg['dhcp6prefixonly'])) {
4590
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4591
			}
4592
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4593
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4594
			}
4595

    
4596
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4597
			$dhcp6cconf .= "\trequest domain-name;\n";
4598

    
4599
			/*
4600
			 * dhcp6c will run different scripts depending on
4601
			 * whether dhcpwithoutra is set or unset.
4602
			 */
4603
			if (isset($wancfg['dhcp6withoutra'])) {
4604
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4605
			} else {
4606
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4607
			}
4608
			$dhcp6cconf .= "};\n";
4609

    
4610
			if (!isset($wancfg['dhcp6prefixonly'])) {
4611
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4612
			}
4613

    
4614
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4615
				/* Setup the prefix delegation */
4616
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4617
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4618
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4619
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4620
				}
4621
				foreach ($trackiflist as $friendly => $ifcfg) {
4622
					if ($g['debug']) {
4623
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4624
					}
4625
					$realif = get_real_interface($friendly);
4626
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4627
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4628
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4629
					$dhcp6cconf .= "\t};\n";
4630
				}
4631
				unset($preflen, $iflist, $ifcfg, $ifname);
4632
				$dhcp6cconf .= "};\n";
4633
			}
4634
			unset($trackiflist);
4635
		}
4636
	}
4637

    
4638
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4639
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4640

    
4641
	/* wide-dhcp6c works for now. */
4642
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4643
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4644
		unset($dhcp6cconf);
4645
		return 1;
4646
	}
4647
	unset($dhcp6cconf);
4648

    
4649
	/*************** Script Debug Logging ***************************
4650
	Both dhcp6 scripts now have a logging message built in.
4651
	These logging messages ONLY appear if dhcp6c debug logging is set.
4652
	The logging messages appear in the dhcp section of the logs,
4653
	not in system.
4654

    
4655
	These scripts now also take advantage of the REASON= env vars
4656
	supplied by dhcp6c.
4657
	****************************************************************/
4658

    
4659
	/* Script create for dhcp6withoutRA mode */
4660
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4661
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4662
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4663
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4664
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4665
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4666
	// Need to pass params to  the final script
4667
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4668
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4669
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4670
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4671
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
4672
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
4673
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4674
	if ($debugOption == '-D') {
4675
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4676
	}
4677
	$dhcp6cscriptwithoutra .= ";;\n";
4678
	$dhcp6cscriptwithoutra .= "REBIND)\n";
4679
	if ($debugOption == '-D') {
4680
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4681
	}
4682
	$dhcp6cscriptwithoutra .= ";;\n";
4683
	if (isset($wancfg['dhcp6norelease'])) {
4684
		$dhcp6cscriptwithoutra .= "EXIT)\n";
4685
	} else {
4686
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
4687
	}
4688
	if ($debugOption == '-D') {
4689
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4690
	}
4691
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4692
	$dhcp6cscriptwithoutra .= ";;\n";
4693
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
4694
	if ($debugOption == '-D') {
4695
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4696
	}
4697
	$dhcp6cscriptwithoutra .= "esac\n";
4698
	if (!@file_put_contents(
4699
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4700
	    $dhcp6cscriptwithoutra)) {
4701
		printf("Error: cannot open " .
4702
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4703
		    "interface_dhcpv6_configure() for writing.\n");
4704
		unset($dhcp6cscriptwithoutra);
4705
		return 1;
4706
	}
4707

    
4708
	unset($dhcp6cscriptwithoutra);
4709
	@chmod(
4710
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4711
	    0755);
4712

    
4713
	/*
4714
	 * Dual mode wan_dhcp6c script with variations depending on node
4715
	 * dhcp6 will run the wan ipv6 configure
4716
	 */
4717
	$dhcp6cscript  = "#!/bin/sh\n";
4718
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4719
	if (!isset($wancfg['dhcp6withoutra'])) {
4720
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4721
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4722
		$dhcp6cscript .= "case \$REASON in\n";
4723
		$dhcp6cscript .= "REQUEST)\n";
4724
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4725
		if ($debugOption == '-D') {
4726
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4727
		}
4728
		$dhcp6cscript .= ";;\n";
4729
		$dhcp6cscript .= "REBIND)\n";
4730
		if ($debugOption == '-D') {
4731
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4732
		}
4733
		$dhcp6cscript .= ";;\n";
4734
		if (isset($wancfg['dhcp6norelease'])) {
4735
			$dhcp6cscript .= "EXIT)\n";
4736
		} else {
4737
			$dhcp6cscript .= "RELEASE)\n";
4738
		}
4739
		if ($debugOption == '-D') {
4740
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4741
		}
4742
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4743
		$dhcp6cscript .= ";;\n";
4744
		$dhcp6cscript .= "RENEW|INFO)\n";
4745
		if ($debugOption == '-D') {
4746
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4747
		}
4748
		$dhcp6cscript .= "esac\n";
4749
	} else {
4750
		// Need to get the parameters from the dhcp6cwithoutRA run
4751
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
4752
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
4753
		$dhcp6cscript .= "/bin/sleep 1\n";
4754
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4755
	}
4756

    
4757
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4758
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4759
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4760
		unset($dhcp6cscript);
4761
		return 1;
4762
	}
4763
	unset($dhcp6cscript);
4764
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4765

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

    
4772
	/* non ipoe Process */
4773
	if (!isset($wancfg['dhcp6withoutra'])) {
4774
		/*
4775
		 * We only want this script to run once, and if it runs twice
4776
		 * then do not launch dhcp6c again, this only happens if
4777
		 * dhcpwithoutra is not set.
4778
		 *
4779
		 * Check for a lock file, trying to prevent multiple instances
4780
		 * of dhcp6c being launched
4781
		 */
4782
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
4783
		/*
4784
		 * Create the lock file, trying to prevent multiple instances
4785
		 * of dhcp6c being launched
4786
		 */
4787
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
4788
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
4789
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4790
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4791
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
4792
		$rtsoldscript .= "\tfi\n";
4793
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
4794
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
4795
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4796
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4797
		$rtsoldscript .= "else\n";
4798
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
4799
		$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c_{$wanif}.pid\")\n";
4800
		$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
4801
		$rtsoldscript .= "fi\n";
4802
	} else {
4803
		/*
4804
		 * The script needs to run in dhcp6withoutra mode as RA may
4805
		 * not have been received, or there can be a delay with
4806
		 * certain ISPs
4807
		 */
4808
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
4809
		$rtsoldscript .= "/bin/sleep 1\n";
4810
	}
4811
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4812
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4813
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4814
		unset($rtsoldscript);
4815
		return 1;
4816
	}
4817
	unset($rtsoldscript);
4818
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4819

    
4820
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4821
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4822
		log_error("Killing running rtsold process");
4823
		sleep(2);
4824
	}
4825

    
4826
	if (isset($wancfg['dhcp6withoutra'])) {
4827
		/*
4828
		 * Start dhcp6c here if we don't want to wait for ra - calls
4829
		 * seperate function
4830
		 *
4831
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
4832
		 * will then run the configure on receipt of the RA.
4833
		 *
4834
		 * Already started. interface_dhcpv6_configure() appears to get
4835
		 * called multiple times.
4836
		 *
4837
		 * Taking the interface down or releasing will kill the client.
4838
		 */
4839
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
4840
		{
4841
			/*
4842
			 * If the interface is being brought up, wait for the
4843
			 * interface to configure accept RA before launching.
4844
			 * Otherwise it is not ready to accept and will fail.
4845
			 */
4846
			sleep(3);
4847
			run_dhcp6client_process($wanif,$interface,$wancfg);
4848
		}
4849
	} else {
4850
		/*
4851
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
4852
		 * ( it does not background, it exits! ) It will launch dhcp6c
4853
		 * if dhcpwihtoutra is not set
4854
		 */
4855
		log_error("Starting rtsold process");
4856
		sleep(2);
4857
		mwexec("/usr/sbin/rtsold -1 " .
4858
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
4859
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
4860
		    $wanif);
4861
	}
4862
	/*
4863
	 * NOTE: will be called from rtsold invoked script
4864
	 * link_interface_to_track6($interface, "update");
4865
	 */
4866

    
4867
	return 0;
4868
}
4869

    
4870
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4871
	global $g;
4872

    
4873
	$send_options = "";
4874
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4875
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4876
		foreach ($options as $option) {
4877
			$send_options .= "\tsend " . trim($option) . ";\n";
4878
		}
4879
	}
4880

    
4881
	$request_options = "";
4882
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4883
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4884
		foreach ($options as $option) {
4885
			$request_options .= "\trequest " . trim($option) . ";\n";
4886
		}
4887
	}
4888

    
4889
	$information_only = "";
4890
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4891
		$information_only = "\tinformation-only;\n";
4892
	}
4893

    
4894
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4895
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4896
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4897
	}
4898

    
4899
	$interface_statement  = "interface";
4900
	$interface_statement .= " {$wanif}";
4901
	$interface_statement .= " {\n";
4902
	$interface_statement .= "$send_options";
4903
	$interface_statement .= "$request_options";
4904
	$interface_statement .= "$information_only";
4905
	$interface_statement .= "$script";
4906
	$interface_statement .= "};\n";
4907

    
4908
	$id_assoc_statement_address = "";
4909
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4910
		$id_assoc_statement_address .= "id-assoc";
4911
		$id_assoc_statement_address .= " na";
4912
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4913
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4914
		}
4915
		$id_assoc_statement_address .= " { ";
4916

    
4917
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4918
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4919
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4920
			$id_assoc_statement_address .= "\n\taddress";
4921
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4922
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4923
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4924
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4925
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4926
			}
4927
			$id_assoc_statement_address .= ";\n";
4928
		}
4929

    
4930
		$id_assoc_statement_address .= "};\n";
4931
	}
4932

    
4933
	$id_assoc_statement_prefix = "";
4934
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4935
		$id_assoc_statement_prefix .= "id-assoc";
4936
		$id_assoc_statement_prefix .= " pd";
4937
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4938
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4939
		}
4940
		$id_assoc_statement_prefix .= " { ";
4941

    
4942
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4943
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4944
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4945
			$id_assoc_statement_prefix .= "\n\tprefix";
4946
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4947
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4948
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4949
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4950
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4951
			}
4952
			$id_assoc_statement_prefix .= ";";
4953
		}
4954

    
4955
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
4956
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4957
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4958
			$id_assoc_statement_prefix .= " {$realif}";
4959
			$id_assoc_statement_prefix .= " {\n";
4960
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4961
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4962
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4963
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4964
			}
4965
			$id_assoc_statement_prefix .= "\t};";
4966
		}
4967

    
4968
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4969
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4970
			$id_assoc_statement_prefix .= "\n";
4971
		}
4972

    
4973
		$id_assoc_statement_prefix .= "};\n";
4974
	}
4975

    
4976
	$authentication_statement = "";
4977
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4978
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4979
		$authentication_statement .= "authentication";
4980
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4981
		$authentication_statement .= " {\n";
4982
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4983
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4984
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4985
		}
4986
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4987
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4988
		}
4989
		$authentication_statement .= "};\n";
4990
	}
4991

    
4992
	$key_info_statement = "";
4993
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4994
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4995
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4996
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4997
		$key_info_statement .= "keyinfo";
4998
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4999
		$key_info_statement .= " {\n";
5000
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5001
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5002
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5003
		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'])) {
5004
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5005
		}
5006
		$key_info_statement .= "};\n";
5007
	}
5008

    
5009
	$dhcp6cconf  = $interface_statement;
5010
	$dhcp6cconf .= $id_assoc_statement_address;
5011
	$dhcp6cconf .= $id_assoc_statement_prefix;
5012
	$dhcp6cconf .= $authentication_statement;
5013
	$dhcp6cconf .= $key_info_statement;
5014

    
5015
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5016

    
5017
	return $dhcp6cconf;
5018
}
5019

    
5020

    
5021
function DHCP6_Config_File_Override($wancfg, $wanif) {
5022

    
5023
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5024

    
5025
	if ($dhcp6cconf === false) {
5026
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5027
		return '';
5028
	} else {
5029
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5030
	}
5031
}
5032

    
5033

    
5034
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5035

    
5036
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5037

    
5038
	return $dhcp6cconf;
5039
}
5040

    
5041

    
5042
function interface_dhcp_configure($interface = "wan") {
5043
	global $config, $g, $vlanprio_values;
5044

    
5045
	$ifcfg = $config['interfaces'][$interface];
5046
	if (empty($ifcfg)) {
5047
		$ifcfg = array();
5048
	}
5049

    
5050
	$dhclientconf_vlantag = "";
5051
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5052
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5053
	}
5054

    
5055
	/* generate dhclient_wan.conf */
5056
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5057
	if (!$fd) {
5058
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5059
		return 1;
5060
	}
5061

    
5062
	if ($ifcfg['dhcphostname']) {
5063
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5064
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5065
	} else {
5066
		$dhclientconf_hostname = "";
5067
	}
5068

    
5069
	$realif = get_real_interface($interface);
5070
	if (empty($realif)) {
5071
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5072
		return 0;
5073
	}
5074
	$dhclientconf = "";
5075

    
5076
	$dhclientconf .= <<<EOD
5077
interface "{$realif}" {
5078
	supersede interface-mtu 0;
5079
	timeout 60;
5080
	retry 15;
5081
	select-timeout 0;
5082
	initial-interval 1;
5083
	{$dhclientconf_vlantag}
5084
	{$dhclientconf_hostname}
5085
	script "/usr/local/sbin/pfSense-dhclient-script";
5086
EOD;
5087

    
5088
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5089
		$dhclientconf .= <<<EOD
5090

    
5091
	reject {$ifcfg['dhcprejectfrom']};
5092
EOD;
5093
	}
5094
	$dhclientconf .= <<<EOD
5095

    
5096
}
5097

    
5098
EOD;
5099

    
5100
	// DHCP Config File Advanced
5101
	if ($ifcfg['adv_dhcp_config_advanced']) {
5102
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5103
	}
5104

    
5105
	if (is_ipaddr($ifcfg['alias-address'])) {
5106
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5107
		$dhclientconf .= <<<EOD
5108
alias {
5109
	interface "{$realif}";
5110
	fixed-address {$ifcfg['alias-address']};
5111
	option subnet-mask {$subnetmask};
5112
}
5113

    
5114
EOD;
5115
	}
5116

    
5117
	// DHCP Config File Override
5118
	if ($ifcfg['adv_dhcp_config_file_override']) {
5119
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5120
	}
5121

    
5122
	fwrite($fd, $dhclientconf);
5123
	fclose($fd);
5124

    
5125
	/* bring wan interface up before starting dhclient */
5126
	if ($realif) {
5127
		interfaces_bring_up($realif);
5128
	}
5129

    
5130
	/* Make sure dhclient is not running */
5131
	kill_dhclient_process($realif);
5132

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

    
5136
	return 0;
5137
}
5138

    
5139
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5140

    
5141
	$hostname = "";
5142
	if ($ifcfg['dhcphostname'] != '') {
5143
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5144
	}
5145

    
5146
	/* DHCP Protocol Timings */
5147
	$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");
5148
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5149
		$pt_variable = "{$Protocol_Timing}";
5150
		${$pt_variable} = "";
5151
		if ($ifcfg[$Protocol_Timing] != "") {
5152
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5153
		}
5154
	}
5155

    
5156
	$send_options = "";
5157
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5158
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5159
		foreach ($options as $option) {
5160
			$send_options .= "\tsend " . trim($option) . ";\n";
5161
		}
5162
	}
5163

    
5164
	$request_options = "";
5165
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5166
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5167
	}
5168

    
5169
	$required_options = "";
5170
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5171
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5172
	}
5173

    
5174
	$option_modifiers = "";
5175
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5176
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5177
		foreach ($modifiers as $modifier) {
5178
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5179
		}
5180
	}
5181

    
5182
	$dhclientconf  = "interface \"{$realif}\" {\n";
5183
	$dhclientconf .= "\n";
5184
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5185
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5186
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5187
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5188
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5189
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5190
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5191
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5192
	$dhclientconf .= "\n";
5193
	$dhclientconf .= "# DHCP Protocol Options\n";
5194
	$dhclientconf .= "{$hostname}";
5195
	$dhclientconf .= "{$send_options}";
5196
	$dhclientconf .= "{$request_options}";
5197
	$dhclientconf .= "{$required_options}";
5198
	$dhclientconf .= "{$option_modifiers}";
5199
	$dhclientconf .= "\n";
5200
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5201
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5202
	}
5203
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5204
	$dhclientconf .= "}\n";
5205

    
5206
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5207

    
5208
	return $dhclientconf;
5209
}
5210

    
5211
function DHCP_Config_Option_Split($option_string) {
5212
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5213
	return $matches ? $matches[0] : [];
5214
}
5215

    
5216
function DHCP_Config_File_Override($ifcfg, $realif) {
5217

    
5218
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5219

    
5220
	if ($dhclientconf === false) {
5221
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5222
		return '';
5223
	} else {
5224
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5225
	}
5226
}
5227

    
5228

    
5229
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5230

    
5231
	/* Apply Interface Substitutions */
5232
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5233

    
5234
	/* Apply Hostname Substitutions */
5235
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5236

    
5237
	/* Arrays of MAC Address Types, Cases, Delimiters */
5238
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5239
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5240
	$various_mac_cases      = array("U", "L");
5241
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5242

    
5243
	/* Apply MAC Address Substitutions */
5244
	foreach ($various_mac_types as $various_mac_type) {
5245
		foreach ($various_mac_cases as $various_mac_case) {
5246
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5247

    
5248
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5249
				if ($res !== false) {
5250

    
5251
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5252
					if ("$various_mac_case" == "U") {
5253
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5254
					}
5255
					if ("$various_mac_case" == "L") {
5256
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5257
					}
5258

    
5259
					if ("$various_mac_type" == "mac_addr_hex") {
5260
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5261
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5262
						$dhcpclientconf_mac_hex = "";
5263
						$delimiter = "";
5264
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5265
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5266
							$delimiter = ":";
5267
						}
5268
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5269
					}
5270

    
5271
					/* MAC Address Delimiter Substitutions */
5272
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5273

    
5274
					/* Apply MAC Address Substitutions */
5275
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5276
				}
5277
			}
5278
		}
5279
	}
5280

    
5281
	return $dhclientconf;
5282
}
5283

    
5284
function interfaces_group_setup() {
5285
	global $config;
5286

    
5287
	if (!isset($config['ifgroups']['ifgroupentry']) || !is_array($config['ifgroups']['ifgroupentry'])) {
5288
		return;
5289
	}
5290

    
5291
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5292
		interface_group_setup($groupar);
5293
	}
5294

    
5295
	return;
5296
}
5297

    
5298
function interface_group_setup(&$groupname /* The parameter is an array */) {
5299
	global $config;
5300

    
5301
	if (!is_array($groupname)) {
5302
		return;
5303
	}
5304
	$members = explode(" ", $groupname['members']);
5305
	foreach ($members as $ifs) {
5306
		$realif = get_real_interface($ifs);
5307
		if ($realif && does_interface_exist($realif)) {
5308
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5309
		}
5310
	}
5311

    
5312
	return;
5313
}
5314

    
5315
function is_interface_group($if) {
5316
	global $config;
5317

    
5318
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5319
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5320
			if ($groupentry['ifname'] === $if) {
5321
				return true;
5322
			}
5323
		}
5324
	}
5325

    
5326
	return false;
5327
}
5328

    
5329
function interface_group_add_member($interface, $groupname) {
5330
	$interface = get_real_interface($interface);
5331
	if (does_interface_exist($interface)) {
5332
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5333
	}
5334
}
5335

    
5336
/* COMPAT Function */
5337
function convert_friendly_interface_to_real_interface_name($interface) {
5338
	return get_real_interface($interface);
5339
}
5340

    
5341
/* COMPAT Function */
5342
function get_real_wan_interface($interface = "wan") {
5343
	return get_real_interface($interface);
5344
}
5345

    
5346
/* COMPAT Function */
5347
function get_current_wan_address($interface = "wan") {
5348
	return get_interface_ip($interface);
5349
}
5350

    
5351
/*
5352
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5353
 */
5354
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5355
	global $config;
5356

    
5357
	/* XXX: For speed reasons reference directly the interface array */
5358
	init_config_arr(array('interfaces'));
5359
	$ifdescrs = &$config['interfaces'];
5360
	//$ifdescrs = get_configured_interface_list(true);
5361

    
5362
	foreach ($ifdescrs as $if => $ifname) {
5363
		if ($if == $interface || $ifname['if'] == $interface) {
5364
			return $if;
5365
		}
5366

    
5367
		if (get_real_interface($if) == $interface) {
5368
			return $if;
5369
		}
5370

    
5371
		if ($checkparent == false) {
5372
			continue;
5373
		}
5374

    
5375
		$int = get_parent_interface($if, true);
5376
		if (is_array($int)) {
5377
			foreach ($int as $iface) {
5378
				if ($iface == $interface) {
5379
					return $if;
5380
				}
5381
			}
5382
		}
5383
	}
5384

    
5385
	if ($interface == "enc0") {
5386
		return 'IPsec';
5387
	}
5388
}
5389

    
5390
/* attempt to resolve interface to friendly descr */
5391
function convert_friendly_interface_to_friendly_descr($interface) {
5392
	global $config;
5393

    
5394
	switch ($interface) {
5395
		case "l2tp":
5396
			$ifdesc = "L2TP";
5397
			break;
5398
		case "pptp":
5399
			$ifdesc = "PPTP";
5400
			break;
5401
		case "pppoe":
5402
			$ifdesc = "PPPoE";
5403
			break;
5404
		case "openvpn":
5405
			$ifdesc = "OpenVPN";
5406
			break;
5407
		case "lo0":
5408
			$ifdesc = "Loopback";
5409
			break;
5410
		case "enc0":
5411
		case "ipsec":
5412
		case "IPsec":
5413
			$ifdesc = "IPsec";
5414
			break;
5415
		default:
5416
			if (isset($config['interfaces'][$interface])) {
5417
				if (empty($config['interfaces'][$interface]['descr'])) {
5418
					$ifdesc = strtoupper($interface);
5419
				} else {
5420
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5421
				}
5422
				break;
5423
			} else if (substr($interface, 0, 4) == '_vip') {
5424
				if (is_array($config['virtualip']['vip'])) {
5425
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5426
						if ($vip['mode'] == "carp") {
5427
							if ($interface == "_vip{$vip['uniqid']}") {
5428
								$descr = $vip['subnet'];
5429
								$descr .= " (vhid {$vip['vhid']})";
5430
								if (!empty($vip['descr'])) {
5431
									$descr .= " - " .$vip['descr'];
5432
								}
5433
								return $descr;
5434
							}
5435
						}
5436
					}
5437
				}
5438
			} else if (substr($interface, 0, 5) == '_lloc') {
5439
				return get_interface_linklocal($interface);
5440
			} else {
5441
				if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5442
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5443
						if ($ifgen['ifname'] === $interface) {
5444
							return $ifgen['ifname'];
5445
						}
5446
					}
5447
				}
5448

    
5449
				/* if list */
5450
				$ifdescrs = get_configured_interface_with_descr(true);
5451
				foreach ($ifdescrs as $if => $ifname) {
5452
					if ($if == $interface || $ifname == $interface) {
5453
						return $ifname;
5454
					}
5455
				}
5456
			}
5457
			break;
5458
	}
5459

    
5460
	return $ifdesc;
5461
}
5462

    
5463
function convert_real_interface_to_friendly_descr($interface) {
5464

    
5465
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5466

    
5467
	if (!empty($ifdesc)) {
5468
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5469
	}
5470

    
5471
	return $interface;
5472
}
5473

    
5474
/*
5475
 *  get_parent_interface($interface):
5476
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5477
 *				or virtual interface (i.e. vlan)
5478
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5479
 *			-- returns $interface passed in if $interface parent is not found
5480
 *			-- returns empty array if an invalid interface is passed
5481
 *	(Only handles ppps and vlans now.)
5482
 */
5483
function get_parent_interface($interface, $avoidrecurse = false) {
5484
	global $config;
5485

    
5486
	$parents = array();
5487
	//Check that we got a valid interface passed
5488
	$realif = get_real_interface($interface);
5489
	if ($realif == NULL) {
5490
		return $parents;
5491
	}
5492

    
5493
	// If we got a real interface, find it's friendly assigned name
5494
	if ($interface == $realif && $avoidrecurse == false) {
5495
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5496
	}
5497

    
5498
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5499
		$ifcfg = $config['interfaces'][$interface];
5500
		switch ($ifcfg['ipaddr']) {
5501
			case "ppp":
5502
			case "pppoe":
5503
			case "pptp":
5504
			case "l2tp":
5505
				if (empty($parents)) {
5506
					if (is_array($config['ppps']['ppp'])) {
5507
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5508
							if ($ifcfg['if'] == $ppp['if']) {
5509
								$ports = explode(',', $ppp['ports']);
5510
								foreach ($ports as $pid => $parent_if) {
5511
									$parents[$pid] = get_real_interface($parent_if);
5512
								}
5513
								break;
5514
							}
5515
						}
5516
					}
5517
				}
5518
				break;
5519
			case "dhcp":
5520
			case "static":
5521
			default:
5522
				// Handle _vlans
5523
				$vlan = interface_is_vlan($ifcfg['if']);
5524
				if ($vlan != NULL) {
5525
					$parents[0] = $vlan['if'];
5526
				}
5527
				break;
5528
		}
5529
	}
5530

    
5531
	if (empty($parents)) {
5532
		// Handle _vlans not assigned to an interface
5533
		$vlan = interface_is_vlan($realif);
5534
		if ($vlan != NULL) {
5535
			$parents[0] = $vlan['if'];
5536
		}
5537
	}
5538

    
5539
	if (empty($parents)) {
5540
		/* Handle LAGGs. */
5541
		$lagg = interface_is_lagg($realif);
5542
		if ($lagg != NULL && isset($lagg['members'])) {
5543
			$parents = explode(",", $lagg['members']);
5544
		}
5545
	}
5546

    
5547
	if (empty($parents)) {
5548
		$parents[0] = $realif;
5549
	}
5550

    
5551
	return $parents;
5552
}
5553

    
5554
/*
5555
 *  get_parent_physical_interface($interface):
5556
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5557
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5558
 */
5559
function get_parent_physical_interface($interface) {
5560
	global $config;
5561

    
5562
	$realif = get_parent_interface($interface);
5563

    
5564
	if (substr($realif[0], 0, 4) == "lagg") {
5565
		foreach ($config['laggs']['lagg'] as $lagg) {
5566
			if ($realif[0] == $lagg['laggif']) {
5567
				return explode(",", $lagg['members']);
5568
			}
5569
		}
5570
	} else {
5571
		return $realif;
5572
	}
5573
}
5574

    
5575
function interface_is_wireless_clone($wlif) {
5576
	if (!stristr($wlif, "_wlan")) {
5577
		return false;
5578
	} else {
5579
		return true;
5580
	}
5581
}
5582

    
5583
function interface_get_wireless_base($wlif) {
5584
	if (!stristr($wlif, "_wlan")) {
5585
		return $wlif;
5586
	} else {
5587
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5588
	}
5589
}
5590

    
5591
function interface_get_wireless_clone($wlif) {
5592
	if (!stristr($wlif, "_wlan")) {
5593
		return $wlif . "_wlan0";
5594
	} else {
5595
		return $wlif;
5596
	}
5597
}
5598

    
5599
function interface_list_wireless() {
5600
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5601

    
5602
	$result = array();
5603
	foreach ($portlist as $port) {
5604
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5605
			continue;
5606
		}
5607

    
5608
		$desc = $port . " ( " . get_single_sysctl(
5609
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5610

    
5611
		$result[] = array(
5612
		    "if" => $port,
5613
		    "descr" => $desc
5614
		);
5615
	}
5616

    
5617
	return $result;
5618
}
5619

    
5620
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
5621
	global $config, $g;
5622

    
5623
	$wanif = NULL;
5624

    
5625
	switch ($interface) {
5626
		case "l2tp":
5627
			$wanif = "l2tp";
5628
			break;
5629
		case "pptp":
5630
			$wanif = "pptp";
5631
			break;
5632
		case "pppoe":
5633
			$wanif = "pppoe";
5634
			break;
5635
		case "openvpn":
5636
			$wanif = "openvpn";
5637
			break;
5638
		case "IPsec":
5639
		case "ipsec":
5640
		case "enc0":
5641
			$wanif = "enc0";
5642
			break;
5643
		case "ppp":
5644
			$wanif = "ppp";
5645
			break;
5646
		default:
5647
			if (substr($interface, 0, 4) == '_vip') {
5648
				$wanif = get_configured_vip_interface($interface);
5649
				if (!empty($wanif)) {
5650
					$wanif = get_real_interface($wanif);
5651
				}
5652
				break;
5653
			} else if (substr($interface, 0, 5) == '_lloc') {
5654
				$interface = substr($interface, 5);
5655
			} else if (interface_is_vlan($interface) != NULL ||
5656
			    does_interface_exist($interface, $flush)) {
5657
				/*
5658
				 * If a real interface was already passed simply
5659
				 * pass the real interface back.  This encourages
5660
				 * the usage of this function in more cases so that
5661
				 * we can combine logic for more flexibility.
5662
				 */
5663
				$wanif = $interface;
5664
				break;
5665
			}
5666

    
5667
			if (empty($config['interfaces'][$interface])) {
5668
				break;
5669
			}
5670

    
5671
			$cfg = &$config['interfaces'][$interface];
5672

    
5673
			if ($family == "inet6") {
5674
				switch ($cfg['ipaddrv6']) {
5675
					case "6rd":
5676
					case "6to4":
5677
						$wanif = "{$interface}_stf";
5678
						break;
5679
					case 'pppoe':
5680
					case 'ppp':
5681
					case 'l2tp':
5682
					case 'pptp':
5683
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5684
							$wanif = interface_get_wireless_clone($cfg['if']);
5685
						} else {
5686
							$wanif = $cfg['if'];
5687
						}
5688
						break;
5689
					default:
5690
						switch ($cfg['ipaddr']) {
5691
							case 'pppoe':
5692
							case 'ppp':
5693
							case 'l2tp':
5694
							case 'pptp':
5695
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
5696
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) || isset($cfg['ipv6usev4iface'])) {
5697
									$wanif = $cfg['if'];
5698
								} else {
5699
									$parents = get_parent_interface($interface);
5700
									if (!empty($parents[0])) {
5701
										$wanif = $parents[0];
5702
									} else {
5703
										$wanif = $cfg['if'];
5704
									}
5705
								}
5706
								break;
5707
							default:
5708
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5709
									$wanif = interface_get_wireless_clone($cfg['if']);
5710
								} else {
5711
									$wanif = $cfg['if'];
5712
								}
5713
								break;
5714
						}
5715
						break;
5716
				}
5717
			} else {
5718
				// Wireless cloned NIC support (FreeBSD 8+)
5719
				// interface name format: $parentnic_wlanparentnic#
5720
				// example: ath0_wlan0
5721
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5722
					$wanif = interface_get_wireless_clone($cfg['if']);
5723
				} else {
5724
					$wanif = $cfg['if'];
5725
				}
5726
			}
5727
			break;
5728
	}
5729

    
5730
	return $wanif;
5731
}
5732

    
5733
/* Guess the physical interface by providing a IP address */
5734
function guess_interface_from_ip($ipaddress) {
5735

    
5736
	$family = '';
5737
	if (is_ipaddrv4($ipaddress)) {
5738
		$family = 'inet';
5739
	}
5740
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5741
		$family = 'inet6';
5742
	}
5743

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

    
5748
	/* create a route table we can search */
5749
	$output = '';
5750
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
5751
	$output[0] = trim($output[0], " \n");
5752
	if (!empty($output[0])) {
5753
		return $output[0];
5754
	}
5755

    
5756
	return false;
5757
}
5758

    
5759
/*
5760
 * find_ip_interface($ip): return the interface where an ip is defined
5761
 *   (or if $bits is specified, where an IP within the subnet is defined)
5762
 */
5763
function find_ip_interface($ip, $bits = null) {
5764
	if (!is_ipaddr($ip)) {
5765
		return false;
5766
	}
5767

    
5768
	$isv6ip = is_ipaddrv6($ip);
5769

    
5770
	/* if list */
5771
	$ifdescrs = get_configured_interface_list();
5772

    
5773
	foreach ($ifdescrs as $ifdescr => $ifname) {
5774
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
5775
		if (is_null($ifip)) {
5776
			continue;
5777
		}
5778
		if (is_null($bits)) {
5779
			if ($ip == $ifip) {
5780
				$int = get_real_interface($ifname);
5781
				return $int;
5782
			}
5783
		} else {
5784
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
5785
				$int = get_real_interface($ifname);
5786
				return $int;
5787
			}
5788
		}
5789
	}
5790

    
5791
	return false;
5792
}
5793

    
5794
/*
5795
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5796
 *   (or if $bits is specified, where an IP within the subnet is found)
5797
 */
5798
function find_virtual_ip_alias($ip, $bits = null) {
5799
	global $config;
5800

    
5801
	if (!is_array($config['virtualip']['vip'])) {
5802
		return false;
5803
	}
5804
	if (!is_ipaddr($ip)) {
5805
		return false;
5806
	}
5807

    
5808
	$isv6ip = is_ipaddrv6($ip);
5809

    
5810
	foreach ($config['virtualip']['vip'] as $vip) {
5811
		if ($vip['mode'] === "ipalias") {
5812
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
5813
				continue;
5814
			}
5815
			if (is_null($bits)) {
5816
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
5817
					return $vip;
5818
				}
5819
			} else {
5820
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5821
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5822
					return $vip;
5823
				}
5824
			}
5825
		}
5826
	}
5827
	return false;
5828
}
5829

    
5830
function link_interface_to_track6($int, $action = "") {
5831
	global $config;
5832

    
5833
	if (empty($int)) {
5834
		return;
5835
	}
5836

    
5837
	if (is_array($config['interfaces'])) {
5838
		$list = array();
5839
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5840
			if (!isset($ifcfg['enable'])) {
5841
				continue;
5842
			}
5843
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5844
				if ($action == "update") {
5845
					interface_track6_configure($ifname, $ifcfg);
5846
				} else if ($action == "") {
5847
					$list[$ifname] = $ifcfg;
5848
				}
5849
			}
5850
		}
5851
		return $list;
5852
	}
5853
}
5854

    
5855
function interface_find_child_cfgmtu($realiface) {
5856
	global $config;
5857

    
5858
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5859
	$vlans = link_interface_to_vlans($realiface);
5860
	$qinqs = link_interface_to_qinqs($realiface);
5861
	$bridge = link_interface_to_bridge($realiface);
5862
	if (!empty($interface)) {
5863
		$gifs = link_interface_to_gif($interface);
5864
		$gres = link_interface_to_gre($interface);
5865
	} else {
5866
		$gifs = array();
5867
		$gres = array();
5868
	}
5869

    
5870
	$mtu = 0;
5871
	if (is_array($vlans)) {
5872
		foreach ($vlans as $vlan) {
5873
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5874
			if (empty($ifass)) {
5875
				continue;
5876
			}
5877
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5878
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5879
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5880
				}
5881
			}
5882
		}
5883
	}
5884
	if (is_array($qinqs)) {
5885
		foreach ($qinqs as $qinq) {
5886
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5887
			if (empty($ifass)) {
5888
				continue;
5889
			}
5890
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5891
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5892
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5893
				}
5894
			}
5895
		}
5896
	}
5897
	if (is_array($gifs)) {
5898
		foreach ($gifs as $gif) {
5899
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5900
			if (empty($ifass)) {
5901
				continue;
5902
			}
5903
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5904
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5905
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5906
				}
5907
			}
5908
		}
5909
	}
5910
	if (is_array($gres)) {
5911
		foreach ($gres as $gre) {
5912
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5913
			if (empty($ifass)) {
5914
				continue;
5915
			}
5916
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5917
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5918
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5919
				}
5920
			}
5921
		}
5922
	}
5923
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5924
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5925
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5926
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5927
		}
5928
	}
5929
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5930

    
5931
	return $mtu;
5932
}
5933

    
5934
function link_interface_to_vlans($int, $action = "") {
5935
	global $config;
5936

    
5937
	if (empty($int)) {
5938
		return;
5939
	}
5940

    
5941
	if (is_array($config['vlans']['vlan'])) {
5942
		$ifaces = array();
5943
		foreach ($config['vlans']['vlan'] as $vlan) {
5944
			if ($int == $vlan['if']) {
5945
				if ($action == "update") {
5946
					interfaces_bring_up($int);
5947
				} else {
5948
					$ifaces[$vlan['tag']] = $vlan;
5949
				}
5950
			}
5951
		}
5952
		if (!empty($ifaces)) {
5953
			return $ifaces;
5954
		}
5955
	}
5956
}
5957

    
5958
function link_interface_to_qinqs($int, $action = "") {
5959
	global $config;
5960

    
5961
	if (empty($int)) {
5962
		return;
5963
	}
5964

    
5965
	if (is_array($config['qinqs']['qinqentry'])) {
5966
		$ifaces = array();
5967
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5968
			if ($int == $qinq['if']) {
5969
				if ($action == "update") {
5970
					interfaces_bring_up($int);
5971
				} else {
5972
					$ifaces[$qinq['tag']] = $qinq;
5973
				}
5974
			}
5975
		}
5976
		if (!empty($ifaces)) {
5977
			return $ifaces;
5978
		}
5979
	}
5980
}
5981

    
5982
function link_interface_to_vips($int, $action = "", $vhid = '') {
5983
	global $config;
5984

    
5985
	$updatevips = false;
5986
	if (is_array($config['virtualip']['vip'])) {
5987
		$result = array();
5988
		foreach ($config['virtualip']['vip'] as $vip) {
5989
			if (substr($vip['interface'], 0, 4) == "_vip") {
5990
				$iface = get_configured_vip_interface($vip['interface']);
5991
			} else {
5992
				$iface = $vip['interface'];
5993
			}
5994
			if ($int != $iface) {
5995
				continue;
5996
			}
5997
			if ($action == "update") {
5998
				$updatevips = true;
5999
			} else {
6000
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
6001
				    substr($vip['interface'], 0, 4) == "_vip") {
6002
					$result[] = $vip;
6003
				}
6004
			}
6005
		}
6006
		if ($updatevips === true) {
6007
			interfaces_vips_configure($int);
6008
		}
6009
		return $result;
6010
	}
6011

    
6012
	return NULL;
6013
}
6014

    
6015
/****f* interfaces/link_interface_to_bridge
6016
 * NAME
6017
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6018
 * INPUTS
6019
 *   $ip
6020
 * RESULT
6021
 *   bridge[0-99]
6022
 ******/
6023
function link_interface_to_bridge($int) {
6024
	global $config;
6025

    
6026
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6027
		foreach ($config['bridges']['bridged'] as $bridge) {
6028
			if (in_array($int, explode(',', $bridge['members']))) {
6029
				return "{$bridge['bridgeif']}";
6030
			}
6031
		}
6032
	}
6033
}
6034

    
6035
function link_interface_to_group($int) {
6036
	global $config;
6037

    
6038
	$result = array();
6039

    
6040
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6041
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6042
			if (in_array($int, explode(" ", $group['members']))) {
6043
				$result[$group['ifname']] = $int;
6044
			}
6045
		}
6046
	}
6047

    
6048
	return $result;
6049
}
6050

    
6051
function link_interface_to_gre($interface) {
6052
	global $config;
6053

    
6054
	$result = array();
6055

    
6056
	if (is_array($config['gres']['gre'])) {
6057
		foreach ($config['gres']['gre'] as $gre) {
6058
			if ($gre['if'] == $interface) {
6059
				$result[] = $gre;
6060
			}
6061
		}
6062
	}
6063

    
6064
	return $result;
6065
}
6066

    
6067
function link_interface_to_gif($interface) {
6068
	global $config;
6069

    
6070
	$result = array();
6071

    
6072
	if (is_array($config['gifs']['gif'])) {
6073
		foreach ($config['gifs']['gif'] as $gif) {
6074
			if ($gif['if'] == $interface) {
6075
				$result[] = $gif;
6076
			}
6077
		}
6078
	}
6079

    
6080
	return $result;
6081
}
6082

    
6083
/*
6084
 * find_interface_ip($interface): return the interface ip (first found)
6085
 */
6086
function find_interface_ip($interface, $flush = false) {
6087
	global $interface_ip_arr_cache;
6088
	global $interface_sn_arr_cache;
6089

    
6090
	$interface = str_replace("\n", "", $interface);
6091

    
6092
	if (!does_interface_exist($interface)) {
6093
		return;
6094
	}
6095

    
6096
	/* Setup IP cache */
6097
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6098
		if (file_exists("/var/db/${interface}_ip")) {
6099
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6100
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6101
			foreach ($ifaddrs as $ifaddr) {
6102
				list($ip, $mask) = explode("/", $ifaddr);
6103
				if ($ip == $ifip) {
6104
					$interface_ip_arr_cache[$interface] = $ip;
6105
					$interface_sn_arr_cache[$interface] = $mask;
6106
					break;
6107
				}
6108
			}
6109
		}
6110
		if (!isset($interface_ip_arr_cache[$interface])) {
6111
			$ifinfo = pfSense_get_interface_addresses($interface);
6112
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6113
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6114
		}
6115
	}
6116

    
6117
	return $interface_ip_arr_cache[$interface];
6118
}
6119

    
6120
/*
6121
 * find_interface_ipv6($interface): return the interface ip (first found)
6122
 */
6123
function find_interface_ipv6($interface, $flush = false) {
6124
	global $interface_ipv6_arr_cache;
6125
	global $interface_snv6_arr_cache;
6126
	global $config;
6127

    
6128
	$interface = trim($interface);
6129
	$interface = get_real_interface($interface);
6130

    
6131
	if (!does_interface_exist($interface)) {
6132
		return;
6133
	}
6134

    
6135
	/* Setup IP cache */
6136
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6137
		$ifinfo = pfSense_get_interface_addresses($interface);
6138
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6139
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6140
	}
6141

    
6142
	return $interface_ipv6_arr_cache[$interface];
6143
}
6144

    
6145
/*
6146
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6147
 */
6148
function find_interface_ipv6_ll($interface, $flush = false) {
6149
	global $interface_llv6_arr_cache;
6150
	global $config;
6151

    
6152
	$interface = str_replace("\n", "", $interface);
6153

    
6154
	if (!does_interface_exist($interface)) {
6155
		return;
6156
	}
6157

    
6158
	/* Setup IP cache */
6159
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6160
		$ifinfo = pfSense_getall_interface_addresses($interface);
6161
		foreach ($ifinfo as $line) {
6162
			if (strstr($line, ":")) {
6163
				$parts = explode("/", $line);
6164
				if (is_linklocal($parts[0])) {
6165
					$ifinfo['linklocal'] = $parts[0];
6166
				}
6167
			}
6168
		}
6169
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6170
	}
6171
	return $interface_llv6_arr_cache[$interface];
6172
}
6173

    
6174
function find_interface_subnet($interface, $flush = false) {
6175
	global $interface_sn_arr_cache;
6176
	global $interface_ip_arr_cache;
6177

    
6178
	$interface = str_replace("\n", "", $interface);
6179
	if (does_interface_exist($interface) == false) {
6180
		return;
6181
	}
6182

    
6183
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6184
		$ifinfo = pfSense_get_interface_addresses($interface);
6185
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6186
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6187
	}
6188

    
6189
	return $interface_sn_arr_cache[$interface];
6190
}
6191

    
6192
function find_interface_subnetv6($interface, $flush = false) {
6193
	global $interface_snv6_arr_cache;
6194
	global $interface_ipv6_arr_cache;
6195

    
6196
	$interface = str_replace("\n", "", $interface);
6197
	if (does_interface_exist($interface) == false) {
6198
		return;
6199
	}
6200

    
6201
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6202
		$ifinfo = pfSense_get_interface_addresses($interface);
6203
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6204
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6205
	}
6206

    
6207
	return $interface_snv6_arr_cache[$interface];
6208
}
6209

    
6210
function ip_in_interface_alias_subnet($interface, $ipalias) {
6211
	global $config;
6212

    
6213
	if (empty($interface) || !is_ipaddr($ipalias)) {
6214
		return false;
6215
	}
6216
	if (is_array($config['virtualip']['vip'])) {
6217
		foreach ($config['virtualip']['vip'] as $vip) {
6218
			switch ($vip['mode']) {
6219
				case "ipalias":
6220
					if ($vip['interface'] <> $interface) {
6221
						break;
6222
					}
6223
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6224
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6225
						return true;
6226
					}
6227
					break;
6228
			}
6229
		}
6230
	}
6231

    
6232
	return false;
6233
}
6234

    
6235
function get_possible_listen_ips($include_ipv6_link_local=false) {
6236

    
6237
	$interfaces = get_configured_interface_with_descr();
6238
	foreach ($interfaces as $iface => $ifacename) {
6239
		if ($include_ipv6_link_local) {
6240
			/* This is to avoid going though added ll below */
6241
			if (substr($iface, 0, 5) == '_lloc') {
6242
				continue;
6243
			}
6244
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6245
			if (!empty($llip)) {
6246
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6247
			}
6248
		}
6249
	}
6250
	$viplist = get_configured_vip_list();
6251
	foreach ($viplist as $vip => $address) {
6252
		$interfaces[$vip] = $address;
6253
		if (get_vip_descr($address)) {
6254
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6255
		}
6256
	}
6257

    
6258
	$interfaces['lo0'] = 'Localhost';
6259

    
6260
	return $interfaces;
6261
}
6262

    
6263
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6264
	global $config;
6265

    
6266
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6267
	foreach (array('server', 'client') as $mode) {
6268
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6269
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6270
				if (!isset($setting['disable'])) {
6271
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6272
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6273
				}
6274
			}
6275
		}
6276
	}
6277
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
6278
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
6279
			if ($ph1ent['disabled']) {
6280
				continue;
6281
			}
6282
			if (ipsec_vti($ph1ent)) {
6283
				$sourceips_key = "ipsec{$ph1ent['ikeid']}";
6284
				$sourceips[$sourceips_key] = gettext("IPsec VTI") . ": " . htmlspecialchars($ph1ent['descr']);
6285
			}
6286
		}
6287
	}
6288
	return $sourceips;
6289
}
6290

    
6291
function get_interface_ip($interface = "wan") {
6292
	global $config;
6293

    
6294
	if (substr($interface, 0, 4) == '_vip') {
6295
		return get_configured_vip_ipv4($interface);
6296
	} else if (substr($interface, 0, 5) == '_lloc') {
6297
		/* No link-local address for v4. */
6298
		return null;
6299
	}
6300

    
6301
	$realif = get_failover_interface($interface, 'inet');
6302
	if (!$realif) {
6303
		return null;
6304
	}
6305

    
6306
	if (substr($realif, 0, 4) == '_vip') {
6307
		return get_configured_vip_ipv4($realif);
6308
	} else if (substr($realif, 0, 5) == '_lloc') {
6309
		/* No link-local address for v4. */
6310
		return null;
6311
	}
6312

    
6313
	if (is_array($config['interfaces'][$interface]) &&
6314
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6315
		return ($config['interfaces'][$interface]['ipaddr']);
6316
	}
6317

    
6318
	/*
6319
	 * Beaware that find_interface_ip() is our last option, it will
6320
	 * return the first IP it find on interface, not necessarily the
6321
	 * main IP address.
6322
	 */
6323
	$curip = find_interface_ip($realif);
6324
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6325
		return $curip;
6326
	} else {
6327
		return null;
6328
	}
6329
}
6330

    
6331
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6332
	global $config;
6333

    
6334
	if (substr($interface, 0, 4) == '_vip') {
6335
		return get_configured_vip_ipv6($interface);
6336
	} else if (substr($interface, 0, 5) == '_lloc') {
6337
		return get_interface_linklocal($interface);
6338
	}
6339

    
6340
	$realif = get_failover_interface($interface, 'inet6');
6341
	if (!$realif) {
6342
		return null;
6343
	}
6344

    
6345
	if (substr($realif, 0, 4) == '_vip') {
6346
		return get_configured_vip_ipv6($realif);
6347
	} else if (substr($realif, 0, 5) == '_lloc') {
6348
		return get_interface_linklocal($realif);
6349
	}
6350

    
6351
	if (is_array($config['interfaces'][$interface])) {
6352
		switch ($config['interfaces'][$interface]['ipaddr']) {
6353
			case 'pppoe':
6354
			case 'l2tp':
6355
			case 'pptp':
6356
			case 'ppp':
6357
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
6358
					$realif = get_real_interface($interface, 'inet6', false);
6359
				}
6360
				break;
6361
		}
6362
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6363
			return ($config['interfaces'][$interface]['ipaddrv6']);
6364
		}
6365
	}
6366

    
6367
	/*
6368
	 * Beaware that find_interface_ip() is our last option, it will
6369
	 * return the first IP it find on interface, not necessarily the
6370
	 * main IP address.
6371
	 */
6372
	$curip = find_interface_ipv6($realif, $flush);
6373
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6374
		return $curip;
6375
	} else {
6376
		/*
6377
		 * NOTE: On the case when only the prefix is requested,
6378
		 * the communication on WAN will be done over link-local.
6379
		 */
6380
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6381
			$curip = find_interface_ipv6_ll($realif, $flush);
6382
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6383
				return $curip;
6384
			}
6385
		}
6386
	}
6387
	return null;
6388
}
6389

    
6390
function get_interface_linklocal($interface = "wan") {
6391

    
6392
	$realif = get_failover_interface($interface, 'inet6');
6393
	if (!$realif) {
6394
		return null;
6395
	}
6396

    
6397
	if (substr($interface, 0, 4) == '_vip') {
6398
		$realif = get_real_interface($interface);
6399
	} else if (substr($interface, 0, 5) == '_lloc') {
6400
		$realif = get_real_interface(substr($interface, 5));
6401
	}
6402

    
6403
	$curip = find_interface_ipv6_ll($realif);
6404
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6405
		return $curip;
6406
	} else {
6407
		return null;
6408
	}
6409
}
6410

    
6411
function get_interface_subnet($interface = "wan") {
6412
	global $config;
6413

    
6414
	if (substr($interface, 0, 4) == '_vip') {
6415
		return (get_configured_vip_subnetv4($interface));
6416
	}
6417

    
6418
	if (is_array($config['interfaces'][$interface]) &&
6419
		!empty($config['interfaces'][$interface]['subnet'])) {
6420
		return ($config['interfaces'][$interface]['subnet']);
6421
	}
6422

    
6423
	$realif = get_real_interface($interface);
6424
	if (!$realif) {
6425
		return (NULL);
6426
	}
6427

    
6428
	$cursn = find_interface_subnet($realif);
6429
	if (!empty($cursn)) {
6430
		return ($cursn);
6431
	}
6432

    
6433
	return (NULL);
6434
}
6435

    
6436
function get_interface_subnetv6($interface = "wan") {
6437
	global $config;
6438

    
6439
	if (substr($interface, 0, 4) == '_vip') {
6440
		return (get_configured_vip_subnetv6($interface));
6441
	} else if (substr($interface, 0, 5) == '_lloc') {
6442
		$interface = substr($interface, 5);
6443
	}
6444

    
6445
	if (is_array($config['interfaces'][$interface]) &&
6446
		!empty($config['interfaces'][$interface]['subnetv6'])) {
6447
		return ($config['interfaces'][$interface]['subnetv6']);
6448
	}
6449

    
6450
	$realif = get_real_interface($interface, 'inet6');
6451
	if (!$realif) {
6452
		return (NULL);
6453
	}
6454

    
6455
	$cursn = find_interface_subnetv6($realif);
6456
	if (!empty($cursn)) {
6457
		return ($cursn);
6458
	}
6459

    
6460
	return (NULL);
6461
}
6462

    
6463
/* return outside interfaces with a gateway */
6464
function get_interfaces_with_gateway() {
6465
	global $config;
6466

    
6467
	$ints = array();
6468

    
6469
	/* loop interfaces, check config for outbound */
6470
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6471
		switch ($ifname['ipaddr']) {
6472
			case "dhcp":
6473
			case "pppoe":
6474
			case "pptp":
6475
			case "l2tp":
6476
			case "ppp":
6477
				$ints[$ifdescr] = $ifdescr;
6478
				break;
6479
			default:
6480
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6481
				    !empty($ifname['gateway'])) {
6482
					$ints[$ifdescr] = $ifdescr;
6483
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6484
				    !empty($ifname['gateway'])) {
6485
					$ints[$ifdescr] = $ifdescr;
6486
				}
6487

    
6488
				break;
6489
		}
6490
	}
6491
	return $ints;
6492
}
6493

    
6494
/* return true if interface has a gateway */
6495
function interface_has_gateway($friendly) {
6496
	global $config;
6497

    
6498
	if (!empty($config['interfaces'][$friendly])) {
6499
		$ifname = &$config['interfaces'][$friendly];
6500
		switch ($ifname['ipaddr']) {
6501
			case "dhcp":
6502
			case "pppoe":
6503
			case "pptp":
6504
			case "l2tp":
6505
			case "ppp":
6506
				return true;
6507
			break;
6508
			default:
6509
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6510
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6511
					return true;
6512
				}
6513
				$tunnelif = substr($ifname['if'], 0, 3);
6514
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6515
					if (find_interface_ip($ifname['if'])) {
6516
						return true;
6517
					}
6518
				}
6519
				if (!empty($ifname['gateway'])) {
6520
					return true;
6521
				}
6522
			break;
6523
		}
6524
	}
6525

    
6526
	return false;
6527
}
6528

    
6529
/* return true if interface has a gateway */
6530
function interface_has_gatewayv6($friendly) {
6531
	global $config;
6532

    
6533
	if (!empty($config['interfaces'][$friendly])) {
6534
		$ifname = &$config['interfaces'][$friendly];
6535
		switch ($ifname['ipaddrv6']) {
6536
			case "slaac":
6537
			case "dhcp6":
6538
			case "6to4":
6539
			case "6rd":
6540
				return true;
6541
				break;
6542
			default:
6543
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6544
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6545
					return true;
6546
				}
6547
				$tunnelif = substr($ifname['if'], 0, 3);
6548
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6549
					if (find_interface_ipv6($ifname['if'])) {
6550
						return true;
6551
					}
6552
				}
6553
				if (!empty($ifname['gatewayv6'])) {
6554
					return true;
6555
				}
6556
				break;
6557
		}
6558
	}
6559

    
6560
	return false;
6561
}
6562

    
6563
/****f* interfaces/is_altq_capable
6564
 * NAME
6565
 *   is_altq_capable - Test if interface is capable of using ALTQ
6566
 * INPUTS
6567
 *   $int            - string containing interface name
6568
 * RESULT
6569
 *   boolean         - true or false
6570
 ******/
6571

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

    
6587
	$int_family = remove_ifindex($int);
6588

    
6589
	if (in_array($int_family, $capable)) {
6590
		return true;
6591
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6592
		return true;
6593
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6594
		return true;
6595
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6596
		return true;
6597
	} else {
6598
		return false;
6599
	}
6600
}
6601

    
6602
/****f* interfaces/is_interface_wireless
6603
 * NAME
6604
 *   is_interface_wireless - Returns if an interface is wireless
6605
 * RESULT
6606
 *   $tmp       - Returns if an interface is wireless
6607
 ******/
6608
function is_interface_wireless($interface) {
6609
	global $config, $g;
6610

    
6611
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6612
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6613
		if (preg_match($g['wireless_regex'], $interface)) {
6614
			if (isset($config['interfaces'][$friendly])) {
6615
				$config['interfaces'][$friendly]['wireless'] = array();
6616
			}
6617
			return true;
6618
		}
6619
		return false;
6620
	} else {
6621
		return true;
6622
	}
6623
}
6624

    
6625
function get_wireless_modes($interface) {
6626
	/* return wireless modes and channels */
6627
	$wireless_modes = array();
6628

    
6629
	$cloned_interface = get_real_interface($interface);
6630

    
6631
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6632
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6633
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6634
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6635

    
6636
		$interface_channels = "";
6637
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6638
		$interface_channel_count = count($interface_channels);
6639

    
6640
		$c = 0;
6641
		while ($c < $interface_channel_count) {
6642
			$channel_line = explode(",", $interface_channels["$c"]);
6643
			$wireless_mode = trim($channel_line[0]);
6644
			$wireless_channel = trim($channel_line[1]);
6645
			if (trim($wireless_mode) != "") {
6646
				/* if we only have 11g also set 11b channels */
6647
				if ($wireless_mode == "11g") {
6648
					if (!isset($wireless_modes["11b"])) {
6649
						$wireless_modes["11b"] = array();
6650
					}
6651
				} else if ($wireless_mode == "11g ht") {
6652
					if (!isset($wireless_modes["11b"])) {
6653
						$wireless_modes["11b"] = array();
6654
					}
6655
					if (!isset($wireless_modes["11g"])) {
6656
						$wireless_modes["11g"] = array();
6657
					}
6658
					$wireless_mode = "11ng";
6659
				} else if ($wireless_mode == "11a ht") {
6660
					if (!isset($wireless_modes["11a"])) {
6661
						$wireless_modes["11a"] = array();
6662
					}
6663
					$wireless_mode = "11na";
6664
				}
6665
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6666
			}
6667
			$c++;
6668
		}
6669
	}
6670
	return($wireless_modes);
6671
}
6672

    
6673
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6674
function get_wireless_channel_info($interface) {
6675
	$wireless_channels = array();
6676

    
6677
	$cloned_interface = get_real_interface($interface);
6678

    
6679
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6680
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
6681
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6682
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
6683

    
6684
		$interface_channels = "";
6685
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6686

    
6687
		foreach ($interface_channels as $channel_line) {
6688
			$channel_line = explode(",", $channel_line);
6689
			if (!isset($wireless_channels[$channel_line[0]])) {
6690
				$wireless_channels[$channel_line[0]] = $channel_line;
6691
			}
6692
		}
6693
	}
6694
	return($wireless_channels);
6695
}
6696

    
6697
function set_interface_mtu($interface, $mtu) {
6698

    
6699
	/* LAGG interface must be destroyed and re-created to change MTU */
6700
	if (substr($interface, 0, 4) == 'lagg') {
6701
		if (isset($config['laggs']['lagg']) &&
6702
		    is_array($config['laggs']['lagg'])) {
6703
			foreach ($config['laggs']['lagg'] as $lagg) {
6704
				if ($lagg['laggif'] == $interface) {
6705
					interface_lagg_configure($lagg);
6706
					break;
6707
				}
6708
			}
6709
		}
6710
	} else {
6711
		pfSense_interface_mtu($interface, $mtu);
6712
	}
6713
}
6714

    
6715
/****f* interfaces/get_interface_mtu
6716
 * NAME
6717
 *   get_interface_mtu - Return the mtu of an interface
6718
 * RESULT
6719
 *   $tmp       - Returns the mtu of an interface
6720
 ******/
6721
function get_interface_mtu($interface) {
6722
	$mtu = pfSense_interface_getmtu($interface);
6723
	return $mtu['mtu'];
6724
}
6725

    
6726
function get_interface_mac($interface) {
6727
	$macinfo = pfSense_get_interface_addresses($interface);
6728
	return $macinfo["macaddr"];
6729
}
6730

    
6731
function get_interface_vendor_mac($interface) {
6732
	global $config, $g;
6733

    
6734
	$macinfo = pfSense_get_interface_addresses($interface);
6735
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
6736
	    "00:00:00:00:00:00") {
6737
		return ($macinfo["hwaddr"]);
6738
	}
6739

    
6740
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
6741
	if (file_exists($hwaddr_file)) {
6742
		$macaddr = trim(file_get_contents($hwaddr_file));
6743
		if (is_macaddr($macaddr)) {
6744
			return ($macaddr);
6745
		}
6746
	} elseif (is_macaddr($macinfo['macaddr'])) {
6747
		/* Save original macaddress to be restored when necessary */
6748
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
6749
	}
6750

    
6751
	return (NULL);
6752
}
6753

    
6754
/****f* pfsense-utils/generate_random_mac_address
6755
 * NAME
6756
 *   generate_random_mac - generates a random mac address
6757
 * INPUTS
6758
 *   none
6759
 * RESULT
6760
 *   $mac - a random mac address
6761
 ******/
6762
function generate_random_mac_address() {
6763
	$mac = "02";
6764
	for ($x = 0; $x < 5; $x++) {
6765
		$mac .= ":" . dechex(rand(16, 255));
6766
	}
6767
	return $mac;
6768
}
6769

    
6770
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6771
	global $g;
6772

    
6773
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6774

    
6775
	if (!empty($iface) && !empty($pppif)) {
6776
		$cron_cmd = <<<EOD
6777
#!/bin/sh
6778
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
6779
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
6780

    
6781
EOD;
6782

    
6783
		@file_put_contents($cron_file, $cron_cmd);
6784
		chmod($cron_file, 0755);
6785
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
6786
	} else {
6787
		unlink_if_exists($cron_file);
6788
	}
6789
}
6790

    
6791
function get_interface_default_mtu($type = "ethernet") {
6792
	switch ($type) {
6793
		case "gre":
6794
			return 1476;
6795
			break;
6796
		case "gif":
6797
			return 1280;
6798
			break;
6799
		case "tun":
6800
		case "vlan":
6801
		case "tap":
6802
		case "ethernet":
6803
		default:
6804
			return 1500;
6805
			break;
6806
	}
6807

    
6808
	/* Never reached */
6809
	return 1500;
6810
}
6811

    
6812
function get_vip_descr($ipaddress) {
6813
	global $config;
6814

    
6815
	foreach ($config['virtualip']['vip'] as $vip) {
6816
		if ($vip['subnet'] == $ipaddress) {
6817
			return ($vip['descr']);
6818
		}
6819
	}
6820
	return "";
6821
}
6822

    
6823
function interfaces_staticarp_configure($if) {
6824
	global $config, $g;
6825
	if (isset($config['system']['developerspew'])) {
6826
		$mt = microtime();
6827
		echo "interfaces_staticarp_configure($if) being called $mt\n";
6828
	}
6829

    
6830
	$ifcfg = $config['interfaces'][$if];
6831

    
6832
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
6833
		return 0;
6834
	}
6835

    
6836
	/* Enable staticarp, if enabled */
6837
	if (isset($config['dhcpd'][$if]['staticarp'])) {
6838
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
6839
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6840
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
6841
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6842
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6843
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6844
				}
6845
			}
6846
		}
6847
	} else {
6848
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
6849
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6850
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
6851
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6852
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6853
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6854
				}
6855
			}
6856
		}
6857
	}
6858

    
6859
	return 0;
6860
}
6861

    
6862
function get_failover_interface($interface, $family = "all") {
6863
	global $config;
6864

    
6865
	/* shortcut to get_real_interface if we find it in the config */
6866
	if (is_array($config['interfaces'][$interface])) {
6867
		return get_real_interface($interface, $family);
6868
	}
6869

    
6870
	/* compare against gateway groups */
6871
	$a_groups = return_gateway_groups_array(true);
6872
	if (is_array($a_groups[$interface])) {
6873
		/* we found a gateway group, fetch the interface or vip */
6874
		if (!empty($a_groups[$interface][0]['vip'])) {
6875
			return $a_groups[$interface][0]['vip'];
6876
		} else {
6877
			return $a_groups[$interface][0]['int'];
6878
		}
6879
	}
6880
	/* fall through to get_real_interface */
6881
	/* XXX: Really needed? */
6882
	return get_real_interface($interface, $family);
6883
}
6884

    
6885
/****f* interfaces/interface_has_dhcp
6886
 * NAME
6887
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6888
 * INPUTS
6889
 *   interface or gateway group name
6890
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6891
 * RESULT
6892
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6893
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6894
 ******/
6895
function interface_has_dhcp($interface, $family = 4) {
6896
	global $config;
6897

    
6898
	if ($config['interfaces'][$interface]) {
6899
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6900
			return true;
6901
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6902
			return true;
6903
		} else {
6904
			return false;
6905
		}
6906
	}
6907

    
6908
	if (!is_array($config['gateways']['gateway_group'])) {
6909
		return false;
6910
	}
6911

    
6912
	if ($family == 6) {
6913
		$dhcp_string = "_DHCP6";
6914
	} else {
6915
		$dhcp_string = "_DHCP";
6916
	}
6917

    
6918
	foreach ($config['gateways']['gateway_group'] as $group) {
6919
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6920
			continue;
6921
		}
6922
		foreach ($group['item'] as $item) {
6923
			$item_data = explode("|", $item);
6924
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6925
				return true;
6926
			}
6927
		}
6928
	}
6929

    
6930
	return false;
6931
}
6932

    
6933
function remove_ifindex($ifname) {
6934
	return preg_replace("/[0-9]+$/", "", $ifname);
6935
}
6936

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

    
6940
	$viplist = get_configured_vip_list($family, $type);
6941
	foreach ($viplist as $vip => $address) {
6942
		$interfaces[$vip] = $address;
6943
		if ($type = VIP_CARP) {
6944
			$vip = get_configured_vip($vipid);
6945
			if (isset($vip) && is_array($vip) ) {
6946
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
6947
			}
6948
		}
6949
		if (get_vip_descr($address)) {
6950
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
6951
		}
6952
	}
6953
	return $interfaces;
6954
}
6955

    
6956
function return_gateway_groups_array_with_descr() {
6957
	$interfaces = array();
6958
	$grouplist = return_gateway_groups_array();
6959
	foreach ($grouplist as $name => $group) {
6960
		if ($group[0]['vip'] != "") {
6961
			$vipif = $group[0]['vip'];
6962
		} else {
6963
			$vipif = $group[0]['int'];
6964
		}
6965

    
6966
		$interfaces[$name] = "GW Group {$name}";
6967
	}
6968
	return $interfaces;
6969
}
6970

    
6971
function get_serial_ports() {
6972
	$linklist = array();
6973
	if (!is_dir("/var/spool/lock")) {
6974
		mwexec("/bin/mkdir -p /var/spool/lock");
6975
	}
6976
	$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);
6977
	foreach ($serialports as $port) {
6978
		$linklist[$port] = trim($port);
6979
	}
6980
	return $linklist;
6981
}
6982

    
6983
function get_interface_ports() {
6984
	global $config;
6985
	$linklist = array();
6986
	$portlist = get_interface_list();
6987
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
6988
		foreach ($config['vlans']['vlan'] as $vlan) {
6989
			$portlist[$vlan['vlanif']] = $vlan;
6990
		}
6991
	}
6992

    
6993
	foreach ($portlist as $ifn => $ifinfo) {
6994
		$string = "";
6995
		if (is_array($ifinfo)) {
6996
			$string .= $ifn;
6997
			if ($ifinfo['mac']) {
6998
				$string .= " ({$ifinfo['mac']})";
6999
			}
7000
			if ($ifinfo['friendly']) {
7001
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7002
			} elseif ($ifinfo['descr']) {
7003
				$string .= " - {$ifinfo['descr']}";
7004
			}
7005
		} else {
7006
			$string .= $ifinfo;
7007
		}
7008

    
7009
		$linklist[$ifn] = $string;
7010
	}
7011
	return $linklist;
7012
}
7013

    
7014
function build_ppps_link_list() {
7015
	global $pconfig;
7016

    
7017
	$linklist = array('list' => array(), 'selected' => array());
7018

    
7019
	if ($pconfig['type'] == 'ppp') {
7020
		$linklist['list'] = get_serial_ports();
7021
	} else {
7022
		$iflist = get_interface_ports();
7023

    
7024
		$viplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7025

    
7026
		$linklist['list'] = array_merge($iflist, $viplist);
7027

    
7028
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7029
		$lagglist = get_lagg_interface_list();
7030
		foreach ($lagglist as $laggif => $lagg) {
7031
			/* LAGG members cannot be assigned */
7032
			$laggmembers = explode(',', $lagg['members']);
7033
			foreach ($laggmembers as $lagm) {
7034
				if (isset($linklist['list'][$lagm])) {
7035
					unset($linklist['list'][$lagm]);
7036
				}
7037
			}
7038
		}
7039
	}
7040

    
7041
	$selected_ports = array();
7042
	if (is_array($pconfig['interfaces'])) {
7043
		$selected_ports = $pconfig['interfaces'];
7044
	} elseif (!empty($pconfig['interfaces'])) {
7045
		$selected_ports = explode(',', $pconfig['interfaces']);
7046
	}
7047
	foreach ($selected_ports as $port) {
7048
		if (isset($linklist['list'][$port])) {
7049
			array_push($linklist['selected'], $port);
7050
		}
7051
	}
7052
	return($linklist);
7053
}
7054

    
7055
function create_interface_list() {
7056
	global $config;
7057

    
7058
	$iflist = array();
7059

    
7060
	// add group interfaces
7061
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7062
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7063
			if (have_ruleint_access($ifgen['ifname'])) {
7064
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7065
			}
7066
		}
7067
	}
7068

    
7069
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7070
		if (have_ruleint_access($ifent)) {
7071
			$iflist[$ifent] = $ifdesc;
7072
		}
7073
	}
7074

    
7075
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
7076
		$iflist['l2tp'] = gettext('L2TP VPN');
7077
	}
7078

    
7079
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
7080
		$iflist['pppoe'] = gettext("PPPoE Server");
7081
	}
7082

    
7083
	// add ipsec interfaces
7084
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
7085
		$iflist["enc0"] = gettext("IPsec");
7086
	}
7087

    
7088
	// add openvpn/tun interfaces
7089
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7090
		$iflist["openvpn"] = gettext("OpenVPN");
7091
	}
7092

    
7093
	return($iflist);
7094
}
7095

    
7096
?>
(23-23/59)