Project

General

Profile

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

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

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

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

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

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

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

    
58
	return true;
59
}
60

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

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

    
72
	return $interface_arr_cache;
73
}
74

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

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

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

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

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

    
105

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

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

    
128
	return false;
129
}
130

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

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

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

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

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

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

    
203
function vlan_valid_tag($tag = NULL) {
204

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

    
212
function qinq_inuse($qinq = NULL, $inqtag = NULL) {
213
        global $config;
214
  
215
	if ($qinq == NULL || $inqtag == NULL ||
216
	    !is_array($qinq) || !vlan_valid_tag($inqtag)) {
217
		return (false);
218
	}
219
 
220
        $iflist = get_configured_interface_list(true);
221
        foreach ($iflist as $if) {
222
                if ($config['interfaces'][$if]['if'] == qinq_interface($qinq, $inqtag)) {
223
                        return (true);
224
                }
225
        }
226
       
227
        return (false);
228
}      
229

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

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

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

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

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

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

    
268
	return (NULL);
269
}
270

    
271
function vlan_inuse($vlan) {
272
	global $config;
273

    
274
	if ($vlan == NULL || !is_array($vlan)) {
275
		return (false);
276
	}
277

    
278
	$iflist = get_configured_interface_list(true);
279
	foreach ($iflist as $if) {
280
		if ($config['interfaces'][$if]['if'] == $vlan['vlanif']) {
281
			return (true);
282
		}
283
	}
284

    
285
	return (false);
286
}
287

    
288
function interface_is_vlan($if = NULL) {
289
	global $config;
290

    
291
	if ($if == NULL || empty($if) || !is_array($config['vlans']['vlan'])) {
292
		return (NULL);
293
	}
294

    
295
	/* Check basic format. */
296
	list($vlanif, $vlantag) = explode(".", $if);
297
	if (empty($vlanif) || empty($vlantag) || !vlan_valid_tag($vlantag)) {
298
		return (NULL);
299
	}
300

    
301
	/* Find the VLAN interface. */
302
	foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
303
		if ($if == $vlan['vlanif']) {
304
			return ($vlan);
305
		}
306
	}
307
	/* Check for the first level tag in QinQ interfaces. */
308
	foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
309
		if ($if == $qinq['vlanif']) {
310
			return ($qinq);
311
		}
312
	}
313

    
314
	return (NULL);
315
}
316

    
317
function vlan_interface($vlan = NULL) {
318

    
319
	if ($vlan == NULL || !is_array($vlan) || !isset($vlan['if']) ||
320
	    !isset($vlan['tag']) || !vlan_valid_tag($vlan['tag'])) {
321
		return (NULL);
322
	}
323
	return ("{$vlan['if']}.{$vlan['tag']}");
324
}
325

    
326
function interfaces_vlan_configure($realif = "") {
327
	global $config, $g;
328
	if (platform_booting()) {
329
		echo gettext("Configuring VLAN interfaces...");
330
	}
331
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
332
		foreach ($config['vlans']['vlan'] as $vlan) {
333
			if (empty($vlan['vlanif'])) {
334
				$vlan['vlanif'] = vlan_interface($vlan);
335
			}
336
			if (!empty($realif) && $realif != $vlan['vlanif']) {
337
				continue;
338
			}
339

    
340
			/* XXX: Maybe we should report any errors?! */
341
			interface_vlan_configure($vlan);
342
		}
343
	}
344
	if (platform_booting()) {
345
		echo gettext("done.") . "\n";
346
	}
347
}
348

    
349
function interface_vlan_configure(&$vlan) {
350
	global $config, $g;
351

    
352
	if (!is_array($vlan)) {
353
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
354
		return(NULL);
355
	}
356
	$if = $vlan['if'];
357
	if (empty($if)) {
358
		log_error(gettext("interface_vlan_configure called with if undefined."));
359
		return(NULL);
360
	}
361

    
362
	$vlanif = empty($vlan['vlanif']) ? vlan_interface($vlan) : $vlan['vlanif'];
363
	if ($vlanif == NULL) {
364
		log_error(gettext("vlan_interface called with if undefined var."));
365
		return(NULL);
366
	}
367
	$tag = $vlan['tag'];
368
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
369

    
370
	/* make sure the parent interface is up */
371
	interfaces_bring_up($if);
372
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
373
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
374

    
375
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
376
		pfSense_interface_destroy($vlanif);
377
	}
378

    
379
	$tmpvlanif = pfSense_interface_create("vlan");
380
	pfSense_interface_rename($tmpvlanif, $vlanif);
381
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
382

    
383
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
384

    
385
	interfaces_bring_up($vlanif);
386

    
387
	/* invalidate interface cache */
388
	get_interface_arr(true);
389

    
390
	/* configure interface if assigned */
391
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
392
	if ($assignedif) {
393
		if (isset($config['interfaces'][$assignedif]['enable'])) {
394
			interface_configure($assignedif, true);
395
		}
396
	}
397

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

    
401
	return $vlanif;
402
}
403

    
404
function interface_qinq_configure(&$qinq, $fd = NULL) {
405
	global $config, $g;
406

    
407
	if (!is_array($qinq)) {
408
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
409
		return;
410
	}
411

    
412
	$qinqif = $qinq['if'];
413
	$tag = $qinq['tag'];
414
	if (empty($qinqif)) {
415
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
416
		return;
417
	}
418

    
419
	if (!does_interface_exist($qinqif)) {
420
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
421
		return;
422
	}
423

    
424
	$vlanif = interface_vlan_configure($qinq);
425
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
426
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
427
		return;
428
	}
429

    
430
	if ($fd == NULL) {
431
		$exec = true;
432
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
433
	} else {
434
		$exec = false;
435
	}
436
	/* make sure the parent is converted to ng_vlan(4) and is up */
437
	interfaces_bring_up($qinqif);
438

    
439
	pfSense_ngctl_attach(".", $qinqif);
440
	$ngif = str_replace(".", "_", $vlanif);
441
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
442
		exec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1");
443
		exec("/usr/sbin/ngctl msg {$ngif}qinq: gettable > /dev/null 2>&1", $result);
444
		if (empty($result)) {
445
			fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
446
			fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
447
			fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
448
		}
449
	} else {
450
		fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
451
		fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
452
		fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
453
	}
454

    
455
	/* invalidate interface cache */
456
	get_interface_arr(true);
457

    
458
	if (interface_is_vlan($qinqif) == NULL) {
459
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
460
	}
461

    
462
	$macaddr = get_interface_mac($qinqif);
463
	if (!empty($qinq['members'])) {
464
		$qinqcmdbuf = "";
465
		$members = explode(" ", $qinq['members']);
466
		foreach ($members as $qtag) {
467
			$qinq2 = array();
468
			$qinq2['tag'] = $qtag;
469
			$qinq2['if'] = $vlanif;
470
			interface_qinq2_configure($qinq2, $qinqcmdbuf, $macaddr);
471
			unset($qinq2);
472
		}
473
		if (strlen($qinqcmdbuf) > 0) {
474
			fwrite($fd, $qinqcmdbuf);
475
		}
476
	}
477
	if ($exec == true) {
478
		fclose($fd);
479
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd > /dev/null 2>&1");
480
	}
481

    
482
	interfaces_bring_up($qinqif);
483
	if (!empty($qinq['members'])) {
484
		$members = explode(" ", $qinq['members']);
485
		foreach ($members as $qtag) {
486
			interfaces_bring_up(qinq_interface($qinq, $qtag));
487
		}
488
	}
489

    
490
	return $vlanif;
491
}
492

    
493
function interfaces_qinq_configure() {
494
	global $config, $g;
495
	if (platform_booting()) {
496
		echo gettext("Configuring QinQ interfaces...");
497
	}
498
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
499
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
500
			/* XXX: Maybe we should report any errors?! */
501
			interface_qinq_configure($qinq);
502
		}
503
	}
504
	if (platform_booting()) {
505
		echo gettext("done.") . "\n";
506
	}
507
}
508

    
509
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr) {
510
	global $config, $g;
511

    
512
	if (!is_array($qinq)) {
513
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
514
		return;
515
	}
516

    
517
	$if = $qinq['if'];
518
	if (empty($if)) {
519
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
520
		return;
521
	}
522
	$tag = $qinq['tag'];
523
	$vlanif = "{$if}.{$tag}";
524
	$ngif = str_replace(".", "_", $if);
525
	if (strlen($vlanif) > IF_NAMESIZE) {
526
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
527
		    $vlanif, IF_NAMESIZE, "\n"));
528
		return;
529
	}
530

    
531
	exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1");
532
	$cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n";
533
	$cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n";
534
	$cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n";
535
	$cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n";
536
	$cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n";
537

    
538
	/* invalidate interface cache */
539
	get_interface_arr(true);
540

    
541
	return $vlanif;
542
}
543

    
544
function interfaces_create_wireless_clones() {
545
	global $config, $g;
546

    
547
	if (platform_booting()) {
548
		echo gettext("Creating wireless clone interfaces...");
549
	}
550

    
551
	$iflist = get_configured_interface_list();
552

    
553
	foreach ($iflist as $if) {
554
		$realif = $config['interfaces'][$if]['if'];
555
		if (is_interface_wireless($realif)) {
556
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
557
		}
558
	}
559

    
560
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
561
		foreach ($config['wireless']['clone'] as $clone) {
562
			if (empty($clone['cloneif'])) {
563
				continue;
564
			}
565
			if (does_interface_exist($clone['cloneif'])) {
566
				continue;
567
			}
568
			/* XXX: Maybe we should report any errors?! */
569
			interface_wireless_clone($clone['cloneif'], $clone);
570
		}
571
	}
572
	if (platform_booting()) {
573
		echo gettext("done.") . "\n";
574
	}
575

    
576
}
577

    
578
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
579
	global $config;
580

    
581
	$i = 0;
582
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
583
		foreach ($config['bridges']['bridged'] as $bridge) {
584
			if (empty($bridge['bridgeif'])) {
585
				$bridge['bridgeif'] = "bridge{$i}";
586
			}
587
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
588
				continue;
589
			}
590

    
591
			if ($checkmember == 1) {
592
				/* XXX: It should not be possible no? */
593
				if (strstr($bridge['if'], '_vip')) {
594
					continue;
595
				}
596
				$members = explode(',', $bridge['members']);
597
				foreach ($members as $member) {
598
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6") {
599
						continue 2;
600
					}
601
				}
602
			}
603
			else if ($checkmember == 2) {
604
				$members = explode(',', $bridge['members']);
605
				foreach ($members as $member) {
606
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6") {
607
						continue 2;
608
					}
609
				}
610
			}
611
			/* XXX: Maybe we should report any errors?! */
612
			interface_bridge_configure($bridge, $checkmember);
613
			$i++;
614
		}
615
	}
616
}
617

    
618
function interface_bridge_configure(&$bridge, $checkmember = 0) {
619
	global $config, $g;
620

    
621
	if (!is_array($bridge)) {
622
		return;
623
	}
624

    
625
	if (empty($bridge['members'])) {
626
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
627
		return;
628
	}
629

    
630
	$members = explode(',', $bridge['members']);
631
	if (!count($members)) {
632
		return;
633
	}
634

    
635
	/* Calculate smaller mtu and enforce it */
636
	$smallermtu = 0;
637
	$foundgif = false;
638
	foreach ($members as $member) {
639
		$realif = get_real_interface($member);
640
		$mtu = get_interface_mtu($realif);
641
		if (substr($realif, 0, 3) == "gif") {
642
			$foundgif = true;
643
			if ($checkmember == 1) {
644
				return;
645
			}
646
			if ($mtu <= 1500) {
647
				continue;
648
			}
649
		}
650
		if ($smallermtu == 0 && !empty($mtu)) {
651
			$smallermtu = $mtu;
652
		} else if (!empty($mtu) && $mtu < $smallermtu) {
653
			$smallermtu = $mtu;
654
		}
655
	}
656
	if ($foundgif == false && $checkmember == 2) {
657
		return;
658
	}
659

    
660
	/* Just in case anything is not working well */
661
	if ($smallermtu == 0) {
662
		$smallermtu = 1500;
663
	}
664

    
665
	if (!empty($bridge['bridgeif'])) {
666
		pfSense_interface_destroy($bridge['bridgeif']);
667
		pfSense_interface_create($bridge['bridgeif']);
668
		$bridgeif = escapeshellarg($bridge['bridgeif']);
669
	} else {
670
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
671
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
672
		$bridgeif = pfSense_interface_create("bridge");
673
		$bridge['bridgeif'] = $bridgeif;
674
	}
675

    
676
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
677
	if ($bridgemtu > $smallermtu) {
678
		$smallermtu = $bridgemtu;
679
	}
680

    
681
	$checklist = get_configured_interface_list();
682

    
683
	/* Add interfaces to bridge */
684
	foreach ($members as $member) {
685
		if (empty($checklist[$member])) {
686
			continue;
687
		}
688
		$realif = get_real_interface($member);
689
		if (!$realif) {
690
			log_error(gettext("realif not defined in interfaces bridge - up"));
691
			continue;
692
		}
693
		/* make sure the parent interface is up */
694
		pfSense_interface_mtu($realif, $smallermtu);
695
		interfaces_bring_up($realif);
696
		enable_hardware_offloading($member);
697
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
698
	}
699

    
700
	if (isset($bridge['enablestp'])) {
701
		interface_bridge_configure_stp($bridge);
702
	}
703

    
704
	interface_bridge_configure_advanced($bridge);
705

    
706
	interface_bridge_configure_ip6linklocal($bridge);
707

    
708
	if ($bridge['bridgeif']) {
709
		interfaces_bring_up($bridge['bridgeif']);
710
	} else {
711
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
712
	}
713
}
714

    
715
function interface_bridge_configure_stp($bridge) {
716
	if (isset($bridge['enablestp'])) {
717
		$bridgeif = $bridge['bridgeif'];
718
		/* configure spanning tree proto */
719
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
720

    
721
		if (!empty($bridge['stp'])) {
722
			$stpifs = explode(',', $bridge['stp']);
723
			foreach ($stpifs as $stpif) {
724
				$realif = get_real_interface($stpif);
725
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
726
			}
727
		}
728
		if (!empty($bridge['maxage'])) {
729
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
730
		}
731
		if (!empty($bridge['fwdelay'])) {
732
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
733
		}
734
		if (!empty($bridge['hellotime'])) {
735
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
736
		}
737
		if (!empty($bridge['priority'])) {
738
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
739
		}
740
		if (!empty($bridge['holdcnt'])) {
741
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
742
		}
743
		if (!empty($bridge['ifpriority'])) {
744
			$pconfig = explode(",", $bridge['ifpriority']);
745
			$ifpriority = array();
746
			foreach ($pconfig as $cfg) {
747
				$embcfg = explode_assoc(":", $cfg);
748
				foreach ($embcfg as $key => $value) {
749
					$ifpriority[$key] = $value;
750
				}
751
			}
752
			foreach ($ifpriority as $key => $value) {
753
				$realif = get_real_interface($key);
754
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
755
			}
756
		}
757
		if (!empty($bridge['ifpathcost'])) {
758
			$pconfig = explode(",", $bridge['ifpathcost']);
759
			$ifpathcost = array();
760
			foreach ($pconfig as $cfg) {
761
				$embcfg = explode_assoc(":", $cfg);
762
				foreach ($embcfg as $key => $value) {
763
					$ifpathcost[$key] = $value;
764
				}
765
			}
766
			foreach ($ifpathcost as $key => $value) {
767
				$realif = get_real_interface($key);
768
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
769
			}
770
		}
771
	}
772
}
773

    
774
function interface_bridge_configure_advanced($bridge) {
775
	$bridgeif = $bridge['bridgeif'];
776

    
777
	if ($bridge['maxaddr'] <> "") {
778
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
779
	}
780
	if ($bridge['timeout'] <> "") {
781
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
782
	}
783
	if (!empty($bridge['span'])) {
784
		$spanifs = explode(",", $bridge['span']);
785
		foreach ($spanifs as $spanif) {
786
			$realif = get_real_interface($spanif);
787
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
788
		}
789
	}
790
	if (!empty($bridge['edge'])) {
791
		$edgeifs = explode(',', $bridge['edge']);
792
		foreach ($edgeifs as $edgeif) {
793
			$realif = get_real_interface($edgeif);
794
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
795
		}
796
	}
797
	if (!empty($bridge['autoedge'])) {
798
		$edgeifs = explode(',', $bridge['autoedge']);
799
		foreach ($edgeifs as $edgeif) {
800
			$realif = get_real_interface($edgeif);
801
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
802
		}
803
	}
804
	if (!empty($bridge['ptp'])) {
805
		$ptpifs = explode(',', $bridge['ptp']);
806
		foreach ($ptpifs as $ptpif) {
807
			$realif = get_real_interface($ptpif);
808
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
809
		}
810
	}
811
	if (!empty($bridge['autoptp'])) {
812
		$ptpifs = explode(',', $bridge['autoptp']);
813
		foreach ($ptpifs as $ptpif) {
814
			$realif = get_real_interface($ptpif);
815
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
816
		}
817
	}
818
	if (!empty($bridge['static'])) {
819
		$stickyifs = explode(',', $bridge['static']);
820
		foreach ($stickyifs as $stickyif) {
821
			$realif = get_real_interface($stickyif);
822
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
823
		}
824
	}
825
	if (!empty($bridge['private'])) {
826
		$privateifs = explode(',', $bridge['private']);
827
		foreach ($privateifs as $privateif) {
828
			$realif = get_real_interface($privateif);
829
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
830
		}
831
	}
832
}
833

    
834
function interface_bridge_configure_ip6linklocal($bridge) {
835
	$bridgeif = $bridge['bridgeif'];
836

    
837
	$members = explode(',', $bridge['members']);
838
	if (!count($members)) {
839
		return;
840
	}
841

    
842
	$auto_linklocal = isset($bridge['ip6linklocal']);
843
	$bridgeop = $auto_linklocal ? '' : '-';
844
	$memberop = $auto_linklocal ? '-' : '';
845

    
846
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
847
	foreach ($members as $member) {
848
		$realif = get_real_interface($member);
849
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
850
	}
851
}
852

    
853
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
854
	global $config;
855

    
856
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
857
		return;
858
	}
859

    
860
	if ($flagsapplied == false) {
861
		$mtu = get_interface_mtu($bridgeif);
862
		$mtum = get_interface_mtu($interface);
863
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
864
			pfSense_interface_mtu($interface, $mtu);
865
		}
866

    
867
		hardware_offloading_applyflags($interface);
868
		interfaces_bring_up($interface);
869
	}
870

    
871
	pfSense_bridge_add_member($bridgeif, $interface);
872
	if (is_array($config['bridges']['bridged'])) {
873
		foreach ($config['bridges']['bridged'] as $bridge) {
874
			if ($bridgeif == $bridge['bridgeif']) {
875
				interface_bridge_configure_stp($bridge);
876
				interface_bridge_configure_advanced($bridge);
877
			}
878
		}
879
	}
880
}
881

    
882
function interfaces_lagg_configure($realif = "") {
883
	global $config, $g;
884
	if (platform_booting()) {
885
		echo gettext("Configuring LAGG interfaces...");
886
	}
887
	$i = 0;
888
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
889
		foreach ($config['laggs']['lagg'] as $lagg) {
890
			if (empty($lagg['laggif'])) {
891
				$lagg['laggif'] = "lagg{$i}";
892
			}
893
			if (!empty($realif) && $realif != $lagg['laggif']) {
894
				continue;
895
			}
896
			/* XXX: Maybe we should report any errors?! */
897
			interface_lagg_configure($lagg);
898
			$i++;
899
		}
900
	}
901
	if (platform_booting()) {
902
		echo gettext("done.") . "\n";
903
	}
904
}
905

    
906
function interface_lagg_configure($lagg) {
907
	global $config, $g;
908

    
909
	if (!is_array($lagg)) {
910
		return -1;
911
	}
912

    
913
	$members = explode(',', $lagg['members']);
914
	if (!count($members)) {
915
		return -1;
916
	}
917

    
918
	if (platform_booting() || !(empty($lagg['laggif']))) {
919
		pfSense_interface_destroy($lagg['laggif']);
920
		pfSense_interface_create($lagg['laggif']);
921
		$laggif = $lagg['laggif'];
922
	} else {
923
		$laggif = pfSense_interface_create("lagg");
924
	}
925

    
926
	/* Check if MTU was defined for this lagg interface */
927
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
928
	if ($lagg_mtu == 0 &&
929
	    is_array($config['interfaces'])) {
930
		foreach ($config['interfaces'] as $tmpinterface) {
931
			if ($tmpinterface['if'] == $lagg['laggif'] &&
932
			    !empty($tmpinterface['mtu'])) {
933
				$lagg_mtu = $tmpinterface['mtu'];
934
				break;
935
			}
936
		}
937
	}
938

    
939
	/* Just in case anything is not working well */
940
	if ($lagg_mtu == 0) {
941
		$lagg_mtu = 1500;
942
	}
943

    
944
	foreach ($members as $member) {
945
		if (!does_interface_exist($member)) {
946
			continue;
947
		}
948
		/* make sure the parent interface is up */
949
		pfSense_interface_mtu($member, $lagg_mtu);
950
		interfaces_bring_up($member);
951
		hardware_offloading_applyflags($member);
952
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
953
	}
954

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

    
957
	interfaces_bring_up($laggif);
958

    
959
	return $laggif;
960
}
961

    
962
function interfaces_gre_configure($checkparent = 0, $realif = "") {
963
	global $config;
964

    
965
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
966
		foreach ($config['gres']['gre'] as $i => $gre) {
967
			if (empty($gre['greif'])) {
968
				$gre['greif'] = "gre{$i}";
969
			}
970
			if (!empty($realif) && $realif != $gre['greif']) {
971
				continue;
972
			}
973

    
974
			if ($checkparent == 1) {
975
				if (substr($gre['if'], 0, 4) == '_vip') {
976
					continue;
977
				}
978
				if (substr($gre['if'], 0, 5) == '_lloc') {
979
					continue;
980
				}
981
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6") {
982
					continue;
983
				}
984
			} else if ($checkparent == 2) {
985
				if ((substr($gre['if'], 0, 4) != '_vip' && substr($gre['if'], 0, 5) != '_lloc') &&
986
				    (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")) {
987
					continue;
988
				}
989
			}
990
			/* XXX: Maybe we should report any errors?! */
991
			interface_gre_configure($gre);
992
		}
993
	}
