Project

General

Profile

Download (194 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
			switch ($vip['mode']) {
2529
				case "proxyarp":
2530
					/* nothing it is handled on interface_proxyarp_configure() */
2531
					if (($interface <> "" && $vip['interface'] <> $interface) ||
2532
					    !isset($config['interfaces'][$vip['interface']]['enable'])) {
2533
						continue;
2534
					}
2535
					$anyproxyarp = true;
2536
					break;
2537
				case "ipalias":
2538
					$iface = $vip['interface'];
2539
					if (substr($iface, 0, 4) == "_vip")
2540
						$iface = get_configured_vip_interface($vip['interface']);
2541
					if (($interface <> "" && $iface <> $interface) ||
2542
					    !isset($config['interfaces'][$iface]['enable'])) {
2543
						continue;
2544
					}
2545
					interface_ipalias_configure($vip);
2546
					break;
2547
				case "carp":
2548
					if (($interface <> "" && $vip['interface'] <> $interface) ||
2549
					    !isset($config['interfaces'][$vip['interface']]['enable'])) {
2550
						continue;
2551
					}
2552
					if ($carp_setuped == false) {
2553
						$carp_setuped = true;
2554
					}
2555
					interface_carp_configure($vip);
2556
					break;
2557
			}
2558
		}
2559
		if ($carp_setuped == true) {
2560
			interfaces_sync_setup();
2561
		}
2562
		if ($anyproxyarp == true) {
2563
			interface_proxyarp_configure();
2564
		}
2565
	}
2566
}
2567

    
2568
function interface_ipalias_configure(&$vip) {
2569
	global $config;
2570

    
2571
	if ($vip['mode'] != 'ipalias') {
2572
		return;
2573
	}
2574

    
2575
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2576
	if ($realif != "lo0") {
2577
		$if = convert_real_interface_to_friendly_interface_name($realif);
2578
		if (!isset($config['interfaces'][$if])) {
2579
			return;
2580
		}
2581

    
2582
		if (!isset($config['interfaces'][$if]['enable'])) {
2583
			return;
2584
		}
2585
	}
2586

    
2587
	$af = 'inet';
2588
	if (is_ipaddrv6($vip['subnet'])) {
2589
		$af = 'inet6';
2590
	}
2591
	$iface = $vip['interface'];
2592
	$vhid = '';
2593
	if (substr($vip['interface'], 0, 4) == "_vip") {
2594
		$carpvip = get_configured_vip($vip['interface']);
2595
		$iface = $carpvip['interface'];
2596
		$vhid = "vhid {$carpvip['vhid']}";
2597
	}
2598
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2599
	unset($iface, $af, $realif, $carpvip, $vhid);
2600
}
2601

    
2602
function interface_carp_configure(&$vip) {
2603
	global $config, $g;
2604
	if (isset($config['system']['developerspew'])) {
2605
		$mt = microtime();
2606
		echo "interface_carp_configure() being called $mt\n";
2607
	}
2608

    
2609
	if ($vip['mode'] != "carp") {
2610
		return;
2611
	}
2612

    
2613
	/* NOTE: Maybe its useless nowadays */
2614
	$realif = get_real_interface($vip['interface']);
2615
	if (!does_interface_exist($realif)) {
2616
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2617
		return;
2618
	}
2619

    
2620
	$vip_password = $vip['password'];
2621
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2622
	if ($vip['password'] != "") {
2623
		$password = " pass {$vip_password}";
2624
	}
2625

    
2626
	$advbase = "";
2627
	if (!empty($vip['advbase'])) {
2628
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2629
	}
2630

    
2631
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2632
	if ($carp_maintenancemode) {
2633
		$advskew = "advskew 254";
2634
	} else {
2635
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2636
	}
2637

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

    
2640
	if (is_ipaddrv4($vip['subnet'])) {
2641
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2642
	} else if (is_ipaddrv6($vip['subnet'])) {
2643
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2644
	}
2645

    
2646
	return $realif;
2647
}
2648

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

    
2691
	if ($needs_clone == true) {
2692
		/* remove previous instance if it exists */
2693
		if (does_interface_exist($realif)) {
2694
			pfSense_interface_destroy($realif);
2695
		}
2696

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

    
2713
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2714
	global $config, $g;
2715

    
2716
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2717
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2718
				 'regdomain', 'regcountry', 'reglocation');
2719

    
2720
	if (!is_interface_wireless($ifcfg['if'])) {
2721
		return;
2722
	}
2723

    
2724
	$baseif = interface_get_wireless_base($ifcfg['if']);
2725

    
2726
	// Sync shared settings for assigned clones
2727
	$iflist = get_configured_interface_list(true);
2728
	foreach ($iflist as $if) {
2729
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2730
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2731
				foreach ($shared_settings as $setting) {
2732
					if ($sync_changes) {
2733
						if (isset($ifcfg['wireless'][$setting])) {
2734
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2735
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2736
							unset($config['interfaces'][$if]['wireless'][$setting]);
2737
						}
2738
					} else {
2739
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2740
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2741
						} else if (isset($ifcfg['wireless'][$setting])) {
2742
							unset($ifcfg['wireless'][$setting]);
2743
						}
2744
					}
2745
				}
2746
				if (!$sync_changes) {
2747
					break;
2748
				}
2749
			}
2750
		}
2751
	}
2752

    
2753
	// Read or write settings at shared area
2754
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2755
		foreach ($shared_settings as $setting) {
2756
			if ($sync_changes) {
2757
				if (isset($ifcfg['wireless'][$setting])) {
2758
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2759
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2760
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2761
				}
2762
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2763
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2764
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2765
				} else if (isset($ifcfg['wireless'][$setting])) {
2766
					unset($ifcfg['wireless'][$setting]);
2767
				}
2768
			}
2769
		}
2770
	}
2771

    
2772
	// Sync the mode on the clone creation page with the configured mode on the interface
2773
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2774
		foreach ($config['wireless']['clone'] as &$clone) {
2775
			if ($clone['cloneif'] == $ifcfg['if']) {
2776
				if ($sync_changes) {
2777
					$clone['mode'] = $ifcfg['wireless']['mode'];
2778
				} else {
2779
					$ifcfg['wireless']['mode'] = $clone['mode'];
2780
				}
2781
				break;
2782
			}
2783
		}
2784
		unset($clone);
2785
	}
2786
}
2787

    
2788
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2789
	global $config, $g;
2790

    
2791
	/*    open up a shell script that will be used to output the commands.
2792
	 *    since wireless is changing a lot, these series of commands are fragile
2793
	 *    and will sometimes need to be verified by a operator by executing the command
2794
	 *    and returning the output of the command to the developers for inspection.  please
2795
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2796
	 */
2797

    
2798
	// Remove script file
2799
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2800

    
2801
	// Clone wireless nic if needed.
2802
	interface_wireless_clone($if, $wl);
2803

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

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

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

    
2813
	/* set values for /path/program */
2814
	if (file_exists("/usr/local/sbin/hostapd")) {
2815
		$hostapd = "/usr/local/sbin/hostapd";
2816
	} else {
2817
		$hostapd = "/usr/sbin/hostapd";
2818
	}
2819
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
2820
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
2821
	} else {
2822
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2823
	}
2824
	$ifconfig = "/sbin/ifconfig";
2825
	$sysctl = "/sbin/sysctl";
2826
	$sysctl_args = "-q";
2827
	$killall = "/usr/bin/killall";
2828

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

    
2831
	$wlcmd = array();
2832
	$wl_sysctl = array();
2833
	/* Set a/b/g standard */
2834
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2835
	/* skip mode entirely for "auto" */
2836
	if ($wlcfg['standard'] != "auto") {
2837
		$wlcmd[] = "mode " . escapeshellarg($standard);
2838
	}
2839

    
2840
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2841
	 * to prevent massive packet loss under certain conditions. */
2842
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2843
		$wlcmd[] = "-ampdu";
2844
	}
2845

    
2846
	/* Set ssid */
2847
	if ($wlcfg['ssid']) {
2848
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2849
	}
2850

    
2851
	/* Set 802.11g protection mode */
2852
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2853

    
2854
	/* set wireless channel value */
2855
	if (isset($wlcfg['channel'])) {
2856
		if ($wlcfg['channel'] == "0") {
2857
			$wlcmd[] = "channel any";
2858
		} else {
2859
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2860
		}
2861
	}
2862

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

    
2868
	/* Set txantenna value */
2869
	if (isset($wlcfg['txantenna'])) {
2870
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2871
	}
2872

    
2873
	/* Set rxantenna value */
2874
	if (isset($wlcfg['rxantenna'])) {
2875
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2876
	}
2877

    
2878
	/* set Distance value */
2879
	if ($wlcfg['distance']) {
2880
		$distance = escapeshellarg($wlcfg['distance']);
2881
	}
2882

    
2883
	/* Set wireless hostap mode */
2884
	if ($wlcfg['mode'] == "hostap") {
2885
		$wlcmd[] = "mediaopt hostap";
2886
	} else {
2887
		$wlcmd[] = "-mediaopt hostap";
2888
	}
2889

    
2890
	/* Set wireless adhoc mode */
2891
	if ($wlcfg['mode'] == "adhoc") {
2892
		$wlcmd[] = "mediaopt adhoc";
2893
	} else {
2894
		$wlcmd[] = "-mediaopt adhoc";
2895
	}
2896

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

    
2899
	/* handle hide ssid option */
2900
	if (isset($wlcfg['hidessid']['enable'])) {
2901
		$wlcmd[] = "hidessid";
2902
	} else {
2903
		$wlcmd[] = "-hidessid";
2904
	}
2905

    
2906
	/* handle pureg (802.11g) only option */
2907
	if (isset($wlcfg['pureg']['enable'])) {
2908
		$wlcmd[] = "mode 11g pureg";
2909
	} else {
2910
		$wlcmd[] = "-pureg";
2911
	}
2912

    
2913
	/* handle puren (802.11n) only option */
2914
	if (isset($wlcfg['puren']['enable'])) {
2915
		$wlcmd[] = "puren";
2916
	} else {
2917
		$wlcmd[] = "-puren";
2918
	}
2919

    
2920
	/* enable apbridge option */
2921
	if (isset($wlcfg['apbridge']['enable'])) {
2922
		$wlcmd[] = "apbridge";
2923
	} else {
2924
		$wlcmd[] = "-apbridge";
2925
	}
2926

    
2927
	/* handle turbo option */
2928
	if (isset($wlcfg['turbo']['enable'])) {
2929
		$wlcmd[] = "mediaopt turbo";
2930
	} else {
2931
		$wlcmd[] = "-mediaopt turbo";
2932
	}
2933

    
2934
	/* handle txpower setting */
2935
	// or don't. this has issues at the moment.
2936
	/*
2937
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2938
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2939
	}*/
2940

    
2941
	/* handle wme option */
2942
	if (isset($wlcfg['wme']['enable'])) {
2943
		$wlcmd[] = "wme";
2944
	} else {
2945
		$wlcmd[] = "-wme";
2946
	}
2947

    
2948
	/* Enable wpa if it's configured. No WEP support anymore. */
2949
	if (isset($wlcfg['wpa']['enable'])) {
2950
		$wlcmd[] = "authmode wpa wepmode off ";
2951
	} else {
2952
		$wlcmd[] = "authmode open wepmode off ";
2953
	}
2954

    
2955
	kill_hostapd($if);
2956
	mwexec(kill_wpasupplicant("{$if}"));
2957

    
2958
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2959

    
2960
	switch ($wlcfg['mode']) {
2961
		case 'bss':
2962
			if (isset($wlcfg['wpa']['enable'])) {
2963
				$wpa .= <<<EOD
2964
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2965
ctrl_interface_group=0
2966
ap_scan=1
2967
#fast_reauth=1
2968
network={
2969
ssid="{$wlcfg['ssid']}"
2970
scan_ssid=1
2971
priority=5
2972
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2973
psk="{$wlcfg['wpa']['passphrase']}"
2974
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2975
group={$wlcfg['wpa']['wpa_pairwise']}
2976
}
2977
EOD;
2978

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

    
3013
EOD;
3014

    
3015
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3016
					$wpa .= <<<EOD
3017
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3018
rsn_preauth=1
3019
rsn_preauth_interfaces={$if}
3020

    
3021
EOD;
3022
				}
3023
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3024
					$wpa .= "ieee8021x=1\n";
3025

    
3026
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3027
						$auth_server_port = "1812";
3028
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3029
							$auth_server_port = intval($wlcfg['auth_server_port']);
3030
						}
3031
						$wpa .= <<<EOD
3032

    
3033
auth_server_addr={$wlcfg['auth_server_addr']}
3034
auth_server_port={$auth_server_port}
3035
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3036

    
3037
EOD;
3038
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3039
							$auth_server_port2 = "1812";
3040
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3041
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3042
							}
3043

    
3044
							$wpa .= <<<EOD
3045
auth_server_addr={$wlcfg['auth_server_addr2']}
3046
auth_server_port={$auth_server_port2}
3047
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3048

    
3049
EOD;
3050
						}
