Project

General

Profile

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

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

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

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

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

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

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

    
58
	return true;
59
}
60

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

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

    
72
	return $interface_arr_cache;
73
}
74

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

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

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

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

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

    
105

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

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

    
128
	return false;
129
}
130

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

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

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

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

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

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

    
203
function vlan_valid_tag($tag = NULL) {
204

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

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

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

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

    
227
        return (false);
228
}
229

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

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

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

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

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

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

    
268
	return (NULL);
269
}
270

    
271
function 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)) {
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
	if (isset($config['vlans']['vlan']) && is_array($config['vlans']['vlan'])) {
303
		foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
304
			if ($if == $vlan['vlanif']) {
305
				return ($vlan);
306
			}
307
		}
308
	}
309

    
310
	/* Check for the first level tag in QinQ interfaces. */
311
	if (isset($config['qinqs']['qinqentry']) && is_array($config['qinqs']['qinqentry'])) {
312
		foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
313
			if ($if == $qinq['vlanif']) {
314
				return ($qinq);
315
			}
316
		}
317
	}
318

    
319
	return (NULL);
320
}
321

    
322
function vlan_interface($vlan = NULL) {
323

    
324
	if ($vlan == NULL || !is_array($vlan) || !isset($vlan['if']) ||
325
	    !isset($vlan['tag']) || !vlan_valid_tag($vlan['tag'])) {
326
		return (NULL);
327
	}
328
	return ("{$vlan['if']}.{$vlan['tag']}");
329
}
330

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

    
345
			/* XXX: Maybe we should report any errors?! */
346
			interface_vlan_configure($vlan);
347
		}
348
	}
349
	if (platform_booting()) {
350
		echo gettext("done.") . "\n";
351
	}
352
}
353

    
354
function interface_vlan_configure(&$vlan) {
355
	global $config, $g;
356

    
357
	if (!is_array($vlan)) {
358
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
359
		return(NULL);
360
	}
361
	$if = $vlan['if'];
362
	if (empty($if)) {
363
		log_error(gettext("interface_vlan_configure called with if undefined."));
364
		return(NULL);
365
	}
366

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

    
375
	/* make sure the parent interface is up */
376
	interfaces_bring_up($if);
377
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
378
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
379

    
380
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
381
		pfSense_interface_destroy($vlanif);
382
	}
383

    
384
	$tmpvlanif = pfSense_interface_create("vlan");
385
	pfSense_interface_rename($tmpvlanif, $vlanif);
386
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
387

    
388
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
389

    
390
	interfaces_bring_up($vlanif);
391

    
392
	/* invalidate interface cache */
393
	get_interface_arr(true);
394

    
395
	/* configure interface if assigned */
396
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
397
	if ($assignedif) {
398
		if (isset($config['interfaces'][$assignedif]['enable'])) {
399
			interface_configure($assignedif, true);
400
		}
401
	}
402

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

    
406
	return $vlanif;
407
}
408

    
409
function interface_qinq_configure(&$qinq, $fd = NULL) {
410
	global $config, $g;
411

    
412
	if (!is_array($qinq)) {
413
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
414
		return;
415
	}
416

    
417
	$qinqif = $qinq['if'];
418
	$tag = $qinq['tag'];
419
	if (empty($qinqif)) {
420
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
421
		return;
422
	}
423

    
424
	if (!does_interface_exist($qinqif)) {
425
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
426
		return;
427
	}
428

    
429
	$vlanif = interface_vlan_configure($qinq);
430
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
431
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
432
		return;
433
	}
434

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

    
444
	pfSense_ngctl_attach(".", $qinqif);
445
	$ngif = str_replace(".", "_", $vlanif);
446
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
447
		exec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1");
448
		exec("/usr/sbin/ngctl msg {$ngif}qinq: gettable > /dev/null 2>&1", $result);
449
		if (empty($result)) {
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
	} else {
455
		fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
456
		fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
457
		fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
458
	}
459

    
460
	/* invalidate interface cache */
461
	get_interface_arr(true);
462

    
463
	if (interface_is_vlan($qinqif) == NULL) {
464
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
465
	}
466

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

    
487
	interfaces_bring_up($qinqif);
488
	if (!empty($qinq['members'])) {
489
		$members = explode(" ", $qinq['members']);
490
		foreach ($members as $qtag) {
491
			interfaces_bring_up(qinq_interface($qinq, $qtag));
492
		}
493
	}
494

    
495
	return $vlanif;
496
}
497

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

    
514
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr) {
515
	global $config, $g;
516

    
517
	if (!is_array($qinq)) {
518
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
519
		return;
520
	}
521

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

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

    
543
	/* invalidate interface cache */
544
	get_interface_arr(true);
545

    
546
	return $vlanif;
547
}
548

    
549
function interfaces_create_wireless_clones() {
550
	global $config, $g;
551

    
552
	if (platform_booting()) {
553
		echo gettext("Creating wireless clone interfaces...");
554
	}
555

    
556
	$iflist = get_configured_interface_list();
557

    
558
	foreach ($iflist as $if) {
559
		$realif = $config['interfaces'][$if]['if'];
560
		if (is_interface_wireless($realif)) {
561
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
562
		}
563
	}
564

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

    
581
}
582

    
583
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
584
	global $config;
585

    
586
	$i = 0;
587
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
588
		foreach ($config['bridges']['bridged'] as $bridge) {
589
			if (empty($bridge['bridgeif'])) {
590
				$bridge['bridgeif'] = "bridge{$i}";
591
			}
592
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
593
				continue;
594
			}
595

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

    
623
function interface_bridge_configure(&$bridge, $checkmember = 0) {
624
	global $config, $g;
625

    
626
	if (!is_array($bridge)) {
627
		return;
628
	}
629

    
630
	if (empty($bridge['members'])) {
631
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
632
		return;
633
	}
634

    
635
	$members = explode(',', $bridge['members']);
636
	if (!count($members)) {
637
		return;
638
	}
639

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

    
665
	/* Just in case anything is not working well */
666
	if ($smallermtu == 0) {
667
		$smallermtu = 1500;
668
	}
669

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

    
681
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
682
	if ($bridgemtu > $smallermtu) {
683
		$smallermtu = $bridgemtu;
684
	}
685

    
686
	$checklist = get_configured_interface_list();
687

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

    
705
	if (isset($bridge['enablestp'])) {
706
		interface_bridge_configure_stp($bridge);
707
	}
708

    
709
	interface_bridge_configure_advanced($bridge);
710

    
711
	interface_bridge_configure_ip6linklocal($bridge);
712

    
713
	if ($bridge['bridgeif']) {
714
		interfaces_bring_up($bridge['bridgeif']);
715
	} else {
716
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
717
	}
718
}
719

    
720
function interface_bridge_configure_stp($bridge) {
721
	if (isset($bridge['enablestp'])) {
722
		$bridgeif = $bridge['bridgeif'];
723
		/* configure spanning tree proto */
724
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
725

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

    
779
function interface_bridge_configure_advanced($bridge) {
780
	$bridgeif = $bridge['bridgeif'];
781

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

    
839
function interface_bridge_configure_ip6linklocal($bridge) {
840
	$bridgeif = $bridge['bridgeif'];
841

    
842
	$members = explode(',', $bridge['members']);
843
	if (!count($members)) {
844
		return;
845
	}
846

    
847
	$auto_linklocal = isset($bridge['ip6linklocal']);
848
	$bridgeop = $auto_linklocal ? '' : '-';
849
	$memberop = $auto_linklocal ? '-' : '';
850

    
851
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
852
	foreach ($members as $member) {
853
		$realif = get_real_interface($member);
854
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
855
	}
856
}
857

    
858
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
859
	global $config;
860

    
861
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
862
		return;
863
	}
864

    
865
	if ($flagsapplied == false) {
866
		$mtu = get_interface_mtu($bridgeif);
867
		$mtum = get_interface_mtu($interface);
868
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
869
			pfSense_interface_mtu($interface, $mtu);
870
		}
871

    
872
		hardware_offloading_applyflags($interface);
873
		interfaces_bring_up($interface);
874
	}
875

    
876
	pfSense_bridge_add_member($bridgeif, $interface);
877
	if (is_array($config['bridges']['bridged'])) {
878
		foreach ($config['bridges']['bridged'] as $bridge) {
879
			if ($bridgeif == $bridge['bridgeif']) {
880
				interface_bridge_configure_stp($bridge);
881
				interface_bridge_configure_advanced($bridge);
882
			}
883
		}
884
	}
885
}
886

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

    
911
function interface_lagg_configure($lagg) {
912
	global $config, $g;
913

    
914
	if (!is_array($lagg)) {
915
		return -1;
916
	}
917

    
918
	$members = explode(',', $lagg['members']);
919
	if (!count($members)) {
920
		return -1;
921
	}
922

    
923
	if (platform_booting() || !(empty($lagg['laggif']))) {
924
		pfSense_interface_destroy($lagg['laggif']);
925
		pfSense_interface_create($lagg['laggif']);
926
		$laggif = $lagg['laggif'];
927
	} else {
928
		$laggif = pfSense_interface_create("lagg");
929
	}
930

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

    
944
	/* Just in case anything is not working well */
945
	if ($lagg_mtu == 0) {
946
		$lagg_mtu = 1500;
947
	}
948

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

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

    
962
	interfaces_bring_up($laggif);
963

    
964
	return $laggif;
965
}
966

    
967
function interfaces_gre_configure($checkparent = 0, $realif = "") {
968
	global $config;
969

    
970
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
971
		foreach ($config['gres']['gre'] as $i => $gre) {
972
			if (empty($gre['greif'])) {
973
				$gre['greif'] = "gre{$i}";
974
			}
975
			if (!empty($realif) && $realif != $gre['greif']) {
976
				continue;
977
			}
978

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

    
1001
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
1002
function interface_gre_configure(&$gre, $grekey = "") {
1003
	global $config, $g;
1004

    
1005
	if (!is_array($gre)) {
1006
		return -1;
1007
	}
1008

    
1009
	$realif = get_real_interface($gre['if']);
1010
	$realifip = get_interface_ip($gre['if']);
1011
	$realifip6 = get_interface_ipv6($gre['if']);
1012

    
1013
	/* make sure the parent interface is up */
1014
	interfaces_bring_up($realif);
1015

    
1016
	if (platform_booting() || !(empty($gre['greif']))) {
1017
		pfSense_interface_destroy($gre['greif']);
1018
		pfSense_interface_create($gre['greif']);
1019
		$greif = $gre['greif'];
1020
	} else {
1021
		$greif = pfSense_interface_create("gre");
1022
	}
1023

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

    
1038
	if ($greif) {
1039
		interfaces_bring_up($greif);
1040
	} else {
1041
		log_error(gettext("Could not bring greif up -- variable not defined."));
1042
	}
1043

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

    
1054
	interfaces_bring_up($greif);
1055

    
1056
	return $greif;
1057
}
1058

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

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

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

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

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

    
1102
	$realif = get_real_interface($gif['if']);
1103
	$ipaddr = get_interface_ip($gif['if']);
1104

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

    
1127
	if (platform_booting() || !(empty($gif['gifif']))) {
1128
		pfSense_interface_destroy($gif['gifif']);
1129
		pfSense_interface_create($gif['gifif']);
1130
		$gifif = $gif['gifif'];
1131
	} else {
1132
		$gifif = pfSense_interface_create("gif");
1133
	}
1134

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

    
1174
	if (!platform_booting()) {
1175
		$iflist = get_configured_interface_list();
1176
		foreach ($iflist as $ifname) {
1177
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1178
				if (get_interface_gateway($ifname)) {
1179
					system_routing_configure($ifname);
1180
					break;
1181
				}
1182
				if (get_interface_gateway_v6($ifname)) {
1183
					system_routing_configure($ifname);
1184
					break;
1185
				}
1186
			}
1187
		}
1188
	}
1189

    
1190

    
1191
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1192
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1193
	}
1194
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1195
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1196
	}
1197

    
1198
	if (is_ipaddrv4($realifgw)) {
1199
		route_add_or_change("-host {$gif['remote-addr']} {$realifgw}");
1200
	}
1201
	if (is_ipaddrv6($realifgw)) {
1202
		route_add_or_change("-host -inet6 {$gif['remote-addr']} {$realifgw}");
1203
	}
1204

    
1205
	interfaces_bring_up($gifif);
1206

    
1207
	return $gifif;
1208
}
1209

    
1210
function interfaces_configure() {
1211
	global $config, $g;
1212

    
1213
	/* Set up our loopback interface */
1214
	interfaces_loopback_configure();
1215

    
1216
	/* create the unconfigured wireless clones */
1217
	interfaces_create_wireless_clones();
1218

    
1219
	/* set up LAGG virtual interfaces */
1220
	interfaces_lagg_configure();
1221

    
1222
	/* set up VLAN virtual interfaces */
1223
	interfaces_vlan_configure();
1224

    
1225
	interfaces_qinq_configure();
1226

    
1227
	$iflist = get_configured_interface_with_descr();
1228
	$delayed_list = array();
1229
	$bridge_list = array();
1230
	$track6_list = array();
1231

    
1232
	/* This is needed to speedup interfaces on bootup. */
1233
	$reload = false;
1234
	if (!platform_booting()) {
1235
		$reload = true;
1236
	}
1237

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

    
1256
			if ($g['debug']) {
1257
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1258
			}
1259
			interface_configure($if, $reload);
1260
			if (platform_booting()) {
1261
				echo gettext("done.") . "\n";
1262
			}
1263
		}
1264
	}
1265

    
1266
	/*
1267
	 * NOTE: The following function parameter consists of
1268
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1269
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1270
	 */
1271

    
1272
	/* set up GRE virtual interfaces */
1273
	interfaces_gre_configure(1);
1274

    
1275
	/* set up GIF virtual interfaces */
1276
	interfaces_gif_configure(1);
1277

    
1278
	/* set up BRIDGe virtual interfaces */
1279
	interfaces_bridge_configure(1);
1280

    
1281
	foreach ($track6_list as $if => $ifname) {
1282
		if (platform_booting()) {
1283
			printf(gettext("Configuring %s interface..."), $ifname);
1284
		}
1285
		if ($g['debug']) {
1286
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1287
		}
1288

    
1289
		interface_configure($if, $reload);
1290

    
1291
		if (platform_booting()) {
1292
			echo gettext("done.") . "\n";
1293
		}
1294
	}
1295

    
1296
	/* bring up vip interfaces */
1297
	interfaces_vips_configure();
1298

    
1299
	/* set up GRE virtual interfaces */
1300
	interfaces_gre_configure(2);
1301

    
1302
	/* set up GIF virtual interfaces */
1303
	interfaces_gif_configure(2);
1304

    
1305
	foreach ($delayed_list as $if => $ifname) {
1306
		if (platform_booting()) {
1307
			printf(gettext("Configuring %s interface..."), $ifname);
1308
		}
1309
		if ($g['debug']) {
1310
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1311
		}
1312

    
1313
		interface_configure($if, $reload);
1314

    
1315
		if (platform_booting()) {
1316
			echo gettext("done.") . "\n";
1317
		}
1318
	}
1319

    
1320
	/* set up BRIDGe virtual interfaces */
1321
	interfaces_bridge_configure(2);
1322

    
1323
	foreach ($bridge_list as $if => $ifname) {
1324
		if (platform_booting()) {
1325
			printf(gettext("Configuring %s interface..."), $ifname);
1326
		}
1327
		if ($g['debug']) {
1328
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1329
		}
1330

    
1331
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1332
		// redmine #3997
1333
		interface_reconfigure($if, $reload);
1334
		interfaces_vips_configure($if);
1335

    
1336
		if (platform_booting()) {
1337
			echo gettext("done.") . "\n";
1338
		}
1339
	}
1340

    
1341
	/* configure interface groups */
1342
	interfaces_group_setup();
1343

    
1344
	if (!platform_booting()) {
1345
		/* reconfigure static routes (kernel may have deleted them) */
1346
		system_routing_configure();
1347

    
1348
		/* reload IPsec tunnels */
1349
		vpn_ipsec_configure();
1350

    
1351
		/* restart dns servers (defering dhcpd reload) */
1352
		if (isset($config['dnsmasq']['enable'])) {
1353
			services_dnsmasq_configure(false);
1354
		}
1355
		if (isset($config['unbound']['enable'])) {
1356
			services_unbound_configure(false);
1357
		}
1358

    
1359
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1360
		services_dhcpd_configure();
1361
	}
1362

    
1363
	return 0;
1364
}
1365

    
1366
function interface_reconfigure($interface = "wan", $reloadall = false) {
1367
	interface_bring_down($interface);
1368
	interface_configure($interface, $reloadall);
1369
}
1370

    
1371
function interface_vip_bring_down($vip) {
1372
	global $g;
1373

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

    
1403
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1404
	global $config, $g;
1405

    
1406
	if (!isset($config['interfaces'][$interface])) {
1407
		return;
1408
	}
1409

    
1410
	if ($g['debug']) {
1411
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1412
	}
1413

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

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

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

    
1551
	if (!empty($track6) && is_array($track6)) {
1552
		if (!function_exists('services_dhcpd_configure')) {
1553
			require_once('services.inc');
1554
		}
1555
		/* Bring down radvd and dhcp6 on these interfaces */
1556
		services_dhcpd_configure('inet6', $track6);
1557
	}
1558

    
1559
	$old_router = '';
1560
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1561
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1562
	}
1563

    
1564
	/* remove interface up file if it exists */
1565
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1566
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1567
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1568
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1569
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1570
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1571
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1572

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

    
1580
	if ($destroy == true) {
1581
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1582
			pfSense_interface_destroy($realif);
1583
		}
1584
	}
1585

    
1586
	return;
1587
}
1588

    
1589
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1590
	global $config;
1591
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1592
		unset($config["virtualip_carp_maintenancemode"]);
1593
		write_config("Leave CARP maintenance mode");
1594
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1595
		$config["virtualip_carp_maintenancemode"] = true;
1596
		write_config(gettext("Enter CARP maintenance mode"));
1597
	}
1598

    
1599
	$viparr = &$config['virtualip']['vip'];
1600
	foreach ($viparr as $vip) {
1601
		if ($vip['mode'] == "carp") {
1602
			interface_carp_configure($vip);
1603
		}
1604
	}
1605
}
1606

    
1607
function interface_wait_tentative($interface, $timeout = 10) {
1608
	if (!does_interface_exist($interface)) {
1609
		return false;
1610
	}
1611

    
1612
	$time = 0;
1613
	while ($time <= $timeout) {
1614
		$if = pfSense_get_interface_addresses($interface);
1615
		if (!isset($if['tentative'])) {
1616
			return true;
1617
		}
1618
		sleep(1);
1619
		$time++;
1620
	}
1621

    
1622
	return false;
1623
}
1624

    
1625
function interface_isppp_type($interface) {
1626
	global $config;
1627

    
1628
	if (!is_array($config['interfaces'][$interface])) {
1629
		return false;
1630
	}
1631

    
1632
	switch ($config['interfaces'][$interface]['ipaddr']) {
1633
		case 'pptp':
1634
		case 'l2tp':
1635
		case 'pppoe':
1636
		case 'ppp':
1637
			return true;
1638
			break;
1639
		default:
1640
			return false;
1641
			break;
1642
	}
1643
}
1644

    
1645
function interfaces_ptpid_used($ptpid) {
1646
	global $config;
1647

    
1648
	if (is_array($config['ppps']['ppp'])) {
1649
		foreach ($config['ppps']['ppp'] as & $settings) {
1650
			if ($ptpid == $settings['ptpid']) {
1651
				return true;
1652
			}
1653
		}
1654
	}
1655

    
1656
	return false;
1657
}
1658

    
1659
function interfaces_ptpid_next() {
1660

    
1661
	$ptpid = 0;
1662
	while (interfaces_ptpid_used($ptpid)) {
1663
		$ptpid++;
1664
	}
1665

    
1666
	return $ptpid;
1667
}
1668

    
1669
function getMPDCRONSettings($pppif) {
1670
	global $config;
1671

    
1672
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1673
	if (is_array($config['cron']['item'])) {
1674
		foreach ($config['cron']['item'] as $i => $item) {
1675
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1676
				return array("ID" => $i, "ITEM" => $item);
1677
			}
1678
		}
1679
	}