994
}
995

    
996
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
997
function interface_gre_configure(&$gre, $grekey = "") {
998
	global $config, $g;
999

    
1000
	if (!is_array($gre)) {
1001
		return -1;
1002
	}
1003

    
1004
	$realif = get_real_interface($gre['if']);
1005
	$realifip = get_interface_ip($gre['if']);
1006
	$realifip6 = get_interface_ipv6($gre['if']);
1007

    
1008
	/* make sure the parent interface is up */
1009
	interfaces_bring_up($realif);
1010

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

    
1019
	/* Do not change the order here for more see gre(4) NOTES section. */
1020
	if (is_ipaddrv6($gre['remote-addr'])) {
1021
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1022
	} else {
1023
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1024
	}
1025
	if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
1026
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1027
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
1028
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
1029
	} else {
1030
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1031
	}
1032

    
1033
	if ($greif) {
1034
		interfaces_bring_up($greif);
1035
	} else {
1036
		log_error(gettext("Could not bring greif up -- variable not defined."));
1037
	}
1038

    
1039
	if (isset($gre['link1']) && $gre['link1']) {
1040
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1041
	}
1042
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
1043
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1044
	}
1045
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
1046
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
1047
	}
1048

    
1049
	interfaces_bring_up($greif);
1050

    
1051
	return $greif;
1052
}
1053

    
1054
function interfaces_gif_configure($checkparent = 0, $realif = "") {
1055
	global $config;
1056

    
1057
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
1058
		foreach ($config['gifs']['gif'] as $i => $gif) {
1059
			if (empty($gif['gifif'])) {
1060
				$gre['gifif'] = "gif{$i}";
1061
			}
1062
			if (!empty($realif) && $realif != $gif['gifif']) {
1063
				continue;
1064
			}
1065

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

    
1089
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1090
function interface_gif_configure(&$gif, $gifkey = "") {
1091
	global $config, $g;
1092

    
1093
	if (!is_array($gif)) {
1094
		return -1;
1095
	}
1096

    
1097
	$realif = get_real_interface($gif['if']);
1098
	$ipaddr = get_interface_ip($gif['if']);
1099

    
1100
	if (is_ipaddrv4($gif['remote-addr'])) {
1101
		if (is_ipaddrv4($ipaddr)) {
1102
			$realifip = $ipaddr;
1103
		} else {
1104
			$realifip = get_interface_ip($gif['if']);
1105
		}
1106
		$realifgw = get_interface_gateway($gif['if']);
1107
	} else if (is_ipaddrv6($gif['remote-addr'])) {
1108
		if (is_ipaddrv6($ipaddr)) {
1109
			$realifip = $ipaddr;
1110
		} else {
1111
			$realifip = get_interface_ipv6($gif['if']);
1112
		}
1113
		$realifgw = get_interface_gateway_v6($gif['if']);
1114
	}
1115
	/* make sure the parent interface is up */
1116
	if ($realif) {
1117
		interfaces_bring_up($realif);
1118
	} else {
1119
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
1120
	}
1121

    
1122
	if (platform_booting() || !(empty($gif['gifif']))) {
1123
		pfSense_interface_destroy($gif['gifif']);
1124
		pfSense_interface_create($gif['gifif']);
1125
		$gifif = $gif['gifif'];
1126
	} else {
1127
		$gifif = pfSense_interface_create("gif");
1128
	}
1129

    
1130
	/* Do not change the order here for more see gif(4) NOTES section. */
1131
	if (is_ipaddrv6($gif['remote-addr'])) {
1132
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1133
	} else {
1134
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1135
	}
1136
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1137
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1138
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1139
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1140
	} else {
1141
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1142
	}
1143
	if (isset($gif['link1'])) {
1144
		pfSense_interface_flags($gifif, IFF_LINK1);
1145
	}
1146
	if (isset($gif['link2'])) {
1147
		pfSense_interface_flags($gifif, IFF_LINK2);
1148
	}
1149
	if ($gifif) {
1150
		interfaces_bring_up($gifif);
1151
		$gifmtu = "";
1152
		$currentgifmtu = get_interface_mtu($gifif);
1153
		foreach ($config['interfaces'] as $tmpinterface) {
1154
			if ($tmpinterface['if'] == $gifif) {
1155
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1156
					$gifmtu = $tmpinterface['mtu'];
1157
				}
1158
			}
1159
		}
1160
		if (is_numericint($gifmtu)) {
1161
			if ($gifmtu != $currentgifmtu) {
1162
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1163
			}
1164
		}
1165
	} else {
1166
		log_error(gettext("could not bring gifif up -- variable not defined"));
1167
	}
1168

    
1169
	if (!platform_booting()) {
1170
		$iflist = get_configured_interface_list();
1171
		foreach ($iflist as $ifname) {
1172
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1173
				if (get_interface_gateway($ifname)) {
1174
					system_routing_configure($ifname);
1175
					break;
1176
				}
1177
				if (get_interface_gateway_v6($ifname)) {
1178
					system_routing_configure($ifname);
1179
					break;
1180
				}
1181
			}
1182
		}
1183
	}
1184

    
1185

    
1186
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1187
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1188
	}
1189
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1190
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1191
	}
1192

    
1193
	if (is_ipaddrv4($realifgw)) {
1194
		route_add_or_change("-host {$gif['remote-addr']} {$realifgw}");
1195
	}
1196
	if (is_ipaddrv6($realifgw)) {
1197
		route_add_or_change("-host -inet6 {$gif['remote-addr']} {$realifgw}");
1198
	}
1199

    
1200
	interfaces_bring_up($gifif);
1201

    
1202
	return $gifif;
1203
}
1204

    
1205
function interfaces_configure() {
1206
	global $config, $g;
1207

    
1208
	/* Set up our loopback interface */
1209
	interfaces_loopback_configure();
1210

    
1211
	/* create the unconfigured wireless clones */
1212
	interfaces_create_wireless_clones();
1213

    
1214
	/* set up LAGG virtual interfaces */
1215
	interfaces_lagg_configure();
1216

    
1217
	/* set up VLAN virtual interfaces */
1218
	interfaces_vlan_configure();
1219

    
1220
	interfaces_qinq_configure();
1221

    
1222
	$iflist = get_configured_interface_with_descr();
1223
	$delayed_list = array();
1224
	$bridge_list = array();
1225
	$track6_list = array();
1226

    
1227
	/* This is needed to speedup interfaces on bootup. */
1228
	$reload = false;
1229
	if (!platform_booting()) {
1230
		$reload = true;
1231
	}
1232

    
1233
	foreach ($iflist as $if => $ifname) {
1234
		$realif = $config['interfaces'][$if]['if'];
1235
		if (strstr($realif, "bridge")) {
1236
			$bridge_list[$if] = $ifname;
1237
		} else if (strstr($realif, "gre")) {
1238
			$delayed_list[$if] = $ifname;
1239
		} else if (strstr($realif, "gif")) {
1240
			$delayed_list[$if] = $ifname;
1241
		} else if (strstr($realif, "ovpn")) {
1242
			//echo "Delaying OpenVPN interface configuration...done.\n";
1243
			continue;
1244
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1245
			$track6_list[$if] = $ifname;
1246
		} else {
1247
			if (platform_booting()) {
1248
				printf(gettext("Configuring %s interface..."), $ifname);
1249
			}
1250

    
1251
			if ($g['debug']) {
1252
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1253
			}
1254
			interface_configure($if, $reload);
1255
			if (platform_booting()) {
1256
				echo gettext("done.") . "\n";
1257
			}
1258
		}
1259
	}
1260

    
1261
	/*
1262
	 * NOTE: The following function parameter consists of
1263
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1264
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1265
	 */
1266

    
1267
	/* set up GRE virtual interfaces */
1268
	interfaces_gre_configure(1);
1269

    
1270
	/* set up GIF virtual interfaces */
1271
	interfaces_gif_configure(1);
1272

    
1273
	/* set up BRIDGe virtual interfaces */
1274
	interfaces_bridge_configure(1);
1275

    
1276
	foreach ($track6_list as $if => $ifname) {
1277
		if (platform_booting()) {
1278
			printf(gettext("Configuring %s interface..."), $ifname);
1279
		}
1280
		if ($g['debug']) {
1281
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1282
		}
1283

    
1284
		interface_configure($if, $reload);
1285

    
1286
		if (platform_booting()) {
1287
			echo gettext("done.") . "\n";
1288
		}
1289
	}
1290

    
1291
	/* bring up vip interfaces */
1292
	interfaces_vips_configure();
1293

    
1294
	/* set up GRE virtual interfaces */
1295
	interfaces_gre_configure(2);
1296

    
1297
	/* set up GIF virtual interfaces */
1298
	interfaces_gif_configure(2);
1299

    
1300
	foreach ($delayed_list as $if => $ifname) {
1301
		if (platform_booting()) {
1302
			printf(gettext("Configuring %s interface..."), $ifname);
1303
		}
1304
		if ($g['debug']) {
1305
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1306
		}
1307

    
1308
		interface_configure($if, $reload);
1309

    
1310
		if (platform_booting()) {
1311
			echo gettext("done.") . "\n";
1312
		}
1313
	}
1314

    
1315
	/* set up BRIDGe virtual interfaces */
1316
	interfaces_bridge_configure(2);
1317

    
1318
	foreach ($bridge_list as $if => $ifname) {
1319
		if (platform_booting()) {
1320
			printf(gettext("Configuring %s interface..."), $ifname);
1321
		}
1322
		if ($g['debug']) {
1323
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1324
		}
1325

    
1326
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1327
		// redmine #3997
1328
		interface_reconfigure($if, $reload);
1329
		interfaces_vips_configure($if);
1330

    
1331
		if (platform_booting()) {
1332
			echo gettext("done.") . "\n";
1333
		}
1334
	}
1335

    
1336
	/* configure interface groups */
1337
	interfaces_group_setup();
1338

    
1339
	if (!platform_booting()) {
1340
		/* reconfigure static routes (kernel may have deleted them) */
1341
		system_routing_configure();
1342

    
1343
		/* reload IPsec tunnels */
1344
		vpn_ipsec_configure();
1345

    
1346
		/* restart dns servers (defering dhcpd reload) */
1347
		if (isset($config['dnsmasq']['enable'])) {
1348
			services_dnsmasq_configure(false);
1349
		}
1350
		if (isset($config['unbound']['enable'])) {
1351
			services_unbound_configure(false);
1352
		}
1353

    
1354
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1355
		services_dhcpd_configure();
1356
	}
1357

    
1358
	return 0;
1359
}
1360

    
1361
function interface_reconfigure($interface = "wan", $reloadall = false) {
1362
	interface_bring_down($interface);
1363
	interface_configure($interface, $reloadall);
1364
}
1365

    
1366
function interface_vip_bring_down($vip) {
1367
	global $g;
1368

    
1369
	$vipif = get_real_interface($vip['interface']);
1370
	switch ($vip['mode']) {
1371
		case "proxyarp":
1372
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1373
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1374
			}
1375
			break;
1376
		case "ipalias":
1377
			if (does_interface_exist($vipif)) {
1378
				if (is_ipaddrv6($vip['subnet'])) {
1379
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1380
				} else {
1381
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1382
				}
1383
			}
1384
			break;
1385
		case "carp":
1386
			/* XXX: Is enough to delete ip address? */
1387
			if (does_interface_exist($vipif)) {
1388
				if (is_ipaddrv6($vip['subnet'])) {
1389
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1390
				} else {
1391
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1392
				}
1393
			}
1394
			break;
1395
	}
1396
}
1397

    
1398
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1399
	global $config, $g;
1400

    
1401
	if (!isset($config['interfaces'][$interface])) {
1402
		return;
1403
	}
1404

    
1405
	if ($g['debug']) {
1406
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1407
	}
1408

    
1409
	/*
1410
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1411
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1412
	 * Keep this in mind while doing changes here!
1413
	 */
1414
	if ($ifacecfg === false) {
1415
		$ifcfg = $config['interfaces'][$interface];
1416
		$ppps = $config['ppps']['ppp'];
1417
		$realif = get_real_interface($interface);
1418
		$realifv6 = get_real_interface($interface, "inet6", true);
1419
	} elseif (!is_array($ifacecfg)) {
1420
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1421
		$ifcfg = $config['interfaces'][$interface];
1422
		$ppps = $config['ppps']['ppp'];
1423
		$realif = get_real_interface($interface);
1424
		$realifv6 = get_real_interface($interface, "inet6", true);
1425
	} else {
1426
		$ifcfg = $ifacecfg['ifcfg'];
1427
		$ppps = $ifacecfg['ppps'];
1428
		if (isset($ifacecfg['ifcfg']['realif'])) {
1429
			$realif = $ifacecfg['ifcfg']['realif'];
1430
			/* XXX: Any better way? */
1431
			$realifv6 = $realif;
1432
		} else {
1433
			$realif = get_real_interface($interface);
1434
			$realifv6 = get_real_interface($interface, "inet6", true);
1435
		}
1436
	}
1437

    
1438
	switch ($ifcfg['ipaddr']) {
1439
		case "ppp":
1440
		case "pppoe":
1441
		case "pptp":
1442
		case "l2tp":
1443
			if (is_array($ppps) && count($ppps)) {
1444
				foreach ($ppps as $pppid => $ppp) {
1445
					if ($realif == $ppp['if']) {
1446
						if (isset($ppp['ondemand']) && !$destroy) {
1447
							send_event("interface reconfigure {$interface}");
1448
							break;
1449
						}
1450
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1451
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1452
							sleep(2);
1453
						}
1454
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1455
						break;
1456
					}
1457
				}
1458
			}
1459
			break;
1460
		case "dhcp":
1461
			kill_dhclient_process($realif);
1462
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1463
			if (does_interface_exist("$realif")) {
1464
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1465
				interface_vip_cleanup($interface, "inet4");
1466
				if ($destroy == true) {
1467
					pfSense_interface_flags($realif, -IFF_UP);
1468
				}
1469
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1470
			}
1471
			break;
1472
		default:
1473
			if (does_interface_exist("$realif")) {
1474
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1475
				interface_vip_cleanup($interface, "inet4");
1476
				if ($destroy == true) {
1477
					pfSense_interface_flags($realif, -IFF_UP);
1478
				}
1479
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1480
			}
1481
			break;
1482
	}
1483

    
1484
	$track6 = array();
1485
	switch ($ifcfg['ipaddrv6']) {
1486
		case "slaac":
1487
		case "dhcp6":
1488
			kill_dhcp6client_process($realif, $destroy, false);
1489
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1490
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1491
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1492
			if (does_interface_exist($realifv6)) {
1493
				$ip6 = find_interface_ipv6($realifv6);
1494
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1495
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1496
				}
1497
				interface_vip_cleanup($interface, "inet6");
1498
				if ($destroy == true) {
1499
					pfSense_interface_flags($realif, -IFF_UP);
1500
				}
1501
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1502
			}
1503
			$track6 = link_interface_to_track6($interface);
1504
			break;
1505
		case "6rd":
1506
		case "6to4":
1507
			$realif = "{$interface}_stf";
1508
			if (does_interface_exist("$realif")) {
1509
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1510
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1511
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1512
					$destroy = true;
1513
				} else {
1514
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1515
					$ip6 = get_interface_ipv6($interface);
1516
					if (is_ipaddrv6($ip6)) {
1517
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1518
					}
1519
				}
1520
				interface_vip_cleanup($interface, "inet6");
1521
				if ($destroy == true) {
1522
					pfSense_interface_flags($realif, -IFF_UP);
1523
				}
1524
			}
1525
			$track6 = link_interface_to_track6($interface);
1526
			break;
1527
		default:
1528
			if (does_interface_exist("$realif")) {
1529
				$ip6 = get_interface_ipv6($interface);
1530
				if (is_ipaddrv6($ip6)) {
1531
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1532
				}
1533
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1534
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1535
				}
1536
				interface_vip_cleanup($interface, "inet6");
1537
				if ($destroy == true) {
1538
					pfSense_interface_flags($realif, -IFF_UP);
1539
				}
1540
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1541
			}
1542
			$track6 = link_interface_to_track6($interface);
1543
			break;
1544
	}
1545

    
1546
	if (!empty($track6) && is_array($track6)) {
1547
		if (!function_exists('services_dhcpd_configure')) {
1548
			require_once('services.inc');
1549
		}
1550
		/* Bring down radvd and dhcp6 on these interfaces */
1551
		services_dhcpd_configure('inet6', $track6);
1552
	}
1553

    
1554
	$old_router = '';
1555
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1556
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1557
	}
1558

    
1559
	/* remove interface up file if it exists */
1560
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1561
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1562
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1563
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1564
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1565
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1566
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1567

    
1568
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1569
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1570
	if (is_array($ifcfg['wireless'])) {
1571
		kill_hostapd($realif);
1572
		mwexec(kill_wpasupplicant($realif));
1573
	}
1574

    
1575
	if ($destroy == true) {
1576
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1577
			pfSense_interface_destroy($realif);
1578
		}
1579
	}
1580

    
1581
	return;
1582
}
1583

    
1584
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1585
	global $config;
1586
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1587
		unset($config["virtualip_carp_maintenancemode"]);
1588
		write_config("Leave CARP maintenance mode");
1589
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1590
		$config["virtualip_carp_maintenancemode"] = true;
1591
		write_config(gettext("Enter CARP maintenance mode"));
1592
	}
1593

    
1594
	$viparr = &$config['virtualip']['vip'];
1595
	foreach ($viparr as $vip) {
1596
		if ($vip['mode'] == "carp") {
1597
			interface_carp_configure($vip);
1598
		}
1599
	}
1600
}
1601

    
1602
function interface_wait_tentative($interface, $timeout = 10) {
1603
	if (!does_interface_exist($interface)) {
1604
		return false;
1605
	}
1606

    
1607
	$time = 0;
1608
	while ($time <= $timeout) {
1609
		$if = pfSense_get_interface_addresses($interface);
1610
		if (!isset($if['tentative'])) {
1611
			return true;
1612
		}
1613
		sleep(1);
1614
		$time++;
1615
	}
1616

    
1617
	return false;
1618
}
1619

    
1620
function interface_isppp_type($interface) {
1621
	global $config;
1622

    
1623
	if (!is_array($config['interfaces'][$interface])) {
1624
		return false;
1625
	}
1626

    
1627
	switch ($config['interfaces'][$interface]['ipaddr']) {
1628
		case 'pptp':
1629
		case 'l2tp':
1630
		case 'pppoe':
1631
		case 'ppp':
1632
			return true;
1633
			break;
1634
		default:
1635
			return false;
1636
			break;
1637
	}
1638
}
1639

    
1640
function interfaces_ptpid_used($ptpid) {
1641
	global $config;
1642

    
1643
	if (is_array($config['ppps']['ppp'])) {
1644
		foreach ($config['ppps']['ppp'] as & $settings) {
1645
			if ($ptpid == $settings['ptpid']) {
1646
				return true;
1647
			}
1648
		}
1649
	}
1650

    
1651
	return false;
1652
}
1653

    
1654
function interfaces_ptpid_next() {
1655

    
1656
	$ptpid = 0;
1657
	while (interfaces_ptpid_used($ptpid)) {
1658
		$ptpid++;
1659
	}
1660

    
1661
	return $ptpid;
1662
}
1663

    
1664
function getMPDCRONSettings($pppif) {
1665
	global $config;
1666

    
1667
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1668
	if (is_array($config['cron']['item'])) {
1669
		foreach ($config['cron']['item'] as $i => $item) {
1670
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1671
				return array("ID" => $i, "ITEM" => $item);
1672
			}
1673
		}
1674
	}
1675

    
1676
	return NULL;
1677
}
1678

    
1679
function handle_pppoe_reset($post_array) {
1680
	global $config, $g;
1681

    
1682
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1683
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1684

    
1685
	if (!is_array($config['cron']['item'])) {
1686
		$config['cron']['item'] = array();
1687
	}
1688

    
1689
	$itemhash = getMPDCRONSettings($pppif);
1690

    
1691
	// reset cron items if necessary and return
1692
	if (empty($post_array['pppoe-reset-type'])) {
1693
		if (isset($itemhash)) {
1694
			unset($config['cron']['item'][$itemhash['ID']]);
1695
		}
1696
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1697
		return;
1698
	}
1699

    
1700
	if (empty($itemhash)) {
1701
		$itemhash = array();
1702
	}
1703
	$item = array();
1704
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1705
		$item['minute'] = $post_array['pppoe_resetminute'];
1706
		$item['hour'] = $post_array['pppoe_resethour'];
1707
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1708
			$date = explode("/", $post_array['pppoe_resetdate']);
1709
			$item['mday'] = $date[1];
1710
			$item['month'] = $date[0];
1711
		} else {
1712
			$item['mday'] = "*";
1713
			$item['month'] = "*";
1714
		}
1715
		$item['wday'] = "*";
1716
		$item['who'] = "root";
1717
		$item['command'] = $cron_cmd_file;
1718
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1719
		switch ($post_array['pppoe_pr_preset_val']) {
1720
			case "monthly":
1721
				$item['minute'] = "0";
1722
				$item['hour'] = "0";
1723
				$item['mday'] = "1";
1724
				$item['month'] = "*";
1725
				$item['wday'] = "*";
1726
				break;
1727
			case "weekly":
1728
				$item['minute'] = "0";
1729
				$item['hour'] = "0";
1730
				$item['mday'] = "*";
1731
				$item['month'] = "*";
1732
				$item['wday'] = "0";
1733
				break;
1734
			case "daily":
1735
				$item['minute'] = "0";
1736
				$item['hour'] = "0";
1737
				$item['mday'] = "*";
1738
				$item['month'] = "*";
1739
				$item['wday'] = "*";
1740
				break;
1741
			case "hourly":
1742
				$item['minute'] = "0";
1743
				$item['hour'] = "*";
1744
				$item['mday'] = "*";
1745
				$item['month'] = "*";
1746
				$item['wday'] = "*";
1747
				break;
1748
		} // end switch
1749
		$item['who'] = "root";
1750
		$item['command'] = $cron_cmd_file;
1751
	}
1752
	if (empty($item)) {
1753
		return;
1754
	}
1755
	if (isset($itemhash['ID'])) {
1756
		$config['cron']['item'][$itemhash['ID']] = $item;
1757
	} else {
1758
		$config['cron']['item'][] = $item;
1759
	}
1760
}
1761

    
1762
/*
1763
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1764
 * It writes the mpd config file to /var/etc every time the link is opened.
1765
 */
1766
function interface_ppps_configure($interface) {
1767
	global $config, $g;
1768

    
1769
	/* Return for unassigned interfaces. This is a minimum requirement. */
1770
	if (empty($config['interfaces'][$interface])) {
1771
		return 0;
1772
	}
1773
	$ifcfg = $config['interfaces'][$interface];
1774
	if (!isset($ifcfg['enable'])) {
1775
		return 0;
1776
	}
1777

    
1778
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1779
	if (!is_dir("/var/spool/lock")) {
1780
		mkdir("/var/spool/lock", 0777, true);
1781
	}
1782
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1783
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1784
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1785
	}