3051
					}
3052
				}
3053

    
3054
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3055
				unset($wpa);
3056
			}
3057
			break;
3058
	}
3059

    
3060
	/*
3061
	 *    all variables are set, lets start up everything
3062
	 */
3063

    
3064
	$baseif = interface_get_wireless_base($if);
3065
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3066
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3067

    
3068
	/* set sysctls for the wireless interface */
3069
	if (!empty($wl_sysctl)) {
3070
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3071
		foreach ($wl_sysctl as $wl_sysctl_line) {
3072
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3073
		}
3074
	}
3075

    
3076
	/* set ack timers according to users preference (if he/she has any) */
3077
	if ($distance) {
3078
		fwrite($fd_set, "# Enable ATH distance settings\n");
3079
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3080
	}
3081

    
3082
	if (isset($wlcfg['wpa']['enable'])) {
3083
		if ($wlcfg['mode'] == "bss") {
3084
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3085
		}
3086
		if ($wlcfg['mode'] == "hostap") {
3087
			/* add line to script to restore old mac to make hostapd happy */
3088
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3089
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3090
				$if_curmac = get_interface_mac($if);
3091
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3092
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3093
						" link " . escapeshellarg($if_oldmac) . "\n");
3094
				}
3095
			}
3096

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

    
3099
			/* add line to script to restore spoofed mac after running hostapd */
3100
			if ($wl['spoofmac']) {
3101
				$if_curmac = get_interface_mac($if);
3102
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3103
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3104
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3105
				}
3106
			}
3107
		}
3108
	}
3109

    
3110
	fclose($fd_set);
3111

    
3112
	/* Making sure regulatory settings have actually changed
3113
	 * before applying, because changing them requires bringing
3114
	 * down all wireless networks on the interface. */
3115
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3116
	$ifconfig_str = implode($output);
3117
	unset($output);
3118
	$reg_changing = false;
3119

    
3120
	/* special case for the debug country code */
3121
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3122
		$reg_changing = true;
3123
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3124
		$reg_changing = true;
3125
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3126
		$reg_changing = true;
3127
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3128
		$reg_changing = true;
3129
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3130
		$reg_changing = true;
3131
	}
3132

    
3133
	if ($reg_changing) {
3134
		/* set regulatory domain */
3135
		if ($wlcfg['regdomain']) {
3136
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3137
		}
3138

    
3139
		/* set country */
3140
		if ($wlcfg['regcountry']) {
3141
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3142
		}
3143

    
3144
		/* set location */
3145
		if ($wlcfg['reglocation']) {
3146
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3147
		}
3148

    
3149
		$wlregcmd_args = implode(" ", $wlregcmd);
3150

    
3151
		/* build a complete list of the wireless clones for this interface */
3152
		$clone_list = array();
3153
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3154
			$clone_list[] = interface_get_wireless_clone($baseif);
3155
		}
3156
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3157
			foreach ($config['wireless']['clone'] as $clone) {
3158
				if ($clone['if'] == $baseif) {
3159
					$clone_list[] = $clone['cloneif'];
3160
				}
3161
			}
3162
		}
3163

    
3164
		/* find which clones are up and bring them down */
3165
		$clones_up = array();
3166
		foreach ($clone_list as $clone_if) {
3167
			$clone_status = pfSense_get_interface_addresses($clone_if);
3168
			if ($clone_status['status'] == 'up') {
3169
				$clones_up[] = $clone_if;
3170
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3171
			}
3172
		}
3173

    
3174
		/* apply the regulatory settings */
3175
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3176
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3177

    
3178
		/* bring the clones back up that were previously up */
3179
		foreach ($clones_up as $clone_if) {
3180
			interfaces_bring_up($clone_if);
3181

    
3182
			/*
3183
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3184
			 * is in infrastructure mode, and WPA is enabled.
3185
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3186
			 */
3187
			if ($clone_if != $if) {
3188
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3189
				if ((!empty($friendly_if)) &&
3190
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3191
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3192
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3193
				}
3194
			}
3195
		}
3196
	}
3197

    
3198
	/* The mode must be specified in a separate command before ifconfig
3199
	 * will allow the mode and channel at the same time in the next.
3200
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3201
	 */
3202
	if ($wlcfg['mode'] == "hostap") {
3203
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3204
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3205
	}
3206

    
3207
	/* configure wireless */
3208
	$wlcmd_args = implode(" ", $wlcmd);
3209
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3210
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3211
	/* Bring the interface up only after setting up all the other parameters. */
3212
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3213
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3214
	fclose($wlan_setup_log);
3215

    
3216
	unset($wlcmd_args, $wlcmd);
3217

    
3218

    
3219
	sleep(1);
3220
	/* execute hostapd and wpa_supplicant if required in shell */
3221
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3222

    
3223
	return 0;
3224

    
3225
}
3226

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

    
3230
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3231
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3232
	}
3233
}
3234

    
3235
function kill_wpasupplicant($interface) {
3236
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3237
}
3238

    
3239
function find_dhclient_process($interface) {
3240
	if ($interface) {
3241
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3242
	} else {
3243
		$pid = 0;
3244
	}
3245

    
3246
	return intval($pid);
3247
}
3248

    
3249
function kill_dhclient_process($interface) {
3250
	if (empty($interface) || !does_interface_exist($interface)) {
3251
		return;
3252
	}
3253

    
3254
	$i = 0;
3255
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3256
		/* 3rd time make it die for sure */
3257
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3258
		posix_kill($pid, $sig);
3259
		sleep(1);
3260
		$i++;
3261
	}
3262
	unset($i);
3263
}
3264

    
3265
function find_dhcp6c_process($interface) {
3266
	global $g;
3267

    
3268
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3269
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3270
	} else {
3271
		return(false);
3272
	}
3273

    
3274
	return intval($pid);
3275
}
3276

    
3277
function kill_dhcp6client_process($interface, $force, $release = false) {
3278
	global $g;
3279

    
3280
	$i = 0;
3281

    
3282
	/*
3283
	Beware of the following: Reason, the interface may be down, but
3284
	dhcp6c may still be running, it just complains it cannot send
3285
	and carries on. Commented out as will stop the call to kill.
3286

    
3287
	if (empty($interface) || !does_interface_exist($interface)) {
3288
		return;
3289
	}
3290
	*/
3291

    
3292
	/*********** Notes on signals for dhcp6c and this function *************
3293

    
3294
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3295
	a release and waiting for the response that never comes.
3296
	So we need to tell it that the interface is down and to just die quickly
3297
	otherwise a new client may launch and we have duplicate proceses.
3298
	In this case use SIGUSR1.
3299

    
3300
	If we want to exit normally obeying the no release flag then use SIGTERM.
3301
	If we want to exit with a release overiding the no release flag then
3302
	use SIGUSR2.
3303

    
3304
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3305
	exit quickly without sending release signals.
3306

    
3307
	If $Force is set to false and $release is also set to false dhcp6c will
3308
	follow the no-release flag.
3309

    
3310
	If $Force is set to false and $release is true then dhcp6c will send a
3311
	release regardless of the no-release flag.
3312
	***********************************************************************/
3313

    
3314
	if ($force == true) {
3315
		$psig=SIGUSR1;
3316
	} else if ($release == false) {
3317
		$psig=SIGTERM;
3318
	} else {
3319
		$psig=SIGUSR2;
3320
	}
3321

    
3322
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3323
		/* 3rd time make it die for sure */
3324
		$sig = ($i == 2 ? SIGKILL : $psig);
3325
		posix_kill($pid, $sig);
3326
		sleep(1);
3327
		$i++;
3328
	}
3329
	/* Clear the RTSOLD script created lock & tidy up */
3330
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3331
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
3332
}
3333
function reset_dhcp6client_process($interface) {
3334

    
3335
	$pid = find_dhcp6c_process($interface);
3336

    
3337
	if($pid != 0) {
3338
		posix_kill($pid, SIGHUP);
3339
	}
3340
}
3341

    
3342
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3343
	global $g;
3344

    
3345
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3346
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3347

    
3348
	/*
3349
	 * Only run this if the lock does not exist. In theory the lock being
3350
	 * there in this mode means the user has selected dhcp6withoutRA while
3351
	 * a session is active in the other mode.
3352
	 *
3353
	 * It should not happen as the process should have been killed and the
3354
	 * lock deleted.
3355
	 */
3356

    
3357
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
3358
		kill_dhcp6client_process($interface, true);
3359
		/* Lock it to avoid multiple runs */
3360
		touch("/tmp/dhcp6c_{$interface}_lock");
3361
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3362
		    "{$noreleaseOption} " .
3363
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
3364
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
3365
		    $interface);
3366
		log_error(sprintf(gettext(
3367
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
3368
		    $interface));
3369
	}
3370
}
3371

    
3372
function interface_virtual_create($interface) {
3373
	global $config;
3374

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

    
3414
function interface_vlan_mtu_configured($iface) {
3415
	global $config;
3416

    
3417
	$mtu = 0;
3418
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3419
		foreach ($config['vlans']['vlan'] as $vlan) {
3420

    
3421
			if ($vlan['vlanif'] != $iface)
3422
				continue;
3423

    
3424
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3425
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3426
				/* VLAN MTU */
3427
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3428
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3429
				/* Parent MTU */
3430
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3431
			}
3432
		}
3433
	}
3434

    
3435
	return $mtu;
3436
}
3437

    
3438
function interface_mtu_wanted_for_pppoe($realif) {
3439
	global $config;
3440

    
3441
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3442
		return 0;
3443

    
3444
	$mtu = 0;
3445
	foreach ($config['ppps']['ppp'] as $ppp) {
3446
		if ($ppp['type'] != "pppoe") {
3447
			continue;
3448
		}
3449

    
3450
		$mtus = array();
3451
		if (!empty($ppp['mtu'])) {
3452
			$mtus = explode(',', $ppp['mtu']);
3453
		}
3454
		$ports = explode(',', $ppp['ports']);
3455

    
3456
		foreach ($ports as $pid => $port) {
3457
			$parentifa = get_parent_interface($port);
3458
			$parentif = $parentifa[0];
3459
			if ($parentif != $realif)
3460
				continue;
3461

    
3462
			// there is an MTU configured on the port in question
3463
			if (!empty($mtus[$pid])) {
3464
				$mtu = intval($mtus[$pid]) + 8;
3465
			// or use the MTU configured on the interface ...
3466
			} elseif (is_array($config['interfaces'])) {
3467
				foreach ($config['interfaces'] as $interface) {
3468
					if ($interface['if'] == $ppp['if'] &&
3469
					    !empty($interface['mtu'])) {
3470
						$mtu = intval($interface['mtu']) + 8;
3471
						break;
3472
					}
3473
				}
3474
			}
3475
		}
3476
	}
3477

    
3478
	return $mtu;
3479
}
3480

    
3481
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3482
	global $config, $g;
3483
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3484
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3485

    
3486
	$wancfg = $config['interfaces'][$interface];
3487

    
3488
	if (!isset($wancfg['enable'])) {
3489
		return;
3490
	}
3491

    
3492
	$realif = get_real_interface($interface);
3493
	$realhwif_array = get_parent_interface($interface);
3494
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3495
	$realhwif = $realhwif_array[0];
3496

    
3497
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3498
		/* remove all IPv4 and IPv6 addresses */
3499
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3500
		if (is_array($tmpifaces)) {
3501
			foreach ($tmpifaces as $tmpiface) {
3502
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3503
					if (!is_linklocal($tmpiface)) {
3504
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3505
					}
3506
				} else {
3507
					if (is_subnetv4($tmpiface)) {
3508
						$tmpip = explode('/', $tmpiface);
3509
						$tmpip = $tmpip[0];
3510
					} else {
3511
						$tmpip = $tmpiface;
3512
					}
3513
					pfSense_interface_deladdress($realif, $tmpip);
3514
				}
3515
			}
3516
		}
3517

    
3518
		/* only bring down the interface when both v4 and v6 are set to NONE */
3519
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3520
			interface_bring_down($interface);
3521
		}
3522
	}
3523

    
3524
	$interface_to_check = $realif;
3525
	if (interface_isppp_type($interface)) {
3526
		$interface_to_check = $realhwif;
3527
	}
3528

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

    
3534
	/* Disable Accepting router advertisements unless specifically requested */
3535
	if ($g['debug']) {
3536
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3537
	}
3538
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
3539
	{
3540
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3541
	}
3542
	/* wireless configuration? */
3543
	if (is_array($wancfg['wireless']) && !$linkupevent) {
3544
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3545
	}
3546

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

    
3582
	/* media */
3583
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3584
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3585
		if ($wancfg['media']) {
3586
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3587
		}
3588
		if ($wancfg['mediaopt']) {
3589
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3590
		}
3591
		mwexec($cmd);
3592
	}
3593

    
3594
	/* Apply hw offloading policies as configured */
3595
	enable_hardware_offloading($interface);
3596

    
3597
	/* invalidate interface/ip/sn cache */
3598
	get_interface_arr(true);