1680

    
1681
	return NULL;
1682
}
1683

    
1684
function handle_pppoe_reset($post_array) {
1685
	global $config, $g;
1686

    
1687
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1688
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1689

    
1690
	if (!is_array($config['cron']['item'])) {
1691
		$config['cron']['item'] = array();
1692
	}
1693

    
1694
	$itemhash = getMPDCRONSettings($pppif);
1695

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

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

    
1767
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
1768
	global $config;
1769
	$ppp_list = array();
1770
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1771
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1772
			$ports = explode(",", $ppp['ports']);
1773
			foreach($ports as $port) {
1774
				foreach($triggerinterfaces as $vip) {
1775
					if ($port == "_vip{$vip['uniqid']}") {
1776
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
1777
						$ppp_list[$if] = 1;
1778
					}
1779
				}
1780
			}
1781
		}
1782
	}
1783
	foreach($ppp_list as $pppif => $dummy) {
1784
		interface_ppps_configure($pppif);
1785
	}
1786
}
1787

    
1788
/*
1789
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1790
 * It writes the mpd config file to /var/etc every time the link is opened.
1791
 */
1792
function interface_ppps_configure($interface) {
1793
	global $config, $g;
1794

    
1795
	/* Return for unassigned interfaces. This is a minimum requirement. */
1796
	if (empty($config['interfaces'][$interface])) {
1797
		return 0;
1798
	}
1799
	$ifcfg = $config['interfaces'][$interface];
1800
	if (!isset($ifcfg['enable'])) {
1801
		return 0;
1802
	}
1803

    
1804
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1805
	if (!is_dir("/var/spool/lock")) {
1806
		mkdir("/var/spool/lock", 0777, true);
1807
	}
1808
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1809
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1810
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1811
	}
1812

    
1813
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1814
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1815
			if ($ifcfg['if'] == $ppp['if']) {
1816
				break;
1817
			}
1818
		}
1819
	}
1820
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
1821
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1822
		return 0;
1823
	}
1824
	$pppif = $ifcfg['if'];
1825
	if ($ppp['type'] == "ppp") {
1826
		$type = "modem";
1827
	} else {
1828
		$type = $ppp['type'];
1829
	}
1830
	$upper_type = strtoupper($ppp['type']);
1831

    
1832
	/* XXX: This does not make sense and may create trouble
1833
	 * comment it for now to be removed later on.
1834
	if (platform_booting()) {
1835
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1836
		echo "starting {$pppif} link...";
1837
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1838
			return 0;
1839
	}
1840
	*/
1841
	$confports = explode(',', $ppp['ports']);
1842
	if ($type == "modem") {
1843
		$ports = $confports;
1844
	} else {
1845
		$ports = array();
1846
		foreach ($confports as $pid => $port) {
1847
			if (strstr($port, "_vip")) {
1848
				if (get_carp_interface_status($port) != "MASTER") {
1849
					continue;
1850
				}
1851
			}
1852
			$ports[$pid] = get_real_interface($port);
1853
			if (empty($ports[$pid])) {
1854
				return 0;
1855
			}
1856
		}
1857
	}
1858
	$localips = explode(',', $ppp['localip']);
1859
	$gateways = explode(',', $ppp['gateway']);
1860
	$subnets = explode(',', $ppp['subnet']);
1861

    
1862
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1863
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1864
	 */
1865
	foreach ($ports as $pid => $port) {
1866
		switch ($ppp['type']) {
1867
			case "pppoe":
1868
				/* Bring the parent interface up */
1869
				interfaces_bring_up($port);
1870
				pfSense_ngctl_attach(".", $port);
1871
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1872
				$ngif = str_replace(".", "_", $port);
1873
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
1874
				break;
1875
			case "pptp":
1876
			case "l2tp":
1877
				/* configure interface */
1878
				if (is_ipaddr($localips[$pid])) {
1879
					// Manually configure interface IP/subnet
1880
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1881
					interfaces_bring_up($port);
1882
				} else if (empty($localips[$pid])) {
1883
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1884
				}
1885

    
1886
				if (!is_ipaddr($localips[$pid])) {
1887
					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));
1888
					$localips[$pid] = "0.0.0.0";
1889
				}
1890
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
1891
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1892
				}
1893
				if (!is_ipaddr($gateways[$pid])) {
1894
					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));
1895
					return 0;
1896
				}
1897
				pfSense_ngctl_attach(".", $port);
1898
				break;
1899
			case "ppp":
1900
				if (!file_exists("{$port}")) {
1901
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1902
					return 0;
1903
				}
1904
				break;
1905
			default:
1906
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1907
				break;
1908
		}
1909
	}
1910

    
1911
	if (is_array($ports) && count($ports) > 1) {
1912
		$multilink = "enable";
1913
	} else {
1914
		$multilink = "disable";
1915
	}
1916

    
1917
	if ($type == "modem") {
1918
		if (is_ipaddr($ppp['localip'])) {
1919
			$localip = $ppp['localip'];
1920
		} else {
1921
			$localip = '0.0.0.0';
1922
		}
1923

    
1924
		if (is_ipaddr($ppp['gateway'])) {
1925
			$gateway = $ppp['gateway'];
1926
		} else {
1927
			$gateway = "10.64.64.{$pppid}";
1928
		}
1929
		$ranges = "{$localip}/0 {$gateway}/0";
1930

    
1931
		if (empty($ppp['apnum'])) {
1932
			$ppp['apnum'] = 1;
1933
		}
1934
	} else {
1935
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1936
	}
1937

    
1938
	if (isset($ppp['ondemand'])) {
1939
		$ondemand = "enable";
1940
	} else {
1941
		$ondemand = "disable";
1942
	}
1943
	if (!isset($ppp['idletimeout'])) {
1944
		$ppp['idletimeout'] = 0;
1945
	}
1946

    
1947
	if (empty($ppp['username']) && $type == "modem") {
1948
		$ppp['username'] = "user";
1949
		$ppp['password'] = "none";
1950
	}
1951
	if (empty($ppp['password']) && $type == "modem") {
1952
		$passwd = "none";
1953
	} else {
1954
		$passwd = base64_decode($ppp['password']);
1955
	}
1956

    
1957
	$bandwidths = explode(',', $ppp['bandwidth']);
1958
	$defaultmtu = "1492";
1959
	if (!empty($ifcfg['mtu'])) {
1960
		$defaultmtu = intval($ifcfg['mtu']);
1961
	}
1962
	if (isset($ppp['mtu'])) {
1963
		$mtus = explode(',', $ppp['mtu']);
1964
	}
1965
	if (isset($ppp['mru'])) {
1966
		$mrus = explode(',', $ppp['mru']);
1967
	}
1968
	if (isset($ppp['mrru'])) {
1969
		$mrrus = explode(',', $ppp['mrru']);
1970
	}
1971

    
1972
	// Construct the mpd.conf file
1973
	$mpdconf = <<<EOD
1974
startup:
1975
	# configure the console
1976
	set console close
1977
	# configure the web server
1978
	set web close
1979

    
1980
default:
1981
{$ppp['type']}client:
1982
	create bundle static {$interface}
1983
	set bundle enable ipv6cp
1984
	set iface name {$pppif}
1985

    
1986
EOD;
1987
	$setdefaultgw = false;
1988
	$founddefaultgw = false;
1989
	if (is_array($config['gateways']['gateway_item'])) {
1990
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1991
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1992
				$setdefaultgw = true;
1993
				break;
1994
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1995
				$founddefaultgw = true;
1996
				break;
1997
			}
1998
		}
1999
	}
2000

    
2001
/* Omit this, we maintain the default route by other means, and it causes problems with
2002
 * default gateway switching. See redmine #1837 for original issue
2003
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2004
 * edge case. redmine #6495 open to address.
2005
 */
2006
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
2007
		$setdefaultgw = true;
2008
		$mpdconf .= <<<EOD
2009
	set iface route default
2010

    
2011
EOD;
2012
	}
2013
	$mpdconf .= <<<EOD
2014
	set iface {$ondemand} on-demand
2015
	set iface idle {$ppp['idletimeout']}
2016

    
2017
EOD;
2018

    
2019
	if (isset($ppp['ondemand'])) {
2020
		$mpdconf .= <<<EOD
2021
	set iface addrs 10.10.1.1 10.10.1.2
2022

    
2023
EOD;
2024
	}
2025

    
2026
	if (isset($ppp['tcpmssfix'])) {
2027
		$tcpmss = "disable";
2028
	} else {
2029
		$tcpmss = "enable";
2030
	}
2031
	$mpdconf .= <<<EOD
2032
	set iface {$tcpmss} tcpmssfix
2033

    
2034
EOD;
2035

    
2036
	$mpdconf .= <<<EOD
2037
	set iface up-script /usr/local/sbin/ppp-linkup
2038
	set iface down-script /usr/local/sbin/ppp-linkdown
2039
	set ipcp ranges {$ranges}
2040

    
2041
EOD;
2042
	if (isset($ppp['vjcomp'])) {
2043
		$mpdconf .= <<<EOD
2044
	set ipcp no vjcomp
2045

    
2046
EOD;
2047
	}
2048

    
2049
	if (isset($config['system']['dnsallowoverride'])) {
2050
		$mpdconf .= <<<EOD
2051
	set ipcp enable req-pri-dns
2052
	set ipcp enable req-sec-dns
2053

    
2054
EOD;
2055
	}
2056

    
2057
	if (!isset($ppp['verbose_log'])) {
2058
		$mpdconf .= <<<EOD
2059
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2060

    
2061
EOD;
2062
	}
2063

    
2064
	foreach ($ports as $pid => $port) {
2065
		$port = get_real_interface($port);
2066
		$mpdconf .= <<<EOD
2067

    
2068
	create link static {$interface}_link{$pid} {$type}
2069
	set link action bundle {$interface}
2070
	set link {$multilink} multilink
2071
	set link keep-alive 10 60
2072
	set link max-redial 0
2073

    
2074
EOD;
2075
		if (isset($ppp['shortseq'])) {
2076
			$mpdconf .= <<<EOD
2077
	set link no shortseq
2078

    
2079
EOD;
2080
		}
2081

    
2082
		if (isset($ppp['acfcomp'])) {
2083
			$mpdconf .= <<<EOD
2084
	set link no acfcomp
2085

    
2086
EOD;
2087
		}
2088

    
2089
		if (isset($ppp['protocomp'])) {
2090
			$mpdconf .= <<<EOD
2091
	set link no protocomp
2092

    
2093
EOD;
2094
		}
2095

    
2096
		$mpdconf .= <<<EOD
2097
	set link disable chap pap
2098
	set link accept chap pap eap
2099
	set link disable incoming
2100

    
2101
EOD;
2102

    
2103

    
2104
		if (!empty($bandwidths[$pid])) {
2105
			$mpdconf .= <<<EOD
2106
	set link bandwidth {$bandwidths[$pid]}
2107

    
2108
EOD;
2109
		}
2110

    
2111
		if (empty($mtus[$pid])) {
2112
			$mtus[$pid] = $defaultmtu;
2113
		}
2114
		if ($type == "pppoe") {
2115
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2116
				$mtus[$pid] = get_interface_mtu($port) - 8;
2117
			}
2118
		}
2119
		if (! ($type == "pppoe" && $mtus[$pid] > 1492) ) {
2120
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2121
			$mpdconf .= <<<EOD
2122
	set link mtu {$mtus[$pid]}
2123

    
2124
EOD;
2125
		}
2126

    
2127
		if (!empty($mrus[$pid])) {
2128
			$mpdconf .= <<<EOD
2129
	set link mru {$mrus[$pid]}
2130

    
2131
EOD;
2132
		}
2133

    
2134
		if (!empty($mrrus[$pid])) {
2135
			$mpdconf .= <<<EOD
2136
	set link mrru {$mrrus[$pid]}
2137

    
2138
EOD;
2139
		}
2140

    
2141
		$mpdconf .= <<<EOD
2142
	set auth authname "{$ppp['username']}"
2143
	set auth password {$passwd}
2144

    
2145
EOD;
2146
		if ($type == "modem") {
2147
			$mpdconf .= <<<EOD
2148
	set modem device {$ppp['ports']}
2149
	set modem script DialPeer
2150
	set modem idle-script Ringback
2151
	set modem watch -cd
2152
	set modem var \$DialPrefix "DT"
2153
	set modem var \$Telephone "{$ppp['phone']}"
2154

    
2155
EOD;
2156
		}
2157
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2158
			$mpdconf .= <<<EOD
2159
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2160

    
2161
EOD;
2162
		}
2163
		if (isset($ppp['initstr']) && $type == "modem") {
2164
			$initstr = base64_decode($ppp['initstr']);
2165
			$mpdconf .= <<<EOD
2166
	set modem var \$InitString "{$initstr}"
2167

    
2168
EOD;
2169
		}
2170
		if (isset($ppp['simpin']) && $type == "modem") {
2171
			if ($ppp['pin-wait'] == "") {
2172
				$ppp['pin-wait'] = 0;
2173
			}
2174
			$mpdconf .= <<<EOD
2175
	set modem var \$SimPin "{$ppp['simpin']}"
2176
	set modem var \$PinWait "{$ppp['pin-wait']}"
2177

    
2178
EOD;
2179
		}
2180
		if (isset($ppp['apn']) && $type == "modem") {
2181
			$mpdconf .= <<<EOD
2182
	set modem var \$APN "{$ppp['apn']}"
2183
	set modem var \$APNum "{$ppp['apnum']}"
2184

    
2185
EOD;
2186
		}
2187
		if ($type == "pppoe") {
2188
			// Send a null service name if none is set.
2189
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2190
			$mpdconf .= <<<EOD
2191
	set pppoe service "{$provider}"
2192

    
2193
EOD;
2194
		}
2195
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
2196
			$mpdconf .= <<<EOD
2197
	set pppoe max-payload {$mtus[$pid]}
2198

    
2199
EOD;
2200
		}
2201
		if ($type == "pppoe") {
2202
			$mpdconf .= <<<EOD
2203
	set pppoe iface {$port}
2204

    
2205
EOD;
2206
		}
2207

    
2208
		if ($type == "pptp" || $type == "l2tp") {
2209
			$mpdconf .= <<<EOD
2210
	set {$type} self {$localips[$pid]}
2211
	set {$type} peer {$gateways[$pid]}
2212

    
2213
EOD;
2214
		}
2215

    
2216
		$mpdconf .= "\topen\n";
2217
	} //end foreach ($port)
2218

    
2219

    
2220
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2221
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2222
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2223
	} else {
2224
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2225
		if (!$fd) {
2226
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2227
			return 0;
2228
		}
2229
		// Write out mpd_ppp.conf
2230
		fwrite($fd, $mpdconf);
2231
		fclose($fd);
2232
		unset($mpdconf);
2233
	}
2234

    
2235
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2236
	if (isset($ppp['uptime'])) {
2237
		if (!file_exists("/conf/{$pppif}.log")) {
2238
			file_put_contents("/conf/{$pppif}.log", '');
2239
		}
2240
	} else {
2241
		if (file_exists("/conf/{$pppif}.log")) {
2242
			@unlink("/conf/{$pppif}.log");
2243
		}
2244
	}
2245

    
2246
	/* clean up old lock files */
2247
	foreach ($ports as $port) {
2248
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2249
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2250
		}
2251
	}
2252

    
2253
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2254
	/* random IPv6 interface identifier during boot. More details at */
2255
	/* https://forum.pfsense.org/index.php?topic=101967.msg570519#msg570519 */
2256
	if (platform_booting() && is_array($config['interfaces'])) {
2257
		$count = 0;
2258
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2259
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2260
				$tempaddr[$count]['if'] = $tempiface['if'];
2261
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2262
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2263
				$count++;
2264
			}
2265
			// Maximum /31 is is x.y.z.254/31
2266
			if ($count > 122) {
2267
				break;
2268
			}
2269
		}
2270
		unset($count);
2271
	}
2272

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

    
2278
	// Check for PPPoE periodic reset request
2279
	if ($type == "pppoe") {
2280
		if (!empty($ppp['pppoe-reset-type'])) {
2281
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2282
		} else {
2283
			interface_setup_pppoe_reset_file($ppp['if']);
2284
		}
2285
	}
2286
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
2287
	$i = 0;
2288
	while ($i < 3) {
2289
		sleep(10);
2290
		if (does_interface_exist($ppp['if'], true)) {
2291
			break;
2292
		}
2293
		$i++;
2294
	}
2295

    
2296
	/* Remove all temporary bogon IPv4 addresses */
2297
	if (is_array($tempaddr)) {
2298
		foreach ($tempaddr as $tempiface) {
2299
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2300
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2301
			}
2302
		}
2303
		unset ($tempaddr);
2304
	}
2305

    
2306
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2307
	/* We should be able to launch the right version for each modem */
2308
	/* We can also guess the mondev from the manufacturer */
2309
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2310
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2311
	foreach ($ports as $port) {
2312
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2313
			$mondev = substr(basename($port), 0, -1);
2314
			$devlist = glob("/dev/{$mondev}?");
2315
			$mondev = basename(end($devlist));
2316
		}
2317
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2318
			$mondev = substr(basename($port), 0, -1) . "1";
2319
		}
2320
		if ($mondev != '') {
2321
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2322
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2323
		}
2324
	}
2325

    
2326
	return 1;
2327
}
2328

    
2329
function interfaces_sync_setup() {
2330
	global $g, $config;
2331

    
2332
	if (isset($config['system']['developerspew'])) {
2333
		$mt = microtime();
2334
		echo "interfaces_sync_setup() being called $mt\n";
2335
	}
2336

    
2337
	if (platform_booting()) {
2338
		echo gettext("Configuring CARP settings...");
2339
		mute_kernel_msgs();
2340
	}
2341

    
2342
	/* suck in configuration items */
2343
	if ($config['hasync']) {
2344
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2345
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2346
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2347
	} else {
2348
		unset($pfsyncinterface);
2349
		unset($pfsyncenabled);
2350
	}
2351

    
2352
	set_sysctl(array(
2353
		"net.inet.carp.preempt" => "1",
2354
		"net.inet.carp.log" => "1")
2355
	);
2356

    
2357
	if (!empty($pfsyncinterface)) {
2358
		$carp_sync_int = get_real_interface($pfsyncinterface);
2359
	} else {
2360
		unset($carp_sync_int);
2361
	}
2362

    
2363
	/* setup pfsync interface */
2364
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2365
		if (is_ipaddr($pfsyncpeerip)) {
2366
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2367
		} else {
2368
			$syncpeer = "-syncpeer";
2369
		}
2370

    
2371
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2372
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2373

    
2374
		sleep(1);
2375

    
2376
		/* 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
2377
		 * for existing sessions.
2378
		 */
2379
		log_error(gettext("waiting for pfsync..."));
2380
		$i = 0;
2381
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2382
			$i++;
2383
			sleep(1);
2384
		}
2385
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2386
		log_error(gettext("Configuring CARP settings finalize..."));
2387
	} else {
2388
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2389
	}
2390

    
2391
	$carplist = get_configured_vip_list('all', VIP_CARP);
2392
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2393
		set_single_sysctl("net.inet.carp.allow", "1");
2394
	} else {
2395
		set_single_sysctl("net.inet.carp.allow", "0");
2396
	}
2397

    
2398
	if (platform_booting()) {
2399
		unmute_kernel_msgs();
2400
		echo gettext("done.") . "\n";
2401
	}
2402
}
2403

    
2404
function interface_proxyarp_configure($interface = "") {
2405
	global $config, $g;
2406
	if (isset($config['system']['developerspew'])) {
2407
		$mt = microtime();
2408
		echo "interface_proxyarp_configure() being called $mt\n";
2409
	}
2410

    
2411
	/* kill any running choparp */
2412
	if (empty($interface)) {
2413
		killbyname("choparp");
2414
	} else {
2415
		$vipif = get_real_interface($interface);
2416
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2417
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2418
		}
2419
	}
2420

    
2421
	$paa = array();
2422
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2423

    
2424
		/* group by interface */