1786

    
1787
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1788
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1789
			if ($ifcfg['if'] == $ppp['if']) {
1790
				break;
1791
			}
1792
		}
1793
	}
1794
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
1795
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1796
		return 0;
1797
	}
1798
	$pppif = $ifcfg['if'];
1799
	if ($ppp['type'] == "ppp") {
1800
		$type = "modem";
1801
	} else {
1802
		$type = $ppp['type'];
1803
	}
1804
	$upper_type = strtoupper($ppp['type']);
1805

    
1806
	/* XXX: This does not make sense and may create trouble
1807
	 * comment it for now to be removed later on.
1808
	if (platform_booting()) {
1809
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1810
		echo "starting {$pppif} link...";
1811
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1812
			return 0;
1813
	}
1814
	*/
1815

    
1816
	$ports = explode(',', $ppp['ports']);
1817
	if ($type != "modem") {
1818
		foreach ($ports as $pid => $port) {
1819
			$ports[$pid] = get_real_interface($port);
1820
			if (empty($ports[$pid])) {
1821
				return 0;
1822
			}
1823
		}
1824
	}
1825
	$localips = explode(',', $ppp['localip']);
1826
	$gateways = explode(',', $ppp['gateway']);
1827
	$subnets = explode(',', $ppp['subnet']);
1828

    
1829
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1830
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1831
	 */
1832
	foreach ($ports as $pid => $port) {
1833
		switch ($ppp['type']) {
1834
			case "pppoe":
1835
				/* Bring the parent interface up */
1836
				interfaces_bring_up($port);
1837
				pfSense_ngctl_attach(".", $port);
1838
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1839
				mwexec("/usr/sbin/ngctl msg {$port}: setautosrc 1");
1840
				break;
1841
			case "pptp":
1842
			case "l2tp":
1843
				/* configure interface */
1844
				if (is_ipaddr($localips[$pid])) {
1845
					// Manually configure interface IP/subnet
1846
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1847
					interfaces_bring_up($port);
1848
				} else if (empty($localips[$pid])) {
1849
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1850
				}
1851

    
1852
				if (!is_ipaddr($localips[$pid])) {
1853
					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));
1854
					$localips[$pid] = "0.0.0.0";
1855
				}
1856
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
1857
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1858
				}
1859
				if (!is_ipaddr($gateways[$pid])) {
1860
					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));
1861
					return 0;
1862
				}
1863
				pfSense_ngctl_attach(".", $port);
1864
				break;
1865
			case "ppp":
1866
				if (!file_exists("{$port}")) {
1867
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1868
					return 0;
1869
				}
1870
				break;
1871
			default:
1872
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1873
				break;
1874
		}
1875
	}
1876

    
1877
	if (is_array($ports) && count($ports) > 1) {
1878
		$multilink = "enable";
1879
	} else {
1880
		$multilink = "disable";
1881
	}
1882

    
1883
	if ($type == "modem") {
1884
		if (is_ipaddr($ppp['localip'])) {
1885
			$localip = $ppp['localip'];
1886
		} else {
1887
			$localip = '0.0.0.0';
1888
		}
1889

    
1890
		if (is_ipaddr($ppp['gateway'])) {
1891
			$gateway = $ppp['gateway'];
1892
		} else {
1893
			$gateway = "10.64.64.{$pppid}";
1894
		}
1895
		$ranges = "{$localip}/0 {$gateway}/0";
1896

    
1897
		if (empty($ppp['apnum'])) {
1898
			$ppp['apnum'] = 1;
1899
		}
1900
	} else {
1901
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1902
	}
1903

    
1904
	if (isset($ppp['ondemand'])) {
1905
		$ondemand = "enable";
1906
	} else {
1907
		$ondemand = "disable";
1908
	}
1909
	if (!isset($ppp['idletimeout'])) {
1910
		$ppp['idletimeout'] = 0;
1911
	}
1912

    
1913
	if (empty($ppp['username']) && $type == "modem") {
1914
		$ppp['username'] = "user";
1915
		$ppp['password'] = "none";
1916
	}
1917
	if (empty($ppp['password']) && $type == "modem") {
1918
		$passwd = "none";
1919
	} else {
1920
		$passwd = base64_decode($ppp['password']);
1921
	}
1922

    
1923
	$bandwidths = explode(',', $ppp['bandwidth']);
1924
	$defaultmtu = "1492";
1925
	if (!empty($ifcfg['mtu'])) {
1926
		$defaultmtu = intval($ifcfg['mtu']);
1927
	}
1928
	if (isset($ppp['mtu'])) {
1929
		$mtus = explode(',', $ppp['mtu']);
1930
	}
1931
	if (isset($ppp['mru'])) {
1932
		$mrus = explode(',', $ppp['mru']);
1933
	}
1934
	if (isset($ppp['mrru'])) {
1935
		$mrrus = explode(',', $ppp['mrru']);
1936
	}
1937

    
1938
	// Construct the mpd.conf file
1939
	$mpdconf = <<<EOD
1940
startup:
1941
	# configure the console
1942
	set console close
1943
	# configure the web server
1944
	set web close
1945

    
1946
default:
1947
{$ppp['type']}client:
1948
	create bundle static {$interface}
1949
	set bundle enable ipv6cp
1950
	set iface name {$pppif}
1951

    
1952
EOD;
1953
	$setdefaultgw = false;
1954
	$founddefaultgw = false;
1955
	if (is_array($config['gateways']['gateway_item'])) {
1956
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1957
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1958
				$setdefaultgw = true;
1959
				break;
1960
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1961
				$founddefaultgw = true;
1962
				break;
1963
			}
1964
		}
1965
	}
1966

    
1967
/* Omit this, we maintain the default route by other means, and it causes problems with
1968
 * default gateway switching. See redmine #1837 for original issue
1969
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
1970
 * edge case. redmine #6495 open to address.
1971
 */
1972
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1973
		$setdefaultgw = true;
1974
		$mpdconf .= <<<EOD
1975
	set iface route default
1976

    
1977
EOD;
1978
	}
1979
	$mpdconf .= <<<EOD
1980
	set iface {$ondemand} on-demand
1981
	set iface idle {$ppp['idletimeout']}
1982

    
1983
EOD;
1984

    
1985
	if (isset($ppp['ondemand'])) {
1986
		$mpdconf .= <<<EOD
1987
	set iface addrs 10.10.1.1 10.10.1.2
1988

    
1989
EOD;
1990
	}
1991

    
1992
	if (isset($ppp['tcpmssfix'])) {
1993
		$tcpmss = "disable";
1994
	} else {
1995
		$tcpmss = "enable";
1996
	}
1997
	$mpdconf .= <<<EOD
1998
	set iface {$tcpmss} tcpmssfix
1999

    
2000
EOD;
2001

    
2002
	$mpdconf .= <<<EOD
2003
	set iface up-script /usr/local/sbin/ppp-linkup
2004
	set iface down-script /usr/local/sbin/ppp-linkdown
2005
	set ipcp ranges {$ranges}
2006

    
2007
EOD;
2008
	if (isset($ppp['vjcomp'])) {
2009
		$mpdconf .= <<<EOD
2010
	set ipcp no vjcomp
2011

    
2012
EOD;
2013
	}
2014

    
2015
	if (isset($config['system']['dnsallowoverride'])) {
2016
		$mpdconf .= <<<EOD
2017
	set ipcp enable req-pri-dns
2018
	set ipcp enable req-sec-dns
2019

    
2020
EOD;
2021
	}
2022

    
2023
	if (!isset($ppp['verbose_log'])) {
2024
		$mpdconf .= <<<EOD
2025
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2026

    
2027
EOD;
2028
	}
2029

    
2030
	foreach ($ports as $pid => $port) {
2031
		$port = get_real_interface($port);
2032
		$mpdconf .= <<<EOD
2033

    
2034
	create link static {$interface}_link{$pid} {$type}
2035
	set link action bundle {$interface}
2036
	set link {$multilink} multilink
2037
	set link keep-alive 10 60
2038
	set link max-redial 0
2039

    
2040
EOD;
2041
		if (isset($ppp['shortseq'])) {
2042
			$mpdconf .= <<<EOD
2043
	set link no shortseq
2044

    
2045
EOD;
2046
		}
2047

    
2048
		if (isset($ppp['acfcomp'])) {
2049
			$mpdconf .= <<<EOD
2050
	set link no acfcomp
2051

    
2052
EOD;
2053
		}
2054

    
2055
		if (isset($ppp['protocomp'])) {
2056
			$mpdconf .= <<<EOD
2057
	set link no protocomp
2058

    
2059
EOD;
2060
		}
2061

    
2062
		$mpdconf .= <<<EOD
2063
	set link disable chap pap
2064
	set link accept chap pap eap
2065
	set link disable incoming
2066

    
2067
EOD;
2068

    
2069

    
2070
		if (!empty($bandwidths[$pid])) {
2071
			$mpdconf .= <<<EOD
2072
	set link bandwidth {$bandwidths[$pid]}
2073

    
2074
EOD;
2075
		}
2076

    
2077
		if (empty($mtus[$pid])) {
2078
			$mtus[$pid] = $defaultmtu;
2079
		}
2080
		if ($type == "pppoe") {
2081
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2082
				$mtus[$pid] = get_interface_mtu($port) - 8;
2083
			}
2084
		}
2085
		if (! ($type == "pppoe" && $mtus[$pid] > 1492) ) {
2086
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2087
			$mpdconf .= <<<EOD
2088
	set link mtu {$mtus[$pid]}
2089

    
2090
EOD;
2091
		}
2092

    
2093
		if (!empty($mrus[$pid])) {
2094
			$mpdconf .= <<<EOD
2095
	set link mru {$mrus[$pid]}
2096

    
2097
EOD;
2098
		}
2099

    
2100
		if (!empty($mrrus[$pid])) {
2101
			$mpdconf .= <<<EOD
2102
	set link mrru {$mrrus[$pid]}
2103

    
2104
EOD;
2105
		}
2106

    
2107
		$mpdconf .= <<<EOD
2108
	set auth authname "{$ppp['username']}"
2109
	set auth password {$passwd}
2110

    
2111
EOD;
2112
		if ($type == "modem") {
2113
			$mpdconf .= <<<EOD
2114
	set modem device {$ppp['ports']}
2115
	set modem script DialPeer
2116
	set modem idle-script Ringback
2117
	set modem watch -cd
2118
	set modem var \$DialPrefix "DT"
2119
	set modem var \$Telephone "{$ppp['phone']}"
2120

    
2121
EOD;
2122
		}
2123
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2124
			$mpdconf .= <<<EOD
2125
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2126

    
2127
EOD;
2128
		}
2129
		if (isset($ppp['initstr']) && $type == "modem") {
2130
			$initstr = base64_decode($ppp['initstr']);
2131
			$mpdconf .= <<<EOD
2132
	set modem var \$InitString "{$initstr}"
2133

    
2134
EOD;
2135
		}
2136
		if (isset($ppp['simpin']) && $type == "modem") {
2137
			if ($ppp['pin-wait'] == "") {
2138
				$ppp['pin-wait'] = 0;
2139
			}
2140
			$mpdconf .= <<<EOD
2141
	set modem var \$SimPin "{$ppp['simpin']}"
2142
	set modem var \$PinWait "{$ppp['pin-wait']}"
2143

    
2144
EOD;
2145
		}
2146
		if (isset($ppp['apn']) && $type == "modem") {
2147
			$mpdconf .= <<<EOD
2148
	set modem var \$APN "{$ppp['apn']}"
2149
	set modem var \$APNum "{$ppp['apnum']}"
2150

    
2151
EOD;
2152
		}
2153
		if ($type == "pppoe") {
2154
			// Send a null service name if none is set.
2155
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2156
			$mpdconf .= <<<EOD
2157
	set pppoe service "{$provider}"
2158

    
2159
EOD;
2160
		}
2161
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
2162
			$mpdconf .= <<<EOD
2163
	set pppoe max-payload {$mtus[$pid]}
2164

    
2165
EOD;
2166
		}
2167
		if ($type == "pppoe") {
2168
			$mpdconf .= <<<EOD
2169
	set pppoe iface {$port}
2170

    
2171
EOD;
2172
		}
2173

    
2174
		if ($type == "pptp" || $type == "l2tp") {
2175
			$mpdconf .= <<<EOD
2176
	set {$type} self {$localips[$pid]}
2177
	set {$type} peer {$gateways[$pid]}
2178

    
2179
EOD;
2180
		}
2181

    
2182
		$mpdconf .= "\topen\n";
2183
	} //end foreach ($port)
2184

    
2185

    
2186
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2187
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2188
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2189
	} else {
2190
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2191
		if (!$fd) {
2192
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2193
			return 0;
2194
		}
2195
		// Write out mpd_ppp.conf
2196
		fwrite($fd, $mpdconf);
2197
		fclose($fd);
2198
		unset($mpdconf);
2199
	}
2200

    
2201
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2202
	if (isset($ppp['uptime'])) {
2203
		if (!file_exists("/conf/{$pppif}.log")) {
2204
			file_put_contents("/conf/{$pppif}.log", '');
2205
		}
2206
	} else {
2207
		if (file_exists("/conf/{$pppif}.log")) {
2208
			@unlink("/conf/{$pppif}.log");
2209
		}
2210
	}
2211

    
2212
	/* clean up old lock files */
2213
	foreach ($ports as $port) {
2214
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2215
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2216
		}
2217
	}
2218

    
2219
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2220
	/* random IPv6 interface identifier during boot. More details at */
2221
	/* https://forum.pfsense.org/index.php?topic=101967.msg570519#msg570519 */
2222
	if (platform_booting() && is_array($config['interfaces'])) {
2223
		$count = 0;
2224
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2225
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2226
				$tempaddr[$count]['if'] = $tempiface['if'];
2227
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2228
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2229
				$count++;
2230
			}
2231
			// Maximum /31 is is x.y.z.254/31
2232
			if ($count > 122) {
2233
				break;
2234
			}
2235
		}
2236
		unset($count);
2237
	}
2238

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

    
2244
	// Check for PPPoE periodic reset request
2245
	if ($type == "pppoe") {
2246
		if (!empty($ppp['pppoe-reset-type'])) {
2247
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2248
		} else {
2249
			interface_setup_pppoe_reset_file($ppp['if']);
2250
		}
2251
	}
2252
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
2253
	$i = 0;
2254
	while ($i < 3) {
2255
		sleep(10);
2256
		if (does_interface_exist($ppp['if'], true)) {
2257
			break;
2258
		}
2259
		$i++;
2260
	}
2261

    
2262
	/* Remove all temporary bogon IPv4 addresses */
2263
	if (is_array($tempaddr)) {
2264
		foreach ($tempaddr as $tempiface) {
2265
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2266
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2267
			}
2268
		}
2269
		unset ($tempaddr);
2270
	}
2271

    
2272
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2273
	/* We should be able to launch the right version for each modem */
2274
	/* We can also guess the mondev from the manufacturer */
2275
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2276
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2277
	foreach ($ports as $port) {
2278
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2279
			$mondev = substr(basename($port), 0, -1);
2280
			$devlist = glob("/dev/{$mondev}?");
2281
			$mondev = basename(end($devlist));
2282
		}
2283
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2284
			$mondev = substr(basename($port), 0, -1) . "1";
2285
		}
2286
		if ($mondev != '') {
2287
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2288
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2289
		}
2290
	}
2291

    
2292
	return 1;
2293
}
2294

    
2295
function interfaces_sync_setup() {
2296
	global $g, $config;
2297

    
2298
	if (isset($config['system']['developerspew'])) {
2299
		$mt = microtime();
2300
		echo "interfaces_sync_setup() being called $mt\n";
2301
	}
2302

    
2303
	if (platform_booting()) {
2304
		echo gettext("Configuring CARP settings...");
2305
		mute_kernel_msgs();
2306
	}
2307

    
2308
	/* suck in configuration items */
2309
	if ($config['hasync']) {
2310
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2311
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2312
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2313
	} else {
2314
		unset($pfsyncinterface);
2315
		unset($pfsyncenabled);
2316
	}
2317

    
2318
	set_sysctl(array(
2319
		"net.inet.carp.preempt" => "1",
2320
		"net.inet.carp.log" => "1")
2321
	);
2322

    
2323
	if (!empty($pfsyncinterface)) {
2324
		$carp_sync_int = get_real_interface($pfsyncinterface);
2325
	} else {
2326
		unset($carp_sync_int);
2327
	}
2328

    
2329
	/* setup pfsync interface */
2330
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2331
		if (is_ipaddr($pfsyncpeerip)) {
2332
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2333
		} else {
2334
			$syncpeer = "-syncpeer";
2335
		}
2336

    
2337
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2338
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2339

    
2340
		sleep(1);
2341

    
2342
		/* 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
2343
		 * for existing sessions.
2344
		 */
2345
		log_error(gettext("waiting for pfsync..."));
2346
		$i = 0;
2347
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2348
			$i++;
2349
			sleep(1);
2350
		}
2351
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2352
		log_error(gettext("Configuring CARP settings finalize..."));
2353
	} else {
2354
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2355
	}
2356

    
2357
	$carplist = get_configured_vip_list('all', VIP_CARP);
2358
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2359
		set_single_sysctl("net.inet.carp.allow", "1");
2360
	} else {
2361
		set_single_sysctl("net.inet.carp.allow", "0");
2362
	}
2363

    
2364
	if (platform_booting()) {
2365
		unmute_kernel_msgs();
2366
		echo gettext("done.") . "\n";
2367
	}
2368
}
2369

    
2370
function interface_proxyarp_configure($interface = "") {
2371
	global $config, $g;
2372
	if (isset($config['system']['developerspew'])) {
2373
		$mt = microtime();
2374
		echo "interface_proxyarp_configure() being called $mt\n";
2375
	}
2376

    
2377
	/* kill any running choparp */
2378
	if (empty($interface)) {
2379
		killbyname("choparp");
2380
	} else {
2381
		$vipif = get_real_interface($interface);
2382
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2383
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2384
		}
2385
	}
2386

    
2387
	$paa = array();
2388
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2389

    
2390
		/* group by interface */
2391
		foreach ($config['virtualip']['vip'] as $vipent) {
2392
			if ($vipent['mode'] === "proxyarp") {
2393
				if ($vipent['interface']) {
2394
					$proxyif = $vipent['interface'];
2395
				} else {
2396
					$proxyif = "wan";
2397
				}
2398

    
2399
				if (!empty($interface) && $interface != $proxyif) {
2400
					continue;
2401
				}
2402

    
2403
				if (!is_array($paa[$proxyif])) {
2404
					$paa[$proxyif] = array();
2405
				}
2406

    
2407
				$paa[$proxyif][] = $vipent;
2408
			}
2409
		}
2410
	}
2411

    
2412
	if (!empty($interface)) {
2413
		if (is_array($paa[$interface])) {
2414
			$paaifip = get_interface_ip($interface);
2415
			if (!is_ipaddr($paaifip)) {
2416
				return;
2417
			}
2418
			$vipif = get_real_interface($interface);
2419
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2420
			$args .= $vipif . " auto";
2421
			foreach ($paa[$interface] as $paent) {
2422
				if (isset($paent['subnet'])) {
2423
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2424
				} else if (isset($paent['range'])) {
2425
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2426
				}
2427
			}
2428
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2429
		}
2430
	} else if (count($paa) > 0) {
2431
		foreach ($paa as $paif => $paents) {
2432
			$paaifip = get_interface_ip($paif);
2433
			if (!is_ipaddr($paaifip)) {
2434
				continue;
2435
			}
2436
			$vipif = get_real_interface($paif);
2437
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2438
			$args .= $vipif . " auto";
2439
			foreach ($paents as $paent) {
2440
				if (isset($paent['subnet'])) {
2441
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2442
				} else if (isset($paent['range'])) {
2443
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2444
				}
2445
			}
2446
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2447
		}
2448
	}
2449
}
2450

    
2451
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2452
	global $g, $config;
2453

    
2454
	if (is_array($config['virtualip']['vip'])) {
2455
		foreach ($config['virtualip']['vip'] as $vip) {
2456

    
2457
			$iface = $vip['interface'];
2458
			if (substr($iface, 0, 4) == "_vip")
2459
				$iface = get_configured_vip_interface($vip['interface']);
2460
			if ($iface != $interface)
2461
				continue;
2462
			if ($type == VIP_CARP) {
2463
				if ($vip['mode'] != "carp")
2464
					continue;
2465
			} elseif ($type == VIP_IPALIAS) {
2466
				if ($vip['mode'] != "ipalias")
2467
					continue;
2468
			} else {
2469
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2470
					continue;
2471
			}
2472

    
2473
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2474
				interface_vip_bring_down($vip);
2475
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2476
				interface_vip_bring_down($vip);
2477
			else if ($inet == "all")
2478
				interface_vip_bring_down($vip);
2479
		}
2480
	}