3599
	unset($interface_ip_arr_cache[$realif]);
3600
	unset($interface_sn_arr_cache[$realif]);
3601
	unset($interface_ipv6_arr_cache[$realif]);
3602
	unset($interface_snv6_arr_cache[$realif]);
3603

    
3604
	$tunnelif = substr($realif, 0, 3);
3605

    
3606
	$mtuif = $realif;
3607
	$mtuhwif = $realhwif;
3608

    
3609
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3610
	if (interface_isppp_type($interface)) {
3611
		$mtuif = $realhwif;
3612
		$mtuhwif_array = get_parent_interface($mtuif);
3613
		$mtuhwif = $mtuhwif_array[0];
3614
	}
3615

    
3616
	$wantedmtu = 0;
3617
	if (is_array($config['interfaces'])) {
3618
		foreach ($config['interfaces'] as $tmpinterface) {
3619
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3620
				$wantedmtu = $tmpinterface['mtu'];
3621
				break;
3622
			}
3623
		}
3624
	}
3625

    
3626
	/* MTU is not specified for interface, try the pppoe settings. */
3627
	if ($wantedmtu == 0) {
3628
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3629
	}
3630
	if ($wantedmtu == 0 && interface_is_vlan($mtuif) != NULL && interface_isppp_type($interface)) {
3631
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3632
	}
3633

    
3634
	/* Set the MTU to 1500 if no explicit MTU configured. */
3635
	if ($wantedmtu == 0) {
3636
		$wantedmtu = 1500; /* Default */
3637
	}
3638

    
3639
	if (interface_is_vlan($mtuif) != NULL) {
3640
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3641
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3642
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3643
			if ($wancfg['mtu'] > $parentmtu) {
3644
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3645
			}
3646
		}
3647

    
3648
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3649

    
3650
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3651
			$configuredmtu = $parentmtu;
3652
		if ($configuredmtu != 0)
3653
			$mtu = $configuredmtu;
3654
		else
3655
			$mtu = $wantedmtu;
3656

    
3657
		/* Set the parent MTU. */
3658
		if (get_interface_mtu($mtuhwif) < $mtu)
3659
			set_interface_mtu($mtuhwif, $mtu);
3660
		/* Set the VLAN MTU. */
3661
		if (get_interface_mtu($mtuif) != $mtu)
3662
			set_interface_mtu($mtuif, $mtu);
3663
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3664
		/* LAGG interface must be destroyed and re-created to change MTU */
3665
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3666
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3667
				foreach ($config['laggs']['lagg'] as $lagg) {
3668
					if ($lagg['laggif'] == $mtuif) {
3669
						interface_lagg_configure($lagg);
3670
						break;
3671
					}
3672
				}
3673
			}
3674
		}
3675
	} else {
3676
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3677
			pfSense_interface_mtu($mtuif, $wantedmtu);
3678
		}
3679
	}
3680
	/* XXX: What about gre/gif/.. ? */
3681

    
3682
	if (does_interface_exist($wancfg['if'])) {
3683
		interfaces_bring_up($wancfg['if']);
3684
	}
3685

    
3686
	switch ($wancfg['ipaddr']) {
3687
		case 'dhcp':
3688
			interface_dhcp_configure($interface);
3689
			break;
3690
		case 'pppoe':
3691
		case 'l2tp':
3692
		case 'pptp':
3693
		case 'ppp':
3694
			interface_ppps_configure($interface);
3695
			break;
3696
		default:
3697
			/* XXX: Kludge for now related to #3280 */
3698
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3699
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3700
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3701
				}
3702
			}
3703
			break;
3704
	}
3705

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

    
3740
	interface_netgraph_needed($interface);
3741

    
3742
	if (!platform_booting()) {
3743
		link_interface_to_vips($interface, "update");
3744

    
3745
		if ($tunnelif != 'gre') {
3746
			unset($gre);
3747
			$gre = link_interface_to_gre($interface);
3748
			if (!empty($gre)) {
3749
				array_walk($gre, 'interface_gre_configure');
3750
			}
3751
		}
3752

    
3753
		if ($tunnelif != 'gif') {
3754
			unset($gif);
3755
			$gif = link_interface_to_gif ($interface);
3756
			if (!empty($gif)) {
3757
				array_walk($gif, 'interface_gif_configure');
3758
			}
3759
		}
3760

    
3761
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3762
			unset($bridgetmp);
3763
			$bridgetmp = link_interface_to_bridge($interface);
3764
			if (!empty($bridgetmp)) {
3765
				interface_bridge_add_member($bridgetmp, $realif);
3766
			}
3767
		}
3768

    
3769
		$grouptmp = link_interface_to_group($interface);
3770
		if (!empty($grouptmp)) {
3771
			array_walk($grouptmp, 'interface_group_add_member');
3772
		}
3773

    
3774
		if ($interface == "lan") {
3775
			/* make new hosts file */
3776
			system_hosts_generate();
3777
		}
3778

    
3779
		if ($reloadall == true) {
3780

    
3781
			/* reconfigure static routes (kernel may have deleted them) */
3782
			system_routing_configure($interface);
3783

    
3784
			/* reload ipsec tunnels */
3785
			send_event("service reload ipsecdns");
3786

    
3787
			if (isset($config['dnsmasq']['enable'])) {
3788
				services_dnsmasq_configure();
3789
			}
3790

    
3791
			if (isset($config['unbound']['enable'])) {
3792
				services_unbound_configure();
3793
			}
3794

    
3795
			/* update dyndns */
3796
			send_event("service reload dyndns {$interface}");
3797

    
3798
			/* reload captive portal */
3799
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3800
				require_once('captiveportal.inc');
3801
			}
3802
			captiveportal_init_rules_byinterface($interface);
3803
		}
3804
	}
3805

    
3806
	interfaces_staticarp_configure($interface);
3807
	return 0;
3808
}
3809

    
3810
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3811
	global $config, $g;
3812

    
3813
	if (!is_array($wancfg)) {
3814
		return;
3815
	}
3816

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

    
3821
	/* If the interface is not configured via another, exit */
3822
	if (empty($wancfg['track6-interface'])) {
3823
		return;
3824
	}
3825

    
3826
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3827
	$realif = get_real_interface($interface);
3828
	$linklocal = find_interface_ipv6_ll($realif, true);
3829
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
3830
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3831
	}
3832
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3833
	/* XXX: Probably should remove? */
3834
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3835

    
3836
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3837
	if (!isset($trackcfg['enable'])) {
3838
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
3839
		return;
3840
	}
3841

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

    
3872
	if ($linkupevent == false && !platform_booting()) {
3873
		if (!function_exists('services_dhcpd_configure')) {
3874
			require_once("services.inc");
3875
		}
3876

    
3877
		/* restart dns servers (defering dhcpd reload) */
3878
		if (isset($config['unbound']['enable'])) {
3879
			services_unbound_configure(false);
3880
		}
3881
		if (isset($config['dnsmasq']['enable'])) {
3882
			services_dnsmasq_configure(false);
3883
		}
3884

    
3885
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
3886
		services_dhcpd_configure("inet6");
3887
	}
3888

    
3889
	return 0;
3890
}
3891

    
3892
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3893
	global $config, $g;
3894
	global $interface_ipv6_arr_cache;
3895
	global $interface_snv6_arr_cache;
3896

    
3897
	if (!is_array($lancfg)) {
3898
		return;
3899
	}
3900

    
3901
	/* If the interface is not configured via another, exit */
3902
	if (empty($lancfg['track6-interface'])) {
3903
		return;
3904
	}
3905

    
3906
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3907
	if (empty($wancfg)) {
3908
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3909
		return;
3910
	}
3911

    
3912
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3913
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3914
		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']));
3915
		return;
3916
	}
3917
	$hexwanv4 = return_hex_ipv4($ip4address);
3918

    
3919
	/* create the long prefix notation for math, save the prefix length */
3920
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3921
	$rd6prefixlen = $rd6prefix[1];
3922
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3923

    
3924
	/* binary presentation of the prefix for all 128 bits. */
3925
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3926

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

    
3932
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3933
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3934
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3935
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3936
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3937
	/* fill the rest out with zeros */
3938
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3939

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

    
3943
	$lanif = get_real_interface($interface);
3944
	$oip = find_interface_ipv6($lanif);
3945
	if (is_ipaddrv6($oip)) {
3946
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3947
	}
3948
	unset($interface_ipv6_arr_cache[$lanif]);
3949
	unset($interface_snv6_arr_cache[$lanif]);
3950
	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));
3951
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3952

    
3953
	return 0;
3954
}
3955

    
3956
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3957
	global $config, $g;
3958
	global $interface_ipv6_arr_cache;
3959
	global $interface_snv6_arr_cache;
3960

    
3961
	if (!is_array($lancfg)) {
3962
		return;
3963
	}
3964

    
3965
	/* If the interface is not configured via another, exit */
3966
	if (empty($lancfg['track6-interface'])) {
3967
		return;
3968
	}
3969

    
3970
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3971
	if (empty($wancfg)) {
3972
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3973
		return;
3974
	}
3975

    
3976
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3977
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3978
		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']));
3979
		return;
3980
	}
3981
	$hexwanv4 = return_hex_ipv4($ip4address);
3982

    
3983
	/* create the long prefix notation for math, save the prefix length */
3984
	$sixto4prefix = "2002::";
3985
	$sixto4prefixlen = 16;
3986
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3987

    
3988
	/* binary presentation of the prefix for all 128 bits. */
3989
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3990

    
3991
	/* just save the left prefix length bits */
3992
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3993
	/* add the v4 address */
3994
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3995
	/* add the custom prefix id */
3996
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3997
	/* fill the rest out with zeros */
3998
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3999

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

    
4003
	$lanif = get_real_interface($interface);
4004
	$oip = find_interface_ipv6($lanif);
4005
	if (is_ipaddrv6($oip)) {
4006
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4007
	}
4008
	unset($interface_ipv6_arr_cache[$lanif]);
4009
	unset($interface_snv6_arr_cache[$lanif]);
4010
	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));
4011
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4012

    
4013
	return 0;
4014
}
4015

    
4016
function interface_6rd_configure($interface = "wan", $wancfg) {
4017
	global $config, $g;
4018

    
4019
	/* because this is a tunnel interface we can only function
4020
	 *	with a public IPv4 address on the interface */
4021

    
4022
	if (!is_array($wancfg)) {
4023
		return;
4024
	}
4025

    
4026
	if (!is_module_loaded('if_stf.ko')) {
4027
		mwexec('/sbin/kldload if_stf.ko');
4028
	}
4029

    
4030
	$wanif = get_real_interface($interface);
4031
	$ip4address = find_interface_ip($wanif);
4032
	if (!is_ipaddrv4($ip4address)) {
4033
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4034
		return false;
4035
	}
4036
	$hexwanv4 = return_hex_ipv4($ip4address);
4037

    
4038
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4039
		$wancfg['prefix-6rd-v4plen'] = 0;
4040
	}
4041

    
4042
	/* create the long prefix notation for math, save the prefix length */
4043
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4044
	$rd6prefixlen = $rd6prefix[1];
4045
	$brgw = explode('.', $wancfg['gateway-6rd']);
4046
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4047
	$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);
4048
	if (strlen($rd6brgw) < 128) {
4049
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4050
	}
4051
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4052
	unset($brgw);
4053
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4054

    
4055
	/* binary presentation of the prefix for all 128 bits. */
4056
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4057

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

    
4065
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4066
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4067

    
4068

    
4069
	/* XXX: need to extend to support variable prefix size for v4 */
4070
	$stfiface = "{$interface}_stf";
4071
	if (does_interface_exist($stfiface)) {
4072
		pfSense_interface_destroy($stfiface);
4073
	}
4074
	$tmpstfiface = pfSense_interface_create("stf");
4075
	pfSense_interface_rename($tmpstfiface, $stfiface);
4076
	pfSense_interface_flags($stfiface, IFF_LINK2);
4077
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4078
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4079
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4080
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4081
	}
4082
	if ($g['debug']) {
4083
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4084
	}
4085

    
4086
	/* write out a default router file */
4087
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4088
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4089

    
4090
	$ip4gateway = get_interface_gateway($interface);
4091
	if (is_ipaddrv4($ip4gateway)) {
4092
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
4093
	}
4094

    
4095
	/* configure dependent interfaces */
4096
	if (!platform_booting()) {
4097
		link_interface_to_track6($interface, "update");
4098
	}
4099

    
4100
	return 0;
4101
}
4102

    
4103
function interface_6to4_configure($interface = "wan", $wancfg) {
4104
	global $config, $g;
4105

    
4106
	/* because this is a tunnel interface we can only function
4107
	 *	with a public IPv4 address on the interface */
4108

    
4109
	if (!is_array($wancfg)) {
4110
		return;
4111
	}
4112

    
4113
	$wanif = get_real_interface($interface);
4114
	$ip4address = find_interface_ip($wanif);
4115
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4116
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4117
		return false;
4118
	}
4119

    
4120
	/* create the long prefix notation for math, save the prefix length */