2425
		foreach ($config['virtualip']['vip'] as $vipent) {
2426
			if ($vipent['mode'] === "proxyarp") {
2427
				if ($vipent['interface']) {
2428
					$proxyif = $vipent['interface'];
2429
				} else {
2430
					$proxyif = "wan";
2431
				}
2432

    
2433
				if (!empty($interface) && $interface != $proxyif) {
2434
					continue;
2435
				}
2436

    
2437
				if (!is_array($paa[$proxyif])) {
2438
					$paa[$proxyif] = array();
2439
				}
2440

    
2441
				$paa[$proxyif][] = $vipent;
2442
			}
2443
		}
2444
	}
2445

    
2446
	if (!empty($interface)) {
2447
		if (is_array($paa[$interface])) {
2448
			$paaifip = get_interface_ip($interface);
2449
			if (!is_ipaddr($paaifip)) {
2450
				return;
2451
			}
2452
			$vipif = get_real_interface($interface);
2453
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2454
			$args .= $vipif . " auto";
2455
			foreach ($paa[$interface] as $paent) {
2456
				if (isset($paent['subnet'])) {
2457
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2458
				} else if (isset($paent['range'])) {
2459
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2460
				}
2461
			}
2462
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2463
		}
2464
	} else if (count($paa) > 0) {
2465
		foreach ($paa as $paif => $paents) {
2466
			$paaifip = get_interface_ip($paif);
2467
			if (!is_ipaddr($paaifip)) {
2468
				continue;
2469
			}
2470
			$vipif = get_real_interface($paif);
2471
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2472
			$args .= $vipif . " auto";
2473
			foreach ($paents as $paent) {
2474
				if (isset($paent['subnet'])) {
2475
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2476
				} else if (isset($paent['range'])) {
2477
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2478
				}
2479
			}
2480
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2481
		}
2482
	}
2483
}
2484

    
2485
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2486
	global $g, $config;
2487

    
2488
	if (is_array($config['virtualip']['vip'])) {
2489
		foreach ($config['virtualip']['vip'] as $vip) {
2490

    
2491
			$iface = $vip['interface'];
2492
			if (substr($iface, 0, 4) == "_vip")
2493
				$iface = get_configured_vip_interface($vip['interface']);
2494
			if ($iface != $interface)
2495
				continue;
2496
			if ($type == VIP_CARP) {
2497
				if ($vip['mode'] != "carp")
2498
					continue;
2499
			} elseif ($type == VIP_IPALIAS) {
2500
				if ($vip['mode'] != "ipalias")
2501
					continue;
2502
			} else {
2503
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2504
					continue;
2505
			}
2506

    
2507
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2508
				interface_vip_bring_down($vip);
2509
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2510
				interface_vip_bring_down($vip);
2511
			else if ($inet == "all")
2512
				interface_vip_bring_down($vip);
2513
		}
2514
	}
2515
}
2516

    
2517
function interfaces_vips_configure($interface = "") {
2518
	global $g, $config;
2519
	if (isset($config['system']['developerspew'])) {
2520
		$mt = microtime();
2521
		echo "interfaces_vips_configure() being called $mt\n";
2522
	}
2523
	$paa = array();
2524
	if (is_array($config['virtualip']['vip'])) {
2525
		$carp_setuped = false;
2526
		$anyproxyarp = false;
2527
		foreach ($config['virtualip']['vip'] as $vip) {
2528
			if ($interface <> "" && $vip['interface'] <> $interface) {
2529
				continue;
2530
			}
2531
			switch ($vip['mode']) {
2532
				case "proxyarp":
2533
					/* nothing it is handled on interface_proxyarp_configure() */
2534
					$anyproxyarp = true;
2535
					break;
2536
				case "ipalias":
2537
					interface_ipalias_configure($vip);
2538
					break;
2539
				case "carp":
2540
					if ($carp_setuped == false) {
2541
						$carp_setuped = true;
2542
					}
2543
					interface_carp_configure($vip);
2544
					break;
2545
			}
2546
		}
2547
		if ($carp_setuped == true) {
2548
			interfaces_sync_setup();
2549
		}
2550
		if ($anyproxyarp == true) {
2551
			interface_proxyarp_configure();
2552
		}
2553
	}
2554
}
2555

    
2556
function interface_ipalias_configure(&$vip) {
2557
	global $config;
2558

    
2559
	if ($vip['mode'] != 'ipalias') {
2560
		return;
2561
	}
2562

    
2563
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2564
	if ($realif != "lo0") {
2565
		$if = convert_real_interface_to_friendly_interface_name($realif);
2566
		if (!isset($config['interfaces'][$if]) ||
2567
		    !isset($config['interfaces'][$if]['enable'])) {
2568
			return;
2569
		}
2570
	}
2571

    
2572
	$af = 'inet';
2573
	if (is_ipaddrv6($vip['subnet'])) {
2574
		$af = 'inet6';
2575
	}
2576
	$iface = $vip['interface'];
2577
	$vhid = '';
2578
	if (substr($vip['interface'], 0, 4) == "_vip") {
2579
		$carpvip = get_configured_vip($vip['interface']);
2580
		$iface = $carpvip['interface'];
2581
		$vhid = "vhid {$carpvip['vhid']}";
2582
	}
2583
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2584
	unset($iface, $af, $realif, $carpvip, $vhid);
2585
}
2586

    
2587
function interface_carp_configure(&$vip) {
2588
	global $config, $g;
2589
	if (isset($config['system']['developerspew'])) {
2590
		$mt = microtime();
2591
		echo "interface_carp_configure() being called $mt\n";
2592
	}
2593

    
2594
	if ($vip['mode'] != "carp") {
2595
		return;
2596
	}
2597

    
2598
	$realif = get_real_interface($vip['interface']);
2599
	if (!does_interface_exist($realif)) {
2600
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2601
		return;
2602
	}
2603
	if ($realif != "lo0") {
2604
		if (!isset($config['interfaces'][$vip['interface']]) ||
2605
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
2606
			return;
2607
		}
2608
	}
2609

    
2610
	$vip_password = $vip['password'];
2611
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2612
	if ($vip['password'] != "") {
2613
		$password = " pass {$vip_password}";
2614
	}
2615

    
2616
	$advbase = "";
2617
	if (!empty($vip['advbase'])) {
2618
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2619
	}
2620

    
2621
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2622
	if ($carp_maintenancemode) {
2623
		$advskew = "advskew 254";
2624
	} else {
2625
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2626
	}
2627

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

    
2630
	if (is_ipaddrv4($vip['subnet'])) {
2631
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2632
	} else if (is_ipaddrv6($vip['subnet'])) {
2633
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2634
	}
2635

    
2636
	return $realif;
2637
}
2638

    
2639
function interface_wireless_clone($realif, $wlcfg) {
2640
	global $config, $g;
2641
	/*   Check to see if interface has been cloned as of yet.
2642
	 *   If it has not been cloned then go ahead and clone it.
2643
	 */
2644
	$needs_clone = false;
2645
	if (is_array($wlcfg['wireless'])) {
2646
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2647
	} else {
2648
		$wlcfg_mode = $wlcfg['mode'];
2649
	}
2650
	switch ($wlcfg_mode) {
2651
		case "hostap":
2652
			$mode = "wlanmode hostap";
2653
			break;
2654
		case "adhoc":
2655
			$mode = "wlanmode adhoc";
2656
			break;
2657
		default:
2658
			$mode = "";
2659
			break;
2660
	}
2661
	$baseif = interface_get_wireless_base($wlcfg['if']);
2662
	if (does_interface_exist($realif)) {
2663
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2664
		$ifconfig_str = implode($output);
2665
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2666
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2667
			$needs_clone = true;
2668
		}
2669
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2670
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2671
			$needs_clone = true;
2672
		}
2673
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2674
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2675
			$needs_clone = true;
2676
		}
2677
	} else {
2678
		$needs_clone = true;
2679
	}
2680

    
2681
	if ($needs_clone == true) {
2682
		/* remove previous instance if it exists */
2683
		if (does_interface_exist($realif)) {
2684
			pfSense_interface_destroy($realif);
2685
		}
2686

    
2687
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2688
		// Create the new wlan interface. FreeBSD returns the new interface name.
2689
		// example:  wlan2
2690
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2691
		if ($ret <> 0) {
2692
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2693
			return false;
2694
		}
2695
		$newif = trim($out[0]);
2696
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2697
		pfSense_interface_rename($newif, $realif);
2698
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2699
	}
2700
	return true;
2701
}
2702

    
2703
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2704
	global $config, $g;
2705

    
2706
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2707
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2708
				 'regdomain', 'regcountry', 'reglocation');
2709

    
2710
	if (!is_interface_wireless($ifcfg['if'])) {
2711
		return;
2712
	}
2713

    
2714
	$baseif = interface_get_wireless_base($ifcfg['if']);
2715

    
2716
	// Sync shared settings for assigned clones
2717
	$iflist = get_configured_interface_list(true);
2718
	foreach ($iflist as $if) {
2719
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2720
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2721
				foreach ($shared_settings as $setting) {
2722
					if ($sync_changes) {
2723
						if (isset($ifcfg['wireless'][$setting])) {
2724
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2725
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2726
							unset($config['interfaces'][$if]['wireless'][$setting]);
2727
						}
2728
					} else {
2729
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2730
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2731
						} else if (isset($ifcfg['wireless'][$setting])) {
2732
							unset($ifcfg['wireless'][$setting]);
2733
						}
2734
					}
2735
				}
2736
				if (!$sync_changes) {
2737
					break;
2738
				}
2739
			}
2740
		}
2741
	}
2742

    
2743
	// Read or write settings at shared area
2744
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2745
		foreach ($shared_settings as $setting) {
2746
			if ($sync_changes) {
2747
				if (isset($ifcfg['wireless'][$setting])) {
2748
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2749
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2750
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2751
				}
2752
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2753
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2754
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2755
				} else if (isset($ifcfg['wireless'][$setting])) {
2756
					unset($ifcfg['wireless'][$setting]);
2757
				}
2758
			}
2759
		}
2760
	}
2761

    
2762
	// Sync the mode on the clone creation page with the configured mode on the interface
2763
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2764
		foreach ($config['wireless']['clone'] as &$clone) {
2765
			if ($clone['cloneif'] == $ifcfg['if']) {
2766
				if ($sync_changes) {
2767
					$clone['mode'] = $ifcfg['wireless']['mode'];
2768
				} else {
2769
					$ifcfg['wireless']['mode'] = $clone['mode'];
2770
				}
2771
				break;
2772
			}
2773
		}
2774
		unset($clone);
2775
	}
2776
}
2777

    
2778
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2779
	global $config, $g;
2780

    
2781
	/*    open up a shell script that will be used to output the commands.
2782
	 *    since wireless is changing a lot, these series of commands are fragile
2783
	 *    and will sometimes need to be verified by a operator by executing the command
2784
	 *    and returning the output of the command to the developers for inspection.  please
2785
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2786
	 */
2787

    
2788
	// Remove script file
2789
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2790

    
2791
	// Clone wireless nic if needed.
2792
	interface_wireless_clone($if, $wl);
2793

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

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

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

    
2803
	/* set values for /path/program */
2804
	if (file_exists("/usr/local/sbin/hostapd")) {
2805
		$hostapd = "/usr/local/sbin/hostapd";
2806
	} else {
2807
		$hostapd = "/usr/sbin/hostapd";
2808
	}
2809
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
2810
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
2811
	} else {
2812
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2813
	}
2814
	$ifconfig = "/sbin/ifconfig";
2815
	$sysctl = "/sbin/sysctl";
2816
	$sysctl_args = "-q";
2817
	$killall = "/usr/bin/killall";
2818

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

    
2821
	$wlcmd = array();
2822
	$wl_sysctl = array();
2823
	/* Set a/b/g standard */
2824
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2825
	/* skip mode entirely for "auto" */
2826
	if ($wlcfg['standard'] != "auto") {
2827
		$wlcmd[] = "mode " . escapeshellarg($standard);
2828
	}
2829

    
2830
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2831
	 * to prevent massive packet loss under certain conditions. */
2832
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2833
		$wlcmd[] = "-ampdu";
2834
	}
2835

    
2836
	/* Set ssid */
2837
	if ($wlcfg['ssid']) {
2838
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2839
	}
2840

    
2841
	/* Set 802.11g protection mode */
2842
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2843

    
2844
	/* set wireless channel value */
2845
	if (isset($wlcfg['channel'])) {
2846
		if ($wlcfg['channel'] == "0") {
2847
			$wlcmd[] = "channel any";
2848
		} else {
2849
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2850
		}
2851
	}
2852

    
2853
	/* Set antenna diversity value */
2854
	if (isset($wlcfg['diversity'])) {
2855
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2856
	}
2857

    
2858
	/* Set txantenna value */
2859
	if (isset($wlcfg['txantenna'])) {
2860
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2861
	}
2862

    
2863
	/* Set rxantenna value */
2864
	if (isset($wlcfg['rxantenna'])) {
2865
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2866
	}
2867

    
2868
	/* set Distance value */
2869
	if ($wlcfg['distance']) {
2870
		$distance = escapeshellarg($wlcfg['distance']);
2871
	}
2872

    
2873
	/* Set wireless hostap mode */
2874
	if ($wlcfg['mode'] == "hostap") {
2875
		$wlcmd[] = "mediaopt hostap";
2876
	} else {
2877
		$wlcmd[] = "-mediaopt hostap";
2878
	}
2879

    
2880
	/* Set wireless adhoc mode */
2881
	if ($wlcfg['mode'] == "adhoc") {
2882
		$wlcmd[] = "mediaopt adhoc";
2883
	} else {
2884
		$wlcmd[] = "-mediaopt adhoc";
2885
	}
2886

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

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

    
2896
	/* handle pureg (802.11g) only option */
2897
	if (isset($wlcfg['pureg']['enable'])) {
2898
		$wlcmd[] = "mode 11g pureg";
2899
	} else {
2900
		$wlcmd[] = "-pureg";
2901
	}
2902

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

    
2910
	/* enable apbridge option */
2911
	if (isset($wlcfg['apbridge']['enable'])) {
2912
		$wlcmd[] = "apbridge";
2913
	} else {
2914
		$wlcmd[] = "-apbridge";
2915
	}
2916

    
2917
	/* handle turbo option */
2918
	if (isset($wlcfg['turbo']['enable'])) {
2919
		$wlcmd[] = "mediaopt turbo";
2920
	} else {
2921
		$wlcmd[] = "-mediaopt turbo";
2922
	}
2923

    
2924
	/* handle txpower setting */
2925
	// or don't. this has issues at the moment.
2926
	/*
2927
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2928
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2929
	}*/
2930

    
2931
	/* handle wme option */
2932
	if (isset($wlcfg['wme']['enable'])) {
2933
		$wlcmd[] = "wme";
2934
	} else {
2935
		$wlcmd[] = "-wme";
2936
	}
2937

    
2938
	/* Enable wpa if it's configured. No WEP support anymore. */
2939
	if (isset($wlcfg['wpa']['enable'])) {
2940
		$wlcmd[] = "authmode wpa wepmode off ";
2941
	} else {
2942
		$wlcmd[] = "authmode open wepmode off ";
2943
	}
2944

    
2945
	kill_hostapd($if);
2946
	mwexec(kill_wpasupplicant("{$if}"));
2947

    
2948
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2949

    
2950
	switch ($wlcfg['mode']) {
2951
		case 'bss':
2952
			if (isset($wlcfg['wpa']['enable'])) {
2953
				$wpa .= <<<EOD
2954
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2955
ctrl_interface_group=0
2956
ap_scan=1
2957
#fast_reauth=1
2958
network={
2959
ssid="{$wlcfg['ssid']}"
2960
scan_ssid=1
2961
priority=5
2962
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2963
psk="{$wlcfg['wpa']['passphrase']}"
2964
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2965
group={$wlcfg['wpa']['wpa_pairwise']}
2966
}
2967
EOD;
2968

    
2969
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2970
				unset($wpa);
2971
			}
2972
			break;
2973
		case 'hostap':
2974
			if (!empty($wlcfg['wpa']['passphrase'])) {
2975
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2976
			} else {
2977
				$wpa_passphrase = "";
2978
			}
2979
			if (isset($wlcfg['wpa']['enable'])) {
2980
				$wpa .= <<<EOD
2981
interface={$if}
2982
driver=bsd
2983
logger_syslog=-1
2984
logger_syslog_level=0
2985
logger_stdout=-1
2986
logger_stdout_level=0
2987
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2988
ctrl_interface={$g['varrun_path']}/hostapd
2989
ctrl_interface_group=wheel
2990
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2991
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2992
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2993
ssid={$wlcfg['ssid']}
2994
debug={$wlcfg['wpa']['debug_mode']}
2995
wpa={$wlcfg['wpa']['wpa_mode']}
2996
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2997
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2998
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2999
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3000
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3001
{$wpa_passphrase}
3002

    
3003
EOD;
3004

    
3005
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3006
					$wpa .= <<<EOD
3007
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3008
rsn_preauth=1
3009
rsn_preauth_interfaces={$if}
3010

    
3011
EOD;
3012
				}
3013
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3014
					$wpa .= "ieee8021x=1\n";
3015

    
3016
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3017
						$auth_server_port = "1812";
3018
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3019
							$auth_server_port = intval($wlcfg['auth_server_port']);
3020
						}
3021
						$wpa .= <<<EOD
3022

    
3023
auth_server_addr={$wlcfg['auth_server_addr']}
3024
auth_server_port={$auth_server_port}
3025
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3026

    
3027
EOD;
3028
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3029
							$auth_server_port2 = "1812";
3030
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3031
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3032
							}
3033

    
3034
							$wpa .= <<<EOD
3035
auth_server_addr={$wlcfg['auth_server_addr2']}
3036
auth_server_port={$auth_server_port2}
3037
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3038

    
3039
EOD;
3040
						}
3041
					}
3042
				}
3043

    
3044
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3045
				unset($wpa);
3046
			}
3047
			break;
3048
	}
3049

    
3050
	/*
3051
	 *    all variables are set, lets start up everything
3052
	 */
3053

    
3054
	$baseif = interface_get_wireless_base($if);
3055
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3056
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3057

    
3058
	/* set sysctls for the wireless interface */
3059
	if (!empty($wl_sysctl)) {
3060
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3061
		foreach ($wl_sysctl as $wl_sysctl_line) {
3062
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3063
		}
3064
	}
3065

    
3066
	/* set ack timers according to users preference (if he/she has any) */
3067
	if ($distance) {
3068
		fwrite($fd_set, "# Enable ATH distance settings\n");
3069
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3070
	}
3071

    
3072
	if (isset($wlcfg['wpa']['enable'])) {
3073
		if ($wlcfg['mode'] == "bss") {
3074
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3075
		}
3076
		if ($wlcfg['mode'] == "hostap") {
3077
			/* add line to script to restore old mac to make hostapd happy */
3078
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3079
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3080
				$if_curmac = get_interface_mac($if);
3081
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3082
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3083
						" link " . escapeshellarg($if_oldmac) . "\n");
3084
				}
3085
			}
3086

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

    
3089
			/* add line to script to restore spoofed mac after running hostapd */
3090
			if ($wl['spoofmac']) {
3091
				$if_curmac = get_interface_mac($if);
3092
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3093
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3094
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3095
				}
3096
			}
3097
		}
3098
	}
3099

    
3100
	fclose($fd_set);
3101

    
3102
	/* Making sure regulatory settings have actually changed
3103
	 * before applying, because changing them requires bringing
3104
	 * down all wireless networks on the interface. */
3105
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3106
	$ifconfig_str = implode($output);
3107
	unset($output);
3108
	$reg_changing = false;
3109

    
3110
	/* special case for the debug country code */
3111
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3112
		$reg_changing = true;
3113
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3114
		$reg_changing = true;
3115
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3116
		$reg_changing = true;
3117
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3118
		$reg_changing = true;
3119
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3120
		$reg_changing = true;
3121
	}
3122

    
3123
	if ($reg_changing) {
3124
		/* set regulatory domain */
3125
		if ($wlcfg['regdomain']) {
3126
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3127
		}
3128

    
3129
		/* set country */
3130
		if ($wlcfg['regcountry']) {
3131
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3132
		}
3133

    
3134
		/* set location */
3135
		if ($wlcfg['reglocation']) {
3136
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3137
		}
3138

    
3139
		$wlregcmd_args = implode(" ", $wlregcmd);
3140

    
3141
		/* build a complete list of the wireless clones for this interface */
3142
		$clone_list = array();
3143
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3144
			$clone_list[] = interface_get_wireless_clone($baseif);
3145
		}