2481
}
2482

    
2483
function interfaces_vips_configure($interface = "") {
2484
	global $g, $config;
2485
	if (isset($config['system']['developerspew'])) {
2486
		$mt = microtime();
2487
		echo "interfaces_vips_configure() being called $mt\n";
2488
	}
2489
	$paa = array();
2490
	if (is_array($config['virtualip']['vip'])) {
2491
		$carp_setuped = false;
2492
		$anyproxyarp = false;
2493
		foreach ($config['virtualip']['vip'] as $vip) {
2494
			switch ($vip['mode']) {
2495
				case "proxyarp":
2496
					/* nothing it is handled on interface_proxyarp_configure() */
2497
					if ($interface <> "" && $vip['interface'] <> $interface) {
2498
						continue;
2499
					}
2500
					$anyproxyarp = true;
2501
					break;
2502
				case "ipalias":
2503
					$iface = $vip['interface'];
2504
					if (substr($iface, 0, 4) == "_vip")
2505
						$iface = get_configured_vip_interface($vip['interface']);
2506
					if ($interface <> "" && $iface <> $interface) {
2507
						continue;
2508
					}
2509
					interface_ipalias_configure($vip);
2510
					break;
2511
				case "carp":
2512
					if ($interface <> "" && $vip['interface'] <> $interface) {
2513
						continue;
2514
					}
2515
					if ($carp_setuped == false) {
2516
						$carp_setuped = true;
2517
					}
2518
					interface_carp_configure($vip);
2519
					break;
2520
			}
2521
		}
2522
		if ($carp_setuped == true) {
2523
			interfaces_sync_setup();
2524
		}
2525
		if ($anyproxyarp == true) {
2526
			interface_proxyarp_configure();
2527
		}
2528
	}
2529
}
2530

    
2531
function interface_ipalias_configure(&$vip) {
2532
	global $config;
2533

    
2534
	if ($vip['mode'] != 'ipalias') {
2535
		return;
2536
	}
2537

    
2538
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2539
	if ($realif != "lo0") {
2540
		$if = convert_real_interface_to_friendly_interface_name($realif);
2541
		if (!isset($config['interfaces'][$if])) {
2542
			return;
2543
		}
2544

    
2545
		if (!isset($config['interfaces'][$if]['enable'])) {
2546
			return;
2547
		}
2548
	}
2549

    
2550
	$af = 'inet';
2551
	if (is_ipaddrv6($vip['subnet'])) {
2552
		$af = 'inet6';
2553
	}
2554
	$iface = $vip['interface'];
2555
	$vhid = '';
2556
	if (substr($vip['interface'], 0, 4) == "_vip") {
2557
		$carpvip = get_configured_vip($vip['interface']);
2558
		$iface = $carpvip['interface'];
2559
		$vhid = "vhid {$carpvip['vhid']}";
2560
	}
2561
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2562
	unset($iface, $af, $realif, $carpvip, $vhid);
2563
}
2564

    
2565
function interface_carp_configure(&$vip) {
2566
	global $config, $g;
2567
	if (isset($config['system']['developerspew'])) {
2568
		$mt = microtime();
2569
		echo "interface_carp_configure() being called $mt\n";
2570
	}
2571

    
2572
	if ($vip['mode'] != "carp") {
2573
		return;
2574
	}
2575

    
2576
	/* NOTE: Maybe its useless nowadays */
2577
	$realif = get_real_interface($vip['interface']);
2578
	if (!does_interface_exist($realif)) {
2579
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2580
		return;
2581
	}
2582

    
2583
	$vip_password = $vip['password'];
2584
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2585
	if ($vip['password'] != "") {
2586
		$password = " pass {$vip_password}";
2587
	}
2588

    
2589
	$advbase = "";
2590
	if (!empty($vip['advbase'])) {
2591
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2592
	}
2593

    
2594
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2595
	if ($carp_maintenancemode) {
2596
		$advskew = "advskew 254";
2597
	} else {
2598
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2599
	}
2600

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

    
2603
	if (is_ipaddrv4($vip['subnet'])) {
2604
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2605
	} else if (is_ipaddrv6($vip['subnet'])) {
2606
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2607
	}
2608

    
2609
	return $realif;
2610
}
2611

    
2612
function interface_wireless_clone($realif, $wlcfg) {
2613
	global $config, $g;
2614
	/*   Check to see if interface has been cloned as of yet.
2615
	 *   If it has not been cloned then go ahead and clone it.
2616
	 */
2617
	$needs_clone = false;
2618
	if (is_array($wlcfg['wireless'])) {
2619
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2620
	} else {
2621
		$wlcfg_mode = $wlcfg['mode'];
2622
	}
2623
	switch ($wlcfg_mode) {
2624
		case "hostap":
2625
			$mode = "wlanmode hostap";
2626
			break;
2627
		case "adhoc":
2628
			$mode = "wlanmode adhoc";
2629
			break;
2630
		default:
2631
			$mode = "";
2632
			break;
2633
	}
2634
	$baseif = interface_get_wireless_base($wlcfg['if']);
2635
	if (does_interface_exist($realif)) {
2636
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2637
		$ifconfig_str = implode($output);
2638
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2639
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2640
			$needs_clone = true;
2641
		}
2642
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2643
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2644
			$needs_clone = true;
2645
		}
2646
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2647
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2648
			$needs_clone = true;
2649
		}
2650
	} else {
2651
		$needs_clone = true;
2652
	}
2653

    
2654
	if ($needs_clone == true) {
2655
		/* remove previous instance if it exists */
2656
		if (does_interface_exist($realif)) {
2657
			pfSense_interface_destroy($realif);
2658
		}
2659

    
2660
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2661
		// Create the new wlan interface. FreeBSD returns the new interface name.
2662
		// example:  wlan2
2663
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2664
		if ($ret <> 0) {
2665
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2666
			return false;
2667
		}
2668
		$newif = trim($out[0]);
2669
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2670
		pfSense_interface_rename($newif, $realif);
2671
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2672
	}
2673
	return true;
2674
}
2675

    
2676
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2677
	global $config, $g;
2678

    
2679
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2680
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2681
				 'regdomain', 'regcountry', 'reglocation');
2682

    
2683
	if (!is_interface_wireless($ifcfg['if'])) {
2684
		return;
2685
	}
2686

    
2687
	$baseif = interface_get_wireless_base($ifcfg['if']);
2688

    
2689
	// Sync shared settings for assigned clones
2690
	$iflist = get_configured_interface_list(true);
2691
	foreach ($iflist as $if) {
2692
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2693
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2694
				foreach ($shared_settings as $setting) {
2695
					if ($sync_changes) {
2696
						if (isset($ifcfg['wireless'][$setting])) {
2697
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2698
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2699
							unset($config['interfaces'][$if]['wireless'][$setting]);
2700
						}
2701
					} else {
2702
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2703
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2704
						} else if (isset($ifcfg['wireless'][$setting])) {
2705
							unset($ifcfg['wireless'][$setting]);
2706
						}
2707
					}
2708
				}
2709
				if (!$sync_changes) {
2710
					break;
2711
				}
2712
			}
2713
		}
2714
	}
2715

    
2716
	// Read or write settings at shared area
2717
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2718
		foreach ($shared_settings as $setting) {
2719
			if ($sync_changes) {
2720
				if (isset($ifcfg['wireless'][$setting])) {
2721
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2722
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2723
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2724
				}
2725
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2726
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2727
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2728
				} else if (isset($ifcfg['wireless'][$setting])) {
2729
					unset($ifcfg['wireless'][$setting]);
2730
				}
2731
			}
2732
		}
2733
	}
2734

    
2735
	// Sync the mode on the clone creation page with the configured mode on the interface
2736
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2737
		foreach ($config['wireless']['clone'] as &$clone) {
2738
			if ($clone['cloneif'] == $ifcfg['if']) {
2739
				if ($sync_changes) {
2740
					$clone['mode'] = $ifcfg['wireless']['mode'];
2741
				} else {
2742
					$ifcfg['wireless']['mode'] = $clone['mode'];
2743
				}
2744
				break;
2745
			}
2746
		}
2747
		unset($clone);
2748
	}
2749
}
2750

    
2751
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2752
	global $config, $g;
2753

    
2754
	/*    open up a shell script that will be used to output the commands.
2755
	 *    since wireless is changing a lot, these series of commands are fragile
2756
	 *    and will sometimes need to be verified by a operator by executing the command
2757
	 *    and returning the output of the command to the developers for inspection.  please
2758
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2759
	 */
2760

    
2761
	// Remove script file
2762
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2763

    
2764
	// Clone wireless nic if needed.
2765
	interface_wireless_clone($if, $wl);
2766

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

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

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

    
2776
	/* set values for /path/program */
2777
	if (file_exists("/usr/local/sbin/hostapd")) {
2778
		$hostapd = "/usr/local/sbin/hostapd";
2779
	} else {
2780
		$hostapd = "/usr/sbin/hostapd";
2781
	}
2782
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
2783
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
2784
	} else {
2785
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2786
	}
2787
	$ifconfig = "/sbin/ifconfig";
2788
	$sysctl = "/sbin/sysctl";
2789
	$killall = "/usr/bin/killall";
2790

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

    
2793
	$wlcmd = array();
2794
	$wl_sysctl = array();
2795
	/* Set a/b/g standard */
2796
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2797
	/* skip mode entirely for "auto" */
2798
	if ($wlcfg['standard'] != "auto") {
2799
		$wlcmd[] = "mode " . escapeshellarg($standard);
2800
	}
2801

    
2802
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2803
	 * to prevent massive packet loss under certain conditions. */
2804
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2805
		$wlcmd[] = "-ampdu";
2806
	}
2807

    
2808
	/* Set ssid */
2809
	if ($wlcfg['ssid']) {
2810
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2811
	}
2812

    
2813
	/* Set 802.11g protection mode */
2814
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2815

    
2816
	/* set wireless channel value */
2817
	if (isset($wlcfg['channel'])) {
2818
		if ($wlcfg['channel'] == "0") {
2819
			$wlcmd[] = "channel any";
2820
		} else {
2821
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2822
		}
2823
	}
2824

    
2825
	/* Set antenna diversity value */
2826
	if (isset($wlcfg['diversity'])) {
2827
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2828
	}
2829

    
2830
	/* Set txantenna value */
2831
	if (isset($wlcfg['txantenna'])) {
2832
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2833
	}
2834

    
2835
	/* Set rxantenna value */
2836
	if (isset($wlcfg['rxantenna'])) {
2837
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2838
	}
2839

    
2840
	/* set Distance value */
2841
	if ($wlcfg['distance']) {
2842
		$distance = escapeshellarg($wlcfg['distance']);
2843
	}
2844

    
2845
	/* Set wireless hostap mode */
2846
	if ($wlcfg['mode'] == "hostap") {
2847
		$wlcmd[] = "mediaopt hostap";
2848
	} else {
2849
		$wlcmd[] = "-mediaopt hostap";
2850
	}
2851

    
2852
	/* Set wireless adhoc mode */
2853
	if ($wlcfg['mode'] == "adhoc") {
2854
		$wlcmd[] = "mediaopt adhoc";
2855
	} else {
2856
		$wlcmd[] = "-mediaopt adhoc";
2857
	}
2858

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

    
2861
	/* handle hide ssid option */
2862
	if (isset($wlcfg['hidessid']['enable'])) {
2863
		$wlcmd[] = "hidessid";
2864
	} else {
2865
		$wlcmd[] = "-hidessid";
2866
	}
2867

    
2868
	/* handle pureg (802.11g) only option */
2869
	if (isset($wlcfg['pureg']['enable'])) {
2870
		$wlcmd[] = "mode 11g pureg";
2871
	} else {
2872
		$wlcmd[] = "-pureg";
2873
	}
2874

    
2875
	/* handle puren (802.11n) only option */
2876
	if (isset($wlcfg['puren']['enable'])) {
2877
		$wlcmd[] = "puren";
2878
	} else {
2879
		$wlcmd[] = "-puren";
2880
	}
2881

    
2882
	/* enable apbridge option */
2883
	if (isset($wlcfg['apbridge']['enable'])) {
2884
		$wlcmd[] = "apbridge";
2885
	} else {
2886
		$wlcmd[] = "-apbridge";
2887
	}
2888

    
2889
	/* handle turbo option */
2890
	if (isset($wlcfg['turbo']['enable'])) {
2891
		$wlcmd[] = "mediaopt turbo";
2892
	} else {
2893
		$wlcmd[] = "-mediaopt turbo";
2894
	}
2895

    
2896
	/* handle txpower setting */
2897
	// or don't. this has issues at the moment.
2898
	/*
2899
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2900
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2901
	}*/
2902

    
2903
	/* handle wme option */
2904
	if (isset($wlcfg['wme']['enable'])) {
2905
		$wlcmd[] = "wme";
2906
	} else {
2907
		$wlcmd[] = "-wme";
2908
	}
2909

    
2910
	/* Enable wpa if it's configured. No WEP support anymore. */
2911
	if (isset($wlcfg['wpa']['enable'])) {
2912
		$wlcmd[] = "authmode wpa wepmode off ";
2913
	} else {
2914
		$wlcmd[] = "authmode open wepmode off ";
2915
	}
2916

    
2917
	kill_hostapd($if);
2918
	mwexec(kill_wpasupplicant("{$if}"));
2919

    
2920
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2921

    
2922
	switch ($wlcfg['mode']) {
2923
		case 'bss':
2924
			if (isset($wlcfg['wpa']['enable'])) {
2925
				$wpa .= <<<EOD
2926
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2927
ctrl_interface_group=0
2928
ap_scan=1
2929
#fast_reauth=1
2930
network={
2931
ssid="{$wlcfg['ssid']}"
2932
scan_ssid=1
2933
priority=5
2934
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2935
psk="{$wlcfg['wpa']['passphrase']}"
2936
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2937
group={$wlcfg['wpa']['wpa_pairwise']}
2938
}
2939
EOD;
2940

    
2941
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2942
				unset($wpa);
2943
			}
2944
			break;
2945
		case 'hostap':
2946
			if (!empty($wlcfg['wpa']['passphrase'])) {
2947
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2948
			} else {
2949
				$wpa_passphrase = "";
2950
			}
2951
			if (isset($wlcfg['wpa']['enable'])) {
2952
				$wpa .= <<<EOD
2953
interface={$if}
2954
driver=bsd
2955
logger_syslog=-1
2956
logger_syslog_level=0
2957
logger_stdout=-1
2958
logger_stdout_level=0
2959
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2960
ctrl_interface={$g['varrun_path']}/hostapd
2961
ctrl_interface_group=wheel
2962
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2963
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2964
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2965
ssid={$wlcfg['ssid']}
2966
debug={$wlcfg['wpa']['debug_mode']}
2967
wpa={$wlcfg['wpa']['wpa_mode']}
2968
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2969
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2970
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2971
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2972
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2973
{$wpa_passphrase}
2974

    
2975
EOD;
2976

    
2977
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2978
					$wpa .= <<<EOD
2979
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
2980
rsn_preauth=1
2981
rsn_preauth_interfaces={$if}
2982

    
2983
EOD;
2984
				}
2985
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2986
					$wpa .= "ieee8021x=1\n";
2987

    
2988
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2989
						$auth_server_port = "1812";
2990
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2991
							$auth_server_port = intval($wlcfg['auth_server_port']);
2992
						}
2993
						$wpa .= <<<EOD
2994

    
2995
auth_server_addr={$wlcfg['auth_server_addr']}
2996
auth_server_port={$auth_server_port}
2997
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2998

    
2999
EOD;
3000
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3001
							$auth_server_port2 = "1812";
3002
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3003
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3004
							}
3005

    
3006
							$wpa .= <<<EOD
3007
auth_server_addr={$wlcfg['auth_server_addr2']}
3008
auth_server_port={$auth_server_port2}
3009
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3010

    
3011
EOD;
3012
						}
3013
					}
3014
				}
3015

    
3016
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3017
				unset($wpa);
3018
			}
3019
			break;
3020
	}
3021

    
3022
	/*
3023
	 *    all variables are set, lets start up everything
3024
	 */
3025

    
3026
	$baseif = interface_get_wireless_base($if);
3027
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3028
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3029

    
3030
	/* set sysctls for the wireless interface */
3031
	if (!empty($wl_sysctl)) {
3032
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3033
		foreach ($wl_sysctl as $wl_sysctl_line) {
3034
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3035
		}
3036
	}
3037

    
3038
	/* set ack timers according to users preference (if he/she has any) */
3039
	if ($distance) {
3040
		fwrite($fd_set, "# Enable ATH distance settings\n");
3041
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3042
	}
3043

    
3044
	if (isset($wlcfg['wpa']['enable'])) {
3045
		if ($wlcfg['mode'] == "bss") {
3046
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3047
		}
3048
		if ($wlcfg['mode'] == "hostap") {
3049
			/* add line to script to restore old mac to make hostapd happy */
3050
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3051
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3052
				$if_curmac = get_interface_mac($if);
3053
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3054
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3055
						" link " . escapeshellarg($if_oldmac) . "\n");
3056
				}
3057
			}
3058

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

    
3061
			/* add line to script to restore spoofed mac after running hostapd */
3062
			if ($wl['spoofmac']) {
3063
				$if_curmac = get_interface_mac($if);
3064
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3065
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3066
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3067
				}
3068
			}
3069
		}
3070
	}
3071

    
3072
	fclose($fd_set);
3073

    
3074
	/* Making sure regulatory settings have actually changed
3075
	 * before applying, because changing them requires bringing
3076
	 * down all wireless networks on the interface. */
3077
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3078
	$ifconfig_str = implode($output);
3079
	unset($output);
3080
	$reg_changing = false;
3081

    
3082
	/* special case for the debug country code */
3083
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3084
		$reg_changing = true;
3085
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3086
		$reg_changing = true;
3087
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3088
		$reg_changing = true;
3089
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3090
		$reg_changing = true;
3091
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3092
		$reg_changing = true;
3093
	}
3094

    
3095
	if ($reg_changing) {
3096
		/* set regulatory domain */
3097
		if ($wlcfg['regdomain']) {
3098
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3099
		}
3100

    
3101
		/* set country */
3102
		if ($wlcfg['regcountry']) {
3103
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3104
		}
3105

    
3106
		/* set location */
3107
		if ($wlcfg['reglocation']) {
3108
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3109
		}
3110

    
3111
		$wlregcmd_args = implode(" ", $wlregcmd);
3112

    
3113
		/* build a complete list of the wireless clones for this interface */
3114
		$clone_list = array();
3115
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3116
			$clone_list[] = interface_get_wireless_clone($baseif);
3117
		}
3118
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3119
			foreach ($config['wireless']['clone'] as $clone) {
3120
				if ($clone['if'] == $baseif) {
3121
					$clone_list[] = $clone['cloneif'];
3122
				}
3123
			}
3124
		}
3125

    
3126
		/* find which clones are up and bring them down */
3127
		$clones_up = array();
3128
		foreach ($clone_list as $clone_if) {
3129
			$clone_status = pfSense_get_interface_addresses($clone_if);
3130
			if ($clone_status['status'] == 'up') {
3131
				$clones_up[] = $clone_if;
3132
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3133
			}
3134
		}
3135

    
3136
		/* apply the regulatory settings */
3137
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3138
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3139

    
3140
		/* bring the clones back up that were previously up */
3141
		foreach ($clones_up as $clone_if) {
3142
			interfaces_bring_up($clone_if);
3143

    
3144
			/*
3145
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3146
			 * is in infrastructure mode, and WPA is enabled.
3147
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3148
			 */
3149
			if ($clone_if != $if) {
3150
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3151
				if ((!empty($friendly_if)) &&
3152
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3153
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3154
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3155
				}
3156
			}
3157
		}
3158
	}
3159

    
3160
	/* The mode must be specified in a separate command before ifconfig
3161
	 * will allow the mode and channel at the same time in the next.
3162
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3163
	 */
3164
	if ($wlcfg['mode'] == "hostap") {
3165
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3166
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3167
	}
3168

    
3169
	/* configure wireless */
3170
	$wlcmd_args = implode(" ", $wlcmd);
3171
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3172
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3173
	/* Bring the interface up only after setting up all the other parameters. */
3174
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3175
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3176
	fclose($wlan_setup_log);
3177

    
3178
	unset($wlcmd_args, $wlcmd);
3179

    
3180

    
3181
	sleep(1);
3182
	/* execute hostapd and wpa_supplicant if required in shell */
3183
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3184

    
3185
	return 0;
3186

    
3187
}
3188

    
3189
function kill_hostapd($interface) {
3190
	global $g;
3191

    
3192
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3193
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3194
	}
3195
}
3196

    
3197
function kill_wpasupplicant($interface) {
3198
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3199
}
3200

    
3201
function find_dhclient_process($interface) {
3202
	if ($interface) {
3203
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3204
	} else {
3205
		$pid = 0;
3206
	}
3207

    
3208
	return intval($pid);
3209
}
3210

    
3211
function kill_dhclient_process($interface) {
3212
	if (empty($interface) || !does_interface_exist($interface)) {
3213
		return;
3214
	}
3215

    
3216
	$i = 0;
3217
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3218
		/* 3rd time make it die for sure */
3219
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3220
		posix_kill($pid, $sig);
3221
		sleep(1);
3222
		$i++;
3223
	}
3224
	unset($i);
3225
}
3226

    
3227
function find_dhcp6c_process($interface) {
3228
	global $g;
3229

    
3230
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3231
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3232
	} else {
3233
		return(false);
3234
	}
3235

    
3236
	return intval($pid);
3237
}
3238

    
3239
function kill_dhcp6client_process($interface, $force, $release = false) {
3240
	global $g;
3241

    
3242
	$i = 0;
3243

    
3244
	/*
3245
	Beware of the following: Reason, the interface may be down, but
3246
	dhcp6c may still be running, it just complains it cannot send
3247
	and carries on. Commented out as will stop the call to kill.
3248
	
3249
	if (empty($interface) || !does_interface_exist($interface)) {
3250
		return;
3251
	}
3252
	*/
3253

    
3254
	/*********** Notes on signals for dhcp6c and this function *************
3255

    
3256
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3257
	a release and waiting for the response that never comes.
3258
	So we need to tell it that the interface is down and to just die quickly
3259
	otherwise a new client may launch and we have duplicate proceses.
3260
	In this case use SIGUSR1.
3261
	 
3262
	If we want to exit normally obeying the no release flag then use SIGTERM.
3263
	If we want to exit with a release overiding the no release flag then
3264
	use SIGUSR2.
3265

    
3266
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3267
	exit quickly without sending release signals.
3268

    
3269
	If $Force is set to false and $release is also set to false dhcp6c will
3270
	follow the no-release flag.
3271

    
3272
	If $Force is set to false and $release is true then dhcp6c will send a 
3273
	release regardless of the no-release flag.
3274
	***********************************************************************/
3275

    
3276
	if ($force == true) {
3277
		$psig=SIGUSR1;
3278
	} else if ($release == false) {
3279
		$psig=SIGTERM;
3280
	} else {
3281
		$psig=SIGUSR2;
3282
	}
3283

    
3284
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3285
		/* 3rd time make it die for sure */
3286
		$sig = ($i == 2 ? SIGKILL : $psig);
3287
		posix_kill($pid, $sig); 
3288
		sleep(1);
3289
		$i++;
3290
	}
3291
	/* Clear the RTSOLD script created lock & tidy up */
3292
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3293
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
3294
}
3295
function reset_dhcp6client_process($interface) {
3296
	
3297
	$pid = find_dhcp6c_process($interface);
3298
	
3299
	if($pid != 0) {
3300
		posix_kill($pid, SIGHUP);
3301
	}
3302
}
3303

    
3304
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3305
	global $g;
3306

    
3307
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3308
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3309

    
3310
	/*
3311
	 * Only run this if the lock does not exist. In theory the lock being
3312
	 * there in this mode means the user has selected dhcp6withoutRA while
3313
	 * a session is active in the other mode.
3314
	 *
3315
	 * It should not happen as the process should have been killed and the
3316
	 * lock deleted.
3317
	 */
3318
	 
3319
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
3320
		kill_dhcp6client_process($interface, true);
3321
		/* Lock it to avoid multiple runs */
3322
		touch("/tmp/dhcp6c_{$interface}_lock");
3323
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3324
		    "{$noreleaseOption} " .
3325
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
3326
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
3327
		    $interface);
3328
		log_error(sprintf(gettext(
3329
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
3330
		    $interface));
3331
	}