4121
	$stfprefixlen = 16;
4122
	$stfprefix = Net_IPv6::uncompress("2002::");
4123
	$stfarr = explode(":", $stfprefix);
4124
	$v4prefixlen = "0";
4125

    
4126
	/* we need the hex form of the interface IPv4 address */
4127
	$ip4arr = explode(".", $ip4address);
4128
	$hexwanv4 = "";
4129
	foreach ($ip4arr as $octet) {
4130
		$hexwanv4 .= sprintf("%02x", $octet);
4131
	}
4132

    
4133
	/* we need the hex form of the broker IPv4 address */
4134
	$ip4arr = explode(".", "192.88.99.1");
4135
	$hexbrv4 = "";
4136
	foreach ($ip4arr as $octet) {
4137
		$hexbrv4 .= sprintf("%02x", $octet);
4138
	}
4139

    
4140
	/* binary presentation of the prefix for all 128 bits. */
4141
	$stfprefixbin = "";
4142
	foreach ($stfarr as $element) {
4143
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4144
	}
4145
	/* just save the left prefix length bits */
4146
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4147

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

    
4152
	/* for the local subnet too. */
4153
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4154
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4155

    
4156
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4157
	$stfbrarr = array();
4158
	$stfbrbinarr = array();
4159
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4160
	foreach ($stfbrbinarr as $bin) {
4161
		$stfbrarr[] = dechex(bindec($bin));
4162
	}
4163
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4164

    
4165
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4166
	$stflanarr = array();
4167
	$stflanbinarr = array();
4168
	$stflanbinarr = str_split($stflanbin, 16);
4169
	foreach ($stflanbinarr as $bin) {
4170
		$stflanarr[] = dechex(bindec($bin));
4171
	}
4172
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4173
	$stflanarr[7] = 1;
4174
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4175

    
4176
	/* setup the stf interface */
4177
	if (!is_module_loaded("if_stf")) {
4178
		mwexec("/sbin/kldload if_stf.ko");
4179
	}
4180
	$stfiface = "{$interface}_stf";
4181
	if (does_interface_exist($stfiface)) {
4182
		pfSense_interface_destroy($stfiface);
4183
	}
4184
	$tmpstfiface = pfSense_interface_create("stf");
4185
	pfSense_interface_rename($tmpstfiface, $stfiface);
4186
	pfSense_interface_flags($stfiface, IFF_LINK2);
4187
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4188

    
4189
	if ($g['debug']) {
4190
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4191
	}
4192

    
4193
	/* write out a default router file */
4194
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4195
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4196

    
4197
	$ip4gateway = get_interface_gateway($interface);
4198
	if (is_ipaddrv4($ip4gateway)) {
4199
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
4200
	}
4201

    
4202
	if (!platform_booting()) {
4203
		link_interface_to_track6($interface, "update");
4204
	}
4205

    
4206
	return 0;
4207
}
4208

    
4209
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4210
	global $config, $g;
4211

    
4212
	if (!is_array($wancfg)) {
4213
		return;
4214
	}
4215

    
4216
	$wanif = get_real_interface($interface, "inet6");
4217
	$dhcp6cconf = "";
4218

    
4219
	if (!empty($config['system']['global-v6duid'])) {
4220
		// Write the DUID file
4221
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4222
		    log_error(gettext("Failed to write user DUID file!"));
4223
		}
4224
	}
4225

    
4226
	/* accept router advertisements for this interface                 */
4227
	/* Moved to early in the function as sometimes interface not ready */
4228
	/* RTSOLD fails as interface does not accept .....                 */
4229

    
4230
	log_error("Accept router advertisements on interface {$wanif} ");
4231
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4232

    
4233
	if ($wancfg['adv_dhcp6_config_file_override']) {
4234
		// DHCP6 Config File Override
4235
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4236
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4237
		// DHCP6 Config File Advanced
4238
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4239
	} else {
4240
		// DHCP6 Config File Basic
4241
		$dhcp6cconf .= "interface {$wanif} {\n";
4242

    
4243
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4244
		if ($wancfg['ipaddrv6'] == "slaac") {
4245
			$dhcp6cconf .= "\tinformation-only;\n";
4246
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4247
			$dhcp6cconf .= "\trequest domain-name;\n";
4248
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4249
			$dhcp6cconf .= "};\n";
4250
		} else {
4251
			$trackiflist = array();
4252
			$iflist = link_interface_to_track6($interface);
4253
			foreach ($iflist as $ifname => $ifcfg) {
4254
				if (is_numeric($ifcfg['track6-prefix-id'])) {
4255
					$trackiflist[$ifname] = $ifcfg;
4256
				}
4257
			}
4258

    
4259
			/* skip address request if this is set */
4260
			if (!isset($wancfg['dhcp6prefixonly'])) {
4261
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4262
			}
4263
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4264
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4265
			}
4266

    
4267
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4268
			$dhcp6cconf .= "\trequest domain-name;\n";
4269

    
4270
			/*
4271
			 * dhcp6c will run different scripts depending on
4272
			 * whether dhcpwithoutra is set or unset.
4273
			 */
4274
			if (isset($wancfg['dhcp6withoutra'])) {
4275
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4276
			} else {
4277
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4278
			}
4279
			$dhcp6cconf .= "};\n";
4280

    
4281
			if (!isset($wancfg['dhcp6prefixonly'])) {
4282
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4283
			}
4284

    
4285
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4286
				/* Setup the prefix delegation */
4287
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4288
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4289
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4290
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4291
				}
4292
				foreach ($trackiflist as $friendly => $ifcfg) {
4293
					if ($g['debug']) {
4294
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4295
					}
4296
					$realif = get_real_interface($friendly);
4297
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4298
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4299
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4300
					$dhcp6cconf .= "\t};\n";
4301
				}
4302
				unset($preflen, $iflist, $ifcfg, $ifname);
4303
				$dhcp6cconf .= "};\n";
4304
			}
4305
			unset($trackiflist);
4306
		}
4307
	}
4308

    
4309
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4310
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4311

    
4312
	/* wide-dhcp6c works for now. */
4313
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4314
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4315
		unset($dhcp6cconf);
4316
		return 1;
4317
	}
4318
	unset($dhcp6cconf);
4319

    
4320
	/*************** Script Debug Logging ***************************
4321
	Both dhcp6 scripts now have a logging message built in.
4322
	These logging messages ONLY appear if dhcp6c debug logging is set.
4323
	The logging messages appear in the dhcp section of the logs,
4324
	not in system.
4325

    
4326
	These scripts now also take advantage of the REASON= env vars
4327
	supplied by dhcp6c.
4328
	****************************************************************/
4329

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

    
4379
	unset($dhcp6cscriptwithoutra);
4380
	@chmod(
4381
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4382
	    0755);
4383

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

    
4428
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4429
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4430
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4431
		unset($dhcp6cscript);
4432
		return 1;
4433
	}
4434
	unset($dhcp6cscript);
4435
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4436

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

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

    
4491
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4492
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4493
		log_error("Killing running rtsold process");
4494
		sleep(2);
4495
	}
4496

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

    
4538
	return 0;
4539
}
4540

    
4541
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4542
	global $g;
4543

    
4544
	$send_options = "";
4545
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4546
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4547
		foreach ($options as $option) {
4548
			$send_options .= "\tsend " . trim($option) . ";\n";
4549
		}
4550
	}
4551

    
4552
	$request_options = "";
4553
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4554
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4555
		foreach ($options as $option) {
4556
			$request_options .= "\trequest " . trim($option) . ";\n";
4557
		}
4558
	}
4559

    
4560
	$information_only = "";
4561
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4562
		$information_only = "\tinformation-only;\n";
4563
	}
4564

    
4565
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4566
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4567
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4568
	}
4569

    
4570
	$interface_statement  = "interface";
4571
	$interface_statement .= " {$wanif}";
4572
	$interface_statement .= " {\n";
4573
	$interface_statement .= "$send_options";
4574
	$interface_statement .= "$request_options";
4575
	$interface_statement .= "$information_only";
4576
	$interface_statement .= "$script";
4577
	$interface_statement .= "};\n";
4578

    
4579
	$id_assoc_statement_address = "";
4580
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4581
		$id_assoc_statement_address .= "id-assoc";
4582
		$id_assoc_statement_address .= " na";
4583
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4584
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4585
		}
4586
		$id_assoc_statement_address .= " { ";
4587

    
4588
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4589
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4590
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4591
			$id_assoc_statement_address .= "\n\taddress";
4592
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4593
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4594
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4595
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4596
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4597
			}
4598
			$id_assoc_statement_address .= ";\n";
4599
		}
4600

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

    
4604
	$id_assoc_statement_prefix = "";
4605
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4606
		$id_assoc_statement_prefix .= "id-assoc";
4607
		$id_assoc_statement_prefix .= " pd";
4608
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4609
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4610
		}
4611
		$id_assoc_statement_prefix .= " { ";
4612

    
4613
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4614
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4615
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4616
			$id_assoc_statement_prefix .= "\n\tprefix";
4617
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4618
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4619
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4620
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4621
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4622
			}
4623
			$id_assoc_statement_prefix .= ";";
4624
		}
4625

    
4626
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
4627
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4628
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4629
			$id_assoc_statement_prefix .= " {$realif}";
4630
			$id_assoc_statement_prefix .= " {\n";
4631
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4632
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4633
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4634
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4635
			}
4636
			$id_assoc_statement_prefix .= "\t};";
4637
		}
4638

    
4639
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4640
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4641
			$id_assoc_statement_prefix .= "\n";
4642
		}
4643

    
4644
		$id_assoc_statement_prefix .= "};\n";
4645
	}
4646

    
4647
	$authentication_statement = "";
4648
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4649
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4650
		$authentication_statement .= "authentication";
4651
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4652
		$authentication_statement .= " {\n";
4653
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4654
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4655
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4656
		}
4657
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4658
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4659
		}
4660
		$authentication_statement .= "};\n";
4661
	}
4662

    
4663
	$key_info_statement = "";
4664
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4665
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4666
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4667
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4668
		$key_info_statement .= "keyinfo";
4669
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4670
		$key_info_statement .= " {\n";
4671
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4672
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4673
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4674
		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'])) {
4675
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4676
		}
4677
		$key_info_statement .= "};\n";
4678
	}
4679

    
4680
	$dhcp6cconf  = $interface_statement;
4681
	$dhcp6cconf .= $id_assoc_statement_address;
4682
	$dhcp6cconf .= $id_assoc_statement_prefix;
4683
	$dhcp6cconf .= $authentication_statement;
4684
	$dhcp6cconf .= $key_info_statement;
4685

    
4686
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4687

    
4688
	return $dhcp6cconf;
4689
}
4690

    
4691

    
4692
function DHCP6_Config_File_Override($wancfg, $wanif) {
4693

    
4694
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4695

    
4696
	if ($dhcp6cconf === false) {
4697
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4698
		return '';
4699
	} else {
4700
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4701
	}
4702
}
4703

    
4704

    
4705
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4706

    
4707
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4708

    
4709
	return $dhcp6cconf;
4710
}
4711

    
4712

    
4713
function interface_dhcp_configure($interface = "wan") {
4714
	global $config, $g;
4715

    
4716
	$wancfg = $config['interfaces'][$interface];
4717
	$wanif = $wancfg['if'];
4718
	if (empty($wancfg)) {
4719
		$wancfg = array();
4720
	}
4721

    
4722
	/* generate dhclient_wan.conf */
4723
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4724
	if (!$fd) {
4725
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4726
		return 1;
4727
	}
4728

    
4729
	if ($wancfg['dhcphostname']) {
4730
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4731
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4732
	} else {
4733
		$dhclientconf_hostname = "";
4734
	}
4735

    
4736
	$wanif = get_real_interface($interface);
4737
	if (empty($wanif)) {
4738
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4739
		return 0;
4740
	}
4741
	$dhclientconf = "";
4742

    
4743
	$dhclientconf .= <<<EOD
4744
interface "{$wanif}" {
4745
timeout 60;
4746
retry 15;
4747
select-timeout 0;
4748
initial-interval 1;
4749
	{$dhclientconf_hostname}
4750
	script "/usr/local/sbin/pfSense-dhclient-script";
4751
EOD;
4752

    
4753
	if (validate_ipv4_list($wancfg['dhcprejectfrom'])) {
4754
		$dhclientconf .= <<<EOD
4755

    
4756
	reject {$wancfg['dhcprejectfrom']};
4757
EOD;
4758
	}
4759
	$dhclientconf .= <<<EOD
4760

    
4761
}
4762

    
4763
EOD;
4764

    
4765
	// DHCP Config File Advanced
4766
	if ($wancfg['adv_dhcp_config_advanced']) {
4767
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4768
	}
4769

    
4770
	if (is_ipaddr($wancfg['alias-address'])) {
4771
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4772
		$dhclientconf .= <<<EOD
4773
alias {
4774
	interface "{$wanif}";
4775
	fixed-address {$wancfg['alias-address']};
4776
	option subnet-mask {$subnetmask};
4777
}
4778

    
4779
EOD;
4780
	}
4781

    
4782
	// DHCP Config File Override
4783
	if ($wancfg['adv_dhcp_config_file_override']) {
4784
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4785
	}
4786

    
4787
	fwrite($fd, $dhclientconf);
4788
	fclose($fd);
4789

    
4790
	/* bring wan interface up before starting dhclient */
4791
	if ($wanif) {
4792
		interfaces_bring_up($wanif);
4793
	} else {
4794
		log_error(sprintf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4795
	}
4796

    
4797
	/* Make sure dhclient is not running */
4798
	kill_dhclient_process($wanif);
4799

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

    
4803
	return 0;
4804
}
4805

    
4806
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4807

    
4808
	$hostname = "";
4809
	if ($wancfg['dhcphostname'] != '') {
4810
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4811
	}
4812

    
4813
	/* DHCP Protocol Timings */
4814
	$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");
4815
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4816
		$pt_variable = "{$Protocol_Timing}";
4817
		${$pt_variable} = "";
4818
		if ($wancfg[$Protocol_Timing] != "") {
4819
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4820
		}
4821
	}