3146
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3147
			foreach ($config['wireless']['clone'] as $clone) {
3148
				if ($clone['if'] == $baseif) {
3149
					$clone_list[] = $clone['cloneif'];
3150
				}
3151
			}
3152
		}
3153

    
3154
		/* find which clones are up and bring them down */
3155
		$clones_up = array();
3156
		foreach ($clone_list as $clone_if) {
3157
			$clone_status = pfSense_get_interface_addresses($clone_if);
3158
			if ($clone_status['status'] == 'up') {
3159
				$clones_up[] = $clone_if;
3160
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3161
			}
3162
		}
3163

    
3164
		/* apply the regulatory settings */
3165
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3166
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3167

    
3168
		/* bring the clones back up that were previously up */
3169
		foreach ($clones_up as $clone_if) {
3170
			interfaces_bring_up($clone_if);
3171

    
3172
			/*
3173
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3174
			 * is in infrastructure mode, and WPA is enabled.
3175
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3176
			 */
3177
			if ($clone_if != $if) {
3178
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3179
				if ((!empty($friendly_if)) &&
3180
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3181
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3182
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3183
				}
3184
			}
3185
		}
3186
	}
3187

    
3188
	/* The mode must be specified in a separate command before ifconfig
3189
	 * will allow the mode and channel at the same time in the next.
3190
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3191
	 */
3192
	if ($wlcfg['mode'] == "hostap") {
3193
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3194
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3195
	}
3196

    
3197
	/* configure wireless */
3198
	$wlcmd_args = implode(" ", $wlcmd);
3199
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3200
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3201
	/* Bring the interface up only after setting up all the other parameters. */
3202
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3203
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3204
	fclose($wlan_setup_log);
3205

    
3206
	unset($wlcmd_args, $wlcmd);
3207

    
3208

    
3209
	sleep(1);
3210
	/* execute hostapd and wpa_supplicant if required in shell */
3211
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3212

    
3213
	return 0;
3214

    
3215
}
3216

    
3217
function kill_hostapd($interface) {
3218
	global $g;
3219

    
3220
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3221
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3222
	}
3223
}
3224

    
3225
function kill_wpasupplicant($interface) {
3226
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3227
}
3228

    
3229
function find_dhclient_process($interface) {
3230
	if ($interface) {
3231
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3232
	} else {
3233
		$pid = 0;
3234
	}
3235

    
3236
	return intval($pid);
3237
}
3238

    
3239
function kill_dhclient_process($interface) {
3240
	if (empty($interface) || !does_interface_exist($interface)) {
3241
		return;
3242
	}
3243

    
3244
	$i = 0;
3245
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3246
		/* 3rd time make it die for sure */
3247
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3248
		posix_kill($pid, $sig);
3249
		sleep(1);
3250
		$i++;
3251
	}
3252
	unset($i);
3253
}
3254

    
3255
function find_dhcp6c_process($interface) {
3256
	global $g;
3257

    
3258
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3259
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3260
	} else {
3261
		return(false);
3262
	}
3263

    
3264
	return intval($pid);
3265
}
3266

    
3267
function kill_dhcp6client_process($interface, $force, $release = false) {
3268
	global $g;
3269

    
3270
	$i = 0;
3271

    
3272
	/*
3273
	Beware of the following: Reason, the interface may be down, but
3274
	dhcp6c may still be running, it just complains it cannot send
3275
	and carries on. Commented out as will stop the call to kill.
3276

    
3277
	if (empty($interface) || !does_interface_exist($interface)) {
3278
		return;
3279
	}
3280
	*/
3281

    
3282
	/*********** Notes on signals for dhcp6c and this function *************
3283

    
3284
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3285
	a release and waiting for the response that never comes.
3286
	So we need to tell it that the interface is down and to just die quickly
3287
	otherwise a new client may launch and we have duplicate proceses.
3288
	In this case use SIGUSR1.
3289

    
3290
	If we want to exit normally obeying the no release flag then use SIGTERM.
3291
	If we want to exit with a release overiding the no release flag then
3292
	use SIGUSR2.
3293

    
3294
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3295
	exit quickly without sending release signals.
3296

    
3297
	If $Force is set to false and $release is also set to false dhcp6c will
3298
	follow the no-release flag.
3299

    
3300
	If $Force is set to false and $release is true then dhcp6c will send a
3301
	release regardless of the no-release flag.
3302
	***********************************************************************/
3303

    
3304
	if ($force == true) {
3305
		$psig=SIGUSR1;
3306
	} else if ($release == false) {
3307
		$psig=SIGTERM;
3308
	} else {
3309
		$psig=SIGUSR2;
3310
	}
3311

    
3312
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3313
		/* 3rd time make it die for sure */
3314
		$sig = ($i == 2 ? SIGKILL : $psig);
3315
		posix_kill($pid, $sig);
3316
		sleep(1);
3317
		$i++;
3318
	}
3319
	/* Clear the RTSOLD script created lock & tidy up */
3320
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3321
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
3322
}
3323
function reset_dhcp6client_process($interface) {
3324

    
3325
	$pid = find_dhcp6c_process($interface);
3326

    
3327
	if($pid != 0) {
3328
		posix_kill($pid, SIGHUP);
3329
	}
3330
}
3331

    
3332
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3333
	global $g;
3334

    
3335
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3336
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3337

    
3338
	/*
3339
	 * Only run this if the lock does not exist. In theory the lock being
3340
	 * there in this mode means the user has selected dhcp6withoutRA while
3341
	 * a session is active in the other mode.
3342
	 *
3343
	 * It should not happen as the process should have been killed and the
3344
	 * lock deleted.
3345
	 */
3346

    
3347
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
3348
		kill_dhcp6client_process($interface, true);
3349
		/* Lock it to avoid multiple runs */
3350
		touch("/tmp/dhcp6c_{$interface}_lock");
3351
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3352
		    "{$noreleaseOption} " .
3353
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
3354
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
3355
		    $interface);
3356
		log_error(sprintf(gettext(
3357
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
3358
		    $interface));
3359
	}
3360
}
3361

    
3362
function interface_virtual_create($interface) {
3363
	global $config;
3364

    
3365
	if (interface_is_vlan($interface) != NULL) {
3366
		interfaces_vlan_configure($interface);
3367
	} else if (substr($interface, 0, 3) == "gre") {
3368
		interfaces_gre_configure(0, $interface);
3369
	} else if (substr($interface, 0, 3) == "gif") {
3370
		interfaces_gif_configure(0, $interface);
3371
	} else if (substr($interface, 0, 5) == "ovpns") {
3372
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3373
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3374
				if ($interface == "ovpns{$server['vpnid']}") {
3375
					if (!function_exists('openvpn_resync')) {
3376
						require_once('openvpn.inc');
3377
					}
3378
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3379
					openvpn_resync('server', $server);
3380
				}
3381
			}
3382
			unset($server);
3383
		}
3384
	} else if (substr($interface, 0, 5) == "ovpnc") {
3385
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3386
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3387
				if ($interface == "ovpnc{$client['vpnid']}") {
3388
					if (!function_exists('openvpn_resync')) {
3389
						require_once('openvpn.inc');
3390
					}
3391
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3392
					openvpn_resync('client', $client);
3393
				}
3394
			}
3395
			unset($client);
3396
		}
3397
	} else if (substr($interface, 0, 4) == "lagg") {
3398
		interfaces_lagg_configure($interface);
3399
	} else if (substr($interface, 0, 6) == "bridge") {
3400
		interfaces_bridge_configure(0, $interface);
3401
	}
3402
}
3403

    
3404
function interface_vlan_mtu_configured($iface) {
3405
	global $config;
3406

    
3407
	$mtu = 0;
3408
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3409
		foreach ($config['vlans']['vlan'] as $vlan) {
3410

    
3411
			if ($vlan['vlanif'] != $iface)
3412
				continue;
3413

    
3414
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3415
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3416
				/* VLAN MTU */
3417
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3418
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3419
				/* Parent MTU */
3420
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3421
			}
3422
		}
3423
	}
3424

    
3425
	return $mtu;
3426
}
3427

    
3428
function interface_mtu_wanted_for_pppoe($realif) {
3429
	global $config;
3430

    
3431
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3432
		return 0;
3433

    
3434
	$mtu = 0;
3435
	foreach ($config['ppps']['ppp'] as $ppp) {
3436
		if ($ppp['type'] != "pppoe") {
3437
			continue;
3438
		}
3439

    
3440
		$mtus = array();
3441
		if (!empty($ppp['mtu'])) {
3442
			$mtus = explode(',', $ppp['mtu']);
3443
		}
3444
		$ports = explode(',', $ppp['ports']);
3445

    
3446
		foreach ($ports as $pid => $port) {
3447
			$parentifa = get_parent_interface($port);
3448
			$parentif = $parentifa[0];
3449
			if ($parentif != $realif)
3450
				continue;
3451

    
3452
			// there is an MTU configured on the port in question
3453
			if (!empty($mtus[$pid])) {
3454
				$mtu = intval($mtus[$pid]) + 8;
3455
			// or use the MTU configured on the interface ...
3456
			} elseif (is_array($config['interfaces'])) {
3457
				foreach ($config['interfaces'] as $interface) {
3458
					if ($interface['if'] == $ppp['if'] &&
3459
					    !empty($interface['mtu'])) {
3460
						$mtu = intval($interface['mtu']) + 8;
3461
						break;
3462
					}
3463
				}
3464
			}
3465
		}
3466
	}
3467

    
3468
	return $mtu;
3469
}
3470

    
3471
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3472
	global $config, $g;
3473
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3474
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3475

    
3476
	$wancfg = $config['interfaces'][$interface];
3477

    
3478
	if (!isset($wancfg['enable'])) {
3479
		return;
3480
	}
3481

    
3482
	$realif = get_real_interface($interface);
3483
	$realhwif_array = get_parent_interface($interface);
3484
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3485
	$realhwif = $realhwif_array[0];
3486

    
3487
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3488
		/* remove all IPv4 and IPv6 addresses */
3489
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3490
		if (is_array($tmpifaces)) {
3491
			foreach ($tmpifaces as $tmpiface) {
3492
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3493
					if (!is_linklocal($tmpiface)) {
3494
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3495
					}
3496
				} else {
3497
					if (is_subnetv4($tmpiface)) {
3498
						$tmpip = explode('/', $tmpiface);
3499
						$tmpip = $tmpip[0];
3500
					} else {
3501
						$tmpip = $tmpiface;
3502
					}
3503
					pfSense_interface_deladdress($realif, $tmpip);
3504
				}
3505
			}
3506
		}
3507

    
3508
		/* only bring down the interface when both v4 and v6 are set to NONE */
3509
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3510
			interface_bring_down($interface);
3511
		}
3512
	}
3513

    
3514
	$interface_to_check = $realif;
3515
	if (interface_isppp_type($interface)) {
3516
		$interface_to_check = $realhwif;
3517
	}
3518

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

    
3524
	/* Disable Accepting router advertisements unless specifically requested */
3525
	if ($g['debug']) {
3526
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3527
	}
3528
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
3529
	{
3530
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3531
	}
3532
	/* wireless configuration? */
3533
	if (is_array($wancfg['wireless']) && !$linkupevent) {
3534
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3535
	}
3536

    
3537
	$current_mac = get_interface_mac($realhwif);
3538
	$vendor_mac = get_interface_vendor_mac($realhwif);
3539
	/*
3540
	 * Do not change the MAC address if the interface does not store the original
3541
	 * vendor MAC address.
3542
	 */
3543
	if ($vendor_mac != NULL) {
3544
		/* Get the vendor MAC.  Use source dependent upon whether or not booting. */
3545
		if (platform_booting()) {
3546
			$vendor_mac = $current_mac;
3547
		}
3548
		$mac_addr = $wancfg['spoofmac'] ?: $vendor_mac;
3549
		/*
3550
		 * Don't try to reapply the MAC if it's already applied.
3551
		 * When ifconfig link is used, it cycles the interface down/up, which triggers
3552
		 * the interface config again, which attempts to apply the MAC again,
3553
		 * which cycles the link again...
3554
		 */
3555
		if (!empty($mac_addr) && ($mac_addr != $current_mac)) {
3556
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3557
				" link " . escapeshellarg($mac_addr));
3558
		}
3559
	} elseif ($current_mac == "ff:ff:ff:ff:ff:ff") {
3560
		/*   this is not a valid mac address.  generate a
3561
		 *   temporary mac address so the machine can get online.
3562
		 */
3563
		echo gettext("Generating new MAC address.");
3564
		$random_mac = generate_random_mac_address();
3565
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3566
			" link " . escapeshellarg($random_mac));
3567
		$wancfg['spoofmac'] = $random_mac;
3568
		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));
3569
		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");
3570
	}
3571

    
3572
	/* media */
3573
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3574
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3575
		if ($wancfg['media']) {
3576
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3577
		}
3578
		if ($wancfg['mediaopt']) {
3579
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3580
		}
3581
		mwexec($cmd);
3582
	}
3583

    
3584
	/* Apply hw offloading policies as configured */
3585
	enable_hardware_offloading($interface);
3586

    
3587
	/* invalidate interface/ip/sn cache */
3588
	get_interface_arr(true);
3589
	unset($interface_ip_arr_cache[$realif]);
3590
	unset($interface_sn_arr_cache[$realif]);
3591
	unset($interface_ipv6_arr_cache[$realif]);
3592
	unset($interface_snv6_arr_cache[$realif]);
3593

    
3594
	$tunnelif = substr($realif, 0, 3);
3595

    
3596
	$mtuif = $realif;
3597
	$mtuhwif = $realhwif;
3598

    
3599
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3600
	if (interface_isppp_type($interface)) {
3601
		$mtuif = $realhwif;
3602
		$mtuhwif_array = get_parent_interface($mtuif);
3603
		$mtuhwif = $mtuhwif_array[0];
3604
	}
3605

    
3606
	$wantedmtu = 0;
3607
	if (is_array($config['interfaces'])) {
3608
		foreach ($config['interfaces'] as $tmpinterface) {
3609
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3610
				$wantedmtu = $tmpinterface['mtu'];
3611
				break;
3612
			}
3613
		}
3614
	}
3615

    
3616
	/* MTU is not specified for interface, try the pppoe settings. */
3617
	if ($wantedmtu == 0) {
3618
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3619
	}
3620
	if ($wantedmtu == 0 && interface_is_vlan($mtuif) != NULL && interface_isppp_type($interface)) {
3621
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3622
	}
3623

    
3624
	/* Set the MTU to 1500 if no explicit MTU configured. */
3625
	if ($wantedmtu == 0) {
3626
		$wantedmtu = 1500; /* Default */
3627
	}
3628

    
3629
	if (interface_is_vlan($mtuif) != NULL) {
3630
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3631
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3632
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3633
			if ($wancfg['mtu'] > $parentmtu) {
3634
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3635
			}
3636
		}
3637

    
3638
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3639

    
3640
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3641
			$configuredmtu = $parentmtu;
3642
		if ($configuredmtu != 0)
3643
			$mtu = $configuredmtu;
3644
		else
3645
			$mtu = $wantedmtu;
3646

    
3647
		/* Set the parent MTU. */
3648
		if (get_interface_mtu($mtuhwif) < $mtu)
3649
			set_interface_mtu($mtuhwif, $mtu);
3650
		/* Set the VLAN MTU. */
3651
		if (get_interface_mtu($mtuif) != $mtu)
3652
			set_interface_mtu($mtuif, $mtu);
3653
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3654
		/* LAGG interface must be destroyed and re-created to change MTU */
3655
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3656
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3657
				foreach ($config['laggs']['lagg'] as $lagg) {
3658
					if ($lagg['laggif'] == $mtuif) {
3659
						interface_lagg_configure($lagg);
3660
						break;
3661
					}
3662
				}
3663
			}
3664
		}
3665
	} else {
3666
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3667
			pfSense_interface_mtu($mtuif, $wantedmtu);
3668
		}
3669
	}
3670
	/* XXX: What about gre/gif/.. ? */
3671

    
3672
	if (does_interface_exist($wancfg['if'])) {
3673
		interfaces_bring_up($wancfg['if']);
3674
	}
3675

    
3676
	switch ($wancfg['ipaddr']) {
3677
		case 'dhcp':
3678
			interface_dhcp_configure($interface);
3679
			break;
3680
		case 'pppoe':
3681
		case 'l2tp':
3682
		case 'pptp':
3683
		case 'ppp':
3684
			interface_ppps_configure($interface);
3685
			break;
3686
		default:
3687
			/* XXX: Kludge for now related to #3280 */
3688
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3689
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3690
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3691
				}
3692
			}
3693
			break;
3694
	}
3695

    
3696
	switch ($wancfg['ipaddrv6']) {
3697
		case 'slaac':
3698
		case 'dhcp6':
3699
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
3700
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
3701
			// handles all non-PPP connections with 'dhcp6usev4iface' set
3702
			/* Remove the check file. Should not be there but just in case */
3703
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
3704
			log_error(gettext("calling interface_dhcpv6_configure."));
3705
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
3706
				interface_dhcpv6_configure($interface, $wancfg);
3707
			}
3708
			break;
3709
		case '6rd':
3710
			interface_6rd_configure($interface, $wancfg);
3711
			break;
3712
		case '6to4':
3713
			interface_6to4_configure($interface, $wancfg);
3714
			break;
3715
		case 'track6':
3716
			interface_track6_configure($interface, $wancfg, $linkupevent);
3717
			break;
3718
		default:
3719
			/* XXX: Kludge for now related to #3280 */
3720
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3721
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3722
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3723
					// FIXME: Add IPv6 Support to the pfSense module
3724
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3725
				}
3726
			}
3727
			break;
3728
	}
3729

    
3730
	interface_netgraph_needed($interface);
3731

    
3732
	if (!platform_booting()) {
3733
		link_interface_to_vips($interface, "update");
3734

    
3735
		if ($tunnelif != 'gre') {
3736
			unset($gre);
3737
			$gre = link_interface_to_gre($interface);
3738
			if (!empty($gre)) {
3739
				array_walk($gre, 'interface_gre_configure');
3740
			}
3741
		}
3742

    
3743
		if ($tunnelif != 'gif') {
3744
			unset($gif);
3745
			$gif = link_interface_to_gif ($interface);
3746
			if (!empty($gif)) {
3747
				array_walk($gif, 'interface_gif_configure');
3748
			}
3749
		}
3750

    
3751
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3752
			unset($bridgetmp);
3753
			$bridgetmp = link_interface_to_bridge($interface);
3754
			if (!empty($bridgetmp)) {
3755
				interface_bridge_add_member($bridgetmp, $realif);
3756
			}
3757
		}
3758

    
3759
		$grouptmp = link_interface_to_group($interface);
3760
		if (!empty($grouptmp)) {
3761
			array_walk($grouptmp, 'interface_group_add_member');
3762
		}
3763

    
3764
		if ($interface == "lan") {
3765
			/* make new hosts file */
3766
			system_hosts_generate();
3767
		}
3768

    
3769
		if ($reloadall == true) {
3770

    
3771
			/* reconfigure static routes (kernel may have deleted them) */
3772
			system_routing_configure($interface);
3773

    
3774
			/* reload ipsec tunnels */
3775
			send_event("service reload ipsecdns");
3776

    
3777
			if (isset($config['dnsmasq']['enable'])) {
3778
				services_dnsmasq_configure();
3779
			}
3780

    
3781
			if (isset($config['unbound']['enable'])) {
3782
				services_unbound_configure();
3783
			}
3784

    
3785
			/* update dyndns */
3786
			send_event("service reload dyndns {$interface}");
3787

    
3788
			/* reload captive portal */
3789
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3790
				require_once('captiveportal.inc');
3791
			}
3792
			captiveportal_init_rules_byinterface($interface);
3793
		}
3794
	}
3795

    
3796
	interfaces_staticarp_configure($interface);
3797
	return 0;
3798
}
3799

    
3800
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3801
	global $config, $g;
3802

    
3803
	if (!is_array($wancfg)) {
3804
		return;
3805
	}
3806

    
3807
	if (!isset($wancfg['enable'])) {
3808
		return;
3809
	}
3810

    
3811
	/* If the interface is not configured via another, exit */