3332
}
3333

    
3334
function interface_virtual_create($interface) {
3335
	global $config;
3336

    
3337
	if (interface_is_vlan($interface) != NULL) {
3338
		interfaces_vlan_configure($interface);
3339
	} else if (substr($interface, 0, 3) == "gre") {
3340
		interfaces_gre_configure(0, $interface);
3341
	} else if (substr($interface, 0, 3) == "gif") {
3342
		interfaces_gif_configure(0, $interface);
3343
	} else if (substr($interface, 0, 5) == "ovpns") {
3344
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3345
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3346
				if ($interface == "ovpns{$server['vpnid']}") {
3347
					if (!function_exists('openvpn_resync')) {
3348
						require_once('openvpn.inc');
3349
					}
3350
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3351
					openvpn_resync('server', $server);
3352
				}
3353
			}
3354
			unset($server);
3355
		}
3356
	} else if (substr($interface, 0, 5) == "ovpnc") {
3357
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3358
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3359
				if ($interface == "ovpnc{$client['vpnid']}") {
3360
					if (!function_exists('openvpn_resync')) {
3361
						require_once('openvpn.inc');
3362
					}
3363
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3364
					openvpn_resync('client', $client);
3365
				}
3366
			}
3367
			unset($client);
3368
		}
3369
	} else if (substr($interface, 0, 4) == "lagg") {
3370
		interfaces_lagg_configure($interface);
3371
	} else if (substr($interface, 0, 6) == "bridge") {
3372
		interfaces_bridge_configure(0, $interface);
3373
	}
3374
}
3375

    
3376
function interface_vlan_mtu_configured($iface) {
3377
	global $config;
3378

    
3379
	$mtu = 0;
3380
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3381
		foreach ($config['vlans']['vlan'] as $vlan) {
3382

    
3383
			if ($vlan['vlanif'] != $iface)
3384
				continue;
3385

    
3386
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3387
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3388
				/* VLAN MTU */
3389
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3390
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3391
				/* Parent MTU */
3392
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3393
			}
3394
		}
3395
	}
3396

    
3397
	return $mtu;
3398
}
3399

    
3400
function interface_mtu_wanted_for_pppoe($realif) {
3401
	global $config;
3402

    
3403
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3404
		return 0;
3405

    
3406
	$mtu = 0;
3407
	foreach ($config['ppps']['ppp'] as $ppp) {
3408
		if ($ppp['type'] != "pppoe") {
3409
			continue;
3410
		}
3411

    
3412
		$mtus = array();
3413
		if (!empty($ppp['mtu'])) {
3414
			$mtus = explode(',', $ppp['mtu']);
3415
		}
3416
		$ports = explode(',', $ppp['ports']);
3417

    
3418
		foreach ($ports as $pid => $port) {
3419
			$parentifa = get_parent_interface($port);
3420
			$parentif = $parentifa[0];
3421
			if ($parentif != $realif)
3422
				continue;
3423

    
3424
			// there is an MTU configured on the port in question
3425
			if (!empty($mtus[$pid])) {
3426
				$mtu = intval($mtus[$pid]) + 8;
3427
			// or use the MTU configured on the interface ...
3428
			} elseif (is_array($config['interfaces'])) {
3429
				foreach ($config['interfaces'] as $interface) {
3430
					if ($interface['if'] == $ppp['if'] &&
3431
					    !empty($interface['mtu'])) {
3432
						$mtu = intval($interface['mtu']) + 8;
3433
						break;
3434
					}
3435
				}
3436
			}
3437
		}
3438
	}
3439

    
3440
	return $mtu;
3441
}
3442

    
3443
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3444
	global $config, $g;
3445
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3446
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3447

    
3448
	$wancfg = $config['interfaces'][$interface];
3449

    
3450
	if (!isset($wancfg['enable'])) {
3451
		return;
3452
	}
3453

    
3454
	$realif = get_real_interface($interface);
3455
	$realhwif_array = get_parent_interface($interface);
3456
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3457
	$realhwif = $realhwif_array[0];
3458

    
3459
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3460
		/* remove all IPv4 and IPv6 addresses */
3461
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3462
		if (is_array($tmpifaces)) {
3463
			foreach ($tmpifaces as $tmpiface) {
3464
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3465
					if (!is_linklocal($tmpiface)) {
3466
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3467
					}
3468
				} else {
3469
					if (is_subnetv4($tmpiface)) {
3470
						$tmpip = explode('/', $tmpiface);
3471
						$tmpip = $tmpip[0];
3472
					} else {
3473
						$tmpip = $tmpiface;
3474
					}
3475
					pfSense_interface_deladdress($realif, $tmpip);
3476
				}
3477
			}
3478
		}
3479

    
3480
		/* only bring down the interface when both v4 and v6 are set to NONE */
3481
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3482
			interface_bring_down($interface);
3483
		}
3484
	}
3485

    
3486
	$interface_to_check = $realif;
3487
	if (interface_isppp_type($interface)) {
3488
		$interface_to_check = $realhwif;
3489
	}
3490

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

    
3496
	/* Disable Accepting router advertisements unless specifically requested */
3497
	if ($g['debug']) {
3498
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3499
	}
3500
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
3501
	{
3502
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3503
	}
3504
	/* wireless configuration? */
3505
	if (is_array($wancfg['wireless']) && !$linkupevent) {
3506
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3507
	}
3508

    
3509
	/* Get the vendor MAC.  Use source dependent upon whether or not booting. */
3510
	$current_mac = get_interface_mac($realhwif);
3511
	if (platform_booting()) {
3512
		$vendor_mac = $current_mac;
3513
	} else {
3514
		$vendor_mac = get_interface_vendor_mac($realhwif);
3515
	}
3516
	$mac_addr = $wancfg['spoofmac'] ?: $vendor_mac;
3517
	/*
3518
	 * Don't try to reapply the MAC if it's already applied.
3519
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3520
	 * the interface config again, which attempts to apply the MAC again,
3521
	 * which cycles the link again...
3522
	 */
3523
	if (!empty($mac_addr) && ($mac_addr != $current_mac)) {
3524
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3525
			" link " . escapeshellarg($mac_addr));
3526
	} elseif ($current_mac == "ff:ff:ff:ff:ff:ff") {
3527
		/*   this is not a valid mac address.  generate a
3528
		 *   temporary mac address so the machine can get online.
3529
		 */
3530
		echo gettext("Generating new MAC address.");
3531
		$random_mac = generate_random_mac_address();
3532
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3533
			" link " . escapeshellarg($random_mac));
3534
		$wancfg['spoofmac'] = $random_mac;
3535
		write_config(sprintf(gettext('The invalid MAC address (ff:ff:ff:ff:ff:ff) on interface %1$s has been automatically replaced with %2$s'), $realif, $random_mac));
3536
		file_notice("MAC Address altered", sprintf(gettext('The invalid MAC address (ff:ff:ff:ff:ff:ff) on interface %1$s has been automatically replaced with %2$s'), $realif, $random_mac), "Interfaces");
3537
	}
3538

    
3539
	/* media */
3540
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3541
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3542
		if ($wancfg['media']) {
3543
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3544
		}
3545
		if ($wancfg['mediaopt']) {
3546
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3547
		}
3548
		mwexec($cmd);
3549
	}
3550

    
3551
	/* Apply hw offloading policies as configured */
3552
	enable_hardware_offloading($interface);
3553

    
3554
	/* invalidate interface/ip/sn cache */
3555
	get_interface_arr(true);
3556
	unset($interface_ip_arr_cache[$realif]);
3557
	unset($interface_sn_arr_cache[$realif]);
3558
	unset($interface_ipv6_arr_cache[$realif]);
3559
	unset($interface_snv6_arr_cache[$realif]);
3560

    
3561
	$tunnelif = substr($realif, 0, 3);
3562

    
3563
	$mtuif = $realif;
3564
	$mtuhwif = $realhwif;
3565

    
3566
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3567
	if (interface_isppp_type($interface)) {
3568
		$mtuif = $realhwif;
3569
		$mtuhwif_array = get_parent_interface($mtuif);
3570
		$mtuhwif = $mtuhwif_array[0];
3571
	}
3572

    
3573
	$wantedmtu = 0;
3574
	if (is_array($config['interfaces'])) {
3575
		foreach ($config['interfaces'] as $tmpinterface) {
3576
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3577
				$wantedmtu = $tmpinterface['mtu'];
3578
				break;
3579
			}
3580
		}
3581
	}
3582

    
3583
	/* MTU is not specified for interface, try the pppoe settings. */
3584
	if ($wantedmtu == 0) {
3585
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3586
	}
3587
	if ($wantedmtu == 0 && interface_is_vlan($mtuif) != NULL && interface_isppp_type($interface)) {
3588
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3589
	}
3590

    
3591
	/* Set the MTU to 1500 if no explicit MTU configured. */
3592
	if ($wantedmtu == 0) {
3593
		$wantedmtu = 1500; /* Default */
3594
	}
3595

    
3596
	if (interface_is_vlan($mtuif) != NULL) {
3597
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3598
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3599
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3600
			if ($wancfg['mtu'] > $parentmtu) {
3601
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3602
			}
3603
		}
3604

    
3605
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3606

    
3607
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3608
			$configuredmtu = $parentmtu;
3609
		if ($configuredmtu != 0)
3610
			$mtu = $configuredmtu;
3611
		else
3612
			$mtu = $wantedmtu;
3613

    
3614
		/* Set the parent MTU. */
3615
		if (get_interface_mtu($mtuhwif) < $mtu)
3616
			set_interface_mtu($mtuhwif, $mtu);
3617
		/* Set the VLAN MTU. */
3618
		if (get_interface_mtu($mtuif) != $mtu)
3619
			set_interface_mtu($mtuif, $mtu);
3620
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3621
		/* LAGG interface must be destroyed and re-created to change MTU */
3622
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3623
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3624
				foreach ($config['laggs']['lagg'] as $lagg) {
3625
					if ($lagg['laggif'] == $mtuif) {
3626
						interface_lagg_configure($lagg);
3627
						break;
3628
					}
3629
				}
3630
			}
3631
		}
3632
	} else {
3633
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3634
			pfSense_interface_mtu($mtuif, $wantedmtu);
3635
		}
3636
	}
3637
	/* XXX: What about gre/gif/.. ? */
3638

    
3639
	if (does_interface_exist($wancfg['if'])) {
3640
		interfaces_bring_up($wancfg['if']);
3641
	}
3642

    
3643
	switch ($wancfg['ipaddr']) {
3644
		case 'dhcp':
3645
			interface_dhcp_configure($interface);
3646
			break;
3647
		case 'pppoe':
3648
		case 'l2tp':
3649
		case 'pptp':
3650
		case 'ppp':
3651
			interface_ppps_configure($interface);
3652
			break;
3653
		default:
3654
			/* XXX: Kludge for now related to #3280 */
3655
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3656
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3657
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3658
				}
3659
			}
3660
			break;
3661
	}
3662

    
3663
	switch ($wancfg['ipaddrv6']) {
3664
		case 'slaac':
3665
		case 'dhcp6':
3666
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
3667
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
3668
			// handles all non-PPP connections with 'dhcp6usev4iface' set
3669
			/* Remove the check file. Should not be there but just in case */
3670
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
3671
			log_error(gettext("calling interface_dhcpv6_configure."));																																		  
3672
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
3673
				interface_dhcpv6_configure($interface, $wancfg);
3674
			}
3675
			break;
3676
		case '6rd':
3677
			interface_6rd_configure($interface, $wancfg);
3678
			break;
3679
		case '6to4':
3680
			interface_6to4_configure($interface, $wancfg);
3681
			break;
3682
		case 'track6':
3683
			interface_track6_configure($interface, $wancfg, $linkupevent);
3684
			break;
3685
		default:
3686
			/* XXX: Kludge for now related to #3280 */
3687
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3688
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3689
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3690
					// FIXME: Add IPv6 Support to the pfSense module
3691
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3692
				}
3693
			}
3694
			break;
3695
	}
3696

    
3697
	interface_netgraph_needed($interface);
3698

    
3699
	if (!platform_booting()) {
3700
		link_interface_to_vips($interface, "update");
3701

    
3702
		if ($tunnelif != 'gre') {
3703
			unset($gre);
3704
			$gre = link_interface_to_gre($interface);
3705
			if (!empty($gre)) {
3706
				array_walk($gre, 'interface_gre_configure');
3707
			}
3708
		}
3709

    
3710
		if ($tunnelif != 'gif') {
3711
			unset($gif);
3712
			$gif = link_interface_to_gif ($interface);
3713
			if (!empty($gif)) {
3714
				array_walk($gif, 'interface_gif_configure');
3715
			}
3716
		}
3717

    
3718
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3719
			unset($bridgetmp);
3720
			$bridgetmp = link_interface_to_bridge($interface);
3721
			if (!empty($bridgetmp)) {
3722
				interface_bridge_add_member($bridgetmp, $realif);
3723
			}
3724
		}
3725

    
3726
		$grouptmp = link_interface_to_group($interface);
3727
		if (!empty($grouptmp)) {
3728
			array_walk($grouptmp, 'interface_group_add_member');
3729
		}
3730

    
3731
		if ($interface == "lan") {
3732
			/* make new hosts file */
3733
			system_hosts_generate();
3734
		}
3735

    
3736
		if ($reloadall == true) {
3737

    
3738
			/* reconfigure static routes (kernel may have deleted them) */
3739
			system_routing_configure($interface);
3740

    
3741
			/* reload ipsec tunnels */
3742
			send_event("service reload ipsecdns");
3743

    
3744
			if (isset($config['dnsmasq']['enable'])) {
3745
				services_dnsmasq_configure();
3746
			}
3747

    
3748
			if (isset($config['unbound']['enable'])) {
3749
				services_unbound_configure();
3750
			}
3751

    
3752
			/* update dyndns */
3753
			send_event("service reload dyndns {$interface}");
3754

    
3755
			/* reload captive portal */
3756
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3757
				require_once('captiveportal.inc');
3758
			}
3759
			captiveportal_init_rules_byinterface($interface);
3760
		}
3761
	}
3762

    
3763
	interfaces_staticarp_configure($interface);
3764
	return 0;
3765
}
3766

    
3767
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3768
	global $config, $g;
3769

    
3770
	if (!is_array($wancfg)) {
3771
		return;
3772
	}
3773

    
3774
	if (!isset($wancfg['enable'])) {
3775
		return;
3776
	}
3777

    
3778
	/* If the interface is not configured via another, exit */
3779
	if (empty($wancfg['track6-interface'])) {
3780
		return;
3781
	}
3782

    
3783
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3784
	$realif = get_real_interface($interface);
3785
	$linklocal = find_interface_ipv6_ll($realif, true);
3786
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
3787
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3788
	}
3789
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3790
	/* XXX: Probably should remove? */
3791
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3792

    
3793
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3794
	if (!isset($trackcfg['enable'])) {
3795
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
3796
		return;
3797
	}
3798

    
3799
	switch ($trackcfg['ipaddrv6']) {
3800
		case "6to4":
3801
			if ($g['debug']) {
3802
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3803
			}
3804
			interface_track6_6to4_configure($interface, $wancfg);
3805
			break;
3806
		case "6rd":
3807
			if ($g['debug']) {
3808
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3809
			}
3810
			interface_track6_6rd_configure($interface, $wancfg);
3811
			break;
3812
		case "dhcp6":
3813
			if ($linkupevent == true) {
3814
				/*
3815
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
3816
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3817
				 *
3818
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
3819
				 */
3820
				$parentrealif = get_real_interface($wancfg['track6-interface']);
3821
				$pidv6 = find_dhcp6c_process($parentrealif);
3822
				if ($pidv6) {
3823
					posix_kill($pidv6, SIGHUP);
3824
				}
3825
			}
3826
			break;
3827
	}
3828

    
3829
	if ($linkupevent == false && !platform_booting()) {
3830
		if (!function_exists('services_dhcpd_configure')) {
3831
			require_once("services.inc");
3832
		}
3833

    
3834
		/* restart dns servers (defering dhcpd reload) */
3835
		if (isset($config['unbound']['enable'])) {
3836
			services_unbound_configure(false);
3837
		}
3838
		if (isset($config['dnsmasq']['enable'])) {
3839
			services_dnsmasq_configure(false);
3840
		}
3841

    
3842
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
3843
		services_dhcpd_configure("inet6");
3844
	}
3845

    
3846
	return 0;
3847
}
3848

    
3849
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3850
	global $config, $g;
3851
	global $interface_ipv6_arr_cache;
3852
	global $interface_snv6_arr_cache;
3853

    
3854
	if (!is_array($lancfg)) {
3855
		return;
3856
	}
3857

    
3858
	/* If the interface is not configured via another, exit */
3859
	if (empty($lancfg['track6-interface'])) {
3860
		return;
3861
	}
3862

    
3863
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3864
	if (empty($wancfg)) {
3865
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3866
		return;
3867
	}
3868

    
3869
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3870
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3871
		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']));
3872
		return;
3873
	}
3874
	$hexwanv4 = return_hex_ipv4($ip4address);
3875

    
3876
	/* create the long prefix notation for math, save the prefix length */
3877
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3878
	$rd6prefixlen = $rd6prefix[1];
3879
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3880

    
3881
	/* binary presentation of the prefix for all 128 bits. */
3882
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3883

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

    
3889
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3890
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3891
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3892
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3893
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3894
	/* fill the rest out with zeros */
3895
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3896

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

    
3900
	$lanif = get_real_interface($interface);
3901
	$oip = find_interface_ipv6($lanif);
3902
	if (is_ipaddrv6($oip)) {
3903
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3904
	}
3905
	unset($interface_ipv6_arr_cache[$lanif]);
3906
	unset($interface_snv6_arr_cache[$lanif]);
3907
	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));
3908
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3909

    
3910
	return 0;
3911
}
3912

    
3913
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3914
	global $config, $g;
3915
	global $interface_ipv6_arr_cache;
3916
	global $interface_snv6_arr_cache;
3917

    
3918
	if (!is_array($lancfg)) {
3919
		return;
3920
	}
3921

    
3922
	/* If the interface is not configured via another, exit */
3923
	if (empty($lancfg['track6-interface'])) {
3924
		return;
3925
	}
3926

    
3927
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3928
	if (empty($wancfg)) {
3929
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3930
		return;
3931
	}
3932

    
3933
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3934
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3935
		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']));
3936
		return;
3937
	}
3938
	$hexwanv4 = return_hex_ipv4($ip4address);
3939

    
3940
	/* create the long prefix notation for math, save the prefix length */
3941
	$sixto4prefix = "2002::";
3942
	$sixto4prefixlen = 16;
3943
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3944

    
3945
	/* binary presentation of the prefix for all 128 bits. */
3946
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3947

    
3948
	/* just save the left prefix length bits */
3949
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3950
	/* add the v4 address */
3951
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3952
	/* add the custom prefix id */
3953
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3954
	/* fill the rest out with zeros */
3955
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3956

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

    
3960
	$lanif = get_real_interface($interface);
3961
	$oip = find_interface_ipv6($lanif);
3962
	if (is_ipaddrv6($oip)) {
3963
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3964
	}
3965
	unset($interface_ipv6_arr_cache[$lanif]);
3966
	unset($interface_snv6_arr_cache[$lanif]);
3967
	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));
3968
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3969

    
3970
	return 0;
3971
}
3972

    
3973
function interface_6rd_configure($interface = "wan", $wancfg) {
3974
	global $config, $g;
3975

    
3976
	/* because this is a tunnel interface we can only function
3977
	 *	with a public IPv4 address on the interface */
3978

    
3979
	if (!is_array($wancfg)) {
3980
		return;
3981
	}
3982

    
3983
	if (!is_module_loaded('if_stf.ko')) {
3984
		mwexec('/sbin/kldload if_stf.ko');
3985
	}
3986

    
3987
	$wanif = get_real_interface($interface);
3988
	$ip4address = find_interface_ip($wanif);
3989
	if (!is_ipaddrv4($ip4address)) {
3990
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3991
		return false;
3992
	}
3993
	$hexwanv4 = return_hex_ipv4($ip4address);
3994

    
3995
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3996
		$wancfg['prefix-6rd-v4plen'] = 0;
3997
	}
3998

    
3999
	/* create the long prefix notation for math, save the prefix length */
4000
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4001
	$rd6prefixlen = $rd6prefix[1];
4002
	$brgw = explode('.', $wancfg['gateway-6rd']);
4003
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4004
	$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);
4005
	if (strlen($rd6brgw) < 128) {
4006
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4007
	}
4008
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4009
	unset($brgw);
4010
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4011

    
4012
	/* binary presentation of the prefix for all 128 bits. */
4013
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4014

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

    
4022
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4023
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4024

    
4025

    
4026
	/* XXX: need to extend to support variable prefix size for v4 */
4027
	$stfiface = "{$interface}_stf";
4028
	if (does_interface_exist($stfiface)) {
4029
		pfSense_interface_destroy($stfiface);
4030
	}
4031
	$tmpstfiface = pfSense_interface_create("stf");
4032
	pfSense_interface_rename($tmpstfiface, $stfiface);
4033
	pfSense_interface_flags($stfiface, IFF_LINK2);
4034
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4035
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4036
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4037
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4038
	}
4039
	if ($g['debug']) {
4040
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4041
	}
4042

    
4043
	/* write out a default router file */
4044
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4045
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4046

    
4047
	$ip4gateway = get_interface_gateway($interface);
4048
	if (is_ipaddrv4($ip4gateway)) {
4049
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
4050
	}
4051

    
4052
	/* configure dependent interfaces */
4053
	if (!platform_booting()) {
4054
		link_interface_to_track6($interface, "update");
4055
	}
4056

    
4057
	return 0;
4058
}
4059

    
4060
function interface_6to4_configure($interface = "wan", $wancfg) {
4061
	global $config, $g;
4062

    
4063
	/* because this is a tunnel interface we can only function
4064
	 *	with a public IPv4 address on the interface */
4065

    
4066
	if (!is_array($wancfg)) {
4067
		return;
4068
	}
4069

    
4070
	$wanif = get_real_interface($interface);
4071
	$ip4address = find_interface_ip($wanif);
4072
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4073
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4074
		return false;
4075
	}
4076

    
4077
	/* create the long prefix notation for math, save the prefix length */
4078
	$stfprefixlen = 16;
4079
	$stfprefix = Net_IPv6::uncompress("2002::");
4080
	$stfarr = explode(":", $stfprefix);
4081
	$v4prefixlen = "0";
4082

    
4083
	/* we need the hex form of the interface IPv4 address */
4084
	$ip4arr = explode(".", $ip4address);
4085
	$hexwanv4 = "";
4086
	foreach ($ip4arr as $octet) {
4087
		$hexwanv4 .= sprintf("%02x", $octet);
4088
	}
4089

    
4090
	/* we need the hex form of the broker IPv4 address */
4091
	$ip4arr = explode(".", "192.88.99.1");
4092
	$hexbrv4 = "";