4822

    
4823
	$send_options = "";
4824
	if ($wancfg['adv_dhcp_send_options'] != '') {
4825
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp_send_options']);
4826
		foreach ($options as $option) {
4827
			$send_options .= "\tsend " . trim($option) . ";\n";
4828
		}
4829
	}
4830

    
4831
	$request_options = "";
4832
	if ($wancfg['adv_dhcp_request_options'] != '') {
4833
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4834
	}
4835

    
4836
	$required_options = "";
4837
	if ($wancfg['adv_dhcp_required_options'] != '') {
4838
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4839
	}
4840

    
4841
	$option_modifiers = "";
4842
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4843
		$modifiers = DHCP_Config_Option_Split($wancfg['adv_dhcp_option_modifiers']);
4844
		foreach ($modifiers as $modifier) {
4845
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4846
		}
4847
	}
4848

    
4849
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4850
	$dhclientconf .= "\n";
4851
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4852
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4853
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4854
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4855
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4856
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4857
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4858
	$dhclientconf .= "\n";
4859
	$dhclientconf .= "# DHCP Protocol Options\n";
4860
	$dhclientconf .= "{$hostname}";
4861
	$dhclientconf .= "{$send_options}";
4862
	$dhclientconf .= "{$request_options}";
4863
	$dhclientconf .= "{$required_options}";
4864
	$dhclientconf .= "{$option_modifiers}";
4865
	$dhclientconf .= "\n";
4866
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4867
		$dhclientconf .= "reject {$wancfg['dhcprejectfrom']};\n";
4868
	}
4869
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
4870
	$dhclientconf .= "}\n";
4871

    
4872
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4873

    
4874
	return $dhclientconf;
4875
}
4876

    
4877
function DHCP_Config_Option_Split($option_string) {
4878
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4879
	return $matches ? $matches[0] : [];
4880
}
4881

    
4882
function DHCP_Config_File_Override($wancfg, $wanif) {
4883

    
4884
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4885

    
4886
	if ($dhclientconf === false) {
4887
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $wancfg['adv_dhcp_config_file_override_path']));
4888
		return '';
4889
	} else {
4890
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4891
	}
4892
}
4893

    
4894

    
4895
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4896

    
4897
	/* Apply Interface Substitutions */
4898
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4899

    
4900
	/* Apply Hostname Substitutions */
4901
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4902

    
4903
	/* Arrays of MAC Address Types, Cases, Delimiters */
4904
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4905
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4906
	$various_mac_cases      = array("U", "L");
4907
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4908

    
4909
	/* Apply MAC Address Substitutions */
4910
	foreach ($various_mac_types as $various_mac_type) {
4911
		foreach ($various_mac_cases as $various_mac_case) {
4912
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4913

    
4914
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4915
				if ($res !== false) {
4916

    
4917
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4918
					if ("$various_mac_case" == "U") {
4919
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4920
					}
4921
					if ("$various_mac_case" == "L") {
4922
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4923
					}
4924

    
4925
					if ("$various_mac_type" == "mac_addr_hex") {
4926
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4927
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4928
						$dhcpclientconf_mac_hex = "";
4929
						$delimiter = "";
4930
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4931
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4932
							$delimiter = ":";
4933
						}
4934
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4935
					}
4936

    
4937
					/* MAC Address Delimiter Substitutions */
4938
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4939

    
4940
					/* Apply MAC Address Substitutions */
4941
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4942
				}
4943
			}
4944
		}
4945
	}
4946

    
4947
	return $dhclientconf;
4948
}
4949

    
4950
function interfaces_group_setup() {
4951
	global $config;
4952

    
4953
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4954
		return;
4955
	}
4956

    
4957
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4958
		interface_group_setup($groupar);
4959
	}
4960

    
4961
	return;
4962
}
4963

    
4964
function interface_group_setup(&$groupname /* The parameter is an array */) {
4965
	global $config;
4966

    
4967
	if (!is_array($groupname)) {
4968
		return;
4969
	}
4970
	$members = explode(" ", $groupname['members']);
4971
	foreach ($members as $ifs) {
4972
		$realif = get_real_interface($ifs);
4973
		if ($realif && does_interface_exist($realif)) {
4974
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4975
		}
4976
	}
4977

    
4978
	return;
4979
}
4980

    
4981
function is_interface_group($if) {
4982
	global $config;
4983

    
4984
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4985
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4986
			if ($groupentry['ifname'] === $if) {
4987
				return true;
4988
			}
4989
		}
4990
	}
4991

    
4992
	return false;
4993
}
4994

    
4995
function interface_group_add_member($interface, $groupname) {
4996
	$interface = get_real_interface($interface);
4997
	if (does_interface_exist($interface)) {
4998
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4999
	}
5000
}
5001

    
5002
/* COMPAT Function */
5003
function convert_friendly_interface_to_real_interface_name($interface) {
5004
	return get_real_interface($interface);
5005
}
5006

    
5007
/* COMPAT Function */
5008
function get_real_wan_interface($interface = "wan") {
5009
	return get_real_interface($interface);
5010
}
5011

    
5012
/* COMPAT Function */
5013
function get_current_wan_address($interface = "wan") {
5014
	return get_interface_ip($interface);
5015
}
5016

    
5017
/*
5018
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5019
 */
5020
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5021
	global $config;
5022

    
5023
	/* XXX: For speed reasons reference directly the interface array */
5024
	$ifdescrs = &$config['interfaces'];
5025
	//$ifdescrs = get_configured_interface_list(true);
5026

    
5027
	foreach ($ifdescrs as $if => $ifname) {
5028
		if ($if == $interface || $ifname['if'] == $interface) {
5029
			return $if;
5030
		}
5031

    
5032
		if (get_real_interface($if) == $interface) {
5033
			return $if;
5034
		}
5035

    
5036
		if ($checkparent == false) {
5037
			continue;
5038
		}
5039

    
5040
		$int = get_parent_interface($if, true);
5041
		if (is_array($int)) {
5042
			foreach ($int as $iface) {
5043
				if ($iface == $interface) {
5044
					return $if;
5045
				}
5046
			}
5047
		}
5048
	}
5049

    
5050
	if ($interface == "enc0") {
5051
		return 'IPsec';
5052
	}
5053
}
5054

    
5055
/* attempt to resolve interface to friendly descr */
5056
function convert_friendly_interface_to_friendly_descr($interface) {
5057
	global $config;
5058

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

    
5117
	return $ifdesc;
5118
}
5119

    
5120
function convert_real_interface_to_friendly_descr($interface) {
5121

    
5122
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5123

    
5124
	if (!empty($ifdesc)) {
5125
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5126
	}
5127

    
5128
	return $interface;
5129
}
5130

    
5131
/*
5132
 *  get_parent_interface($interface):
5133
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5134
 *				or virtual interface (i.e. vlan)
5135
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5136
 *			-- returns $interface passed in if $interface parent is not found
5137
 *			-- returns empty array if an invalid interface is passed
5138
 *	(Only handles ppps and vlans now.)
5139
 */
5140
function get_parent_interface($interface, $avoidrecurse = false) {
5141
	global $config;
5142

    
5143
	$parents = array();
5144
	//Check that we got a valid interface passed
5145
	$realif = get_real_interface($interface);
5146
	if ($realif == NULL) {
5147
		return $parents;
5148
	}
5149

    
5150
	// If we got a real interface, find it's friendly assigned name
5151
	if ($interface == $realif && $avoidrecurse == false) {
5152
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5153
	}
5154

    
5155
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5156
		$ifcfg = $config['interfaces'][$interface];
5157
		switch ($ifcfg['ipaddr']) {
5158
			case "ppp":
5159
			case "pppoe":
5160
			case "pptp":
5161
			case "l2tp":
5162
				if (empty($parents)) {
5163
					if (is_array($config['ppps']['ppp'])) {
5164
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5165
							if ($ifcfg['if'] == $ppp['if']) {
5166
								$ports = explode(',', $ppp['ports']);
5167
								foreach ($ports as $pid => $parent_if) {
5168
									$parents[$pid] = get_real_interface($parent_if);
5169
								}
5170
								break;
5171
							}
5172
						}
5173
					}
5174
				}
5175
				break;
5176
			case "dhcp":
5177
			case "static":
5178
			default:
5179
				// Handle _vlans
5180
				$vlan = interface_is_vlan($ifcfg['if']);
5181
				if ($vlan != NULL) {
5182
					$parents[0] = $vlan['if'];
5183
				}
5184
				break;
5185
		}
5186
	}
5187

    
5188
	if (empty($parents)) {
5189
		// Handle _vlans not assigned to an interface
5190
		$vlan = interface_is_vlan($realif);
5191
		if ($vlan != NULL) {
5192
			$parents[0] = $vlan['if'];
5193
		}
5194
	}
5195

    
5196
	if (empty($parents)) {
5197
		$parents[0] = $realif;
5198
	}
5199

    
5200
	return $parents;
5201
}
5202

    
5203
/*
5204
 *  get_parent_physical_interface($interface):
5205
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5206
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5207
 */
5208
function get_parent_physical_interface($interface) {
5209
	global $config;
5210

    
5211
	$realif = get_parent_interface($interface);
5212

    
5213
	if (substr($realif[0], 0, 4) == "lagg") {
5214
		foreach ($config['laggs']['lagg'] as $lagg) {
5215
			if ($realif[0] == $lagg['laggif']) {
5216
				return explode(",", $lagg['members']);
5217
			}
5218
		}
5219
	} else {
5220
		return $realif;
5221
	}
5222
}
5223

    
5224
function interface_is_wireless_clone($wlif) {
5225
	if (!stristr($wlif, "_wlan")) {
5226
		return false;
5227
	} else {
5228
		return true;
5229
	}
5230
}
5231

    
5232
function interface_get_wireless_base($wlif) {
5233
	if (!stristr($wlif, "_wlan")) {
5234
		return $wlif;
5235
	} else {
5236
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5237
	}
5238
}
5239

    
5240
function interface_get_wireless_clone($wlif) {
5241
	if (!stristr($wlif, "_wlan")) {
5242
		return $wlif . "_wlan0";
5243
	} else {
5244
		return $wlif;
5245
	}
5246
}
5247

    
5248
function interface_list_wireless() {
5249
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5250

    
5251
	$result = array();
5252
	foreach ($portlist as $port) {
5253
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5254
			continue;
5255
		}
5256

    
5257
		$desc = $port . " ( " . get_single_sysctl(
5258
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5259

    
5260
		$result[] = array(
5261
		    "if" => $port,
5262
		    "descr" => $desc
5263
		);
5264
	}
5265

    
5266
	return $result;
5267
}
5268

    
5269
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
5270
	global $config, $g;
5271

    
5272
	$wanif = NULL;