3812
	if (empty($wancfg['track6-interface'])) {
3813
		return;
3814
	}
3815

    
3816
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3817
	$realif = get_real_interface($interface);
3818
	$linklocal = find_interface_ipv6_ll($realif, true);
3819
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
3820
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3821
	}
3822
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3823
	/* XXX: Probably should remove? */
3824
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3825

    
3826
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3827
	if (!isset($trackcfg['enable'])) {
3828
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
3829
		return;
3830
	}
3831

    
3832
	switch ($trackcfg['ipaddrv6']) {
3833
		case "6to4":
3834
			if ($g['debug']) {
3835
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3836
			}
3837
			interface_track6_6to4_configure($interface, $wancfg);
3838
			break;
3839
		case "6rd":
3840
			if ($g['debug']) {
3841
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3842
			}
3843
			interface_track6_6rd_configure($interface, $wancfg);
3844
			break;
3845
		case "dhcp6":
3846
			if ($linkupevent == true) {
3847
				/*
3848
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
3849
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3850
				 *
3851
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
3852
				 */
3853
				$parentrealif = get_real_interface($wancfg['track6-interface']);
3854
				$pidv6 = find_dhcp6c_process($parentrealif);
3855
				if ($pidv6) {
3856
					posix_kill($pidv6, SIGHUP);
3857
				}
3858
			}
3859
			break;
3860
	}
3861

    
3862
	if ($linkupevent == false && !platform_booting()) {
3863
		if (!function_exists('services_dhcpd_configure')) {
3864
			require_once("services.inc");
3865
		}
3866

    
3867
		/* restart dns servers (defering dhcpd reload) */
3868
		if (isset($config['unbound']['enable'])) {
3869
			services_unbound_configure(false);
3870
		}
3871
		if (isset($config['dnsmasq']['enable'])) {
3872
			services_dnsmasq_configure(false);
3873
		}
3874

    
3875
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
3876
		services_dhcpd_configure("inet6");
3877
	}
3878

    
3879
	return 0;
3880
}
3881

    
3882
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3883
	global $config, $g;
3884
	global $interface_ipv6_arr_cache;
3885
	global $interface_snv6_arr_cache;
3886

    
3887
	if (!is_array($lancfg)) {
3888
		return;
3889
	}
3890

    
3891
	/* If the interface is not configured via another, exit */
3892
	if (empty($lancfg['track6-interface'])) {
3893
		return;
3894
	}
3895

    
3896
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3897
	if (empty($wancfg)) {
3898
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3899
		return;
3900
	}
3901

    
3902
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3903
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3904
		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']));
3905
		return;
3906
	}
3907
	$hexwanv4 = return_hex_ipv4($ip4address);
3908

    
3909
	/* create the long prefix notation for math, save the prefix length */
3910
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3911
	$rd6prefixlen = $rd6prefix[1];
3912
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3913

    
3914
	/* binary presentation of the prefix for all 128 bits. */
3915
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3916

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

    
3922
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3923
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3924
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3925
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3926
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3927
	/* fill the rest out with zeros */
3928
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3929

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

    
3933
	$lanif = get_real_interface($interface);
3934
	$oip = find_interface_ipv6($lanif);
3935
	if (is_ipaddrv6($oip)) {
3936
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3937
	}
3938
	unset($interface_ipv6_arr_cache[$lanif]);
3939
	unset($interface_snv6_arr_cache[$lanif]);
3940
	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));
3941
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3942

    
3943
	return 0;
3944
}
3945

    
3946
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3947
	global $config, $g;
3948
	global $interface_ipv6_arr_cache;
3949
	global $interface_snv6_arr_cache;
3950

    
3951
	if (!is_array($lancfg)) {
3952
		return;
3953
	}
3954

    
3955
	/* If the interface is not configured via another, exit */
3956
	if (empty($lancfg['track6-interface'])) {
3957
		return;
3958
	}
3959

    
3960
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3961
	if (empty($wancfg)) {
3962
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3963
		return;
3964
	}
3965

    
3966
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3967
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3968
		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']));
3969
		return;
3970
	}
3971
	$hexwanv4 = return_hex_ipv4($ip4address);
3972

    
3973
	/* create the long prefix notation for math, save the prefix length */
3974
	$sixto4prefix = "2002::";
3975
	$sixto4prefixlen = 16;
3976
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3977

    
3978
	/* binary presentation of the prefix for all 128 bits. */
3979
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3980

    
3981
	/* just save the left prefix length bits */
3982
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3983
	/* add the v4 address */
3984
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3985
	/* add the custom prefix id */
3986
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3987
	/* fill the rest out with zeros */
3988
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3989

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

    
3993
	$lanif = get_real_interface($interface);
3994
	$oip = find_interface_ipv6($lanif);
3995
	if (is_ipaddrv6($oip)) {
3996
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3997
	}
3998
	unset($interface_ipv6_arr_cache[$lanif]);
3999
	unset($interface_snv6_arr_cache[$lanif]);
4000
	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));
4001
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4002

    
4003
	return 0;
4004
}
4005

    
4006
function interface_6rd_configure($interface = "wan", $wancfg) {
4007
	global $config, $g;
4008

    
4009
	/* because this is a tunnel interface we can only function
4010
	 *	with a public IPv4 address on the interface */
4011

    
4012
	if (!is_array($wancfg)) {
4013
		return;
4014
	}
4015

    
4016
	if (!is_module_loaded('if_stf.ko')) {
4017
		mwexec('/sbin/kldload if_stf.ko');
4018
	}
4019

    
4020
	$wanif = get_real_interface($interface);
4021
	$ip4address = find_interface_ip($wanif);
4022
	if (!is_ipaddrv4($ip4address)) {
4023
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4024
		return false;
4025
	}
4026
	$hexwanv4 = return_hex_ipv4($ip4address);
4027

    
4028
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4029
		$wancfg['prefix-6rd-v4plen'] = 0;
4030
	}
4031

    
4032
	/* create the long prefix notation for math, save the prefix length */
4033
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4034
	$rd6prefixlen = $rd6prefix[1];
4035
	$brgw = explode('.', $wancfg['gateway-6rd']);
4036
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4037
	$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);
4038
	if (strlen($rd6brgw) < 128) {
4039
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4040
	}
4041
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4042
	unset($brgw);
4043
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4044

    
4045
	/* binary presentation of the prefix for all 128 bits. */
4046
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4047

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

    
4055
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4056
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4057

    
4058

    
4059
	/* XXX: need to extend to support variable prefix size for v4 */
4060
	$stfiface = "{$interface}_stf";
4061
	if (does_interface_exist($stfiface)) {
4062
		pfSense_interface_destroy($stfiface);
4063
	}
4064
	$tmpstfiface = pfSense_interface_create("stf");
4065
	pfSense_interface_rename($tmpstfiface, $stfiface);
4066
	pfSense_interface_flags($stfiface, IFF_LINK2);
4067
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4068
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4069
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4070
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4071
	}
4072
	if ($g['debug']) {
4073
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4074
	}
4075

    
4076
	/* write out a default router file */
4077
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4078
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4079

    
4080
	$ip4gateway = get_interface_gateway($interface);
4081
	if (is_ipaddrv4($ip4gateway)) {
4082
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
4083
	}
4084

    
4085
	/* configure dependent interfaces */
4086
	if (!platform_booting()) {
4087
		link_interface_to_track6($interface, "update");
4088
	}
4089

    
4090
	return 0;
4091
}
4092

    
4093
function interface_6to4_configure($interface = "wan", $wancfg) {
4094
	global $config, $g;
4095

    
4096
	/* because this is a tunnel interface we can only function
4097
	 *	with a public IPv4 address on the interface */
4098

    
4099
	if (!is_array($wancfg)) {
4100
		return;
4101
	}
4102

    
4103
	$wanif = get_real_interface($interface);
4104
	$ip4address = find_interface_ip($wanif);
4105
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4106
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4107
		return false;
4108
	}
4109

    
4110
	/* create the long prefix notation for math, save the prefix length */
4111
	$stfprefixlen = 16;
4112
	$stfprefix = Net_IPv6::uncompress("2002::");
4113
	$stfarr = explode(":", $stfprefix);
4114
	$v4prefixlen = "0";
4115

    
4116
	/* we need the hex form of the interface IPv4 address */
4117
	$ip4arr = explode(".", $ip4address);
4118
	$hexwanv4 = "";
4119
	foreach ($ip4arr as $octet) {
4120
		$hexwanv4 .= sprintf("%02x", $octet);
4121
	}
4122

    
4123
	/* we need the hex form of the broker IPv4 address */
4124
	$ip4arr = explode(".", "192.88.99.1");
4125
	$hexbrv4 = "";
4126
	foreach ($ip4arr as $octet) {
4127
		$hexbrv4 .= sprintf("%02x", $octet);
4128
	}
4129

    
4130
	/* binary presentation of the prefix for all 128 bits. */
4131
	$stfprefixbin = "";
4132
	foreach ($stfarr as $element) {
4133
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4134
	}
4135
	/* just save the left prefix length bits */
4136
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4137

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

    
4142
	/* for the local subnet too. */
4143
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4144
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4145

    
4146
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4147
	$stfbrarr = array();
4148
	$stfbrbinarr = array();
4149
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4150
	foreach ($stfbrbinarr as $bin) {
4151
		$stfbrarr[] = dechex(bindec($bin));
4152
	}
4153
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4154

    
4155
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4156
	$stflanarr = array();
4157
	$stflanbinarr = array();
4158
	$stflanbinarr = str_split($stflanbin, 16);
4159
	foreach ($stflanbinarr as $bin) {
4160
		$stflanarr[] = dechex(bindec($bin));
4161
	}
4162
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4163
	$stflanarr[7] = 1;
4164
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4165

    
4166
	/* setup the stf interface */
4167
	if (!is_module_loaded("if_stf")) {
4168
		mwexec("/sbin/kldload if_stf.ko");
4169
	}
4170
	$stfiface = "{$interface}_stf";
4171
	if (does_interface_exist($stfiface)) {
4172
		pfSense_interface_destroy($stfiface);
4173
	}
4174
	$tmpstfiface = pfSense_interface_create("stf");
4175
	pfSense_interface_rename($tmpstfiface, $stfiface);
4176
	pfSense_interface_flags($stfiface, IFF_LINK2);
4177
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4178

    
4179
	if ($g['debug']) {
4180
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4181
	}
4182

    
4183
	/* write out a default router file */
4184
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4185
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4186

    
4187
	$ip4gateway = get_interface_gateway($interface);
4188
	if (is_ipaddrv4($ip4gateway)) {
4189
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
4190
	}
4191

    
4192
	if (!platform_booting()) {
4193
		link_interface_to_track6($interface, "update");
4194
	}
4195

    
4196
	return 0;
4197
}
4198

    
4199
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4200
	global $config, $g;
4201

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

    
4206
	$wanif = get_real_interface($interface, "inet6");
4207
	$dhcp6cconf = "";
4208

    
4209
	if (!empty($config['system']['global-v6duid'])) {
4210
		// Write the DUID file
4211
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4212
		    log_error(gettext("Failed to write user DUID file!"));
4213
		}
4214
	}
4215

    
4216
	/* accept router advertisements for this interface                 */
4217
	/* Moved to early in the function as sometimes interface not ready */
4218
	/* RTSOLD fails as interface does not accept .....                 */
4219

    
4220
	log_error("Accept router advertisements on interface {$wanif} ");
4221
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4222

    
4223
	if ($wancfg['adv_dhcp6_config_file_override']) {
4224
		// DHCP6 Config File Override
4225
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4226
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4227
		// DHCP6 Config File Advanced
4228
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4229
	} else {
4230
		// DHCP6 Config File Basic
4231
		$dhcp6cconf .= "interface {$wanif} {\n";
4232

    
4233
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4234
		if ($wancfg['ipaddrv6'] == "slaac") {
4235
			$dhcp6cconf .= "\tinformation-only;\n";
4236
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4237
			$dhcp6cconf .= "\trequest domain-name;\n";
4238
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4239
			$dhcp6cconf .= "};\n";
4240
		} else {
4241
			$trackiflist = array();
4242
			$iflist = link_interface_to_track6($interface);
4243
			foreach ($iflist as $ifname => $ifcfg) {
4244
				if (is_numeric($ifcfg['track6-prefix-id'])) {
4245
					$trackiflist[$ifname] = $ifcfg;
4246
				}
4247
			}
4248

    
4249
			/* skip address request if this is set */
4250
			if (!isset($wancfg['dhcp6prefixonly'])) {
4251
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4252
			}
4253
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4254
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4255
			}
4256

    
4257
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4258
			$dhcp6cconf .= "\trequest domain-name;\n";
4259

    
4260
			/*
4261
			 * dhcp6c will run different scripts depending on
4262
			 * whether dhcpwithoutra is set or unset.
4263
			 */
4264
			if (isset($wancfg['dhcp6withoutra'])) {
4265
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4266
			} else {
4267
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4268
			}
4269
			$dhcp6cconf .= "};\n";
4270

    
4271
			if (!isset($wancfg['dhcp6prefixonly'])) {
4272
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4273
			}
4274

    
4275
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4276
				/* Setup the prefix delegation */
4277
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4278
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4279
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4280
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4281
				}
4282
				foreach ($trackiflist as $friendly => $ifcfg) {
4283
					if ($g['debug']) {
4284
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4285
					}
4286
					$realif = get_real_interface($friendly);
4287
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4288
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4289
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4290
					$dhcp6cconf .= "\t};\n";
4291
				}
4292
				unset($preflen, $iflist, $ifcfg, $ifname);
4293
				$dhcp6cconf .= "};\n";
4294
			}
4295
			unset($trackiflist);
4296
		}
4297
	}
4298

    
4299
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4300
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4301

    
4302
	/* wide-dhcp6c works for now. */
4303
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4304
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4305
		unset($dhcp6cconf);
4306
		return 1;
4307
	}
4308
	unset($dhcp6cconf);
4309

    
4310
	/*************** Script Debug Logging ***************************
4311
	Both dhcp6 scripts now have a logging message built in.
4312
	These logging messages ONLY appear if dhcp6c debug logging is set.
4313
	The logging messages appear in the dhcp section of the logs,
4314
	not in system.
4315

    
4316
	These scripts now also take advantage of the REASON= env vars
4317
	supplied by dhcp6c.
4318
	****************************************************************/
4319

    
4320
	/* Script create for dhcp6withoutRA mode */
4321
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4322
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4323
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4324
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4325
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4326
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4327
	// Need to pass params to  the final script
4328
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4329
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4330
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4331
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4332
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
4333
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
4334
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4335
	if ($debugOption == '-D') {
4336
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4337
	}
4338
	$dhcp6cscriptwithoutra .= ";;\n";
4339
	$dhcp6cscriptwithoutra .= "REBIND)\n";
4340
	if ($debugOption == '-D') {
4341
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4342
	}
4343
	$dhcp6cscriptwithoutra .= ";;\n";
4344
	if (isset($wancfg['dhcp6norelease'])) {
4345
		$dhcp6cscriptwithoutra .= "EXIT)\n";
4346
	} else {
4347
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
4348
	}
4349
	if ($debugOption == '-D') {
4350
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4351
	}
4352
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4353
	$dhcp6cscriptwithoutra .= ";;\n";
4354
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
4355
	if ($debugOption == '-D') {
4356
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4357
	}
4358
	$dhcp6cscriptwithoutra .= "esac\n";
4359
	if (!@file_put_contents(
4360
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4361
	    $dhcp6cscriptwithoutra)) {
4362
		printf("Error: cannot open " .
4363
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4364
		    "interface_dhcpv6_configure() for writing.\n");
4365
		unset($dhcp6cscriptwithoutra);
4366
		return 1;
4367
	}
4368

    
4369
	unset($dhcp6cscriptwithoutra);
4370
	@chmod(
4371
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4372
	    0755);
4373

    
4374
	/*
4375
	 * Dual mode wan_dhcp6c script with variations depending on node
4376
	 * dhcp6 will run the wan ipv6 configure
4377
	 */
4378
	$dhcp6cscript  = "#!/bin/sh\n";
4379
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4380
	if (!isset($wancfg['dhcp6withoutra'])) {
4381
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4382
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4383
		$dhcp6cscript .= "case \$REASON in\n";
4384
		$dhcp6cscript .= "REQUEST)\n";
4385
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4386
		if ($debugOption == '-D') {
4387
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4388
		}
4389
		$dhcp6cscript .= ";;\n";
4390
		$dhcp6cscript .= "REBIND)\n";
4391
		if ($debugOption == '-D') {
4392
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4393
		}
4394
		$dhcp6cscript .= ";;\n";
4395
		if (isset($wancfg['dhcp6norelease'])) {
4396
			$dhcp6cscript .= "EXIT)\n";
4397
		} else {
4398
			$dhcp6cscript .= "RELEASE)\n";
4399
		}
4400
		if ($debugOption == '-D') {
4401
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4402
		}
4403
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4404
		$dhcp6cscript .= ";;\n";
4405
		$dhcp6cscript .= "RENEW|INFO)\n";
4406
		if ($debugOption == '-D') {
4407
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4408
		}
4409
		$dhcp6cscript .= "esac\n";
4410
	} else {
4411
		// Need to get the parameters from the dhcp6cwithoutRA run
4412
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
4413
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
4414
		$dhcp6cscript .= "/bin/sleep 1\n";
4415
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4416
	}
4417

    
4418
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4419
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4420
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4421
		unset($dhcp6cscript);
4422
		return 1;
4423
	}
4424
	unset($dhcp6cscript);
4425
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4426

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

    
4433
	/* non ipoe Process */
4434
	if (!isset($wancfg['dhcp6withoutra'])) {
4435
		/*
4436
		 * We only want this script to run once, and if it runs twice
4437
		 * then do not launch dhcp6c again, this only happens if
4438
		 * dhcpwithoutra is not set.
4439
		 *
4440
		 * Check for a lock file, trying to prevent multiple instances
4441
		 * of dhcp6c being launched
4442
		 */
4443
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
4444
		/*
4445
		 * Create the lock file, trying to prevent multiple instances
4446
		 * of dhcp6c being launched
4447
		 */
4448
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
4449
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
4450
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4451
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4452
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
4453
		$rtsoldscript .= "\tfi\n";
4454
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
4455
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
4456
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4457
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4458
		$rtsoldscript .= "else\n";
4459
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
4460
		$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c_{$wanif}.pid\")\n";
4461
		$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
4462
		$rtsoldscript .= "fi\n";
4463
	} else {
4464
		/*
4465
		 * The script needs to run in dhcp6withoutra mode as RA may
4466
		 * not have been received, or there can be a delay with
4467
		 * certain ISPs
4468
		 */
4469
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
4470
		$rtsoldscript .= "/bin/sleep 1\n";
4471
	}
4472
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4473
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4474
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4475
		unset($rtsoldscript);
4476
		return 1;
4477
	}
4478
	unset($rtsoldscript);
4479
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4480

    
4481
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4482
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4483
		log_error("Killing running rtsold process");
4484
		sleep(2);
4485
	}
4486

    
4487
	if (isset($wancfg['dhcp6withoutra'])) {
4488
		/*
4489
		 * Start dhcp6c here if we don't want to wait for ra - calls
4490
		 * seperate function
4491
		 *
4492
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
4493
		 * will then run the configure on receipt of the RA.
4494
		 *
4495
		 * Already started. interface_dhcpv6_configure() appears to get
4496
		 * called multiple times.
4497
		 *
4498
		 * Taking the interface down or releasing will kill the client.
4499
		 */
4500
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
4501
		{
4502
			/*
4503
			 * If the interface is being brought up, wait for the
4504
			 * interface to configure accept RA before launching.
4505
			 * Otherwise it is not ready to accept and will fail.
4506
			 */
4507
			sleep(3);
4508
			run_dhcp6client_process($wanif,$interface,$wancfg);
4509
		}
4510
	} else {
4511
		/*
4512
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
4513
		 * ( it does not background, it exits! ) It will launch dhcp6c
4514
		 * if dhcpwihtoutra is not set
4515
		 */
4516
		log_error("Starting rtsold process");
4517
		sleep(2);
4518
		mwexec("/usr/sbin/rtsold -1 " .
4519
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
4520
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
4521
		    $wanif);
4522
	}