4093
	foreach ($ip4arr as $octet) {
4094
		$hexbrv4 .= sprintf("%02x", $octet);
4095
	}
4096

    
4097
	/* binary presentation of the prefix for all 128 bits. */
4098
	$stfprefixbin = "";
4099
	foreach ($stfarr as $element) {
4100
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4101
	}
4102
	/* just save the left prefix length bits */
4103
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4104

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

    
4109
	/* for the local subnet too. */
4110
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4111
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4112

    
4113
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4114
	$stfbrarr = array();
4115
	$stfbrbinarr = array();
4116
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4117
	foreach ($stfbrbinarr as $bin) {
4118
		$stfbrarr[] = dechex(bindec($bin));
4119
	}
4120
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4121

    
4122
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4123
	$stflanarr = array();
4124
	$stflanbinarr = array();
4125
	$stflanbinarr = str_split($stflanbin, 16);
4126
	foreach ($stflanbinarr as $bin) {
4127
		$stflanarr[] = dechex(bindec($bin));
4128
	}
4129
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4130
	$stflanarr[7] = 1;
4131
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4132

    
4133
	/* setup the stf interface */
4134
	if (!is_module_loaded("if_stf")) {
4135
		mwexec("/sbin/kldload if_stf.ko");
4136
	}
4137
	$stfiface = "{$interface}_stf";
4138
	if (does_interface_exist($stfiface)) {
4139
		pfSense_interface_destroy($stfiface);
4140
	}
4141
	$tmpstfiface = pfSense_interface_create("stf");
4142
	pfSense_interface_rename($tmpstfiface, $stfiface);
4143
	pfSense_interface_flags($stfiface, IFF_LINK2);
4144
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4145

    
4146
	if ($g['debug']) {
4147
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4148
	}
4149

    
4150
	/* write out a default router file */
4151
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4152
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4153

    
4154
	$ip4gateway = get_interface_gateway($interface);
4155
	if (is_ipaddrv4($ip4gateway)) {
4156
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
4157
	}
4158

    
4159
	if (!platform_booting()) {
4160
		link_interface_to_track6($interface, "update");
4161
	}
4162

    
4163
	return 0;
4164
}
4165

    
4166
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4167
	global $config, $g;
4168

    
4169
	if (!is_array($wancfg)) {
4170
		return;
4171
	}
4172

    
4173
	$wanif = get_real_interface($interface, "inet6");
4174
	$dhcp6cconf = "";
4175

    
4176
	if (!empty($config['system']['global-v6duid'])) {
4177
		// Write the DUID file
4178
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4179
		    log_error(gettext("Failed to write user DUID file!"));
4180
		}
4181
	}
4182
	
4183
	/* accept router advertisements for this interface                 */
4184
	/* Moved to early in the function as sometimes interface not ready */
4185
	/* RTSOLD fails as interface does not accept .....                 */
4186

    
4187
	log_error("Accept router advertisements on interface {$wanif} ");
4188
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4189

    
4190
	if ($wancfg['adv_dhcp6_config_file_override']) {
4191
		// DHCP6 Config File Override
4192
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4193
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4194
		// DHCP6 Config File Advanced
4195
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4196
	} else {
4197
		// DHCP6 Config File Basic
4198
		$dhcp6cconf .= "interface {$wanif} {\n";
4199

    
4200
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4201
		if ($wancfg['ipaddrv6'] == "slaac") {
4202
			$dhcp6cconf .= "\tinformation-only;\n";
4203
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4204
			$dhcp6cconf .= "\trequest domain-name;\n";
4205
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4206
			$dhcp6cconf .= "};\n";
4207
		} else {
4208
			$trackiflist = array();
4209
			$iflist = link_interface_to_track6($interface);
4210
			foreach ($iflist as $ifname => $ifcfg) {
4211
				if (is_numeric($ifcfg['track6-prefix-id'])) {
4212
					$trackiflist[$ifname] = $ifcfg;
4213
				}
4214
			}
4215

    
4216
			/* skip address request if this is set */
4217
			if (!isset($wancfg['dhcp6prefixonly'])) {
4218
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4219
			}
4220
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4221
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4222
			}
4223

    
4224
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4225
			$dhcp6cconf .= "\trequest domain-name;\n";
4226

    
4227
			/*
4228
			 * dhcp6c will run different scripts depending on
4229
			 * whether dhcpwithoutra is set or unset.
4230
			 */
4231
			if (isset($wancfg['dhcp6withoutra'])) {
4232
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4233
			} else {
4234
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4235
			}
4236
			$dhcp6cconf .= "};\n";
4237

    
4238
			if (!isset($wancfg['dhcp6prefixonly'])) {
4239
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4240
			}
4241

    
4242
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4243
				/* Setup the prefix delegation */
4244
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4245
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4246
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4247
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4248
				}
4249
				foreach ($trackiflist as $friendly => $ifcfg) {
4250
					if ($g['debug']) {
4251
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4252
					}
4253
					$realif = get_real_interface($friendly);
4254
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4255
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4256
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4257
					$dhcp6cconf .= "\t};\n";
4258
				}
4259
				unset($preflen, $iflist, $ifcfg, $ifname);
4260
				$dhcp6cconf .= "};\n";
4261
			}
4262
			unset($trackiflist);
4263
		}
4264
	}
4265

    
4266
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4267
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4268

    
4269
	/* wide-dhcp6c works for now. */
4270
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4271
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4272
		unset($dhcp6cconf);
4273
		return 1;
4274
	}
4275
	unset($dhcp6cconf);
4276

    
4277
	/*************** Script Debug Logging ***************************
4278
	Both dhcp6 scripts now have a logging message built in.
4279
	These logging messages ONLY appear if dhcp6c debug logging is set.
4280
	The logging messages appear in the dhcp section of the logs,
4281
	not in system.
4282

    
4283
	These scripts now also take advantage of the REASON= env vars 
4284
	supplied by dhcp6c.
4285
	****************************************************************/
4286
	
4287
	/* Script create for dhcp6withoutRA mode */
4288
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4289
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4290
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4291
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4292
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4293
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4294
	// Need to pass params to  the final script
4295
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4296
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4297
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4298
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4299
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
4300
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
4301
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4302
	if ($debugOption == '-D') {
4303
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4304
	}
4305
	$dhcp6cscriptwithoutra .= ";;\n";
4306
	$dhcp6cscriptwithoutra .= "REBIND)\n";
4307
	if ($debugOption == '-D') {
4308
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4309
	}
4310
	$dhcp6cscriptwithoutra .= ";;\n";
4311
	if (isset($wancfg['dhcp6norelease'])) {
4312
		$dhcp6cscriptwithoutra .= "EXIT)\n";
4313
	} else {
4314
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
4315
	}
4316
	if ($debugOption == '-D') {
4317
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4318
	}
4319
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4320
	$dhcp6cscriptwithoutra .= ";;\n";
4321
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
4322
	if ($debugOption == '-D') {
4323
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4324
	}
4325
	$dhcp6cscriptwithoutra .= "esac\n";
4326
	if (!@file_put_contents(
4327
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4328
	    $dhcp6cscriptwithoutra)) {
4329
		printf("Error: cannot open " .
4330
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4331
		    "interface_dhcpv6_configure() for writing.\n");
4332
		unset($dhcp6cscriptwithoutra);
4333
		return 1;
4334
	}
4335

    
4336
	unset($dhcp6cscriptwithoutra);
4337
	@chmod(
4338
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4339
	    0755);
4340

    
4341
	/*
4342
	 * Dual mode wan_dhcp6c script with variations depending on node
4343
	 * dhcp6 will run the wan ipv6 configure
4344
	 */
4345
	$dhcp6cscript  = "#!/bin/sh\n";
4346
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4347
	if (!isset($wancfg['dhcp6withoutra'])) {
4348
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4349
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4350
		$dhcp6cscript .= "case \$REASON in\n";
4351
		$dhcp6cscript .= "REQUEST)\n";
4352
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4353
		if ($debugOption == '-D') {
4354
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4355
		}
4356
		$dhcp6cscript .= ";;\n";
4357
		$dhcp6cscript .= "REBIND)\n";
4358
		if ($debugOption == '-D') {
4359
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4360
		}
4361
		$dhcp6cscript .= ";;\n";
4362
		if (isset($wancfg['dhcp6norelease'])) {
4363
			$dhcp6cscript .= "EXIT)\n";
4364
		} else {
4365
			$dhcp6cscript .= "RELEASE)\n";
4366
		}
4367
		if ($debugOption == '-D') {
4368
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4369
		}
4370
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4371
		$dhcp6cscript .= ";;\n";
4372
		$dhcp6cscript .= "RENEW|INFO)\n";
4373
		if ($debugOption == '-D') {
4374
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4375
		}
4376
		$dhcp6cscript .= "esac\n";
4377
	} else {
4378
		// Need to get the paramaters from the dhcp6cwithoutRA run
4379
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
4380
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
4381
		$dhcp6cscript .= "/bin/sleep 1\n";
4382
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4383
	}
4384

    
4385
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4386
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4387
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4388
		unset($dhcp6cscript);
4389
		return 1;
4390
	}
4391
	unset($dhcp6cscript);
4392
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4393

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

    
4400
	/* non ipoe Process */
4401
	if (!isset($wancfg['dhcp6withoutra'])) {
4402
		/*
4403
		 * We only want this script to run once, and if it runs twice
4404
		 * then do not launch dhcp6c again, this only happens if
4405
		 * dhcpwithoutra is not set.
4406
		 *
4407
		 * Check for a lock file, trying to prevent multiple instances
4408
		 * of dhcp6c being launched
4409
		 */
4410
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
4411
		/*
4412
		 * Create the lock file, trying to prevent multiple instances
4413
		 * of dhcp6c being launched
4414
		 */
4415
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
4416
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
4417
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4418
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4419
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
4420
		$rtsoldscript .= "\tfi\n";
4421
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
4422
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
4423
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4424
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4425
		$rtsoldscript .= "else\n";
4426
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
4427
		$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c_{$wanif}.pid\")\n";
4428
		$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
4429
		$rtsoldscript .= "fi\n";
4430
	} else {
4431
		/*
4432
		 * The script needs to run in dhcp6withoutra mode as RA may
4433
		 * not have been received, or there can be a delay with
4434
		 * certain ISPs
4435
		 */
4436
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
4437
		$rtsoldscript .= "/bin/sleep 1\n";
4438
	}
4439
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4440
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4441
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4442
		unset($rtsoldscript);
4443
		return 1;
4444
	}
4445
	unset($rtsoldscript);
4446
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4447

    
4448
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4449
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4450
		log_error("Killing running rtsold process");
4451
		sleep(2);
4452
	}
4453

    
4454
	if (isset($wancfg['dhcp6withoutra'])) {
4455
		/*
4456
		 * Start dhcp6c here if we don't want to wait for ra - calls
4457
		 * seperate function
4458
		 *
4459
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
4460
		 * will then run the configure on receipt of the RA.
4461
		 *
4462
		 * Already started. interface_dhcpv6_configure() appears to get
4463
		 * called multiple times.
4464
		 *
4465
		 * Taking the interface down or releasing will kill the client.
4466
		 */
4467
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
4468
		{
4469
			/*
4470
			 * If the interface is being brought up, wait for the
4471
			 * interface to configure accept RA before launching.
4472
			 * Otherwise it is not ready to accept and will fail.
4473
			 */
4474
			sleep(3);
4475
			run_dhcp6client_process($wanif,$interface,$wancfg);
4476
		}
4477
	} else {
4478
		/*
4479
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
4480
		 * ( it does not background, it exits! ) It will launch dhcp6c
4481
		 * if dhcpwihtoutra is not set
4482
		 */
4483
		log_error("Starting rtsold process");
4484
		sleep(2);
4485
		mwexec("/usr/sbin/rtsold -1 " .
4486
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
4487
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
4488
		    $wanif);
4489
	}
4490
	/*
4491
	 * NOTE: will be called from rtsold invoked script
4492
	 * link_interface_to_track6($interface, "update");
4493
	 */
4494

    
4495
	return 0;
4496
}
4497

    
4498
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4499
	global $g;
4500

    
4501
	$send_options = "";
4502
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4503
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4504
		foreach ($options as $option) {
4505
			$send_options .= "\tsend " . trim($option) . ";\n";
4506
		}
4507
	}
4508

    
4509
	$request_options = "";
4510
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4511
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4512
		foreach ($options as $option) {
4513
			$request_options .= "\trequest " . trim($option) . ";\n";
4514
		}
4515
	}
4516

    
4517
	$information_only = "";
4518
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4519
		$information_only = "\tinformation-only;\n";
4520
	}
4521

    
4522
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4523
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4524
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4525
	}
4526

    
4527
	$interface_statement  = "interface";
4528
	$interface_statement .= " {$wanif}";
4529
	$interface_statement .= " {\n";
4530
	$interface_statement .= "$send_options";
4531
	$interface_statement .= "$request_options";
4532
	$interface_statement .= "$information_only";
4533
	$interface_statement .= "$script";
4534
	$interface_statement .= "};\n";
4535

    
4536
	$id_assoc_statement_address = "";
4537
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4538
		$id_assoc_statement_address .= "id-assoc";
4539
		$id_assoc_statement_address .= " na";
4540
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4541
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4542
		}
4543
		$id_assoc_statement_address .= " { ";
4544

    
4545
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4546
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4547
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4548
			$id_assoc_statement_address .= "\n\taddress";
4549
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4550
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4551
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4552
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4553
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4554
			}
4555
			$id_assoc_statement_address .= ";\n";
4556
		}
4557

    
4558
		$id_assoc_statement_address .= "};\n";
4559
	}
4560

    
4561
	$id_assoc_statement_prefix = "";
4562
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4563
		$id_assoc_statement_prefix .= "id-assoc";
4564
		$id_assoc_statement_prefix .= " pd";
4565
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4566
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4567
		}
4568
		$id_assoc_statement_prefix .= " { ";
4569

    
4570
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4571
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4572
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4573
			$id_assoc_statement_prefix .= "\n\tprefix";
4574
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4575
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4576
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4577
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4578
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4579
			}
4580
			$id_assoc_statement_prefix .= ";";
4581
		}
4582
		
4583
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
4584
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4585
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4586
			$id_assoc_statement_prefix .= " {$realif}";
4587
			$id_assoc_statement_prefix .= " {\n";
4588
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4589
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4590
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4591
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4592
			}
4593
			$id_assoc_statement_prefix .= "\t};";
4594
		}
4595

    
4596
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4597
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4598
			$id_assoc_statement_prefix .= "\n";
4599
		}
4600

    
4601
		$id_assoc_statement_prefix .= "};\n";
4602
	}
4603

    
4604
	$authentication_statement = "";
4605
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4606
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4607
		$authentication_statement .= "authentication";
4608
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4609
		$authentication_statement .= " {\n";
4610
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4611
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4612
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4613
		}
4614
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4615
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4616
		}
4617
		$authentication_statement .= "};\n";
4618
	}
4619

    
4620
	$key_info_statement = "";
4621
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4622
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4623
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4624
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4625
		$key_info_statement .= "keyinfo";
4626
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4627
		$key_info_statement .= " {\n";
4628
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4629
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4630
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4631
		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'])) {
4632
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4633
		}
4634
		$key_info_statement .= "};\n";
4635
	}
4636

    
4637
	$dhcp6cconf  = $interface_statement;
4638
	$dhcp6cconf .= $id_assoc_statement_address;
4639
	$dhcp6cconf .= $id_assoc_statement_prefix;
4640
	$dhcp6cconf .= $authentication_statement;
4641
	$dhcp6cconf .= $key_info_statement;
4642

    
4643
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4644

    
4645
	return $dhcp6cconf;
4646
}
4647

    
4648

    
4649
function DHCP6_Config_File_Override($wancfg, $wanif) {
4650

    
4651
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4652

    
4653
	if ($dhcp6cconf === false) {
4654
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4655
		return '';
4656
	} else {
4657
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4658
	}
4659
}
4660

    
4661

    
4662
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4663

    
4664
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4665

    
4666
	return $dhcp6cconf;
4667
}
4668

    
4669

    
4670
function interface_dhcp_configure($interface = "wan") {
4671
	global $config, $g;
4672

    
4673
	$wancfg = $config['interfaces'][$interface];
4674
	$wanif = $wancfg['if'];
4675
	if (empty($wancfg)) {
4676
		$wancfg = array();
4677
	}
4678

    
4679
	/* generate dhclient_wan.conf */
4680
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4681
	if (!$fd) {
4682
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4683
		return 1;
4684
	}
4685

    
4686
	if ($wancfg['dhcphostname']) {
4687
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4688
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4689
	} else {
4690
		$dhclientconf_hostname = "";
4691
	}
4692

    
4693
	$wanif = get_real_interface($interface);
4694
	if (empty($wanif)) {
4695
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4696
		return 0;
4697
	}
4698
	$dhclientconf = "";
4699

    
4700
	$dhclientconf .= <<<EOD
4701
interface "{$wanif}" {
4702
timeout 60;
4703
retry 15;
4704
select-timeout 0;
4705
initial-interval 1;
4706
	{$dhclientconf_hostname}
4707
	script "/usr/local/sbin/pfSense-dhclient-script";
4708
EOD;
4709

    
4710
	if (validate_ipv4_list($wancfg['dhcprejectfrom'])) {
4711
		$dhclientconf .= <<<EOD
4712

    
4713
	reject {$wancfg['dhcprejectfrom']};
4714
EOD;
4715
	}
4716
	$dhclientconf .= <<<EOD
4717

    
4718
}
4719

    
4720
EOD;
4721

    
4722
	// DHCP Config File Advanced
4723
	if ($wancfg['adv_dhcp_config_advanced']) {
4724
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4725
	}
4726

    
4727
	if (is_ipaddr($wancfg['alias-address'])) {
4728
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4729
		$dhclientconf .= <<<EOD
4730
alias {
4731
	interface "{$wanif}";
4732
	fixed-address {$wancfg['alias-address']};
4733
	option subnet-mask {$subnetmask};
4734
}
4735

    
4736
EOD;
4737
	}
4738

    
4739
	// DHCP Config File Override
4740
	if ($wancfg['adv_dhcp_config_file_override']) {
4741
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4742
	}
4743

    
4744
	fwrite($fd, $dhclientconf);
4745
	fclose($fd);
4746

    
4747
	/* bring wan interface up before starting dhclient */
4748
	if ($wanif) {
4749
		interfaces_bring_up($wanif);
4750
	} else {
4751
		log_error(sprintf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4752
	}
4753

    
4754
	/* Make sure dhclient is not running */
4755
	kill_dhclient_process($wanif);
4756

    
4757
	/* fire up dhclient */
4758
	mwexec("/sbin/dhclient -c {$g['varetc_path']}/dhclient_{$interface}.conf {$wanif} > {$g['tmp_path']}/{$wanif}_output 2> {$g['tmp_path']}/{$wanif}_error_output");
4759

    
4760
	return 0;
4761
}
4762

    
4763
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4764

    
4765
	$hostname = "";
4766
	if ($wancfg['dhcphostname'] != '') {
4767
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4768
	}
4769

    
4770
	/* DHCP Protocol Timings */
4771
	$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");
4772
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4773
		$pt_variable = "{$Protocol_Timing}";
4774
		${$pt_variable} = "";
4775
		if ($wancfg[$Protocol_Timing] != "") {
4776
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4777
		}
4778
	}
4779

    
4780
	$send_options = "";
4781
	if ($wancfg['adv_dhcp_send_options'] != '') {
4782
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp_send_options']);
4783
		foreach ($options as $option) {
4784
			$send_options .= "\tsend " . trim($option) . ";\n";
4785
		}
4786
	}
4787

    
4788
	$request_options = "";
4789
	if ($wancfg['adv_dhcp_request_options'] != '') {
4790
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4791
	}
4792

    
4793
	$required_options = "";
4794
	if ($wancfg['adv_dhcp_required_options'] != '') {
4795
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4796
	}
4797

    
4798
	$option_modifiers = "";
4799
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4800
		$modifiers = DHCP_Config_Option_Split($wancfg['adv_dhcp_option_modifiers']);
4801
		foreach ($modifiers as $modifier) {
4802
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4803
		}
4804
	}
4805

    
4806
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4807
	$dhclientconf .= "\n";
4808
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4809
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4810
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4811
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4812
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4813
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4814
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4815
	$dhclientconf .= "\n";
4816
	$dhclientconf .= "# DHCP Protocol Options\n";
4817
	$dhclientconf .= "{$hostname}";
4818
	$dhclientconf .= "{$send_options}";
4819
	$dhclientconf .= "{$request_options}";
4820
	$dhclientconf .= "{$required_options}";
4821
	$dhclientconf .= "{$option_modifiers}";
4822
	$dhclientconf .= "\n";
4823
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4824
		$dhclientconf .= "reject {$wancfg['dhcprejectfrom']};\n";
4825
	}
4826
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
4827
	$dhclientconf .= "}\n";
4828

    
4829
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4830

    
4831
	return $dhclientconf;
4832
}
4833

    
4834
function DHCP_Config_Option_Split($option_string) {
4835
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4836
	return $matches ? $matches[0] : [];
4837
}
4838

    
4839
function DHCP_Config_File_Override($wancfg, $wanif) {
4840

    
4841
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4842

    
4843
	if ($dhclientconf === false) {
4844
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $wancfg['adv_dhcp_config_file_override_path']));
4845
		return '';
4846
	} else {
4847
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4848
	}
4849
}
4850

    
4851

    
4852
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4853

    
4854
	/* Apply Interface Substitutions */
4855
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4856

    
4857
	/* Apply Hostname Substitutions */
4858
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4859

    
4860
	/* Arrays of MAC Address Types, Cases, Delimiters */
4861
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4862
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4863
	$various_mac_cases      = array("U", "L");
4864
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4865

    
4866
	/* Apply MAC Address Substitutions */
4867
	foreach ($various_mac_types as $various_mac_type) {
4868
		foreach ($various_mac_cases as $various_mac_case) {
4869
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4870

    
4871
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4872
				if ($res !== false) {
4873

    
4874
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4875
					if ("$various_mac_case" == "U") {
4876
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4877
					}
4878
					if ("$various_mac_case" == "L") {
4879
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4880
					}
4881

    
4882
					if ("$various_mac_type" == "mac_addr_hex") {
4883
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4884
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4885
						$dhcpclientconf_mac_hex = "";
4886
						$delimiter = "";
4887
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4888
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4889
							$delimiter = ":";
4890
						}
4891
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4892
					}
4893

    
4894
					/* MAC Address Delimiter Substitutions */
4895
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4896

    
4897
					/* Apply MAC Address Substitutions */
4898
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4899
				}
4900
			}
4901
		}
4902
	}
4903

    
4904
	return $dhclientconf;