5273

    
5274
	switch ($interface) {
5275
		case "l2tp":
5276
			$wanif = "l2tp";
5277
			break;
5278
		case "pptp":
5279
			$wanif = "pptp";
5280
			break;
5281
		case "pppoe":
5282
			$wanif = "pppoe";
5283
			break;
5284
		case "openvpn":
5285
			$wanif = "openvpn";
5286
			break;
5287
		case "IPsec":
5288
		case "ipsec":
5289
		case "enc0":
5290
			$wanif = "enc0";
5291
			break;
5292
		case "ppp":
5293
			$wanif = "ppp";
5294
			break;
5295
		default:
5296
			if (substr($interface, 0, 4) == '_vip') {
5297
				$wanif = get_configured_vip_interface($interface);
5298
				if (!empty($wanif)) {
5299
					$wanif = get_real_interface($wanif);
5300
				}
5301
				break;
5302
			} else if (substr($interface, 0, 5) == '_lloc') {
5303
				$interface = substr($interface, 5);
5304
			} else if (interface_is_vlan($interface) != NULL ||
5305
			    does_interface_exist($interface, $flush)) {
5306
				/*
5307
				 * If a real interface was already passed simply
5308
				 * pass the real interface back.  This encourages
5309
				 * the usage of this function in more cases so that
5310
				 * we can combine logic for more flexibility.
5311
				 */
5312
				$wanif = $interface;
5313
				break;
5314
			}
5315

    
5316
			if (empty($config['interfaces'][$interface])) {
5317
				break;
5318
			}
5319

    
5320
			$cfg = &$config['interfaces'][$interface];
5321

    
5322
			if ($family == "inet6") {
5323
				switch ($cfg['ipaddrv6']) {
5324
					case "6rd":
5325
					case "6to4":
5326
						$wanif = "{$interface}_stf";
5327
						break;
5328
					case 'pppoe':
5329
					case 'ppp':
5330
					case 'l2tp':
5331
					case 'pptp':
5332
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5333
							$wanif = interface_get_wireless_clone($cfg['if']);
5334
						} else {
5335
							$wanif = $cfg['if'];
5336
						}
5337
						break;
5338
					default:
5339
						switch ($cfg['ipaddr']) {
5340
							case 'pppoe':
5341
							case 'ppp':
5342
							case 'l2tp':
5343
							case 'pptp':
5344
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
5345
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) || isset($cfg['ipv6usev4iface'])) {
5346
									$wanif = $cfg['if'];
5347
								} else {
5348
									$parents = get_parent_interface($interface);
5349
									if (!empty($parents[0])) {
5350
										$wanif = $parents[0];
5351
									} else {
5352
										$wanif = $cfg['if'];
5353
									}
5354
								}
5355
								break;
5356
							default:
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
								break;
5363
						}
5364
						break;
5365
				}
5366
			} else {
5367
				// Wireless cloned NIC support (FreeBSD 8+)
5368
				// interface name format: $parentnic_wlanparentnic#
5369
				// example: ath0_wlan0
5370
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5371
					$wanif = interface_get_wireless_clone($cfg['if']);
5372
				} else {
5373
					$wanif = $cfg['if'];
5374
				}
5375
			}
5376
			break;
5377
	}
5378

    
5379
	return $wanif;
5380
}
5381

    
5382
/* Guess the physical interface by providing a IP address */
5383
function guess_interface_from_ip($ipaddress) {
5384

    
5385
	$family = '';
5386
	if (is_ipaddrv4($ipaddress)) {
5387
		$family = 'inet';
5388
	}
5389
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5390
		$family = 'inet6';
5391
	}
5392

    
5393
	if (empty($family)) {
5394
		return false;
5395
	}
5396

    
5397
	/* create a route table we can search */
5398
	$output = '';
5399
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
5400
	$output[0] = trim($output[0], " \n");
5401
	if (!empty($output[0])) {
5402
		return $output[0];
5403
	}
5404

    
5405
	return false;
5406
}
5407

    
5408
/*
5409
 * find_ip_interface($ip): return the interface where an ip is defined
5410
 *   (or if $bits is specified, where an IP within the subnet is defined)
5411
 */
5412
function find_ip_interface($ip, $bits = null) {
5413
	if (!is_ipaddr($ip)) {
5414
		return false;
5415
	}
5416

    
5417
	$isv6ip = is_ipaddrv6($ip);
5418

    
5419
	/* if list */
5420
	$ifdescrs = get_configured_interface_list();
5421

    
5422
	foreach ($ifdescrs as $ifdescr => $ifname) {
5423
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
5424
		if (is_null($ifip)) {
5425
			continue;
5426
		}
5427
		if (is_null($bits)) {
5428
			if ($ip == $ifip) {
5429
				$int = get_real_interface($ifname);
5430
				return $int;
5431
			}
5432
		} else {
5433
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
5434
				$int = get_real_interface($ifname);
5435
				return $int;
5436
			}
5437
		}
5438
	}
5439

    
5440
	return false;
5441
}
5442

    
5443
/*
5444
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5445
 *   (or if $bits is specified, where an IP within the subnet is found)
5446
 */
5447
function find_virtual_ip_alias($ip, $bits = null) {
5448
	global $config;
5449

    
5450
	if (!is_array($config['virtualip']['vip'])) {
5451
		return false;
5452
	}
5453
	if (!is_ipaddr($ip)) {
5454
		return false;
5455
	}
5456

    
5457
	$isv6ip = is_ipaddrv6($ip);
5458

    
5459
	foreach ($config['virtualip']['vip'] as $vip) {
5460
		if ($vip['mode'] === "ipalias") {
5461
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
5462
				continue;
5463
			}
5464
			if (is_null($bits)) {
5465
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
5466
					return $vip;
5467
				}
5468
			} else {
5469
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5470
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5471
					return $vip;
5472
				}
5473
			}
5474
		}
5475
	}
5476
	return false;
5477
}
5478

    
5479
function link_interface_to_track6($int, $action = "") {
5480
	global $config;
5481

    
5482
	if (empty($int)) {
5483
		return;
5484
	}
5485

    
5486
	if (is_array($config['interfaces'])) {
5487
		$list = array();
5488
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5489
			if (!isset($ifcfg['enable'])) {
5490
				continue;
5491
			}
5492
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5493
				if ($action == "update") {
5494
					interface_track6_configure($ifname, $ifcfg);
5495
				} else if ($action == "") {
5496
					$list[$ifname] = $ifcfg;
5497
				}
5498
			}
5499
		}
5500
		return $list;
5501
	}
5502
}
5503

    
5504
function interface_find_child_cfgmtu($realiface) {
5505
	global $config;
5506

    
5507
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5508
	$vlans = link_interface_to_vlans($realiface);
5509
	$qinqs = link_interface_to_qinqs($realiface);
5510
	$bridge = link_interface_to_bridge($realiface);
5511
	if (!empty($interface)) {
5512
		$gifs = link_interface_to_gif($interface);
5513
		$gres = link_interface_to_gre($interface);
5514
	} else {
5515
		$gifs = array();
5516
		$gres = array();
5517
	}
5518

    
5519
	$mtu = 0;
5520
	if (is_array($vlans)) {
5521
		foreach ($vlans as $vlan) {
5522
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['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($qinqs)) {
5534
		foreach ($qinqs as $qinq) {
5535
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
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($gifs)) {
5547
		foreach ($gifs as $gif) {
5548
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
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
	if (is_array($gres)) {
5560
		foreach ($gres as $gre) {
5561
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5562
			if (empty($ifass)) {
5563
				continue;
5564
			}
5565
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5566
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5567
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5568
				}
5569
			}
5570
		}
5571
	}
5572
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5573
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5574
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5575
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5576
		}
5577
	}
5578
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5579

    
5580
	return $mtu;
5581
}
5582

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

    
5586
	if (empty($int)) {
5587
		return;
5588
	}
5589

    
5590
	if (is_array($config['vlans']['vlan'])) {
5591
		$ifaces = array();
5592
		foreach ($config['vlans']['vlan'] as $vlan) {
5593
			if ($int == $vlan['if']) {
5594
				if ($action == "update") {
5595
					interfaces_bring_up($int);
5596
				} else {
5597
					$ifaces[$vlan['tag']] = $vlan;
5598
				}
5599
			}
5600
		}
5601
		if (!empty($ifaces)) {
5602
			return $ifaces;
5603
		}
5604
	}
5605
}
5606

    
5607
function link_interface_to_qinqs($int, $action = "") {
5608
	global $config;
5609

    
5610
	if (empty($int)) {
5611
		return;
5612
	}
5613

    
5614
	if (is_array($config['qinqs']['qinqentry'])) {
5615
		$ifaces = array();
5616
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5617
			if ($int == $qinq['if']) {
5618
				if ($action == "update") {
5619
					interfaces_bring_up($int);
5620
				} else {
5621
					$ifaces[$qinq['tag']] = $qinq;
5622
				}
5623
			}
5624
		}
5625
		if (!empty($ifaces)) {
5626
			return $ifaces;
5627
		}
5628
	}
5629
}
5630

    
5631
function link_interface_to_vips($int, $action = "", $vhid = '') {
5632
	global $config;
5633

    
5634
	$updatevips = false;
5635
	if (is_array($config['virtualip']['vip'])) {
5636
		$result = array();
5637
		foreach ($config['virtualip']['vip'] as $vip) {
5638
			if (substr($vip['interface'], 0, 4) == "_vip") {
5639
				$iface = get_configured_vip_interface($vip['interface']);
5640
			} else {
5641
				$iface = $vip['interface'];
5642
			}
5643
			if ($int != $iface) {
5644
				continue;
5645
			}
5646
			if ($action == "update") {
5647
				$updatevips = true;
5648
			} else {
5649
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5650
				    substr($vip['interface'], 0, 4) == "_vip") {
5651
					$result[] = $vip;
5652
				}
5653
			}
5654
		}
5655
		if ($updatevips === true) {
5656
			interfaces_vips_configure($int);
5657
		}
5658
		return $result;
5659
	}
5660

    
5661
	return NULL;
5662
}
5663

    
5664
/****f* interfaces/link_interface_to_bridge
5665
 * NAME
5666
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5667
 * INPUTS
5668
 *   $ip
5669
 * RESULT
5670
 *   bridge[0-99]
5671
 ******/
5672
function link_interface_to_bridge($int) {
5673
	global $config;
5674

    
5675
	if (is_array($config['bridges']['bridged'])) {
5676
		foreach ($config['bridges']['bridged'] as $bridge) {
5677
			if (in_array($int, explode(',', $bridge['members']))) {
5678
				return "{$bridge['bridgeif']}";
5679
			}
5680
		}
5681
	}
5682
}
5683

    
5684
function link_interface_to_group($int) {
5685
	global $config;
5686

    
5687
	$result = array();
5688

    
5689
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5690
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5691
			if (in_array($int, explode(" ", $group['members']))) {
5692
				$result[$group['ifname']] = $int;
5693
			}
5694
		}
5695
	}
5696

    
5697
	return $result;
5698
}
5699

    
5700
function link_interface_to_gre($interface) {
5701
	global $config;
5702

    
5703
	$result = array();
5704

    
5705
	if (is_array($config['gres']['gre'])) {
5706
		foreach ($config['gres']['gre'] as $gre) {
5707
			if ($gre['if'] == $interface) {
5708
				$result[] = $gre;
5709
			}
5710
		}
5711
	}
5712

    
5713
	return $result;
5714
}
5715

    
5716
function link_interface_to_gif($interface) {
5717
	global $config;
5718

    
5719
	$result = array();
5720

    
5721
	if (is_array($config['gifs']['gif'])) {
5722
		foreach ($config['gifs']['gif'] as $gif) {
5723
			if ($gif['if'] == $interface) {
5724
				$result[] = $gif;
5725
			}
5726
		}
5727
	}
5728

    
5729
	return $result;
5730
}
5731

    
5732
/*
5733
 * find_interface_ip($interface): return the interface ip (first found)
5734
 */
5735
function find_interface_ip($interface, $flush = false) {
5736
	global $interface_ip_arr_cache;
5737
	global $interface_sn_arr_cache;
5738

    
5739
	$interface = str_replace("\n", "", $interface);
5740

    
5741
	if (!does_interface_exist($interface)) {
5742
		return;
5743
	}
5744

    
5745
	/* Setup IP cache */
5746
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5747
		if (file_exists("/var/db/${interface}_ip")) {
5748
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
5749
			$ifaddrs = pfSense_getall_interface_addresses($interface);
5750
			foreach ($ifaddrs as $ifaddr) {
5751
				list($ip, $mask) = explode("/", $ifaddr);
5752
				if ($ip == $ifip) {
5753
					$interface_ip_arr_cache[$interface] = $ip;
5754
					$interface_sn_arr_cache[$interface] = $mask;
5755
					break;
5756
				}
5757
			}
5758
		}
5759
		if (!isset($interface_ip_arr_cache[$interface])) {
5760
			$ifinfo = pfSense_get_interface_addresses($interface);
5761
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5762
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5763
		}
5764
	}
5765

    
5766
	return $interface_ip_arr_cache[$interface];
5767
}
5768

    
5769
/*
5770
 * find_interface_ipv6($interface): return the interface ip (first found)
5771
 */
5772
function find_interface_ipv6($interface, $flush = false) {
5773
	global $interface_ipv6_arr_cache;
5774
	global $interface_snv6_arr_cache;
5775
	global $config;
5776

    
5777
	$interface = trim($interface);
5778
	$interface = get_real_interface($interface);
5779

    
5780
	if (!does_interface_exist($interface)) {
5781
		return;
5782
	}
5783

    
5784
	/* Setup IP cache */
5785
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5786
		$ifinfo = pfSense_get_interface_addresses($interface);
5787
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5788
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5789
	}
5790

    
5791
	return $interface_ipv6_arr_cache[$interface];
5792
}
5793

    
5794
/*
5795
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5796
 */