4523
	/*
4524
	 * NOTE: will be called from rtsold invoked script
4525
	 * link_interface_to_track6($interface, "update");
4526
	 */
4527

    
4528
	return 0;
4529
}
4530

    
4531
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4532
	global $g;
4533

    
4534
	$send_options = "";
4535
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4536
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4537
		foreach ($options as $option) {
4538
			$send_options .= "\tsend " . trim($option) . ";\n";
4539
		}
4540
	}
4541

    
4542
	$request_options = "";
4543
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4544
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4545
		foreach ($options as $option) {
4546
			$request_options .= "\trequest " . trim($option) . ";\n";
4547
		}
4548
	}
4549

    
4550
	$information_only = "";
4551
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4552
		$information_only = "\tinformation-only;\n";
4553
	}
4554

    
4555
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4556
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4557
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4558
	}
4559

    
4560
	$interface_statement  = "interface";
4561
	$interface_statement .= " {$wanif}";
4562
	$interface_statement .= " {\n";
4563
	$interface_statement .= "$send_options";
4564
	$interface_statement .= "$request_options";
4565
	$interface_statement .= "$information_only";
4566
	$interface_statement .= "$script";
4567
	$interface_statement .= "};\n";
4568

    
4569
	$id_assoc_statement_address = "";
4570
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4571
		$id_assoc_statement_address .= "id-assoc";
4572
		$id_assoc_statement_address .= " na";
4573
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4574
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4575
		}
4576
		$id_assoc_statement_address .= " { ";
4577

    
4578
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4579
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4580
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4581
			$id_assoc_statement_address .= "\n\taddress";
4582
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4583
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4584
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4585
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4586
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4587
			}
4588
			$id_assoc_statement_address .= ";\n";
4589
		}
4590

    
4591
		$id_assoc_statement_address .= "};\n";
4592
	}
4593

    
4594
	$id_assoc_statement_prefix = "";
4595
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4596
		$id_assoc_statement_prefix .= "id-assoc";
4597
		$id_assoc_statement_prefix .= " pd";
4598
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4599
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4600
		}
4601
		$id_assoc_statement_prefix .= " { ";
4602

    
4603
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4604
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4605
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4606
			$id_assoc_statement_prefix .= "\n\tprefix";
4607
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4608
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4609
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4610
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4611
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4612
			}
4613
			$id_assoc_statement_prefix .= ";";
4614
		}
4615

    
4616
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
4617
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4618
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4619
			$id_assoc_statement_prefix .= " {$realif}";
4620
			$id_assoc_statement_prefix .= " {\n";
4621
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4622
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4623
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4624
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4625
			}
4626
			$id_assoc_statement_prefix .= "\t};";
4627
		}
4628

    
4629
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4630
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4631
			$id_assoc_statement_prefix .= "\n";
4632
		}
4633

    
4634
		$id_assoc_statement_prefix .= "};\n";
4635
	}
4636

    
4637
	$authentication_statement = "";
4638
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4639
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4640
		$authentication_statement .= "authentication";
4641
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4642
		$authentication_statement .= " {\n";
4643
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4644
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4645
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4646
		}
4647
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4648
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4649
		}
4650
		$authentication_statement .= "};\n";
4651
	}
4652

    
4653
	$key_info_statement = "";
4654
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4655
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4656
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4657
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4658
		$key_info_statement .= "keyinfo";
4659
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4660
		$key_info_statement .= " {\n";
4661
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4662
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4663
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4664
		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'])) {
4665
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4666
		}
4667
		$key_info_statement .= "};\n";
4668
	}
4669

    
4670
	$dhcp6cconf  = $interface_statement;
4671
	$dhcp6cconf .= $id_assoc_statement_address;
4672
	$dhcp6cconf .= $id_assoc_statement_prefix;
4673
	$dhcp6cconf .= $authentication_statement;
4674
	$dhcp6cconf .= $key_info_statement;
4675

    
4676
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4677

    
4678
	return $dhcp6cconf;
4679
}
4680

    
4681

    
4682
function DHCP6_Config_File_Override($wancfg, $wanif) {
4683

    
4684
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4685

    
4686
	if ($dhcp6cconf === false) {
4687
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4688
		return '';
4689
	} else {
4690
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4691
	}
4692
}
4693

    
4694

    
4695
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4696

    
4697
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4698

    
4699
	return $dhcp6cconf;
4700
}
4701

    
4702

    
4703
function interface_dhcp_configure($interface = "wan") {
4704
	global $config, $g;
4705

    
4706
	$ifcfg = $config['interfaces'][$interface];
4707
	if (empty($ifcfg)) {
4708
		$ifcfg = array();
4709
	}
4710

    
4711
	/* generate dhclient_wan.conf */
4712
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4713
	if (!$fd) {
4714
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4715
		return 1;
4716
	}
4717

    
4718
	if ($ifcfg['dhcphostname']) {
4719
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
4720
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
4721
	} else {
4722
		$dhclientconf_hostname = "";
4723
	}
4724

    
4725
	$realif = get_real_interface($interface);
4726
	if (empty($realif)) {
4727
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4728
		return 0;
4729
	}
4730
	$dhclientconf = "";
4731

    
4732
	$dhclientconf .= <<<EOD
4733
interface "{$realif}" {
4734
timeout 60;
4735
retry 15;
4736
select-timeout 0;
4737
initial-interval 1;
4738
	{$dhclientconf_hostname}
4739
	script "/usr/local/sbin/pfSense-dhclient-script";
4740
EOD;
4741

    
4742
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
4743
		$dhclientconf .= <<<EOD
4744

    
4745
	reject {$ifcfg['dhcprejectfrom']};
4746
EOD;
4747
	}
4748
	$dhclientconf .= <<<EOD
4749

    
4750
}
4751

    
4752
EOD;
4753

    
4754
	// DHCP Config File Advanced
4755
	if ($ifcfg['adv_dhcp_config_advanced']) {
4756
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
4757
	}
4758

    
4759
	if (is_ipaddr($ifcfg['alias-address'])) {
4760
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
4761
		$dhclientconf .= <<<EOD
4762
alias {
4763
	interface "{$realif}";
4764
	fixed-address {$ifcfg['alias-address']};
4765
	option subnet-mask {$subnetmask};
4766
}
4767

    
4768
EOD;
4769
	}
4770

    
4771
	// DHCP Config File Override
4772
	if ($ifcfg['adv_dhcp_config_file_override']) {
4773
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
4774
	}
4775

    
4776
	fwrite($fd, $dhclientconf);
4777
	fclose($fd);
4778

    
4779
	/* bring wan interface up before starting dhclient */
4780
	if ($realif) {
4781
		interfaces_bring_up($realif);
4782
	}
4783

    
4784
	/* Make sure dhclient is not running */
4785
	kill_dhclient_process($realif);
4786

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

    
4790
	return 0;
4791
}
4792

    
4793
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
4794

    
4795
	$hostname = "";
4796
	if ($ifcfg['dhcphostname'] != '') {
4797
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
4798
	}
4799

    
4800
	/* DHCP Protocol Timings */
4801
	$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");
4802
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4803
		$pt_variable = "{$Protocol_Timing}";
4804
		${$pt_variable} = "";
4805
		if ($ifcfg[$Protocol_Timing] != "") {
4806
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
4807
		}
4808
	}
4809

    
4810
	$send_options = "";
4811
	if ($ifcfg['adv_dhcp_send_options'] != '') {
4812
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
4813
		foreach ($options as $option) {
4814
			$send_options .= "\tsend " . trim($option) . ";\n";
4815
		}
4816
	}
4817

    
4818
	$request_options = "";
4819
	if ($ifcfg['adv_dhcp_request_options'] != '') {
4820
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
4821
	}
4822

    
4823
	$required_options = "";
4824
	if ($ifcfg['adv_dhcp_required_options'] != '') {
4825
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
4826
	}
4827

    
4828
	$option_modifiers = "";
4829
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
4830
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
4831
		foreach ($modifiers as $modifier) {
4832
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4833
		}
4834
	}
4835

    
4836
	$dhclientconf  = "interface \"{$realif}\" {\n";
4837
	$dhclientconf .= "\n";
4838
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4839
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4840
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4841
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4842
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4843
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4844
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4845
	$dhclientconf .= "\n";
4846
	$dhclientconf .= "# DHCP Protocol Options\n";
4847
	$dhclientconf .= "{$hostname}";
4848
	$dhclientconf .= "{$send_options}";
4849
	$dhclientconf .= "{$request_options}";
4850
	$dhclientconf .= "{$required_options}";
4851
	$dhclientconf .= "{$option_modifiers}";
4852
	$dhclientconf .= "\n";
4853
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
4854
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
4855
	}
4856
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
4857
	$dhclientconf .= "}\n";
4858

    
4859
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
4860

    
4861
	return $dhclientconf;
4862
}
4863

    
4864
function DHCP_Config_Option_Split($option_string) {
4865
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4866
	return $matches ? $matches[0] : [];
4867
}
4868

    
4869
function DHCP_Config_File_Override($ifcfg, $realif) {
4870

    
4871
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
4872

    
4873
	if ($dhclientconf === false) {
4874
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
4875
		return '';
4876
	} else {
4877
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
4878
	}
4879
}
4880

    
4881

    
4882
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
4883

    
4884
	/* Apply Interface Substitutions */
4885
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
4886

    
4887
	/* Apply Hostname Substitutions */
4888
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
4889

    
4890
	/* Arrays of MAC Address Types, Cases, Delimiters */
4891
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4892
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4893
	$various_mac_cases      = array("U", "L");
4894
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4895

    
4896
	/* Apply MAC Address Substitutions */
4897
	foreach ($various_mac_types as $various_mac_type) {
4898
		foreach ($various_mac_cases as $various_mac_case) {
4899
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4900

    
4901
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4902
				if ($res !== false) {
4903

    
4904
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4905
					if ("$various_mac_case" == "U") {
4906
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
4907
					}
4908
					if ("$various_mac_case" == "L") {
4909
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
4910
					}
4911

    
4912
					if ("$various_mac_type" == "mac_addr_hex") {
4913
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4914
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4915
						$dhcpclientconf_mac_hex = "";
4916
						$delimiter = "";
4917
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4918
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4919
							$delimiter = ":";
4920
						}
4921
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4922
					}
4923

    
4924
					/* MAC Address Delimiter Substitutions */
4925
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4926

    
4927
					/* Apply MAC Address Substitutions */
4928
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4929
				}
4930
			}
4931
		}
4932
	}
4933

    
4934
	return $dhclientconf;
4935
}
4936

    
4937
function interfaces_group_setup() {
4938
	global $config;
4939

    
4940
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4941
		return;
4942
	}
4943

    
4944
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4945
		interface_group_setup($groupar);
4946
	}
4947

    
4948
	return;
4949
}
4950

    
4951
function interface_group_setup(&$groupname /* The parameter is an array */) {
4952
	global $config;
4953

    
4954
	if (!is_array($groupname)) {
4955
		return;
4956
	}
4957
	$members = explode(" ", $groupname['members']);
4958
	foreach ($members as $ifs) {
4959
		$realif = get_real_interface($ifs);
4960
		if ($realif && does_interface_exist($realif)) {
4961
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4962
		}
4963
	}
4964

    
4965
	return;
4966
}
4967

    
4968
function is_interface_group($if) {
4969
	global $config;
4970

    
4971
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4972
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4973
			if ($groupentry['ifname'] === $if) {
4974
				return true;
4975
			}
4976
		}
4977
	}
4978

    
4979
	return false;
4980
}
4981

    
4982
function interface_group_add_member($interface, $groupname) {
4983
	$interface = get_real_interface($interface);
4984
	if (does_interface_exist($interface)) {
4985
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4986
	}
4987
}
4988

    
4989
/* COMPAT Function */
4990
function convert_friendly_interface_to_real_interface_name($interface) {
4991
	return get_real_interface($interface);
4992
}
4993

    
4994
/* COMPAT Function */
4995
function get_real_wan_interface($interface = "wan") {
4996
	return get_real_interface($interface);
4997
}
4998

    
4999
/* COMPAT Function */
5000
function get_current_wan_address($interface = "wan") {
5001
	return get_interface_ip($interface);
5002
}
5003

    
5004
/*
5005
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5006
 */
5007
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5008
	global $config;
5009

    
5010
	/* XXX: For speed reasons reference directly the interface array */
5011
	$ifdescrs = &$config['interfaces'];
5012
	//$ifdescrs = get_configured_interface_list(true);
5013

    
5014
	foreach ($ifdescrs as $if => $ifname) {
5015
		if ($if == $interface || $ifname['if'] == $interface) {
5016
			return $if;
5017
		}
5018

    
5019
		if (get_real_interface($if) == $interface) {
5020
			return $if;
5021
		}
5022

    
5023
		if ($checkparent == false) {
5024
			continue;
5025
		}
5026

    
5027
		$int = get_parent_interface($if, true);
5028
		if (is_array($int)) {
5029
			foreach ($int as $iface) {
5030
				if ($iface == $interface) {
5031
					return $if;
5032
				}
5033
			}
5034
		}
5035
	}
5036

    
5037
	if ($interface == "enc0") {
5038
		return 'IPsec';
5039
	}
5040
}
5041

    
5042
/* attempt to resolve interface to friendly descr */
5043
function convert_friendly_interface_to_friendly_descr($interface) {
5044
	global $config;
5045

    
5046
	switch ($interface) {
5047
		case "l2tp":
5048
			$ifdesc = "L2TP";
5049
			break;
5050
		case "pptp":
5051
			$ifdesc = "PPTP";
5052
			break;
5053
		case "pppoe":
5054
			$ifdesc = "PPPoE";
5055
			break;
5056
		case "openvpn":
5057
			$ifdesc = "OpenVPN";
5058
			break;
5059
		case "lo0":
5060
			$ifdesc = "Loopback";
5061
			break;
5062
		case "enc0":
5063
		case "ipsec":
5064
		case "IPsec":
5065
			$ifdesc = "IPsec";
5066
			break;
5067
		default:
5068
			if (isset($config['interfaces'][$interface])) {
5069
				if (empty($config['interfaces'][$interface]['descr'])) {
5070
					$ifdesc = strtoupper($interface);
5071
				} else {
5072
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5073
				}
5074
				break;
5075
			} else if (substr($interface, 0, 4) == '_vip') {
5076
				if (is_array($config['virtualip']['vip'])) {
5077
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5078
						if ($vip['mode'] == "carp") {
5079
							if ($interface == "_vip{$vip['uniqid']}") {
5080
								$descr = $vip['subnet'];
5081
								$descr .= " (vhid {$vip['vhid']})";
5082
								if (!empty($vip['descr'])) {
5083
									$descr .= " - " .$vip['descr'];
5084
								}
5085
								return $descr;
5086
							}
5087
						}
5088
					}
5089
				}
5090
			} else if (substr($interface, 0, 5) == '_lloc') {
5091
				return get_interface_linklocal($interface);
5092
			} else {
5093
				/* if list */
5094
				$ifdescrs = get_configured_interface_with_descr(true);
5095
				foreach ($ifdescrs as $if => $ifname) {
5096
					if ($if == $interface || $ifname == $interface) {
5097
						return $ifname;
5098
					}
5099
				}
5100
			}
5101
			break;
5102
	}
5103

    
5104
	return $ifdesc;
5105
}
5106

    
5107
function convert_real_interface_to_friendly_descr($interface) {
5108

    
5109
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5110

    
5111
	if (!empty($ifdesc)) {
5112
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5113
	}
5114

    
5115
	return $interface;
5116
}
5117

    
5118
/*
5119
 *  get_parent_interface($interface):
5120
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5121
 *				or virtual interface (i.e. vlan)
5122
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5123
 *			-- returns $interface passed in if $interface parent is not found
5124
 *			-- returns empty array if an invalid interface is passed
5125
 *	(Only handles ppps and vlans now.)
5126
 */
5127
function get_parent_interface($interface, $avoidrecurse = false) {
5128
	global $config;
5129

    
5130
	$parents = array();
5131
	//Check that we got a valid interface passed
5132
	$realif = get_real_interface($interface);
5133
	if ($realif == NULL) {
5134
		return $parents;
5135
	}
5136

    
5137
	// If we got a real interface, find it's friendly assigned name
5138
	if ($interface == $realif && $avoidrecurse == false) {
5139
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5140
	}
5141

    
5142
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5143
		$ifcfg = $config['interfaces'][$interface];
5144
		switch ($ifcfg['ipaddr']) {
5145
			case "ppp":
5146
			case "pppoe":
5147
			case "pptp":
5148
			case "l2tp":
5149
				if (empty($parents)) {
5150
					if (is_array($config['ppps']['ppp'])) {
5151
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5152
							if ($ifcfg['if'] == $ppp['if']) {
5153
								$ports = explode(',', $ppp['ports']);
5154
								foreach ($ports as $pid => $parent_if) {
5155
									$parents[$pid] = get_real_interface($parent_if);
5156
								}
5157
								break;
5158
							}
5159
						}
5160
					}
5161
				}
5162
				break;
5163
			case "dhcp":
5164
			case "static":
5165
			default:
5166
				// Handle _vlans
5167
				$vlan = interface_is_vlan($ifcfg['if']);
5168
				if ($vlan != NULL) {
5169
					$parents[0] = $vlan['if'];
5170
				}
5171
				break;
5172
		}
5173
	}
5174

    
5175
	if (empty($parents)) {
5176
		// Handle _vlans not assigned to an interface
5177
		$vlan = interface_is_vlan($realif);
5178
		if ($vlan != NULL) {
5179
			$parents[0] = $vlan['if'];
5180
		}
5181
	}
5182

    
5183
	if (empty($parents)) {
5184
		$parents[0] = $realif;
5185
	}
5186

    
5187
	return $parents;
5188
}
5189

    
5190
/*
5191
 *  get_parent_physical_interface($interface):
5192
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5193
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5194
 */
5195
function get_parent_physical_interface($interface) {
5196
	global $config;
5197

    
5198
	$realif = get_parent_interface($interface);
5199

    
5200
	if (substr($realif[0], 0, 4) == "lagg") {
5201
		foreach ($config['laggs']['lagg'] as $lagg) {
5202
			if ($realif[0] == $lagg['laggif']) {
5203
				return explode(",", $lagg['members']);
5204
			}
5205
		}
5206
	} else {
5207
		return $realif;
5208
	}
5209
}
5210

    
5211
function interface_is_wireless_clone($wlif) {
5212
	if (!stristr($wlif, "_wlan")) {
5213
		return false;
5214
	} else {
5215
		return true;
5216
	}
5217
}
5218

    
5219
function interface_get_wireless_base($wlif) {
5220
	if (!stristr($wlif, "_wlan")) {
5221
		return $wlif;
5222
	} else {
5223
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5224
	}
5225
}
5226

    
5227
function interface_get_wireless_clone($wlif) {
5228
	if (!stristr($wlif, "_wlan")) {
5229
		return $wlif . "_wlan0";
5230
	} else {
5231
		return $wlif;
5232
	}
5233
}
5234

    
5235
function interface_list_wireless() {
5236
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5237

    
5238
	$result = array();
5239
	foreach ($portlist as $port) {
5240
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5241
			continue;
5242
		}
5243

    
5244
		$desc = $port . " ( " . get_single_sysctl(
5245
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5246

    
5247
		$result[] = array(
5248
		    "if" => $port,
5249
		    "descr" => $desc
5250
		);
5251
	}
5252

    
5253
	return $result;
5254
}
5255

    
5256
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
5257
	global $config, $g;
5258

    
5259
	$wanif = NULL;