4905
}
4906

    
4907
function interfaces_group_setup() {
4908
	global $config;
4909

    
4910
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4911
		return;
4912
	}
4913

    
4914
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4915
		interface_group_setup($groupar);
4916
	}
4917

    
4918
	return;
4919
}
4920

    
4921
function interface_group_setup(&$groupname /* The parameter is an array */) {
4922
	global $config;
4923

    
4924
	if (!is_array($groupname)) {
4925
		return;
4926
	}
4927
	$members = explode(" ", $groupname['members']);
4928
	foreach ($members as $ifs) {
4929
		$realif = get_real_interface($ifs);
4930
		if ($realif && does_interface_exist($realif)) {
4931
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4932
		}
4933
	}
4934

    
4935
	return;
4936
}
4937

    
4938
function is_interface_group($if) {
4939
	global $config;
4940

    
4941
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4942
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4943
			if ($groupentry['ifname'] === $if) {
4944
				return true;
4945
			}
4946
		}
4947
	}
4948

    
4949
	return false;
4950
}
4951

    
4952
function interface_group_add_member($interface, $groupname) {
4953
	$interface = get_real_interface($interface);
4954
	if (does_interface_exist($interface)) {
4955
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4956
	}
4957
}
4958

    
4959
/* COMPAT Function */
4960
function convert_friendly_interface_to_real_interface_name($interface) {
4961
	return get_real_interface($interface);
4962
}
4963

    
4964
/* COMPAT Function */
4965
function get_real_wan_interface($interface = "wan") {
4966
	return get_real_interface($interface);
4967
}
4968

    
4969
/* COMPAT Function */
4970
function get_current_wan_address($interface = "wan") {
4971
	return get_interface_ip($interface);
4972
}
4973

    
4974
/*
4975
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4976
 */
4977
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4978
	global $config;
4979

    
4980
	/* XXX: For speed reasons reference directly the interface array */
4981
	$ifdescrs = &$config['interfaces'];
4982
	//$ifdescrs = get_configured_interface_list(true);
4983

    
4984
	foreach ($ifdescrs as $if => $ifname) {
4985
		if ($if == $interface || $ifname['if'] == $interface) {
4986
			return $if;
4987
		}
4988

    
4989
		if (get_real_interface($if) == $interface) {
4990
			return $if;
4991
		}
4992

    
4993
		if ($checkparent == false) {
4994
			continue;
4995
		}
4996

    
4997
		$int = get_parent_interface($if, true);
4998
		if (is_array($int)) {
4999
			foreach ($int as $iface) {
5000
				if ($iface == $interface) {
5001
					return $if;
5002
				}
5003
			}
5004
		}
5005
	}
5006

    
5007
	if ($interface == "enc0") {
5008
		return 'IPsec';
5009
	}
5010
}
5011

    
5012
/* attempt to resolve interface to friendly descr */
5013
function convert_friendly_interface_to_friendly_descr($interface) {
5014
	global $config;
5015

    
5016
	switch ($interface) {
5017
		case "l2tp":
5018
			$ifdesc = "L2TP";
5019
			break;
5020
		case "pptp":
5021
			$ifdesc = "PPTP";
5022
			break;
5023
		case "pppoe":
5024
			$ifdesc = "PPPoE";
5025
			break;
5026
		case "openvpn":
5027
			$ifdesc = "OpenVPN";
5028
			break;
5029
		case "lo0":
5030
			$ifdesc = "Loopback";
5031
			break;
5032
		case "enc0":
5033
		case "ipsec":
5034
		case "IPsec":
5035
			$ifdesc = "IPsec";
5036
			break;
5037
		default:
5038
			if (isset($config['interfaces'][$interface])) {
5039
				if (empty($config['interfaces'][$interface]['descr'])) {
5040
					$ifdesc = strtoupper($interface);
5041
				} else {
5042
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5043
				}
5044
				break;
5045
			} else if (substr($interface, 0, 4) == '_vip') {
5046
				if (is_array($config['virtualip']['vip'])) {
5047
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5048
						if ($vip['mode'] == "carp") {
5049
							if ($interface == "_vip{$vip['uniqid']}") {
5050
								return "{$vip['subnet']} - {$vip['descr']}";
5051
							}
5052
						}
5053
					}
5054
				}
5055
			} else if (substr($interface, 0, 5) == '_lloc') {
5056
				return get_interface_linklocal($interface);
5057
			} else {
5058
				/* if list */
5059
				$ifdescrs = get_configured_interface_with_descr(true);
5060
				foreach ($ifdescrs as $if => $ifname) {
5061
					if ($if == $interface || $ifname == $interface) {
5062
						return $ifname;
5063
					}
5064
				}
5065
			}
5066
			break;
5067
	}
5068

    
5069
	return $ifdesc;
5070
}
5071

    
5072
function convert_real_interface_to_friendly_descr($interface) {
5073

    
5074
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5075

    
5076
	if (!empty($ifdesc)) {
5077
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5078
	}
5079

    
5080
	return $interface;
5081
}
5082

    
5083
/*
5084
 *  get_parent_interface($interface):
5085
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5086
 *				or virtual interface (i.e. vlan)
5087
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5088
 *			-- returns $interface passed in if $interface parent is not found
5089
 *			-- returns empty array if an invalid interface is passed
5090
 *	(Only handles ppps and vlans now.)
5091
 */
5092
function get_parent_interface($interface, $avoidrecurse = false) {
5093
	global $config;
5094

    
5095
	$parents = array();
5096
	//Check that we got a valid interface passed
5097
	$realif = get_real_interface($interface);
5098
	if ($realif == NULL) {
5099
		return $parents;
5100
	}
5101

    
5102
	// If we got a real interface, find it's friendly assigned name
5103
	if ($interface == $realif && $avoidrecurse == false) {
5104
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5105
	}
5106

    
5107
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5108
		$ifcfg = $config['interfaces'][$interface];
5109
		switch ($ifcfg['ipaddr']) {
5110
			case "ppp":
5111
			case "pppoe":
5112
			case "pptp":
5113
			case "l2tp":
5114
				if (empty($parents)) {
5115
					if (is_array($config['ppps']['ppp'])) {
5116
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5117
							if ($ifcfg['if'] == $ppp['if']) {
5118
								$ports = explode(',', $ppp['ports']);
5119
								foreach ($ports as $pid => $parent_if) {
5120
									$parents[$pid] = get_real_interface($parent_if);
5121
								}
5122
								break;
5123
							}
5124
						}
5125
					}
5126
				}
5127
				break;
5128
			case "dhcp":
5129
			case "static":
5130
			default:
5131
				// Handle _vlans
5132
				$vlan = interface_is_vlan($ifcfg['if']);
5133
				if ($vlan != NULL) {
5134
					$parents[0] = $vlan['if'];
5135
				}
5136
				break;
5137
		}
5138
	}
5139

    
5140
	if (empty($parents)) {
5141
		// Handle _vlans not assigned to an interface
5142
		$vlan = interface_is_vlan($realif);
5143
		if ($vlan != NULL) {
5144
			$parents[0] = $vlan['if'];
5145
		}
5146
	}
5147

    
5148
	if (empty($parents)) {
5149
		$parents[0] = $realif;
5150
	}
5151

    
5152
	return $parents;
5153
}
5154

    
5155
/*
5156
 *  get_parent_physical_interface($interface):
5157
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5158
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5159
 */
5160
function get_parent_physical_interface($interface) {
5161
	global $config;
5162

    
5163
	$realif = get_parent_interface($interface);
5164

    
5165
	if (substr($realif[0], 0, 4) == "lagg") {
5166
		foreach ($config['laggs']['lagg'] as $lagg) {
5167
			if ($realif[0] == $lagg['laggif']) {
5168
				return explode(",", $lagg['members']);
5169
			}
5170
		}
5171
	} else {
5172
		return $realif;
5173
	}
5174
}
5175

    
5176
function interface_is_wireless_clone($wlif) {
5177
	if (!stristr($wlif, "_wlan")) {
5178
		return false;
5179
	} else {
5180
		return true;
5181
	}
5182
}
5183

    
5184
function interface_get_wireless_base($wlif) {
5185
	if (!stristr($wlif, "_wlan")) {
5186
		return $wlif;
5187
	} else {
5188
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5189
	}
5190
}
5191

    
5192
function interface_get_wireless_clone($wlif) {
5193
	if (!stristr($wlif, "_wlan")) {
5194
		return $wlif . "_wlan0";
5195
	} else {
5196
		return $wlif;
5197
	}
5198
}
5199

    
5200
function interface_list_wireless() {
5201
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5202

    
5203
	$result = array();
5204
	foreach ($portlist as $port) {
5205
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5206
			continue;
5207
		}
5208

    
5209
		$desc = $port . " ( " . get_single_sysctl(
5210
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5211

    
5212
		$result[] = array(
5213
		    "if" => $port,
5214
		    "descr" => $desc
5215
		);
5216
	}
5217

    
5218
	return $result;
5219
}
5220

    
5221
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
5222
	global $config, $g;
5223

    
5224
	$wanif = NULL;
5225

    
5226
	switch ($interface) {
5227
		case "l2tp":
5228
			$wanif = "l2tp";
5229
			break;
5230
		case "pptp":
5231
			$wanif = "pptp";
5232
			break;
5233
		case "pppoe":
5234
			$wanif = "pppoe";
5235
			break;
5236
		case "openvpn":
5237
			$wanif = "openvpn";
5238
			break;
5239
		case "IPsec":
5240
		case "ipsec":
5241
		case "enc0":
5242
			$wanif = "enc0";
5243
			break;
5244
		case "ppp":
5245
			$wanif = "ppp";
5246
			break;
5247
		default:
5248
			if (substr($interface, 0, 4) == '_vip') {
5249
				$wanif = get_configured_vip_interface($interface);
5250
				if (!empty($wanif)) {
5251
					$wanif = get_real_interface($wanif);
5252
				}
5253
				break;
5254
			} else if (substr($interface, 0, 5) == '_lloc') {
5255
				$interface = substr($interface, 5);
5256
			} else if (interface_is_vlan($interface) != NULL ||
5257
			    does_interface_exist($interface, $flush)) {
5258
				/*
5259
				 * If a real interface was already passed simply
5260
				 * pass the real interface back.  This encourages
5261
				 * the usage of this function in more cases so that
5262
				 * we can combine logic for more flexibility.
5263
				 */
5264
				$wanif = $interface;
5265
				break;
5266
			}
5267

    
5268
			if (empty($config['interfaces'][$interface])) {
5269
				break;
5270
			}
5271

    
5272
			$cfg = &$config['interfaces'][$interface];
5273

    
5274
			if ($family == "inet6") {
5275
				switch ($cfg['ipaddrv6']) {
5276
					case "6rd":
5277
					case "6to4":
5278
						$wanif = "{$interface}_stf";
5279
						break;
5280
					case 'pppoe':
5281
					case 'ppp':
5282
					case 'l2tp':
5283
					case 'pptp':
5284
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5285
							$wanif = interface_get_wireless_clone($cfg['if']);
5286
						} else {
5287
							$wanif = $cfg['if'];
5288
						}
5289
						break;
5290
					default:
5291
						switch ($cfg['ipaddr']) {
5292
							case 'pppoe':
5293
							case 'ppp':
5294
							case 'l2tp':
5295
							case 'pptp':
5296
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
5297
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) || isset($cfg['ipv6usev4iface'])) {
5298
									$wanif = $cfg['if'];
5299
								} else {
5300
									$parents = get_parent_interface($interface);
5301
									if (!empty($parents[0])) {
5302
										$wanif = $parents[0];
5303
									} else {
5304
										$wanif = $cfg['if'];
5305
									}
5306
								}
5307
								break;
5308
							default:
5309
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5310
									$wanif = interface_get_wireless_clone($cfg['if']);
5311
								} else {
5312
									$wanif = $cfg['if'];
5313
								}
5314
								break;
5315
						}
5316
						break;
5317
				}
5318
			} else {
5319
				// Wireless cloned NIC support (FreeBSD 8+)
5320
				// interface name format: $parentnic_wlanparentnic#
5321
				// example: ath0_wlan0
5322
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5323
					$wanif = interface_get_wireless_clone($cfg['if']);
5324
				} else {
5325
					$wanif = $cfg['if'];
5326
				}
5327
			}
5328
			break;
5329
	}
5330

    
5331
	return $wanif;
5332
}
5333

    
5334
/* Guess the physical interface by providing a IP address */
5335
function guess_interface_from_ip($ipaddress) {
5336

    
5337
	$family = '';
5338
	if (is_ipaddrv4($ipaddress)) {
5339
		$family = 'inet';
5340
	}
5341
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5342
		$family = 'inet6';
5343
	}
5344

    
5345
	if (empty($family)) {
5346
		return false;
5347
	}
5348

    
5349
	/* create a route table we can search */
5350
	$output = '';
5351
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
5352
	$output[0] = trim($output[0], " \n");
5353
	if (!empty($output[0])) {
5354
		return $output[0];
5355
	}
5356

    
5357
	return false;
5358
}
5359

    
5360
/*
5361
 * find_ip_interface($ip): return the interface where an ip is defined
5362
 *   (or if $bits is specified, where an IP within the subnet is defined)
5363
 */
5364
function find_ip_interface($ip, $bits = null) {
5365
	if (!is_ipaddr($ip)) {
5366
		return false;
5367
	}
5368

    
5369
	$isv6ip = is_ipaddrv6($ip);
5370

    
5371
	/* if list */
5372
	$ifdescrs = get_configured_interface_list();
5373

    
5374
	foreach ($ifdescrs as $ifdescr => $ifname) {
5375
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
5376
		if (is_null($ifip)) {
5377
			continue;
5378
		}
5379
		if (is_null($bits)) {
5380
			if ($ip == $ifip) {
5381
				$int = get_real_interface($ifname);
5382
				return $int;
5383
			}
5384
		} else {
5385
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
5386
				$int = get_real_interface($ifname);
5387
				return $int;
5388
			}
5389
		}
5390
	}
5391

    
5392
	return false;
5393
}
5394

    
5395
/*
5396
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5397
 *   (or if $bits is specified, where an IP within the subnet is found)
5398
 */
5399
function find_virtual_ip_alias($ip, $bits = null) {
5400
	global $config;
5401

    
5402
	if (!is_array($config['virtualip']['vip'])) {
5403
		return false;
5404
	}
5405
	if (!is_ipaddr($ip)) {
5406
		return false;
5407
	}
5408

    
5409
	$isv6ip = is_ipaddrv6($ip);
5410

    
5411
	foreach ($config['virtualip']['vip'] as $vip) {
5412
		if ($vip['mode'] === "ipalias") {
5413
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
5414
				continue;
5415
			}
5416
			if (is_null($bits)) {
5417
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
5418
					return $vip;
5419
				}
5420
			} else {
5421
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5422
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5423
					return $vip;
5424
				}
5425
			}
5426
		}
5427
	}
5428
	return false;
5429
}
5430

    
5431
function link_interface_to_track6($int, $action = "") {
5432
	global $config;
5433

    
5434
	if (empty($int)) {
5435
		return;
5436
	}
5437

    
5438
	if (is_array($config['interfaces'])) {
5439
		$list = array();
5440
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5441
			if (!isset($ifcfg['enable'])) {
5442
				continue;
5443
			}
5444
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5445
				if ($action == "update") {
5446
					interface_track6_configure($ifname, $ifcfg);
5447
				} else if ($action == "") {
5448
					$list[$ifname] = $ifcfg;
5449
				}
5450
			}
5451
		}
5452
		return $list;
5453
	}
5454
}
5455

    
5456
function interface_find_child_cfgmtu($realiface) {
5457
	global $config;
5458

    
5459
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5460
	$vlans = link_interface_to_vlans($realiface);
5461
	$qinqs = link_interface_to_qinqs($realiface);
5462
	$bridge = link_interface_to_bridge($realiface);
5463
	if (!empty($interface)) {
5464
		$gifs = link_interface_to_gif($interface);
5465
		$gres = link_interface_to_gre($interface);
5466
	} else {
5467
		$gifs = array();
5468
		$gres = array();
5469
	}
5470

    
5471
	$mtu = 0;
5472
	if (is_array($vlans)) {
5473
		foreach ($vlans as $vlan) {
5474
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5475
			if (empty($ifass)) {
5476
				continue;
5477
			}
5478
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5479
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5480
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5481
				}
5482
			}
5483
		}
5484
	}
5485
	if (is_array($qinqs)) {
5486
		foreach ($qinqs as $qinq) {
5487
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5488
			if (empty($ifass)) {
5489
				continue;
5490
			}
5491
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5492
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5493
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5494
				}
5495
			}
5496
		}
5497
	}
5498
	if (is_array($gifs)) {
5499
		foreach ($gifs as $gif) {
5500
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5501
			if (empty($ifass)) {
5502
				continue;
5503
			}
5504
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5505
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5506
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5507
				}
5508
			}
5509
		}
5510
	}
5511
	if (is_array($gres)) {
5512
		foreach ($gres as $gre) {
5513
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5514
			if (empty($ifass)) {
5515
				continue;
5516
			}
5517
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5518
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5519
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5520
				}
5521
			}
5522
		}
5523
	}
5524
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5525
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5526
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5527
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5528
		}
5529
	}
5530
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5531

    
5532
	return $mtu;
5533
}
5534

    
5535
function link_interface_to_vlans($int, $action = "") {
5536
	global $config;
5537

    
5538
	if (empty($int)) {
5539
		return;
5540
	}
5541

    
5542
	if (is_array($config['vlans']['vlan'])) {
5543
		$ifaces = array();
5544
		foreach ($config['vlans']['vlan'] as $vlan) {
5545
			if ($int == $vlan['if']) {
5546
				if ($action == "update") {
5547
					interfaces_bring_up($int);
5548
				} else {
5549
					$ifaces[$vlan['tag']] = $vlan;
5550
				}
5551
			}
5552
		}
5553
		if (!empty($ifaces)) {
5554
			return $ifaces;
5555
		}
5556
	}
5557
}
5558

    
5559
function link_interface_to_qinqs($int, $action = "") {
5560
	global $config;
5561

    
5562
	if (empty($int)) {
5563
		return;
5564
	}
5565

    
5566
	if (is_array($config['qinqs']['qinqentry'])) {
5567
		$ifaces = array();
5568
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5569
			if ($int == $qinq['if']) {
5570
				if ($action == "update") {
5571
					interfaces_bring_up($int);
5572
				} else {
5573
					$ifaces[$qinq['tag']] = $qinq;
5574
				}
5575
			}
5576
		}
5577
		if (!empty($ifaces)) {
5578
			return $ifaces;
5579
		}
5580
	}
5581
}
5582

    
5583
function link_interface_to_vips($int, $action = "", $vhid = '') {
5584
	global $config;
5585

    
5586
	$updatevips = false;
5587
	if (is_array($config['virtualip']['vip'])) {
5588
		$result = array();
5589
		foreach ($config['virtualip']['vip'] as $vip) {
5590
			if (substr($vip['interface'], 0, 4) == "_vip") {
5591
				$iface = get_configured_vip_interface($vip['interface']);
5592
			} else {
5593
				$iface = $vip['interface'];
5594
			}
5595
			if ($int != $iface) {
5596
				continue;
5597
			}
5598
			if ($action == "update") {
5599
				$updatevips = true;
5600
			} else {
5601
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5602
				    substr($vip['interface'], 0, 4) == "_vip") {
5603
					$result[] = $vip;
5604
				}
5605
			}
5606
		}
5607
		if ($updatevips === true) {
5608
			interfaces_vips_configure($int);
5609
		}
5610
		return $result;
5611
	}
5612

    
5613
	return NULL;
5614
}
5615

    
5616
/****f* interfaces/link_interface_to_bridge
5617
 * NAME
5618
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5619
 * INPUTS
5620
 *   $ip
5621
 * RESULT
5622
 *   bridge[0-99]
5623
 ******/
5624
function link_interface_to_bridge($int) {
5625
	global $config;
5626

    
5627
	if (is_array($config['bridges']['bridged'])) {
5628
		foreach ($config['bridges']['bridged'] as $bridge) {
5629
			if (in_array($int, explode(',', $bridge['members']))) {
5630
				return "{$bridge['bridgeif']}";
5631
			}
5632
		}
5633
	}
5634
}
5635

    
5636
function link_interface_to_group($int) {
5637
	global $config;
5638

    
5639
	$result = array();
5640

    
5641
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5642
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5643
			if (in_array($int, explode(" ", $group['members']))) {
5644
				$result[$group['ifname']] = $int;
5645
			}
5646
		}
5647
	}
5648

    
5649
	return $result;
5650
}
5651

    
5652
function link_interface_to_gre($interface) {
5653
	global $config;
5654

    
5655
	$result = array();
5656

    
5657
	if (is_array($config['gres']['gre'])) {
5658
		foreach ($config['gres']['gre'] as $gre) {
5659
			if ($gre['if'] == $interface) {
5660
				$result[] = $gre;
5661
			}
5662
		}
5663
	}
5664

    
5665
	return $result;
5666
}
5667

    
5668
function link_interface_to_gif($interface) {
5669
	global $config;
5670

    
5671
	$result = array();
5672

    
5673
	if (is_array($config['gifs']['gif'])) {
5674
		foreach ($config['gifs']['gif'] as $gif) {
5675
			if ($gif['if'] == $interface) {
5676
				$result[] = $gif;
5677
			}
5678
		}
5679
	}
5680

    
5681
	return $result;
5682
}
5683

    
5684
/*
5685
 * find_interface_ip($interface): return the interface ip (first found)
5686
 */
5687
function find_interface_ip($interface, $flush = false) {
5688
	global $interface_ip_arr_cache;
5689
	global $interface_sn_arr_cache;
5690

    
5691
	$interface = str_replace("\n", "", $interface);
5692

    
5693
	if (!does_interface_exist($interface)) {
5694
		return;
5695
	}
5696

    
5697
	/* Setup IP cache */
5698
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5699
		if (file_exists("/var/db/${interface}_ip")) {
5700
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
5701
			$ifaddrs = pfSense_getall_interface_addresses($interface);
5702
			foreach ($ifaddrs as $ifaddr) {
5703
				list($ip, $mask) = explode("/", $ifaddr);
5704
				if ($ip == $ifip) {
5705
					$interface_ip_arr_cache[$interface] = $ip;
5706
					$interface_sn_arr_cache[$interface] = $mask;
5707
					break;
5708
				}
5709
			}
5710
		}
5711
		if (!isset($interface_ip_arr_cache[$interface])) {
5712
			$ifinfo = pfSense_get_interface_addresses($interface);
5713
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5714
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5715
		}
5716
	}
5717

    
5718
	return $interface_ip_arr_cache[$interface];