5797
function find_interface_ipv6_ll($interface, $flush = false) {
5798
	global $interface_llv6_arr_cache;
5799
	global $config;
5800

    
5801
	$interface = str_replace("\n", "", $interface);
5802

    
5803
	if (!does_interface_exist($interface)) {
5804
		return;
5805
	}
5806

    
5807
	/* Setup IP cache */
5808
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5809
		$ifinfo = pfSense_getall_interface_addresses($interface);
5810
		foreach ($ifinfo as $line) {
5811
			if (strstr($line, ":")) {
5812
				$parts = explode("/", $line);
5813
				if (is_linklocal($parts[0])) {
5814
					$ifinfo['linklocal'] = $parts[0];
5815
				}
5816
			}
5817
		}
5818
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5819
	}
5820
	return $interface_llv6_arr_cache[$interface];
5821
}
5822

    
5823
function find_interface_subnet($interface, $flush = false) {
5824
	global $interface_sn_arr_cache;
5825
	global $interface_ip_arr_cache;
5826

    
5827
	$interface = str_replace("\n", "", $interface);
5828
	if (does_interface_exist($interface) == false) {
5829
		return;
5830
	}
5831

    
5832
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5833
		$ifinfo = pfSense_get_interface_addresses($interface);
5834
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5835
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5836
	}
5837

    
5838
	return $interface_sn_arr_cache[$interface];
5839
}
5840

    
5841
function find_interface_subnetv6($interface, $flush = false) {
5842
	global $interface_snv6_arr_cache;
5843
	global $interface_ipv6_arr_cache;
5844

    
5845
	$interface = str_replace("\n", "", $interface);
5846
	if (does_interface_exist($interface) == false) {
5847
		return;
5848
	}
5849

    
5850
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5851
		$ifinfo = pfSense_get_interface_addresses($interface);
5852
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5853
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5854
	}
5855

    
5856
	return $interface_snv6_arr_cache[$interface];
5857
}
5858

    
5859
function ip_in_interface_alias_subnet($interface, $ipalias) {
5860
	global $config;
5861

    
5862
	if (empty($interface) || !is_ipaddr($ipalias)) {
5863
		return false;
5864
	}
5865
	if (is_array($config['virtualip']['vip'])) {
5866
		foreach ($config['virtualip']['vip'] as $vip) {
5867
			switch ($vip['mode']) {
5868
				case "ipalias":
5869
					if ($vip['interface'] <> $interface) {
5870
						break;
5871
					}
5872
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5873
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5874
						return true;
5875
					}
5876
					break;
5877
			}
5878
		}
5879
	}
5880

    
5881
	return false;
5882
}
5883

    
5884
function get_possible_listen_ips($include_ipv6_link_local=false) {
5885

    
5886
	$interfaces = get_configured_interface_with_descr();
5887
	foreach ($interfaces as $iface => $ifacename) {
5888
		if ($include_ipv6_link_local) {
5889
			/* This is to avoid going though added ll below */
5890
			if (substr($iface, 0, 5) == '_lloc') {
5891
				continue;
5892
			}
5893
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5894
			if (!empty($llip)) {
5895
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5896
			}
5897
		}
5898
	}
5899
	$viplist = get_configured_vip_list();
5900
	foreach ($viplist as $vip => $address) {
5901
		$interfaces[$vip] = $address;
5902
		if (get_vip_descr($address)) {
5903
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5904
		}
5905
	}
5906

    
5907
	$interfaces['lo0'] = 'Localhost';
5908

    
5909
	return $interfaces;
5910
}
5911

    
5912
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5913
	global $config;
5914

    
5915
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5916
	foreach (array('server', 'client') as $mode) {
5917
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5918
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5919
				if (!isset($setting['disable'])) {
5920
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5921
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5922
				}
5923
			}
5924
		}
5925
	}
5926
	return $sourceips;
5927
}
5928

    
5929
function get_interface_ip($interface = "wan") {
5930
	global $config;
5931

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

    
5939
	$realif = get_failover_interface($interface, 'inet');
5940
	if (!$realif) {
5941
		return null;
5942
	}
5943

    
5944
	if (substr($realif, 0, 4) == '_vip') {
5945
		return get_configured_vip_ipv4($realif);
5946
	} else if (substr($realif, 0, 5) == '_lloc') {
5947
		/* No link-local address for v4. */
5948
		return null;
5949
	}
5950

    
5951
	if (is_array($config['interfaces'][$interface]) &&
5952
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5953
		return ($config['interfaces'][$interface]['ipaddr']);
5954
	}
5955

    
5956
	/*
5957
	 * Beaware that find_interface_ip() is our last option, it will
5958
	 * return the first IP it find on interface, not necessarily the
5959
	 * main IP address.
5960
	 */
5961
	$curip = find_interface_ip($realif);
5962
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5963
		return $curip;
5964
	} else {
5965
		return null;
5966
	}
5967
}
5968

    
5969
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5970
	global $config;
5971

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

    
5978
	$realif = get_failover_interface($interface, 'inet6');
5979
	if (!$realif) {
5980
		return null;
5981
	}
5982

    
5983
	if (substr($realif, 0, 4) == '_vip') {
5984
		return get_configured_vip_ipv6($realif);
5985
	} else if (substr($realif, 0, 5) == '_lloc') {
5986
		return get_interface_linklocal($realif);
5987
	}
5988

    
5989
	if (is_array($config['interfaces'][$interface])) {
5990
		switch ($config['interfaces'][$interface]['ipaddr']) {
5991
			case 'pppoe':
5992
			case 'l2tp':
5993
			case 'pptp':
5994
			case 'ppp':
5995
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5996
					$realif = get_real_interface($interface, 'inet6', false);
5997
				}
5998
				break;
5999
		}
6000
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6001
			return ($config['interfaces'][$interface]['ipaddrv6']);
6002
		}
6003
	}
6004

    
6005
	/*
6006
	 * Beaware that find_interface_ip() is our last option, it will
6007
	 * return the first IP it find on interface, not necessarily the
6008
	 * main IP address.
6009
	 */
6010
	$curip = find_interface_ipv6($realif, $flush);
6011
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6012
		return $curip;
6013
	} else {
6014
		/*
6015
		 * NOTE: On the case when only the prefix is requested,
6016
		 * the communication on WAN will be done over link-local.
6017
		 */
6018
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6019
			$curip = find_interface_ipv6_ll($realif, $flush);
6020
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6021
				return $curip;
6022
			}
6023
		}
6024
	}
6025
	return null;
6026
}
6027

    
6028
function get_interface_linklocal($interface = "wan") {
6029

    
6030
	$realif = get_failover_interface($interface, 'inet6');
6031
	if (!$realif) {
6032
		return null;
6033
	}
6034

    
6035
	if (substr($interface, 0, 4) == '_vip') {
6036
		$realif = get_real_interface($interface);
6037
	} else if (substr($interface, 0, 5) == '_lloc') {
6038
		$realif = get_real_interface(substr($interface, 5));
6039
	}
6040

    
6041
	$curip = find_interface_ipv6_ll($realif);
6042
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6043
		return $curip;
6044
	} else {
6045
		return null;
6046
	}
6047
}
6048

    
6049
function get_interface_subnet($interface = "wan") {
6050
	global $config;
6051

    
6052
	if (substr($interface, 0, 4) == '_vip') {
6053
		return (get_configured_vip_subnetv4($interface));
6054
	}
6055

    
6056
	if (is_array($config['interfaces'][$interface]) &&
6057
		!empty($config['interfaces'][$interface]['subnet'])) {
6058
		return ($config['interfaces'][$interface]['subnet']);
6059
	}
6060

    
6061
	$realif = get_real_interface($interface);
6062
	if (!$realif) {
6063
		return (NULL);
6064
	}
6065

    
6066
	$cursn = find_interface_subnet($realif);
6067
	if (!empty($cursn)) {
6068
		return ($cursn);
6069
	}
6070

    
6071
	return (NULL);
6072
}
6073

    
6074
function get_interface_subnetv6($interface = "wan") {
6075
	global $config;
6076

    
6077
	if (substr($interface, 0, 4) == '_vip') {
6078
		return (get_configured_vip_subnetv6($interface));
6079
	} else if (substr($interface, 0, 5) == '_lloc') {
6080
		$interface = substr($interface, 5);
6081
	}
6082

    
6083
	if (is_array($config['interfaces'][$interface]) &&
6084
		!empty($config['interfaces'][$interface]['subnetv6'])) {
6085
		return ($config['interfaces'][$interface]['subnetv6']);
6086
	}
6087

    
6088
	$realif = get_real_interface($interface, 'inet6');
6089
	if (!$realif) {
6090
		return (NULL);
6091
	}
6092

    
6093
	$cursn = find_interface_subnetv6($realif);
6094
	if (!empty($cursn)) {
6095
		return ($cursn);
6096
	}
6097

    
6098
	return (NULL);
6099
}
6100

    
6101
/* return outside interfaces with a gateway */
6102
function get_interfaces_with_gateway() {
6103
	global $config;
6104

    
6105
	$ints = array();
6106

    
6107
	/* loop interfaces, check config for outbound */
6108
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6109
		switch ($ifname['ipaddr']) {
6110
			case "dhcp":
6111
			case "pppoe":
6112
			case "pptp":
6113
			case "l2tp":
6114
			case "ppp":
6115
				$ints[$ifdescr] = $ifdescr;
6116
				break;
6117
			default:
6118
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6119
				    !empty($ifname['gateway'])) {
6120
					$ints[$ifdescr] = $ifdescr;
6121
				}
6122
				break;
6123
		}
6124
	}
6125
	return $ints;
6126
}
6127

    
6128
/* return true if interface has a gateway */
6129
function interface_has_gateway($friendly) {
6130
	global $config;
6131

    
6132
	if (!empty($config['interfaces'][$friendly])) {
6133
		$ifname = &$config['interfaces'][$friendly];
6134
		switch ($ifname['ipaddr']) {
6135
			case "dhcp":
6136
			case "pppoe":
6137
			case "pptp":
6138
			case "l2tp":
6139
			case "ppp":
6140
				return true;
6141
			break;
6142
			default:
6143
				if (substr($ifname['if'], 0, 4) == "ovpn") {
6144
					return true;
6145
				}
6146
				$tunnelif = substr($ifname['if'], 0, 3);
6147
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6148
					if (find_interface_ip($ifname['if'])) {
6149
						return true;
6150
					}
6151
				}
6152
				if (!empty($ifname['gateway'])) {
6153
					return true;
6154
				}
6155
			break;
6156
		}
6157
	}
6158

    
6159
	return false;
6160
}
6161

    
6162
/* return true if interface has a gateway */
6163
function interface_has_gatewayv6($friendly) {
6164
	global $config;
6165

    
6166
	if (!empty($config['interfaces'][$friendly])) {
6167
		$ifname = &$config['interfaces'][$friendly];
6168
		switch ($ifname['ipaddrv6']) {
6169
			case "slaac":
6170
			case "dhcp6":
6171
			case "6to4":
6172
			case "6rd":
6173
				return true;
6174
				break;
6175
			default:
6176
				if (substr($ifname['if'], 0, 4) == "ovpn") {
6177
					return true;
6178
				}
6179
				$tunnelif = substr($ifname['if'], 0, 3);
6180
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6181
					if (find_interface_ipv6($ifname['if'])) {
6182
						return true;
6183
					}
6184
				}
6185
				if (!empty($ifname['gatewayv6'])) {
6186
					return true;
6187
				}
6188
				break;
6189
		}
6190
	}
6191

    
6192
	return false;
6193
}
6194

    
6195
/****f* interfaces/is_altq_capable
6196
 * NAME
6197
 *   is_altq_capable - Test if interface is capable of using ALTQ
6198
 * INPUTS
6199
 *   $int            - string containing interface name
6200
 * RESULT
6201
 *   boolean         - true or false
6202
 ******/
6203

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

    
6219
	$int_family = remove_ifindex($int);
6220

    
6221
	if (in_array($int_family, $capable)) {
6222
		return true;
6223
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6224
		return true;
6225
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6226
		return true;
6227
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6228
		return true;
6229
	} else {
6230
		return false;
6231
	}
6232
}
6233

    
6234
/****f* interfaces/is_interface_wireless
6235
 * NAME
6236
 *   is_interface_wireless - Returns if an interface is wireless
6237
 * RESULT
6238
 *   $tmp       - Returns if an interface is wireless
6239
 ******/
6240
function is_interface_wireless($interface) {
6241
	global $config, $g;
6242

    
6243
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6244
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6245
		if (preg_match($g['wireless_regex'], $interface)) {
6246
			if (isset($config['interfaces'][$friendly])) {
6247
				$config['interfaces'][$friendly]['wireless'] = array();
6248
			}
6249
			return true;
6250
		}
6251
		return false;
6252
	} else {
6253
		return true;
6254
	}