5260

    
5261
	switch ($interface) {
5262
		case "l2tp":
5263
			$wanif = "l2tp";
5264
			break;
5265
		case "pptp":
5266
			$wanif = "pptp";
5267
			break;
5268
		case "pppoe":
5269
			$wanif = "pppoe";
5270
			break;
5271
		case "openvpn":
5272
			$wanif = "openvpn";
5273
			break;
5274
		case "IPsec":
5275
		case "ipsec":
5276
		case "enc0":
5277
			$wanif = "enc0";
5278
			break;
5279
		case "ppp":
5280
			$wanif = "ppp";
5281
			break;
5282
		default:
5283
			if (substr($interface, 0, 4) == '_vip') {
5284
				$wanif = get_configured_vip_interface($interface);
5285
				if (!empty($wanif)) {
5286
					$wanif = get_real_interface($wanif);
5287
				}
5288
				break;
5289
			} else if (substr($interface, 0, 5) == '_lloc') {
5290
				$interface = substr($interface, 5);
5291
			} else if (interface_is_vlan($interface) != NULL ||
5292
			    does_interface_exist($interface, $flush)) {
5293
				/*
5294
				 * If a real interface was already passed simply
5295
				 * pass the real interface back.  This encourages
5296
				 * the usage of this function in more cases so that
5297
				 * we can combine logic for more flexibility.
5298
				 */
5299
				$wanif = $interface;
5300
				break;
5301
			}
5302

    
5303
			if (empty($config['interfaces'][$interface])) {
5304
				break;
5305
			}
5306

    
5307
			$cfg = &$config['interfaces'][$interface];
5308

    
5309
			if ($family == "inet6") {
5310
				switch ($cfg['ipaddrv6']) {
5311
					case "6rd":
5312
					case "6to4":
5313
						$wanif = "{$interface}_stf";
5314
						break;
5315
					case 'pppoe':
5316
					case 'ppp':
5317
					case 'l2tp':
5318
					case 'pptp':
5319
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5320
							$wanif = interface_get_wireless_clone($cfg['if']);
5321
						} else {
5322
							$wanif = $cfg['if'];
5323
						}
5324
						break;
5325
					default:
5326
						switch ($cfg['ipaddr']) {
5327
							case 'pppoe':
5328
							case 'ppp':
5329
							case 'l2tp':
5330
							case 'pptp':
5331
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
5332
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) || isset($cfg['ipv6usev4iface'])) {
5333
									$wanif = $cfg['if'];
5334
								} else {
5335
									$parents = get_parent_interface($interface);
5336
									if (!empty($parents[0])) {
5337
										$wanif = $parents[0];
5338
									} else {
5339
										$wanif = $cfg['if'];
5340
									}
5341
								}
5342
								break;
5343
							default:
5344
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5345
									$wanif = interface_get_wireless_clone($cfg['if']);
5346
								} else {
5347
									$wanif = $cfg['if'];
5348
								}
5349
								break;
5350
						}
5351
						break;
5352
				}
5353
			} else {
5354
				// Wireless cloned NIC support (FreeBSD 8+)
5355
				// interface name format: $parentnic_wlanparentnic#
5356
				// example: ath0_wlan0
5357
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5358
					$wanif = interface_get_wireless_clone($cfg['if']);
5359
				} else {
5360
					$wanif = $cfg['if'];
5361
				}
5362
			}
5363
			break;
5364
	}
5365

    
5366
	return $wanif;
5367
}
5368

    
5369
/* Guess the physical interface by providing a IP address */
5370
function guess_interface_from_ip($ipaddress) {
5371

    
5372
	$family = '';
5373
	if (is_ipaddrv4($ipaddress)) {
5374
		$family = 'inet';
5375
	}
5376
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5377
		$family = 'inet6';
5378
	}
5379

    
5380
	if (empty($family)) {
5381
		return false;
5382
	}
5383

    
5384
	/* create a route table we can search */
5385
	$output = '';
5386
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
5387
	$output[0] = trim($output[0], " \n");
5388
	if (!empty($output[0])) {
5389
		return $output[0];
5390
	}
5391

    
5392
	return false;
5393
}
5394

    
5395
/*
5396
 * find_ip_interface($ip): return the interface where an ip is defined
5397
 *   (or if $bits is specified, where an IP within the subnet is defined)
5398
 */
5399
function find_ip_interface($ip, $bits = null) {
5400
	if (!is_ipaddr($ip)) {
5401
		return false;
5402
	}
5403

    
5404
	$isv6ip = is_ipaddrv6($ip);
5405

    
5406
	/* if list */
5407
	$ifdescrs = get_configured_interface_list();
5408

    
5409
	foreach ($ifdescrs as $ifdescr => $ifname) {
5410
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
5411
		if (is_null($ifip)) {
5412
			continue;
5413
		}
5414
		if (is_null($bits)) {
5415
			if ($ip == $ifip) {
5416
				$int = get_real_interface($ifname);
5417
				return $int;
5418
			}
5419
		} else {
5420
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
5421
				$int = get_real_interface($ifname);
5422
				return $int;
5423
			}
5424
		}
5425
	}
5426

    
5427
	return false;
5428
}
5429

    
5430
/*
5431
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5432
 *   (or if $bits is specified, where an IP within the subnet is found)
5433
 */
5434
function find_virtual_ip_alias($ip, $bits = null) {
5435
	global $config;
5436

    
5437
	if (!is_array($config['virtualip']['vip'])) {
5438
		return false;
5439
	}
5440
	if (!is_ipaddr($ip)) {
5441
		return false;
5442
	}
5443

    
5444
	$isv6ip = is_ipaddrv6($ip);
5445

    
5446
	foreach ($config['virtualip']['vip'] as $vip) {
5447
		if ($vip['mode'] === "ipalias") {
5448
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
5449
				continue;
5450
			}
5451
			if (is_null($bits)) {
5452
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
5453
					return $vip;
5454
				}
5455
			} else {
5456
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5457
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5458
					return $vip;
5459
				}
5460
			}
5461
		}
5462
	}
5463
	return false;
5464
}
5465

    
5466
function link_interface_to_track6($int, $action = "") {
5467
	global $config;
5468

    
5469
	if (empty($int)) {
5470
		return;
5471
	}
5472

    
5473
	if (is_array($config['interfaces'])) {
5474
		$list = array();
5475
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5476
			if (!isset($ifcfg['enable'])) {
5477
				continue;
5478
			}
5479
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5480
				if ($action == "update") {
5481
					interface_track6_configure($ifname, $ifcfg);
5482
				} else if ($action == "") {
5483
					$list[$ifname] = $ifcfg;
5484
				}
5485
			}
5486
		}
5487
		return $list;
5488
	}
5489
}
5490

    
5491
function interface_find_child_cfgmtu($realiface) {
5492
	global $config;
5493

    
5494
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5495
	$vlans = link_interface_to_vlans($realiface);
5496
	$qinqs = link_interface_to_qinqs($realiface);
5497
	$bridge = link_interface_to_bridge($realiface);
5498
	if (!empty($interface)) {
5499
		$gifs = link_interface_to_gif($interface);
5500
		$gres = link_interface_to_gre($interface);
5501
	} else {
5502
		$gifs = array();
5503
		$gres = array();
5504
	}
5505

    
5506
	$mtu = 0;
5507
	if (is_array($vlans)) {
5508
		foreach ($vlans as $vlan) {
5509
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5510
			if (empty($ifass)) {
5511
				continue;
5512
			}
5513
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5514
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5515
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5516
				}
5517
			}
5518
		}
5519
	}
5520
	if (is_array($qinqs)) {
5521
		foreach ($qinqs as $qinq) {
5522
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5523
			if (empty($ifass)) {
5524
				continue;
5525
			}
5526
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5527
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5528
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5529
				}
5530
			}
5531
		}
5532
	}
5533
	if (is_array($gifs)) {
5534
		foreach ($gifs as $gif) {
5535
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5536
			if (empty($ifass)) {
5537
				continue;
5538
			}
5539
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5540
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5541
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5542
				}
5543
			}
5544
		}
5545
	}
5546
	if (is_array($gres)) {
5547
		foreach ($gres as $gre) {
5548
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5549
			if (empty($ifass)) {
5550
				continue;
5551
			}
5552
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5553
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5554
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5555
				}
5556
			}
5557
		}
5558
	}
5559
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5560
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5561
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5562
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5563
		}
5564
	}
5565
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5566

    
5567
	return $mtu;
5568
}
5569

    
5570
function link_interface_to_vlans($int, $action = "") {
5571
	global $config;
5572

    
5573
	if (empty($int)) {
5574
		return;
5575
	}
5576

    
5577
	if (is_array($config['vlans']['vlan'])) {
5578
		$ifaces = array();
5579
		foreach ($config['vlans']['vlan'] as $vlan) {
5580
			if ($int == $vlan['if']) {
5581
				if ($action == "update") {
5582
					interfaces_bring_up($int);
5583
				} else {
5584
					$ifaces[$vlan['tag']] = $vlan;
5585
				}
5586
			}
5587
		}
5588
		if (!empty($ifaces)) {
5589
			return $ifaces;
5590
		}
5591
	}
5592
}
5593

    
5594
function link_interface_to_qinqs($int, $action = "") {
5595
	global $config;
5596

    
5597
	if (empty($int)) {
5598
		return;
5599
	}
5600

    
5601
	if (is_array($config['qinqs']['qinqentry'])) {
5602
		$ifaces = array();
5603
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5604
			if ($int == $qinq['if']) {
5605
				if ($action == "update") {
5606
					interfaces_bring_up($int);
5607
				} else {
5608
					$ifaces[$qinq['tag']] = $qinq;
5609
				}
5610
			}
5611
		}
5612
		if (!empty($ifaces)) {
5613
			return $ifaces;
5614
		}
5615
	}
5616
}
5617

    
5618
function link_interface_to_vips($int, $action = "", $vhid = '') {
5619
	global $config;
5620

    
5621
	$updatevips = false;
5622
	if (is_array($config['virtualip']['vip'])) {
5623
		$result = array();
5624
		foreach ($config['virtualip']['vip'] as $vip) {
5625
			if (substr($vip['interface'], 0, 4) == "_vip") {
5626
				$iface = get_configured_vip_interface($vip['interface']);
5627
			} else {
5628
				$iface = $vip['interface'];
5629
			}
5630
			if ($int != $iface) {
5631
				continue;
5632
			}
5633
			if ($action == "update") {
5634
				$updatevips = true;
5635
			} else {
5636
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5637
				    substr($vip['interface'], 0, 4) == "_vip") {
5638
					$result[] = $vip;
5639
				}
5640
			}
5641
		}
5642
		if ($updatevips === true) {
5643
			interfaces_vips_configure($int);
5644
		}
5645
		return $result;
5646
	}
5647

    
5648
	return NULL;
5649
}
5650

    
5651
/****f* interfaces/link_interface_to_bridge
5652
 * NAME
5653
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5654
 * INPUTS
5655
 *   $ip
5656
 * RESULT
5657
 *   bridge[0-99]
5658
 ******/
5659
function link_interface_to_bridge($int) {
5660
	global $config;
5661

    
5662
	if (is_array($config['bridges']['bridged'])) {
5663
		foreach ($config['bridges']['bridged'] as $bridge) {
5664
			if (in_array($int, explode(',', $bridge['members']))) {
5665
				return "{$bridge['bridgeif']}";
5666
			}
5667
		}
5668
	}
5669
}
5670

    
5671
function link_interface_to_group($int) {
5672
	global $config;
5673

    
5674
	$result = array();
5675

    
5676
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5677
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5678
			if (in_array($int, explode(" ", $group['members']))) {
5679
				$result[$group['ifname']] = $int;
5680
			}
5681
		}
5682
	}
5683

    
5684
	return $result;
5685
}
5686

    
5687
function link_interface_to_gre($interface) {
5688
	global $config;
5689

    
5690
	$result = array();
5691

    
5692
	if (is_array($config['gres']['gre'])) {
5693
		foreach ($config['gres']['gre'] as $gre) {
5694
			if ($gre['if'] == $interface) {
5695
				$result[] = $gre;
5696
			}
5697
		}
5698
	}
5699

    
5700
	return $result;
5701
}
5702

    
5703
function link_interface_to_gif($interface) {
5704
	global $config;
5705

    
5706
	$result = array();
5707

    
5708
	if (is_array($config['gifs']['gif'])) {
5709
		foreach ($config['gifs']['gif'] as $gif) {
5710
			if ($gif['if'] == $interface) {
5711
				$result[] = $gif;
5712
			}
5713
		}
5714
	}
5715

    
5716
	return $result;
5717
}
5718

    
5719
/*
5720
 * find_interface_ip($interface): return the interface ip (first found)
5721
 */
5722
function find_interface_ip($interface, $flush = false) {
5723
	global $interface_ip_arr_cache;
5724
	global $interface_sn_arr_cache;
5725

    
5726
	$interface = str_replace("\n", "", $interface);
5727

    
5728
	if (!does_interface_exist($interface)) {
5729
		return;
5730
	}
5731

    
5732
	/* Setup IP cache */
5733
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5734
		if (file_exists("/var/db/${interface}_ip")) {
5735
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
5736
			$ifaddrs = pfSense_getall_interface_addresses($interface);
5737
			foreach ($ifaddrs as $ifaddr) {
5738
				list($ip, $mask) = explode("/", $ifaddr);
5739
				if ($ip == $ifip) {
5740
					$interface_ip_arr_cache[$interface] = $ip;
5741
					$interface_sn_arr_cache[$interface] = $mask;
5742
					break;
5743
				}
5744
			}
5745
		}
5746
		if (!isset($interface_ip_arr_cache[$interface])) {
5747
			$ifinfo = pfSense_get_interface_addresses($interface);
5748
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5749
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5750
		}
5751
	}
5752

    
5753
	return $interface_ip_arr_cache[$interface];
5754
}
5755

    
5756
/*
5757
 * find_interface_ipv6($interface): return the interface ip (first found)
5758
 */
5759
function find_interface_ipv6($interface, $flush = false) {
5760
	global $interface_ipv6_arr_cache;
5761
	global $interface_snv6_arr_cache;
5762
	global $config;
5763

    
5764
	$interface = trim($interface);
5765
	$interface = get_real_interface($interface);
5766

    
5767
	if (!does_interface_exist($interface)) {
5768
		return;
5769
	}
5770

    
5771
	/* Setup IP cache */
5772
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5773
		$ifinfo = pfSense_get_interface_addresses($interface);
5774
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5775
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5776
	}
5777

    
5778
	return $interface_ipv6_arr_cache[$interface];
5779
}
5780

    
5781
/*
5782
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5783
 */
5784
function find_interface_ipv6_ll($interface, $flush = false) {
5785
	global $interface_llv6_arr_cache;
5786
	global $config;
5787

    
5788
	$interface = str_replace("\n", "", $interface);
5789

    
5790
	if (!does_interface_exist($interface)) {
5791
		return;
5792
	}
5793

    
5794
	/* Setup IP cache */
5795
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5796
		$ifinfo = pfSense_getall_interface_addresses($interface);
5797
		foreach ($ifinfo as $line) {
5798
			if (strstr($line, ":")) {
5799
				$parts = explode("/", $line);
5800
				if (is_linklocal($parts[0])) {
5801
					$ifinfo['linklocal'] = $parts[0];
5802
				}
5803
			}
5804
		}
5805
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5806
	}
5807
	return $interface_llv6_arr_cache[$interface];
5808
}
5809

    
5810
function find_interface_subnet($interface, $flush = false) {
5811
	global $interface_sn_arr_cache;
5812
	global $interface_ip_arr_cache;
5813

    
5814
	$interface = str_replace("\n", "", $interface);
5815
	if (does_interface_exist($interface) == false) {
5816
		return;
5817
	}
5818

    
5819
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5820
		$ifinfo = pfSense_get_interface_addresses($interface);
5821
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5822
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5823
	}
5824

    
5825
	return $interface_sn_arr_cache[$interface];
5826
}
5827

    
5828
function find_interface_subnetv6($interface, $flush = false) {
5829
	global $interface_snv6_arr_cache;
5830
	global $interface_ipv6_arr_cache;
5831

    
5832
	$interface = str_replace("\n", "", $interface);
5833
	if (does_interface_exist($interface) == false) {
5834
		return;
5835
	}
5836

    
5837
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5838
		$ifinfo = pfSense_get_interface_addresses($interface);
5839
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5840
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5841
	}
5842

    
5843
	return $interface_snv6_arr_cache[$interface];
5844
}
5845

    
5846
function ip_in_interface_alias_subnet($interface, $ipalias) {
5847
	global $config;
5848

    
5849
	if (empty($interface) || !is_ipaddr($ipalias)) {
5850
		return false;
5851
	}
5852
	if (is_array($config['virtualip']['vip'])) {
5853
		foreach ($config['virtualip']['vip'] as $vip) {
5854
			switch ($vip['mode']) {
5855
				case "ipalias":
5856
					if ($vip['interface'] <> $interface) {
5857
						break;
5858
					}
5859
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5860
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5861
						return true;
5862
					}
5863
					break;
5864
			}
5865
		}
5866
	}
5867

    
5868
	return false;
5869
}
5870

    
5871
function get_possible_listen_ips($include_ipv6_link_local=false) {
5872

    
5873
	$interfaces = get_configured_interface_with_descr();
5874
	foreach ($interfaces as $iface => $ifacename) {
5875
		if ($include_ipv6_link_local) {
5876
			/* This is to avoid going though added ll below */
5877
			if (substr($iface, 0, 5) == '_lloc') {
5878
				continue;
5879
			}
5880
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5881
			if (!empty($llip)) {
5882
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5883
			}
5884
		}
5885
	}
5886
	$viplist = get_configured_vip_list();
5887
	foreach ($viplist as $vip => $address) {
5888
		$interfaces[$vip] = $address;
5889
		if (get_vip_descr($address)) {
5890
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5891
		}
5892
	}
5893

    
5894
	$interfaces['lo0'] = 'Localhost';
5895

    
5896
	return $interfaces;
5897
}
5898

    
5899
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5900
	global $config;
5901

    
5902
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5903
	foreach (array('server', 'client') as $mode) {
5904
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5905
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5906
				if (!isset($setting['disable'])) {
5907
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5908
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5909
				}
5910
			}
5911
		}
5912
	}
5913
	return $sourceips;
5914
}
5915

    
5916
function get_interface_ip($interface = "wan") {
5917
	global $config;
5918

    
5919
	if (substr($interface, 0, 4) == '_vip') {
5920
		return get_configured_vip_ipv4($interface);
5921
	} else if (substr($interface, 0, 5) == '_lloc') {
5922
		/* No link-local address for v4. */
5923
		return null;
5924
	}
5925

    
5926
	$realif = get_failover_interface($interface, 'inet');
5927
	if (!$realif) {
5928
		return null;
5929
	}
5930

    
5931
	if (substr($realif, 0, 4) == '_vip') {
5932
		return get_configured_vip_ipv4($realif);
5933
	} else if (substr($realif, 0, 5) == '_lloc') {
5934
		/* No link-local address for v4. */
5935
		return null;
5936
	}
5937

    
5938
	if (is_array($config['interfaces'][$interface]) &&
5939
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5940
		return ($config['interfaces'][$interface]['ipaddr']);
5941
	}
5942

    
5943
	/*
5944
	 * Beaware that find_interface_ip() is our last option, it will
5945
	 * return the first IP it find on interface, not necessarily the
5946
	 * main IP address.
5947
	 */
5948
	$curip = find_interface_ip($realif);
5949
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5950
		return $curip;
5951
	} else {
5952
		return null;
5953
	}
5954
}
5955

    
5956
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5957
	global $config;
5958

    
5959
	if (substr($interface, 0, 4) == '_vip') {
5960
		return get_configured_vip_ipv6($interface);
5961
	} else if (substr($interface, 0, 5) == '_lloc') {
5962
		return get_interface_linklocal($interface);
5963
	}
5964

    
5965
	$realif = get_failover_interface($interface, 'inet6');
5966
	if (!$realif) {
5967
		return null;
5968
	}
5969

    
5970
	if (substr($realif, 0, 4) == '_vip') {
5971
		return get_configured_vip_ipv6($realif);
5972
	} else if (substr($realif, 0, 5) == '_lloc') {
5973
		return get_interface_linklocal($realif);
5974
	}
5975

    
5976
	if (is_array($config['interfaces'][$interface])) {
5977
		switch ($config['interfaces'][$interface]['ipaddr']) {
5978
			case 'pppoe':
5979
			case 'l2tp':
5980
			case 'pptp':
5981
			case 'ppp':
5982
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5983
					$realif = get_real_interface($interface, 'inet6', false);
5984
				}
5985
				break;
5986
		}
5987
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5988
			return ($config['interfaces'][$interface]['ipaddrv6']);
5989
		}
5990
	}