5719
}
5720

    
5721
/*
5722
 * find_interface_ipv6($interface): return the interface ip (first found)
5723
 */
5724
function find_interface_ipv6($interface, $flush = false) {
5725
	global $interface_ipv6_arr_cache;
5726
	global $interface_snv6_arr_cache;
5727
	global $config;
5728

    
5729
	$interface = trim($interface);
5730
	$interface = get_real_interface($interface);
5731

    
5732
	if (!does_interface_exist($interface)) {
5733
		return;
5734
	}
5735

    
5736
	/* Setup IP cache */
5737
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5738
		$ifinfo = pfSense_get_interface_addresses($interface);
5739
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5740
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5741
	}
5742

    
5743
	return $interface_ipv6_arr_cache[$interface];
5744
}
5745

    
5746
/*
5747
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5748
 */
5749
function find_interface_ipv6_ll($interface, $flush = false) {
5750
	global $interface_llv6_arr_cache;
5751
	global $config;
5752

    
5753
	$interface = str_replace("\n", "", $interface);
5754

    
5755
	if (!does_interface_exist($interface)) {
5756
		return;
5757
	}
5758

    
5759
	/* Setup IP cache */
5760
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5761
		$ifinfo = pfSense_getall_interface_addresses($interface);
5762
		foreach ($ifinfo as $line) {
5763
			if (strstr($line, ":")) {
5764
				$parts = explode("/", $line);
5765
				if (is_linklocal($parts[0])) {
5766
					$ifinfo['linklocal'] = $parts[0];
5767
				}
5768
			}
5769
		}
5770
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5771
	}
5772
	return $interface_llv6_arr_cache[$interface];
5773
}
5774

    
5775
function find_interface_subnet($interface, $flush = false) {
5776
	global $interface_sn_arr_cache;
5777
	global $interface_ip_arr_cache;
5778

    
5779
	$interface = str_replace("\n", "", $interface);
5780
	if (does_interface_exist($interface) == false) {
5781
		return;
5782
	}
5783

    
5784
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5785
		$ifinfo = pfSense_get_interface_addresses($interface);
5786
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5787
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5788
	}
5789

    
5790
	return $interface_sn_arr_cache[$interface];
5791
}
5792

    
5793
function find_interface_subnetv6($interface, $flush = false) {
5794
	global $interface_snv6_arr_cache;
5795
	global $interface_ipv6_arr_cache;
5796

    
5797
	$interface = str_replace("\n", "", $interface);
5798
	if (does_interface_exist($interface) == false) {
5799
		return;
5800
	}
5801

    
5802
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5803
		$ifinfo = pfSense_get_interface_addresses($interface);
5804
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5805
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5806
	}
5807

    
5808
	return $interface_snv6_arr_cache[$interface];
5809
}
5810

    
5811
function ip_in_interface_alias_subnet($interface, $ipalias) {
5812
	global $config;
5813

    
5814
	if (empty($interface) || !is_ipaddr($ipalias)) {
5815
		return false;
5816
	}
5817
	if (is_array($config['virtualip']['vip'])) {
5818
		foreach ($config['virtualip']['vip'] as $vip) {
5819
			switch ($vip['mode']) {
5820
				case "ipalias":
5821
					if ($vip['interface'] <> $interface) {
5822
						break;
5823
					}
5824
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5825
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5826
						return true;
5827
					}
5828
					break;
5829
			}
5830
		}
5831
	}
5832

    
5833
	return false;
5834
}
5835

    
5836
function get_possible_listen_ips($include_ipv6_link_local=false) {
5837

    
5838
	$interfaces = get_configured_interface_with_descr();
5839
	foreach ($interfaces as $iface => $ifacename) {
5840
		if ($include_ipv6_link_local) {
5841
			/* This is to avoid going though added ll below */
5842
			if (substr($iface, 0, 5) == '_lloc') {
5843
				continue;
5844
			}
5845
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5846
			if (!empty($llip)) {
5847
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5848
			}
5849
		}
5850
	}
5851
	$viplist = get_configured_vip_list();
5852
	foreach ($viplist as $vip => $address) {
5853
		$interfaces[$vip] = $address;
5854
		if (get_vip_descr($address)) {
5855
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5856
		}
5857
	}
5858

    
5859
	$interfaces['lo0'] = 'Localhost';
5860

    
5861
	return $interfaces;
5862
}
5863

    
5864
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5865
	global $config;
5866

    
5867
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5868
	foreach (array('server', 'client') as $mode) {
5869
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5870
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5871
				if (!isset($setting['disable'])) {
5872
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5873
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5874
				}
5875
			}
5876
		}
5877
	}
5878
	return $sourceips;
5879
}
5880

    
5881
function get_interface_ip($interface = "wan") {
5882

    
5883
	if (substr($interface, 0, 4) == '_vip') {
5884
		return get_configured_vip_ipv4($interface);
5885
	} else if (substr($interface, 0, 5) == '_lloc') {
5886
		/* No link-local address for v4. */
5887
		return null;
5888
	}
5889

    
5890
	$realif = get_failover_interface($interface, 'inet');
5891
	if (!$realif) {
5892
		return null;
5893
	}
5894

    
5895
	if (substr($realif, 0, 4) == '_vip') {
5896
		return get_configured_vip_ipv4($realif);
5897
	} else if (substr($realif, 0, 5) == '_lloc') {
5898
		/* No link-local address for v4. */
5899
		return null;
5900
	}
5901

    
5902
	if (is_array($config['interfaces'][$interface]) &&
5903
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5904
		return ($config['interfaces'][$interface]['ipaddr']);
5905
	}
5906

    
5907
	/*
5908
	 * Beaware that find_interface_ip() is our last option, it will
5909
	 * return the first IP it find on interface, not necessarily the
5910
	 * main IP address.
5911
	 */
5912
	$curip = find_interface_ip($realif);
5913
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5914
		return $curip;
5915
	} else {
5916
		return null;
5917
	}
5918
}
5919

    
5920
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5921
	global $config;
5922

    
5923
	if (substr($interface, 0, 4) == '_vip') {
5924
		return get_configured_vip_ipv6($interface);
5925
	} else if (substr($interface, 0, 5) == '_lloc') {
5926
		return get_interface_linklocal($interface);
5927
	}
5928

    
5929
	$realif = get_failover_interface($interface, 'inet6');
5930
	if (!$realif) {
5931
		return null;
5932
	}
5933

    
5934
	if (substr($realif, 0, 4) == '_vip') {
5935
		return get_configured_vip_ipv6($realif);
5936
	} else if (substr($realif, 0, 5) == '_lloc') {
5937
		return get_interface_linklocal($realif);
5938
	}
5939

    
5940
	if (is_array($config['interfaces'][$interface])) {
5941
		switch ($config['interfaces'][$interface]['ipaddr']) {
5942
			case 'pppoe':
5943
			case 'l2tp':
5944
			case 'pptp':
5945
			case 'ppp':
5946
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5947
					$realif = get_real_interface($interface, 'inet6', false);
5948
				}
5949
				break;
5950
		}
5951
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5952
			return ($config['interfaces'][$interface]['ipaddrv6']);
5953
		}
5954
	}
5955

    
5956
	/*
5957
	 * Beaware that find_interface_ip() is our last option, it will
5958
	 * return the first IP it find on interface, not necessarily the
5959
	 * main IP address.
5960
	 */
5961
	$curip = find_interface_ipv6($realif, $flush);
5962
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5963
		return $curip;
5964
	} else {
5965
		/*
5966
		 * NOTE: On the case when only the prefix is requested,
5967
		 * the communication on WAN will be done over link-local.
5968
		 */
5969
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
5970
			$curip = find_interface_ipv6_ll($realif, $flush);
5971
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5972
				return $curip;
5973
			}
5974
		}
5975
	}
5976
	return null;
5977
}
5978

    
5979
function get_interface_linklocal($interface = "wan") {
5980

    
5981
	$realif = get_failover_interface($interface, 'inet6');
5982
	if (!$realif) {
5983
		return null;
5984
	}
5985

    
5986
	if (substr($interface, 0, 4) == '_vip') {
5987
		$realif = get_real_interface($interface);
5988
	} else if (substr($interface, 0, 5) == '_lloc') {
5989
		$realif = get_real_interface(substr($interface, 5));
5990
	}
5991

    
5992
	$curip = find_interface_ipv6_ll($realif);
5993
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5994
		return $curip;
5995
	} else {
5996
		return null;
5997
	}
5998
}
5999

    
6000
function get_interface_subnet($interface = "wan") {
6001

    
6002
	if (substr($interface, 0, 4) == '_vip') {
6003
		return (get_configured_vip_subnetv4($interface));
6004
	}
6005

    
6006
	$realif = get_real_interface($interface);
6007
	if (!$realif) {
6008
		return (NULL);
6009
	}
6010

    
6011
	$cursn = find_interface_subnet($realif);
6012
	if (!empty($cursn)) {
6013
		return ($cursn);
6014
	}
6015

    
6016
	return (NULL);
6017
}
6018

    
6019
function get_interface_subnetv6($interface = "wan") {
6020

    
6021
	if (substr($interface, 0, 4) == '_vip') {
6022
		return (get_configured_vip_subnetv6($interface));
6023
	} else if (substr($interface, 0, 5) == '_lloc') {
6024
		$interface = substr($interface, 5);
6025
	}
6026

    
6027
	$realif = get_real_interface($interface, 'inet6');
6028
	if (!$realif) {
6029
		return (NULL);
6030
	}
6031

    
6032
	$cursn = find_interface_subnetv6($realif);
6033
	if (!empty($cursn)) {
6034
		return ($cursn);
6035
	}
6036

    
6037
	return (NULL);
6038
}
6039

    
6040
/* return outside interfaces with a gateway */
6041
function get_interfaces_with_gateway() {
6042
	global $config;
6043

    
6044
	$ints = array();
6045

    
6046
	/* loop interfaces, check config for outbound */
6047
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6048
		switch ($ifname['ipaddr']) {
6049
			case "dhcp":
6050
			case "pppoe":
6051
			case "pptp":
6052
			case "l2tp":
6053
			case "ppp":
6054
				$ints[$ifdescr] = $ifdescr;
6055
				break;
6056
			default:
6057
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6058
				    !empty($ifname['gateway'])) {
6059
					$ints[$ifdescr] = $ifdescr;
6060
				}
6061
				break;
6062
		}
6063
	}
6064
	return $ints;
6065
}
6066

    
6067
/* return true if interface has a gateway */
6068
function interface_has_gateway($friendly) {
6069
	global $config;
6070

    
6071
	if (!empty($config['interfaces'][$friendly])) {
6072
		$ifname = &$config['interfaces'][$friendly];
6073
		switch ($ifname['ipaddr']) {
6074
			case "dhcp":
6075
			case "pppoe":
6076
			case "pptp":
6077
			case "l2tp":
6078
			case "ppp":
6079
				return true;
6080
			break;
6081
			default:
6082
				if (substr($ifname['if'], 0, 4) == "ovpn") {
6083
					return true;
6084
				}
6085
				$tunnelif = substr($ifname['if'], 0, 3);
6086
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6087
					if (find_interface_ip($ifname['if'])) {
6088
						return true;
6089
					}
6090
				}
6091
				if (!empty($ifname['gateway'])) {
6092
					return true;
6093
				}
6094
			break;
6095
		}
6096
	}
6097

    
6098
	return false;
6099
}
6100

    
6101
/* return true if interface has a gateway */
6102
function interface_has_gatewayv6($friendly) {
6103
	global $config;
6104

    
6105
	if (!empty($config['interfaces'][$friendly])) {
6106
		$ifname = &$config['interfaces'][$friendly];
6107
		switch ($ifname['ipaddrv6']) {
6108
			case "slaac":
6109
			case "dhcp6":
6110
			case "6to4":
6111
			case "6rd":
6112
				return true;
6113
				break;
6114
			default:
6115
				if (substr($ifname['if'], 0, 4) == "ovpn") {
6116
					return true;
6117
				}
6118
				$tunnelif = substr($ifname['if'], 0, 3);
6119
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6120
					if (find_interface_ipv6($ifname['if'])) {
6121
						return true;
6122
					}
6123
				}
6124
				if (!empty($ifname['gatewayv6'])) {
6125
					return true;
6126
				}
6127
				break;
6128
		}
6129
	}
6130

    
6131
	return false;
6132
}
6133

    
6134
/****f* interfaces/is_altq_capable
6135
 * NAME
6136
 *   is_altq_capable - Test if interface is capable of using ALTQ
6137
 * INPUTS
6138
 *   $int            - string containing interface name
6139
 * RESULT
6140
 *   boolean         - true or false
6141
 ******/
6142

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

    
6158
	$int_family = remove_ifindex($int);
6159

    
6160
	if (in_array($int_family, $capable)) {
6161
		return true;
6162
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6163
		return true;
6164
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6165
		return true;
6166
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6167
		return true;
6168
	} else {
6169
		return false;
6170
	}
6171
}
6172

    
6173
/****f* interfaces/is_interface_wireless
6174
 * NAME
6175
 *   is_interface_wireless - Returns if an interface is wireless
6176
 * RESULT
6177
 *   $tmp       - Returns if an interface is wireless
6178
 ******/
6179
function is_interface_wireless($interface) {
6180
	global $config, $g;
6181

    
6182
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6183
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6184
		if (preg_match($g['wireless_regex'], $interface)) {
6185
			if (isset($config['interfaces'][$friendly])) {
6186
				$config['interfaces'][$friendly]['wireless'] = array();
6187
			}
6188
			return true;
6189
		}
6190
		return false;
6191
	} else {
6192
		return true;
6193
	}
6194
}
6195

    
6196
function get_wireless_modes($interface) {
6197
	/* return wireless modes and channels */
6198
	$wireless_modes = array();
6199

    
6200
	$cloned_interface = get_real_interface($interface);
6201

    
6202
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6203
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6204
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6205
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6206

    
6207
		$interface_channels = "";
6208
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6209
		$interface_channel_count = count($interface_channels);
6210

    
6211
		$c = 0;
6212
		while ($c < $interface_channel_count) {
6213
			$channel_line = explode(",", $interface_channels["$c"]);
6214
			$wireless_mode = trim($channel_line[0]);
6215
			$wireless_channel = trim($channel_line[1]);
6216
			if (trim($wireless_mode) != "") {
6217
				/* if we only have 11g also set 11b channels */
6218
				if ($wireless_mode == "11g") {
6219
					if (!isset($wireless_modes["11b"])) {
6220
						$wireless_modes["11b"] = array();
6221
					}
6222
				} else if ($wireless_mode == "11g ht") {
6223
					if (!isset($wireless_modes["11b"])) {
6224
						$wireless_modes["11b"] = array();
6225
					}
6226
					if (!isset($wireless_modes["11g"])) {
6227
						$wireless_modes["11g"] = array();
6228
					}
6229
					$wireless_mode = "11ng";
6230
				} else if ($wireless_mode == "11a ht") {
6231
					if (!isset($wireless_modes["11a"])) {
6232
						$wireless_modes["11a"] = array();
6233
					}
6234
					$wireless_mode = "11na";
6235
				}
6236
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6237
			}
6238
			$c++;
6239
		}
6240
	}
6241
	return($wireless_modes);
6242
}
6243

    
6244
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6245
function get_wireless_channel_info($interface) {
6246
	$wireless_channels = array();
6247

    
6248
	$cloned_interface = get_real_interface($interface);
6249

    
6250
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6251
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
6252
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6253
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
6254

    
6255
		$interface_channels = "";
6256
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6257

    
6258
		foreach ($interface_channels as $channel_line) {
6259
			$channel_line = explode(",", $channel_line);
6260
			if (!isset($wireless_channels[$channel_line[0]])) {
6261
				$wireless_channels[$channel_line[0]] = $channel_line;
6262
			}
6263
		}
6264
	}
6265
	return($wireless_channels);
6266
}
6267

    
6268
function set_interface_mtu($interface, $mtu) {
6269

    
6270
	/* LAGG interface must be destroyed and re-created to change MTU */
6271
	if (substr($interface, 0, 4) == 'lagg') {
6272
		if (isset($config['laggs']['lagg']) &&
6273
		    is_array($config['laggs']['lagg'])) {
6274
			foreach ($config['laggs']['lagg'] as $lagg) {
6275
				if ($lagg['laggif'] == $interface) {
6276
					interface_lagg_configure($lagg);
6277
					break;
6278
				}
6279
			}
6280
		}
6281
	} else {
6282
		pfSense_interface_mtu($interface, $mtu);
6283
	}
6284
}
6285

    
6286
/****f* interfaces/get_interface_mtu
6287
 * NAME
6288
 *   get_interface_mtu - Return the mtu of an interface
6289
 * RESULT
6290
 *   $tmp       - Returns the mtu of an interface
6291
 ******/
6292
function get_interface_mtu($interface) {
6293
	$mtu = pfSense_interface_getmtu($interface);
6294
	return $mtu['mtu'];
6295
}
6296

    
6297
function get_interface_mac($interface) {
6298
	$macinfo = pfSense_get_interface_addresses($interface);
6299
	return $macinfo["macaddr"];
6300
}
6301

    
6302
function get_interface_vendor_mac($interface) {
6303
	$macinfo = pfSense_get_interface_addresses($interface);
6304
	return $macinfo["hwaddr"] ?: '';
6305
}
6306

    
6307
/****f* pfsense-utils/generate_random_mac_address
6308
 * NAME
6309
 *   generate_random_mac - generates a random mac address
6310
 * INPUTS
6311
 *   none
6312
 * RESULT
6313
 *   $mac - a random mac address
6314
 ******/
6315
function generate_random_mac_address() {
6316
	$mac = "02";
6317
	for ($x = 0; $x < 5; $x++) {
6318
		$mac .= ":" . dechex(rand(16, 255));
6319
	}
6320
	return $mac;
6321
}
6322

    
6323
/****f* interfaces/is_jumbo_capable
6324
 * NAME
6325
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
6326
 * INPUTS
6327
 *   $int             - string containing interface name
6328
 * RESULT
6329
 *   boolean          - true or false
6330
 ******/
6331
function is_jumbo_capable($iface) {
6332
	$iface = trim($iface);
6333
	$capable = pfSense_get_interface_addresses($iface);
6334

    
6335
	if (isset($capable['caps']['vlanmtu'])) {
6336
		return true;
6337
	}
6338

    
6339
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
6340
	if (substr($iface, 0, 4) == "lagg") {
6341
		return true;
6342
	}
6343

    
6344
	return false;
6345
}
6346

    
6347
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6348
	global $g;
6349

    
6350
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6351

    
6352
	if (!empty($iface) && !empty($pppif)) {
6353
		$cron_cmd = <<<EOD
6354
#!/bin/sh
6355
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
6356
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
6357

    
6358
EOD;
6359

    
6360
		@file_put_contents($cron_file, $cron_cmd);
6361
		chmod($cron_file, 0755);
6362
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
6363
	} else {
6364
		unlink_if_exists($cron_file);
6365
	}
6366
}
6367

    
6368
function get_interface_default_mtu($type = "ethernet") {
6369
	switch ($type) {
6370
		case "gre":
6371
			return 1476;
6372
			break;
6373
		case "gif":
6374
			return 1280;
6375
			break;
6376
		case "tun":
6377
		case "vlan":
6378
		case "tap":
6379
		case "ethernet":
6380
		default:
6381
			return 1500;
6382
			break;
6383
	}
6384

    
6385
	/* Never reached */
6386
	return 1500;
6387
}
6388

    
6389
function get_vip_descr($ipaddress) {
6390
	global $config;
6391

    
6392
	foreach ($config['virtualip']['vip'] as $vip) {
6393
		if ($vip['subnet'] == $ipaddress) {
6394
			return ($vip['descr']);
6395
		}
6396
	}
6397
	return "";
6398
}
6399

    
6400
function interfaces_staticarp_configure($if) {
6401
	global $config, $g;
6402
	if (isset($config['system']['developerspew'])) {
6403
		$mt = microtime();
6404
		echo "interfaces_staticarp_configure($if) being called $mt\n";
6405
	}
6406

    
6407
	$ifcfg = $config['interfaces'][$if];
6408

    
6409
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
6410
		return 0;
6411
	}
6412

    
6413
	/* Enable staticarp, if enabled */
6414
	if (isset($config['dhcpd'][$if]['staticarp'])) {
6415
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
6416
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6417
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
6418
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6419
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6420
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6421
				}
6422
			}
6423
		}
6424
	} else {
6425
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
6426
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6427
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
6428
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6429
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6430
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6431
				}
6432
			}
6433
		}
6434
	}
6435

    
6436
	return 0;
6437
}
6438

    
6439
function get_failover_interface($interface, $family = "all") {
6440
	global $config;
6441

    
6442
	/* shortcut to get_real_interface if we find it in the config */
6443
	if (is_array($config['interfaces'][$interface])) {
6444
		return get_real_interface($interface, $family);
6445
	}
6446

    
6447
	/* compare against gateway groups */
6448
	$a_groups = return_gateway_groups_array();
6449
	if (is_array($a_groups[$interface])) {
6450
		/* we found a gateway group, fetch the interface or vip */
6451
		if (!empty($a_groups[$interface][0]['vip'])) {
6452
			return $a_groups[$interface][0]['vip'];
6453
		} else {
6454
			return $a_groups[$interface][0]['int'];
6455
		}
6456
	}
6457
	/* fall through to get_real_interface */
6458
	/* XXX: Really needed? */
6459
	return get_real_interface($interface, $family);
6460
}
6461

    
6462
/****f* interfaces/interface_has_dhcp
6463
 * NAME
6464
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6465
 * INPUTS
6466
 *   interface or gateway group name
6467
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6468
 * RESULT
6469
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6470
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6471
 ******/
6472
function interface_has_dhcp($interface, $family = 4) {
6473
	global $config;
6474

    
6475
	if ($config['interfaces'][$interface]) {
6476
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6477
			return true;
6478
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6479
			return true;
6480
		} else {
6481
			return false;
6482
		}
6483
	}
6484

    
6485
	if (!is_array($config['gateways']['gateway_group'])) {
6486
		return false;
6487
	}
6488

    
6489
	if ($family == 6) {
6490
		$dhcp_string = "_DHCP6";
6491
	} else {
6492
		$dhcp_string = "_DHCP";
6493
	}
6494

    
6495
	foreach ($config['gateways']['gateway_group'] as $group) {
6496
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6497
			continue;
6498
		}
6499
		foreach ($group['item'] as $item) {
6500
			$item_data = explode("|", $item);
6501
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6502
				return true;
6503
			}
6504
		}
6505
	}
6506

    
6507
	return false;
6508
}
6509

    
6510
function remove_ifindex($ifname) {
6511
	return preg_replace("/[0-9]+$/", "", $ifname);
6512
}
6513

    
6514
?>
(20-20/54)