6255
}
6256

    
6257
function get_wireless_modes($interface) {
6258
	/* return wireless modes and channels */
6259
	$wireless_modes = array();
6260

    
6261
	$cloned_interface = get_real_interface($interface);
6262

    
6263
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6264
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6265
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6266
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6267

    
6268
		$interface_channels = "";
6269
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6270
		$interface_channel_count = count($interface_channels);
6271

    
6272
		$c = 0;
6273
		while ($c < $interface_channel_count) {
6274
			$channel_line = explode(",", $interface_channels["$c"]);
6275
			$wireless_mode = trim($channel_line[0]);
6276
			$wireless_channel = trim($channel_line[1]);
6277
			if (trim($wireless_mode) != "") {
6278
				/* if we only have 11g also set 11b channels */
6279
				if ($wireless_mode == "11g") {
6280
					if (!isset($wireless_modes["11b"])) {
6281
						$wireless_modes["11b"] = array();
6282
					}
6283
				} else if ($wireless_mode == "11g ht") {
6284
					if (!isset($wireless_modes["11b"])) {
6285
						$wireless_modes["11b"] = array();
6286
					}
6287
					if (!isset($wireless_modes["11g"])) {
6288
						$wireless_modes["11g"] = array();
6289
					}
6290
					$wireless_mode = "11ng";
6291
				} else if ($wireless_mode == "11a ht") {
6292
					if (!isset($wireless_modes["11a"])) {
6293
						$wireless_modes["11a"] = array();
6294
					}
6295
					$wireless_mode = "11na";
6296
				}
6297
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6298
			}
6299
			$c++;
6300
		}
6301
	}
6302
	return($wireless_modes);
6303
}
6304

    
6305
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6306
function get_wireless_channel_info($interface) {
6307
	$wireless_channels = array();
6308

    
6309
	$cloned_interface = get_real_interface($interface);
6310

    
6311
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6312
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
6313
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6314
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
6315

    
6316
		$interface_channels = "";
6317
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6318

    
6319
		foreach ($interface_channels as $channel_line) {
6320
			$channel_line = explode(",", $channel_line);
6321
			if (!isset($wireless_channels[$channel_line[0]])) {
6322
				$wireless_channels[$channel_line[0]] = $channel_line;
6323
			}
6324
		}
6325
	}
6326
	return($wireless_channels);
6327
}
6328

    
6329
function set_interface_mtu($interface, $mtu) {
6330

    
6331
	/* LAGG interface must be destroyed and re-created to change MTU */
6332
	if (substr($interface, 0, 4) == 'lagg') {
6333
		if (isset($config['laggs']['lagg']) &&
6334
		    is_array($config['laggs']['lagg'])) {
6335
			foreach ($config['laggs']['lagg'] as $lagg) {
6336
				if ($lagg['laggif'] == $interface) {
6337
					interface_lagg_configure($lagg);
6338
					break;
6339
				}
6340
			}
6341
		}
6342
	} else {
6343
		pfSense_interface_mtu($interface, $mtu);
6344
	}
6345
}
6346

    
6347
/****f* interfaces/get_interface_mtu
6348
 * NAME
6349
 *   get_interface_mtu - Return the mtu of an interface
6350
 * RESULT
6351
 *   $tmp       - Returns the mtu of an interface
6352
 ******/
6353
function get_interface_mtu($interface) {
6354
	$mtu = pfSense_interface_getmtu($interface);
6355
	return $mtu['mtu'];
6356
}
6357

    
6358
function get_interface_mac($interface) {
6359
	$macinfo = pfSense_get_interface_addresses($interface);
6360
	return $macinfo["macaddr"];
6361
}
6362

    
6363
function get_interface_vendor_mac($interface) {
6364
	$macinfo = pfSense_get_interface_addresses($interface);
6365
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] != "00:00:00:00:00:00") {
6366
		return ($macinfo["hwaddr"]);
6367
	}
6368
	return (NULL);
6369
}
6370

    
6371
/****f* pfsense-utils/generate_random_mac_address
6372
 * NAME
6373
 *   generate_random_mac - generates a random mac address
6374
 * INPUTS
6375
 *   none
6376
 * RESULT
6377
 *   $mac - a random mac address
6378
 ******/
6379
function generate_random_mac_address() {
6380
	$mac = "02";
6381
	for ($x = 0; $x < 5; $x++) {
6382
		$mac .= ":" . dechex(rand(16, 255));
6383
	}
6384
	return $mac;
6385
}
6386

    
6387
/****f* interfaces/is_jumbo_capable
6388
 * NAME
6389
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
6390
 * INPUTS
6391
 *   $int             - string containing interface name
6392
 * RESULT
6393
 *   boolean          - true or false
6394
 ******/
6395
function is_jumbo_capable($iface) {
6396
	$iface = trim($iface);
6397
	$capable = pfSense_get_interface_addresses($iface);
6398

    
6399
	if (isset($capable['caps']['vlanmtu'])) {
6400
		return true;
6401
	}
6402

    
6403
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
6404
	if (substr($iface, 0, 4) == "lagg") {
6405
		return true;
6406
	}
6407

    
6408
	return false;
6409
}
6410

    
6411
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6412
	global $g;
6413

    
6414
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6415

    
6416
	if (!empty($iface) && !empty($pppif)) {
6417
		$cron_cmd = <<<EOD
6418
#!/bin/sh
6419
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
6420
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
6421

    
6422
EOD;
6423

    
6424
		@file_put_contents($cron_file, $cron_cmd);
6425
		chmod($cron_file, 0755);
6426
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
6427
	} else {
6428
		unlink_if_exists($cron_file);
6429
	}
6430
}
6431

    
6432
function get_interface_default_mtu($type = "ethernet") {
6433
	switch ($type) {
6434
		case "gre":
6435
			return 1476;
6436
			break;
6437
		case "gif":
6438
			return 1280;
6439
			break;
6440
		case "tun":
6441
		case "vlan":
6442
		case "tap":
6443
		case "ethernet":
6444
		default:
6445
			return 1500;
6446
			break;
6447
	}
6448

    
6449
	/* Never reached */
6450
	return 1500;
6451
}
6452

    
6453
function get_vip_descr($ipaddress) {
6454
	global $config;
6455

    
6456
	foreach ($config['virtualip']['vip'] as $vip) {
6457
		if ($vip['subnet'] == $ipaddress) {
6458
			return ($vip['descr']);
6459
		}
6460
	}
6461
	return "";
6462
}
6463

    
6464
function interfaces_staticarp_configure($if) {
6465
	global $config, $g;
6466
	if (isset($config['system']['developerspew'])) {
6467
		$mt = microtime();
6468
		echo "interfaces_staticarp_configure($if) being called $mt\n";
6469
	}
6470

    
6471
	$ifcfg = $config['interfaces'][$if];
6472

    
6473
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
6474
		return 0;
6475
	}
6476

    
6477
	/* Enable staticarp, if enabled */
6478
	if (isset($config['dhcpd'][$if]['staticarp'])) {
6479
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
6480
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6481
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
6482
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6483
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6484
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6485
				}
6486
			}
6487
		}
6488
	} else {
6489
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
6490
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6491
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
6492
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6493
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6494
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6495
				}
6496
			}
6497
		}
6498
	}
6499

    
6500
	return 0;
6501
}
6502

    
6503
function get_failover_interface($interface, $family = "all") {
6504
	global $config;
6505

    
6506
	/* shortcut to get_real_interface if we find it in the config */
6507
	if (is_array($config['interfaces'][$interface])) {
6508
		return get_real_interface($interface, $family);
6509
	}
6510

    
6511
	/* compare against gateway groups */
6512
	$a_groups = return_gateway_groups_array();
6513
	if (is_array($a_groups[$interface])) {
6514
		/* we found a gateway group, fetch the interface or vip */
6515
		if (!empty($a_groups[$interface][0]['vip'])) {
6516
			return $a_groups[$interface][0]['vip'];
6517
		} else {
6518
			return $a_groups[$interface][0]['int'];
6519
		}
6520
	}
6521
	/* fall through to get_real_interface */
6522
	/* XXX: Really needed? */
6523
	return get_real_interface($interface, $family);
6524
}
6525

    
6526
/****f* interfaces/interface_has_dhcp
6527
 * NAME
6528
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6529
 * INPUTS
6530
 *   interface or gateway group name
6531
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6532
 * RESULT
6533
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6534
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6535
 ******/
6536
function interface_has_dhcp($interface, $family = 4) {
6537
	global $config;
6538

    
6539
	if ($config['interfaces'][$interface]) {
6540
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6541
			return true;
6542
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6543
			return true;
6544
		} else {
6545
			return false;
6546
		}
6547
	}
6548

    
6549
	if (!is_array($config['gateways']['gateway_group'])) {
6550
		return false;
6551
	}
6552

    
6553
	if ($family == 6) {
6554
		$dhcp_string = "_DHCP6";
6555
	} else {
6556
		$dhcp_string = "_DHCP";
6557
	}
6558

    
6559
	foreach ($config['gateways']['gateway_group'] as $group) {
6560
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6561
			continue;
6562
		}
6563
		foreach ($group['item'] as $item) {
6564
			$item_data = explode("|", $item);
6565
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6566
				return true;
6567
			}
6568
		}
6569
	}
6570

    
6571
	return false;
6572
}
6573

    
6574
function remove_ifindex($ifname) {
6575
	return preg_replace("/[0-9]+$/", "", $ifname);
6576
}
6577

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

    
6581
	$viplist = get_configured_vip_list($family, $type);
6582
	foreach ($viplist as $vip => $address) {
6583
		$interfaces[$vip] = $address;
6584
		if ($type = VIP_CARP) {
6585
			$vip = get_configured_vip($vipid);
6586
			if (isset($vip) && is_array($vip) ) {
6587
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
6588
			}
6589
		}
6590
		if (get_vip_descr($address)) {
6591
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
6592
		}
6593
	}
6594
	return $interfaces;
6595
}
6596

    
6597
function return_gateway_groups_array_with_descr() {
6598
	$interfaces = array();
6599
	$grouplist = return_gateway_groups_array();
6600
	foreach ($grouplist as $name => $group) {
6601
		if ($group[0]['vip'] != "") {
6602
			$vipif = $group[0]['vip'];
6603
		} else {
6604
			$vipif = $group[0]['int'];
6605
		}
6606

    
6607
		$interfaces[$name] = "GW Group {$name}";
6608
	}
6609
	return $interfaces;
6610
}
6611

    
6612
function get_serial_ports() {
6613
	$linklist = array();
6614
	if (!is_dir("/var/spool/lock")) {
6615
		mwexec("/bin/mkdir -p /var/spool/lock");
6616
	}
6617
	$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);
6618
	foreach ($serialports as $port) {
6619
		$linklist[$port] = trim($port);
6620
	}
6621
	return $linklist;
6622
}
6623

    
6624
function get_interface_ports() {
6625
	global $config;
6626
	$linklist = array();
6627
	$portlist = get_interface_list();
6628
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
6629
		foreach ($config['vlans']['vlan'] as $vlan) {
6630
			$portlist[$vlan['vlanif']] = $vlan;
6631
		}
6632
	}
6633

    
6634
	foreach ($portlist as $ifn => $ifinfo) {
6635
		$string = "";
6636
		if (is_array($ifinfo)) {
6637
			$string .= $ifn;
6638
			if ($ifinfo['mac']) {
6639
				$string .= " ({$ifinfo['mac']})";
6640
			}
6641
			if ($ifinfo['friendly']) {
6642
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
6643
			} elseif ($ifinfo['descr']) {
6644
				$string .= " - {$ifinfo['descr']}";
6645
			}
6646
		} else {
6647
			$string .= $ifinfo;
6648
		}
6649

    
6650
		$linklist[$ifn] = $string;
6651
	}
6652
	return $linklist;
6653
}
6654

    
6655
function build_ppps_link_list() {
6656
	global $pconfig;
6657

    
6658
	$linklist = array('list' => array(), 'selected' => array());
6659

    
6660
	if ($pconfig['type'] == 'ppp') {
6661
		$linklist['list'] = get_serial_ports();
6662
	} else {
6663
		$iflist = get_interface_ports();
6664

    
6665
		$viplist = get_configured_vip_list_with_descr('all', VIP_CARP);
6666

    
6667
		$linklist['list'] = array_merge($iflist, $viplist);
6668

    
6669
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
6670
		$lagglist = get_lagg_interface_list();
6671
		foreach ($lagglist as $laggif => $lagg) {
6672
			/* LAGG members cannot be assigned */
6673
			$laggmembers = explode(',', $lagg['members']);
6674
			foreach ($laggmembers as $lagm) {
6675
				if (isset($linklist['list'][$lagm])) {
6676
					unset($linklist['list'][$lagm]);
6677
				}
6678
			}
6679
		}
6680
	}
6681

    
6682
	$selected_ports = array();
6683
	if (is_array($pconfig['interfaces'])) {
6684
		$selected_ports = $pconfig['interfaces'];
6685
	} elseif (!empty($pconfig['interfaces'])) {
6686
		$selected_ports = explode(',', $pconfig['interfaces']);
6687
	}
6688
	foreach ($selected_ports as $port) {
6689
		if (isset($linklist['list'][$port])) {
6690
			array_push($linklist['selected'], $port);
6691
		}
6692
	}
6693
	return($linklist);
6694
}
6695

    
6696
?>
(20-20/55)