5991

    
5992
	/*
5993
	 * Beaware that find_interface_ip() is our last option, it will
5994
	 * return the first IP it find on interface, not necessarily the
5995
	 * main IP address.
5996
	 */
5997
	$curip = find_interface_ipv6($realif, $flush);
5998
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5999
		return $curip;
6000
	} else {
6001
		/*
6002
		 * NOTE: On the case when only the prefix is requested,
6003
		 * the communication on WAN will be done over link-local.
6004
		 */
6005
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6006
			$curip = find_interface_ipv6_ll($realif, $flush);
6007
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6008
				return $curip;
6009
			}
6010
		}
6011
	}
6012
	return null;
6013
}
6014

    
6015
function get_interface_linklocal($interface = "wan") {
6016

    
6017
	$realif = get_failover_interface($interface, 'inet6');
6018
	if (!$realif) {
6019
		return null;
6020
	}
6021

    
6022
	if (substr($interface, 0, 4) == '_vip') {
6023
		$realif = get_real_interface($interface);
6024
	} else if (substr($interface, 0, 5) == '_lloc') {
6025
		$realif = get_real_interface(substr($interface, 5));
6026
	}
6027

    
6028
	$curip = find_interface_ipv6_ll($realif);
6029
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6030
		return $curip;
6031
	} else {
6032
		return null;
6033
	}
6034
}
6035

    
6036
function get_interface_subnet($interface = "wan") {
6037
	global $config;
6038

    
6039
	if (substr($interface, 0, 4) == '_vip') {
6040
		return (get_configured_vip_subnetv4($interface));
6041
	}
6042

    
6043
	if (is_array($config['interfaces'][$interface]) &&
6044
		!empty($config['interfaces'][$interface]['subnet'])) {
6045
		return ($config['interfaces'][$interface]['subnet']);
6046
	}
6047

    
6048
	$realif = get_real_interface($interface);
6049
	if (!$realif) {
6050
		return (NULL);
6051
	}
6052

    
6053
	$cursn = find_interface_subnet($realif);
6054
	if (!empty($cursn)) {
6055
		return ($cursn);
6056
	}
6057

    
6058
	return (NULL);
6059
}
6060

    
6061
function get_interface_subnetv6($interface = "wan") {
6062
	global $config;
6063

    
6064
	if (substr($interface, 0, 4) == '_vip') {
6065
		return (get_configured_vip_subnetv6($interface));
6066
	} else if (substr($interface, 0, 5) == '_lloc') {
6067
		$interface = substr($interface, 5);
6068
	}
6069

    
6070
	if (is_array($config['interfaces'][$interface]) &&
6071
		!empty($config['interfaces'][$interface]['subnetv6'])) {
6072
		return ($config['interfaces'][$interface]['subnetv6']);
6073
	}
6074

    
6075
	$realif = get_real_interface($interface, 'inet6');
6076
	if (!$realif) {
6077
		return (NULL);
6078
	}
6079

    
6080
	$cursn = find_interface_subnetv6($realif);
6081
	if (!empty($cursn)) {
6082
		return ($cursn);
6083
	}
6084

    
6085
	return (NULL);
6086
}
6087

    
6088
/* return outside interfaces with a gateway */
6089
function get_interfaces_with_gateway() {
6090
	global $config;
6091

    
6092
	$ints = array();
6093

    
6094
	/* loop interfaces, check config for outbound */
6095
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6096
		switch ($ifname['ipaddr']) {
6097
			case "dhcp":
6098
			case "pppoe":
6099
			case "pptp":
6100
			case "l2tp":
6101
			case "ppp":
6102
				$ints[$ifdescr] = $ifdescr;
6103
				break;
6104
			default:
6105
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6106
				    !empty($ifname['gateway'])) {
6107
					$ints[$ifdescr] = $ifdescr;
6108
				}
6109
				break;
6110
		}
6111
	}
6112
	return $ints;
6113
}
6114

    
6115
/* return true if interface has a gateway */
6116
function interface_has_gateway($friendly) {
6117
	global $config;
6118

    
6119
	if (!empty($config['interfaces'][$friendly])) {
6120
		$ifname = &$config['interfaces'][$friendly];
6121
		switch ($ifname['ipaddr']) {
6122
			case "dhcp":
6123
			case "pppoe":
6124
			case "pptp":
6125
			case "l2tp":
6126
			case "ppp":
6127
				return true;
6128
			break;
6129
			default:
6130
				if (substr($ifname['if'], 0, 4) == "ovpn") {
6131
					return true;
6132
				}
6133
				$tunnelif = substr($ifname['if'], 0, 3);
6134
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6135
					if (find_interface_ip($ifname['if'])) {
6136
						return true;
6137
					}
6138
				}
6139
				if (!empty($ifname['gateway'])) {
6140
					return true;
6141
				}
6142
			break;
6143
		}
6144
	}
6145

    
6146
	return false;
6147
}
6148

    
6149
/* return true if interface has a gateway */
6150
function interface_has_gatewayv6($friendly) {
6151
	global $config;
6152

    
6153
	if (!empty($config['interfaces'][$friendly])) {
6154
		$ifname = &$config['interfaces'][$friendly];
6155
		switch ($ifname['ipaddrv6']) {
6156
			case "slaac":
6157
			case "dhcp6":
6158
			case "6to4":
6159
			case "6rd":
6160
				return true;
6161
				break;
6162
			default:
6163
				if (substr($ifname['if'], 0, 4) == "ovpn") {
6164
					return true;
6165
				}
6166
				$tunnelif = substr($ifname['if'], 0, 3);
6167
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6168
					if (find_interface_ipv6($ifname['if'])) {
6169
						return true;
6170
					}
6171
				}
6172
				if (!empty($ifname['gatewayv6'])) {
6173
					return true;
6174
				}
6175
				break;
6176
		}
6177
	}
6178

    
6179
	return false;
6180
}
6181

    
6182
/****f* interfaces/is_altq_capable
6183
 * NAME
6184
 *   is_altq_capable - Test if interface is capable of using ALTQ
6185
 * INPUTS
6186
 *   $int            - string containing interface name
6187
 * RESULT
6188
 *   boolean         - true or false
6189
 ******/
6190

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

    
6206
	$int_family = remove_ifindex($int);
6207

    
6208
	if (in_array($int_family, $capable)) {
6209
		return true;
6210
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6211
		return true;
6212
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6213
		return true;
6214
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6215
		return true;
6216
	} else {
6217
		return false;
6218
	}
6219
}
6220

    
6221
/****f* interfaces/is_interface_wireless
6222
 * NAME
6223
 *   is_interface_wireless - Returns if an interface is wireless
6224
 * RESULT
6225
 *   $tmp       - Returns if an interface is wireless
6226
 ******/
6227
function is_interface_wireless($interface) {
6228
	global $config, $g;
6229

    
6230
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6231
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6232
		if (preg_match($g['wireless_regex'], $interface)) {
6233
			if (isset($config['interfaces'][$friendly])) {
6234
				$config['interfaces'][$friendly]['wireless'] = array();
6235
			}
6236
			return true;
6237
		}
6238
		return false;
6239
	} else {
6240
		return true;
6241
	}
6242
}
6243

    
6244
function get_wireless_modes($interface) {
6245
	/* return wireless modes and channels */
6246
	$wireless_modes = 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 chan";
6252
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6253
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6254

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

    
6259
		$c = 0;
6260
		while ($c < $interface_channel_count) {
6261
			$channel_line = explode(",", $interface_channels["$c"]);
6262
			$wireless_mode = trim($channel_line[0]);
6263
			$wireless_channel = trim($channel_line[1]);
6264
			if (trim($wireless_mode) != "") {
6265
				/* if we only have 11g also set 11b channels */
6266
				if ($wireless_mode == "11g") {
6267
					if (!isset($wireless_modes["11b"])) {
6268
						$wireless_modes["11b"] = array();
6269
					}
6270
				} else if ($wireless_mode == "11g ht") {
6271
					if (!isset($wireless_modes["11b"])) {
6272
						$wireless_modes["11b"] = array();
6273
					}
6274
					if (!isset($wireless_modes["11g"])) {
6275
						$wireless_modes["11g"] = array();
6276
					}
6277
					$wireless_mode = "11ng";
6278
				} else if ($wireless_mode == "11a ht") {
6279
					if (!isset($wireless_modes["11a"])) {
6280
						$wireless_modes["11a"] = array();
6281
					}
6282
					$wireless_mode = "11na";
6283
				}
6284
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6285
			}
6286
			$c++;
6287
		}
6288
	}
6289
	return($wireless_modes);
6290
}
6291

    
6292
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6293
function get_wireless_channel_info($interface) {
6294
	$wireless_channels = array();
6295

    
6296
	$cloned_interface = get_real_interface($interface);
6297

    
6298
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6299
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
6300
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6301
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
6302

    
6303
		$interface_channels = "";
6304
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6305

    
6306
		foreach ($interface_channels as $channel_line) {
6307
			$channel_line = explode(",", $channel_line);
6308
			if (!isset($wireless_channels[$channel_line[0]])) {
6309
				$wireless_channels[$channel_line[0]] = $channel_line;
6310
			}
6311
		}
6312
	}
6313
	return($wireless_channels);
6314
}
6315

    
6316
function set_interface_mtu($interface, $mtu) {
6317

    
6318
	/* LAGG interface must be destroyed and re-created to change MTU */
6319
	if (substr($interface, 0, 4) == 'lagg') {
6320
		if (isset($config['laggs']['lagg']) &&
6321
		    is_array($config['laggs']['lagg'])) {
6322
			foreach ($config['laggs']['lagg'] as $lagg) {
6323
				if ($lagg['laggif'] == $interface) {
6324
					interface_lagg_configure($lagg);
6325
					break;
6326
				}
6327
			}
6328
		}
6329
	} else {
6330
		pfSense_interface_mtu($interface, $mtu);
6331
	}
6332
}
6333

    
6334
/****f* interfaces/get_interface_mtu
6335
 * NAME
6336
 *   get_interface_mtu - Return the mtu of an interface
6337
 * RESULT
6338
 *   $tmp       - Returns the mtu of an interface
6339
 ******/
6340
function get_interface_mtu($interface) {
6341
	$mtu = pfSense_interface_getmtu($interface);
6342
	return $mtu['mtu'];
6343
}
6344

    
6345
function get_interface_mac($interface) {
6346
	$macinfo = pfSense_get_interface_addresses($interface);
6347
	return $macinfo["macaddr"];
6348
}
6349

    
6350
function get_interface_vendor_mac($interface) {
6351
	$macinfo = pfSense_get_interface_addresses($interface);
6352
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] != "00:00:00:00:00:00") {
6353
		return ($macinfo["hwaddr"]);
6354
	}
6355
	return (NULL);
6356
}
6357

    
6358
/****f* pfsense-utils/generate_random_mac_address
6359
 * NAME
6360
 *   generate_random_mac - generates a random mac address
6361
 * INPUTS
6362
 *   none
6363
 * RESULT
6364
 *   $mac - a random mac address
6365
 ******/
6366
function generate_random_mac_address() {
6367
	$mac = "02";
6368
	for ($x = 0; $x < 5; $x++) {
6369
		$mac .= ":" . dechex(rand(16, 255));
6370
	}
6371
	return $mac;
6372
}
6373

    
6374
/****f* interfaces/is_jumbo_capable
6375
 * NAME
6376
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
6377
 * INPUTS
6378
 *   $int             - string containing interface name
6379
 * RESULT
6380
 *   boolean          - true or false
6381
 ******/
6382
function is_jumbo_capable($iface) {
6383
	$iface = trim($iface);
6384
	$capable = pfSense_get_interface_addresses($iface);
6385

    
6386
	if (isset($capable['caps']['vlanmtu'])) {
6387
		return true;
6388
	}
6389

    
6390
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
6391
	if (substr($iface, 0, 4) == "lagg") {
6392
		return true;
6393
	}
6394

    
6395
	return false;
6396
}
6397

    
6398
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6399
	global $g;
6400

    
6401
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6402

    
6403
	if (!empty($iface) && !empty($pppif)) {
6404
		$cron_cmd = <<<EOD
6405
#!/bin/sh
6406
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
6407
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
6408

    
6409
EOD;
6410

    
6411
		@file_put_contents($cron_file, $cron_cmd);
6412
		chmod($cron_file, 0755);
6413
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
6414
	} else {
6415
		unlink_if_exists($cron_file);
6416
	}
6417
}
6418

    
6419
function get_interface_default_mtu($type = "ethernet") {
6420
	switch ($type) {
6421
		case "gre":
6422
			return 1476;
6423
			break;
6424
		case "gif":
6425
			return 1280;
6426
			break;
6427
		case "tun":
6428
		case "vlan":
6429
		case "tap":
6430
		case "ethernet":
6431
		default:
6432
			return 1500;
6433
			break;
6434
	}
6435

    
6436
	/* Never reached */
6437
	return 1500;
6438
}
6439

    
6440
function get_vip_descr($ipaddress) {
6441
	global $config;
6442

    
6443
	foreach ($config['virtualip']['vip'] as $vip) {
6444
		if ($vip['subnet'] == $ipaddress) {
6445
			return ($vip['descr']);
6446
		}
6447
	}
6448
	return "";
6449
}
6450

    
6451
function interfaces_staticarp_configure($if) {
6452
	global $config, $g;
6453
	if (isset($config['system']['developerspew'])) {
6454
		$mt = microtime();
6455
		echo "interfaces_staticarp_configure($if) being called $mt\n";
6456
	}
6457

    
6458
	$ifcfg = $config['interfaces'][$if];
6459

    
6460
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
6461
		return 0;
6462
	}
6463

    
6464
	/* Enable staticarp, if enabled */
6465
	if (isset($config['dhcpd'][$if]['staticarp'])) {
6466
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
6467
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6468
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
6469
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6470
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6471
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6472
				}
6473
			}
6474
		}
6475
	} else {
6476
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
6477
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6478
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
6479
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6480
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6481
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6482
				}
6483
			}
6484
		}
6485
	}
6486

    
6487
	return 0;
6488
}
6489

    
6490
function get_failover_interface($interface, $family = "all") {
6491
	global $config;
6492

    
6493
	/* shortcut to get_real_interface if we find it in the config */
6494
	if (is_array($config['interfaces'][$interface])) {
6495
		return get_real_interface($interface, $family);
6496
	}
6497

    
6498
	/* compare against gateway groups */
6499
	$a_groups = return_gateway_groups_array();
6500
	if (is_array($a_groups[$interface])) {
6501
		/* we found a gateway group, fetch the interface or vip */
6502
		if (!empty($a_groups[$interface][0]['vip'])) {
6503
			return $a_groups[$interface][0]['vip'];
6504
		} else {
6505
			return $a_groups[$interface][0]['int'];
6506
		}
6507
	}
6508
	/* fall through to get_real_interface */
6509
	/* XXX: Really needed? */
6510
	return get_real_interface($interface, $family);
6511
}
6512

    
6513
/****f* interfaces/interface_has_dhcp
6514
 * NAME
6515
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6516
 * INPUTS
6517
 *   interface or gateway group name
6518
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6519
 * RESULT
6520
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6521
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6522
 ******/
6523
function interface_has_dhcp($interface, $family = 4) {
6524
	global $config;
6525

    
6526
	if ($config['interfaces'][$interface]) {
6527
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6528
			return true;
6529
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6530
			return true;
6531
		} else {
6532
			return false;
6533
		}
6534
	}
6535

    
6536
	if (!is_array($config['gateways']['gateway_group'])) {
6537
		return false;
6538
	}
6539

    
6540
	if ($family == 6) {
6541
		$dhcp_string = "_DHCP6";
6542
	} else {
6543
		$dhcp_string = "_DHCP";
6544
	}
6545

    
6546
	foreach ($config['gateways']['gateway_group'] as $group) {
6547
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6548
			continue;
6549
		}
6550
		foreach ($group['item'] as $item) {
6551
			$item_data = explode("|", $item);
6552
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6553
				return true;
6554
			}
6555
		}
6556
	}
6557

    
6558
	return false;
6559
}
6560

    
6561
function remove_ifindex($ifname) {
6562
	return preg_replace("/[0-9]+$/", "", $ifname);
6563
}
6564

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

    
6568
	$viplist = get_configured_vip_list($family, $type);
6569
	foreach ($viplist as $vip => $address) {
6570
		$interfaces[$vip] = $address;
6571
		if ($type = VIP_CARP) {
6572
			$vip = get_configured_vip($vipid);
6573
			if (isset($vip) && is_array($vip) ) {
6574
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
6575
			}
6576
		}
6577
		if (get_vip_descr($address)) {
6578
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
6579
		}
6580
	}
6581
	return $interfaces;
6582
}
6583

    
6584
function return_gateway_groups_array_with_descr() {
6585
	$interfaces = array();
6586
	$grouplist = return_gateway_groups_array();
6587
	foreach ($grouplist as $name => $group) {
6588
		if ($group[0]['vip'] != "") {
6589
			$vipif = $group[0]['vip'];
6590
		} else {
6591
			$vipif = $group[0]['int'];
6592
		}
6593

    
6594
		$interfaces[$name] = "GW Group {$name}";
6595
	}
6596
	return $interfaces;
6597
}
6598

    
6599
function get_serial_ports() {
6600
	$linklist = array();
6601
	if (!is_dir("/var/spool/lock")) {
6602
		mwexec("/bin/mkdir -p /var/spool/lock");
6603
	}
6604
	$serialports = glob("/dev/cua[a-zA-Z][0-9]{,.[0-9],.[0-9][0-9],[0-9],[0-9].[0-9],[0-9].[0-9][0-9]}", GLOB_BRACE);
6605
	foreach ($serialports as $port) {
6606
		$linklist[$port] = trim($port);
6607
	}
6608
	return $linklist;
6609
}
6610

    
6611
function get_interface_ports() {
6612
	global $config;
6613
	$linklist = array();
6614
	$portlist = get_interface_list();
6615
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
6616
		foreach ($config['vlans']['vlan'] as $vlan) {
6617
			$portlist[$vlan['vlanif']] = $vlan;
6618
		}
6619
	}
6620

    
6621
	foreach ($portlist as $ifn => $ifinfo) {
6622
		$string = "";
6623
		if (is_array($ifinfo)) {
6624
			$string .= $ifn;
6625
			if ($ifinfo['mac']) {
6626
				$string .= " ({$ifinfo['mac']})";
6627
			}
6628
			if ($ifinfo['friendly']) {
6629
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
6630
			} elseif ($ifinfo['descr']) {
6631
				$string .= " - {$ifinfo['descr']}";
6632
			}
6633
		} else {
6634
			$string .= $ifinfo;
6635
		}
6636

    
6637
		$linklist[$ifn] = $string;
6638
	}
6639
	return $linklist;
6640
}
6641

    
6642
function build_ppps_link_list() {
6643
	global $pconfig;
6644

    
6645
	$linklist = array('list' => array(), 'selected' => array());
6646

    
6647
	if ($pconfig['type'] == 'ppp') {
6648
		$linklist['list'] = get_serial_ports();
6649
	} else {
6650
		$iflist = get_interface_ports();
6651

    
6652
		$viplist = get_configured_vip_list_with_descr('all', VIP_CARP);
6653

    
6654
		$linklist['list'] = array_merge($iflist, $viplist);
6655

    
6656
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
6657
		$lagglist = get_lagg_interface_list();
6658
		foreach ($lagglist as $laggif => $lagg) {
6659
			/* LAGG members cannot be assigned */
6660
			$laggmembers = explode(',', $lagg['members']);
6661
			foreach ($laggmembers as $lagm) {
6662
				if (isset($linklist['list'][$lagm])) {
6663
					unset($linklist['list'][$lagm]);
6664
				}
6665
			}
6666
		}
6667
	}
6668

    
6669
	$selected_ports = array();
6670
	if (is_array($pconfig['interfaces'])) {
6671
		$selected_ports = $pconfig['interfaces'];
6672
	} elseif (!empty($pconfig['interfaces'])) {
6673
		$selected_ports = explode(',', $pconfig['interfaces']);
6674
	}
6675
	foreach ($selected_ports as $port) {
6676
		if (isset($linklist['list'][$port])) {
6677
			array_push($linklist['selected'], $port);
6678
		}
6679
	}
6680
	return($linklist);
6681
}
6682

    
6683
?>
(22-22/60)