Project

General

Profile

Download (189 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * interfaces.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-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
/*
1768
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1769
 * It writes the mpd config file to /var/etc every time the link is opened.
1770
 */
1771
function interface_ppps_configure($interface) {
1772
	global $config, $g;
1773

    
1774
	/* Return for unassigned interfaces. This is a minimum requirement. */
1775
	if (empty($config['interfaces'][$interface])) {
1776
		return 0;
1777
	}
1778
	$ifcfg = $config['interfaces'][$interface];
1779
	if (!isset($ifcfg['enable'])) {
1780
		return 0;
1781
	}
1782

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

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

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

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

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

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

    
1883
	if (is_array($ports) && count($ports) > 1) {
1884
		$multilink = "enable";
1885
	} else {
1886
		$multilink = "disable";
1887
	}
1888

    
1889
	if ($type == "modem") {
1890
		if (is_ipaddr($ppp['localip'])) {
1891
			$localip = $ppp['localip'];
1892
		} else {
1893
			$localip = '0.0.0.0';
1894
		}
1895

    
1896
		if (is_ipaddr($ppp['gateway'])) {
1897
			$gateway = $ppp['gateway'];
1898
		} else {
1899
			$gateway = "10.64.64.{$pppid}";
1900
		}
1901
		$ranges = "{$localip}/0 {$gateway}/0";
1902

    
1903
		if (empty($ppp['apnum'])) {
1904
			$ppp['apnum'] = 1;
1905
		}
1906
	} else {
1907
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1908
	}
1909

    
1910
	if (isset($ppp['ondemand'])) {
1911
		$ondemand = "enable";
1912
	} else {
1913
		$ondemand = "disable";
1914
	}
1915
	if (!isset($ppp['idletimeout'])) {
1916
		$ppp['idletimeout'] = 0;
1917
	}
1918

    
1919
	if (empty($ppp['username']) && $type == "modem") {
1920
		$ppp['username'] = "user";
1921
		$ppp['password'] = "none";
1922
	}
1923
	if (empty($ppp['password']) && $type == "modem") {
1924
		$passwd = "none";
1925
	} else {
1926
		$passwd = base64_decode($ppp['password']);
1927
	}
1928

    
1929
	$bandwidths = explode(',', $ppp['bandwidth']);
1930
	$defaultmtu = "1492";
1931
	if (!empty($ifcfg['mtu'])) {
1932
		$defaultmtu = intval($ifcfg['mtu']);
1933
	}
1934
	if (isset($ppp['mtu'])) {
1935
		$mtus = explode(',', $ppp['mtu']);
1936
	}
1937
	if (isset($ppp['mru'])) {
1938
		$mrus = explode(',', $ppp['mru']);
1939
	}
1940
	if (isset($ppp['mrru'])) {
1941
		$mrrus = explode(',', $ppp['mrru']);
1942
	}
1943

    
1944
	// Construct the mpd.conf file
1945
	$mpdconf = <<<EOD
1946
startup:
1947
	# configure the console
1948
	set console close
1949
	# configure the web server
1950
	set web close
1951

    
1952
default:
1953
{$ppp['type']}client:
1954
	create bundle static {$interface}
1955
	set bundle enable ipv6cp
1956
	set iface name {$pppif}
1957

    
1958
EOD;
1959
	$setdefaultgw = false;
1960
	$founddefaultgw = false;
1961
	if (is_array($config['gateways']['gateway_item'])) {
1962
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1963
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1964
				$setdefaultgw = true;
1965
				break;
1966
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1967
				$founddefaultgw = true;
1968
				break;
1969
			}
1970
		}
1971
	}
1972

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

    
1983
EOD;
1984
	}
1985
	$mpdconf .= <<<EOD
1986
	set iface {$ondemand} on-demand
1987
	set iface idle {$ppp['idletimeout']}
1988

    
1989
EOD;
1990

    
1991
	if (isset($ppp['ondemand'])) {
1992
		$mpdconf .= <<<EOD
1993
	set iface addrs 10.10.1.1 10.10.1.2
1994

    
1995
EOD;
1996
	}
1997

    
1998
	if (isset($ppp['tcpmssfix'])) {
1999
		$tcpmss = "disable";
2000
	} else {
2001
		$tcpmss = "enable";
2002
	}
2003
	$mpdconf .= <<<EOD
2004
	set iface {$tcpmss} tcpmssfix
2005

    
2006
EOD;
2007

    
2008
	$mpdconf .= <<<EOD
2009
	set iface up-script /usr/local/sbin/ppp-linkup
2010
	set iface down-script /usr/local/sbin/ppp-linkdown
2011
	set ipcp ranges {$ranges}
2012

    
2013
EOD;
2014
	if (isset($ppp['vjcomp'])) {
2015
		$mpdconf .= <<<EOD
2016
	set ipcp no vjcomp
2017

    
2018
EOD;
2019
	}
2020

    
2021
	if (isset($config['system']['dnsallowoverride'])) {
2022
		$mpdconf .= <<<EOD
2023
	set ipcp enable req-pri-dns
2024
	set ipcp enable req-sec-dns
2025

    
2026
EOD;
2027
	}
2028

    
2029
	if (!isset($ppp['verbose_log'])) {
2030
		$mpdconf .= <<<EOD
2031
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2032

    
2033
EOD;
2034
	}
2035

    
2036
	foreach ($ports as $pid => $port) {
2037
		$port = get_real_interface($port);
2038
		$mpdconf .= <<<EOD
2039

    
2040
	create link static {$interface}_link{$pid} {$type}
2041
	set link action bundle {$interface}
2042
	set link {$multilink} multilink
2043
	set link keep-alive 10 60
2044
	set link max-redial 0
2045

    
2046
EOD;
2047
		if (isset($ppp['shortseq'])) {
2048
			$mpdconf .= <<<EOD
2049
	set link no shortseq
2050

    
2051
EOD;
2052
		}
2053

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

    
2058
EOD;
2059
		}
2060

    
2061
		if (isset($ppp['protocomp'])) {
2062
			$mpdconf .= <<<EOD
2063
	set link no protocomp
2064

    
2065
EOD;
2066
		}
2067

    
2068
		$mpdconf .= <<<EOD
2069
	set link disable chap pap
2070
	set link accept chap pap eap
2071
	set link disable incoming
2072

    
2073
EOD;
2074

    
2075

    
2076
		if (!empty($bandwidths[$pid])) {
2077
			$mpdconf .= <<<EOD
2078
	set link bandwidth {$bandwidths[$pid]}
2079

    
2080
EOD;
2081
		}
2082

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

    
2096
EOD;
2097
		}
2098

    
2099
		if (!empty($mrus[$pid])) {
2100
			$mpdconf .= <<<EOD
2101
	set link mru {$mrus[$pid]}
2102

    
2103
EOD;
2104
		}
2105

    
2106
		if (!empty($mrrus[$pid])) {
2107
			$mpdconf .= <<<EOD
2108
	set link mrru {$mrrus[$pid]}
2109

    
2110
EOD;
2111
		}
2112

    
2113
		$mpdconf .= <<<EOD
2114
	set auth authname "{$ppp['username']}"
2115
	set auth password {$passwd}
2116

    
2117
EOD;
2118
		if ($type == "modem") {
2119
			$mpdconf .= <<<EOD
2120
	set modem device {$ppp['ports']}
2121
	set modem script DialPeer
2122
	set modem idle-script Ringback
2123
	set modem watch -cd
2124
	set modem var \$DialPrefix "DT"
2125
	set modem var \$Telephone "{$ppp['phone']}"
2126

    
2127
EOD;
2128
		}
2129
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2130
			$mpdconf .= <<<EOD
2131
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2132

    
2133
EOD;
2134
		}
2135
		if (isset($ppp['initstr']) && $type == "modem") {
2136
			$initstr = base64_decode($ppp['initstr']);
2137
			$mpdconf .= <<<EOD
2138
	set modem var \$InitString "{$initstr}"
2139

    
2140
EOD;
2141
		}
2142
		if (isset($ppp['simpin']) && $type == "modem") {
2143
			if ($ppp['pin-wait'] == "") {
2144
				$ppp['pin-wait'] = 0;
2145
			}
2146
			$mpdconf .= <<<EOD
2147
	set modem var \$SimPin "{$ppp['simpin']}"
2148
	set modem var \$PinWait "{$ppp['pin-wait']}"
2149

    
2150
EOD;
2151
		}
2152
		if (isset($ppp['apn']) && $type == "modem") {
2153
			$mpdconf .= <<<EOD
2154
	set modem var \$APN "{$ppp['apn']}"
2155
	set modem var \$APNum "{$ppp['apnum']}"
2156

    
2157
EOD;
2158
		}
2159
		if ($type == "pppoe") {
2160
			// Send a null service name if none is set.
2161
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2162
			$mpdconf .= <<<EOD
2163
	set pppoe service "{$provider}"
2164

    
2165
EOD;
2166
		}
2167
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
2168
			$mpdconf .= <<<EOD
2169
	set pppoe max-payload {$mtus[$pid]}
2170

    
2171
EOD;
2172
		}
2173
		if ($type == "pppoe") {
2174
			$mpdconf .= <<<EOD
2175
	set pppoe iface {$port}
2176

    
2177
EOD;
2178
		}
2179

    
2180
		if ($type == "pptp" || $type == "l2tp") {
2181
			$mpdconf .= <<<EOD
2182
	set {$type} self {$localips[$pid]}
2183
	set {$type} peer {$gateways[$pid]}
2184

    
2185
EOD;
2186
		}
2187

    
2188
		$mpdconf .= "\topen\n";
2189
	} //end foreach ($port)
2190

    
2191

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

    
2207
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2208
	if (isset($ppp['uptime'])) {
2209
		if (!file_exists("/conf/{$pppif}.log")) {
2210
			file_put_contents("/conf/{$pppif}.log", '');
2211
		}
2212
	} else {
2213
		if (file_exists("/conf/{$pppif}.log")) {
2214
			@unlink("/conf/{$pppif}.log");
2215
		}
2216
	}
2217

    
2218
	/* clean up old lock files */
2219
	foreach ($ports as $port) {
2220
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2221
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2222
		}
2223
	}
2224

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

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

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

    
2268
	/* Remove all temporary bogon IPv4 addresses */
2269
	if (is_array($tempaddr)) {
2270
		foreach ($tempaddr as $tempiface) {
2271
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2272
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2273
			}
2274
		}
2275
		unset ($tempaddr);
2276
	}
2277

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

    
2298
	return 1;
2299
}
2300

    
2301
function interfaces_sync_setup() {
2302
	global $g, $config;
2303

    
2304
	if (isset($config['system']['developerspew'])) {
2305
		$mt = microtime();
2306
		echo "interfaces_sync_setup() being called $mt\n";
2307
	}
2308

    
2309
	if (platform_booting()) {
2310
		echo gettext("Configuring CARP settings...");
2311
		mute_kernel_msgs();
2312
	}
2313

    
2314
	/* suck in configuration items */
2315
	if ($config['hasync']) {
2316
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2317
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2318
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2319
	} else {
2320
		unset($pfsyncinterface);
2321
		unset($pfsyncenabled);
2322
	}
2323

    
2324
	set_sysctl(array(
2325
		"net.inet.carp.preempt" => "1",
2326
		"net.inet.carp.log" => "1")
2327
	);
2328

    
2329
	if (!empty($pfsyncinterface)) {
2330
		$carp_sync_int = get_real_interface($pfsyncinterface);
2331
	} else {
2332
		unset($carp_sync_int);
2333
	}
2334

    
2335
	/* setup pfsync interface */
2336
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2337
		if (is_ipaddr($pfsyncpeerip)) {
2338
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2339
		} else {
2340
			$syncpeer = "-syncpeer";
2341
		}
2342

    
2343
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2344
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2345

    
2346
		sleep(1);
2347

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

    
2363
	$carplist = get_configured_vip_list('all', VIP_CARP);
2364
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2365
		set_single_sysctl("net.inet.carp.allow", "1");
2366
	} else {
2367
		set_single_sysctl("net.inet.carp.allow", "0");
2368
	}
2369

    
2370
	if (platform_booting()) {
2371
		unmute_kernel_msgs();
2372
		echo gettext("done.") . "\n";
2373
	}
2374
}
2375

    
2376
function interface_proxyarp_configure($interface = "") {
2377
	global $config, $g;
2378
	if (isset($config['system']['developerspew'])) {
2379
		$mt = microtime();
2380
		echo "interface_proxyarp_configure() being called $mt\n";
2381
	}
2382

    
2383
	/* kill any running choparp */
2384
	if (empty($interface)) {
2385
		killbyname("choparp");
2386
	} else {
2387
		$vipif = get_real_interface($interface);
2388
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2389
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2390
		}
2391
	}
2392

    
2393
	$paa = array();
2394
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2395

    
2396
		/* group by interface */
2397
		foreach ($config['virtualip']['vip'] as $vipent) {
2398
			if ($vipent['mode'] === "proxyarp") {
2399
				if ($vipent['interface']) {
2400
					$proxyif = $vipent['interface'];
2401
				} else {
2402
					$proxyif = "wan";
2403
				}
2404

    
2405
				if (!empty($interface) && $interface != $proxyif) {
2406
					continue;
2407
				}
2408

    
2409
				if (!is_array($paa[$proxyif])) {
2410
					$paa[$proxyif] = array();
2411
				}
2412

    
2413
				$paa[$proxyif][] = $vipent;
2414
			}
2415
		}
2416
	}
2417

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

    
2457
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2458
	global $g, $config;
2459

    
2460
	if (is_array($config['virtualip']['vip'])) {
2461
		foreach ($config['virtualip']['vip'] as $vip) {
2462

    
2463
			$iface = $vip['interface'];
2464
			if (substr($iface, 0, 4) == "_vip")
2465
				$iface = get_configured_vip_interface($vip['interface']);
2466
			if ($iface != $interface)
2467
				continue;
2468
			if ($type == VIP_CARP) {
2469
				if ($vip['mode'] != "carp")
2470
					continue;
2471
			} elseif ($type == VIP_IPALIAS) {
2472
				if ($vip['mode'] != "ipalias")
2473
					continue;
2474
			} else {
2475
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2476
					continue;
2477
			}
2478

    
2479
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2480
				interface_vip_bring_down($vip);
2481
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2482
				interface_vip_bring_down($vip);
2483
			else if ($inet == "all")
2484
				interface_vip_bring_down($vip);
2485
		}
2486
	}
2487
}
2488

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

    
2537
function interface_ipalias_configure(&$vip) {
2538
	global $config;
2539

    
2540
	if ($vip['mode'] != 'ipalias') {
2541
		return;
2542
	}
2543

    
2544
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2545
	if ($realif != "lo0") {
2546
		$if = convert_real_interface_to_friendly_interface_name($realif);
2547
		if (!isset($config['interfaces'][$if])) {
2548
			return;
2549
		}
2550

    
2551
		if (!isset($config['interfaces'][$if]['enable'])) {
2552
			return;
2553
		}
2554
	}
2555

    
2556
	$af = 'inet';
2557
	if (is_ipaddrv6($vip['subnet'])) {
2558
		$af = 'inet6';
2559
	}
2560
	$iface = $vip['interface'];
2561
	$vhid = '';
2562
	if (substr($vip['interface'], 0, 4) == "_vip") {
2563
		$carpvip = get_configured_vip($vip['interface']);
2564
		$iface = $carpvip['interface'];
2565
		$vhid = "vhid {$carpvip['vhid']}";
2566
	}
2567
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2568
	unset($iface, $af, $realif, $carpvip, $vhid);
2569
}
2570

    
2571
function interface_carp_configure(&$vip) {
2572
	global $config, $g;
2573
	if (isset($config['system']['developerspew'])) {
2574
		$mt = microtime();
2575
		echo "interface_carp_configure() being called $mt\n";
2576
	}
2577

    
2578
	if ($vip['mode'] != "carp") {
2579
		return;
2580
	}
2581

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

    
2589
	$vip_password = $vip['password'];
2590
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2591
	if ($vip['password'] != "") {
2592
		$password = " pass {$vip_password}";
2593
	}
2594

    
2595
	$advbase = "";
2596
	if (!empty($vip['advbase'])) {
2597
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2598
	}
2599

    
2600
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2601
	if ($carp_maintenancemode) {
2602
		$advskew = "advskew 254";
2603
	} else {
2604
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2605
	}
2606

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

    
2609
	if (is_ipaddrv4($vip['subnet'])) {
2610
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2611
	} else if (is_ipaddrv6($vip['subnet'])) {
2612
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2613
	}
2614

    
2615
	return $realif;
2616
}
2617

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

    
2660
	if ($needs_clone == true) {
2661
		/* remove previous instance if it exists */
2662
		if (does_interface_exist($realif)) {
2663
			pfSense_interface_destroy($realif);
2664
		}
2665

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

    
2682
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2683
	global $config, $g;
2684

    
2685
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2686
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2687
				 'regdomain', 'regcountry', 'reglocation');
2688

    
2689
	if (!is_interface_wireless($ifcfg['if'])) {
2690
		return;
2691
	}
2692

    
2693
	$baseif = interface_get_wireless_base($ifcfg['if']);
2694

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

    
2722
	// Read or write settings at shared area
2723
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2724
		foreach ($shared_settings as $setting) {
2725
			if ($sync_changes) {
2726
				if (isset($ifcfg['wireless'][$setting])) {
2727
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2728
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2729
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2730
				}
2731
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2732
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2733
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2734
				} else if (isset($ifcfg['wireless'][$setting])) {
2735
					unset($ifcfg['wireless'][$setting]);
2736
				}
2737
			}
2738
		}
2739
	}
2740

    
2741
	// Sync the mode on the clone creation page with the configured mode on the interface
2742
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2743
		foreach ($config['wireless']['clone'] as &$clone) {
2744
			if ($clone['cloneif'] == $ifcfg['if']) {
2745
				if ($sync_changes) {
2746
					$clone['mode'] = $ifcfg['wireless']['mode'];
2747
				} else {
2748
					$ifcfg['wireless']['mode'] = $clone['mode'];
2749
				}
2750
				break;
2751
			}
2752
		}
2753
		unset($clone);
2754
	}
2755
}
2756

    
2757
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2758
	global $config, $g;
2759

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

    
2767
	// Remove script file
2768
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2769

    
2770
	// Clone wireless nic if needed.
2771
	interface_wireless_clone($if, $wl);
2772

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

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

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

    
2782
	/* set values for /path/program */
2783
	if (file_exists("/usr/local/sbin/hostapd")) {
2784
		$hostapd = "/usr/local/sbin/hostapd";
2785
	} else {
2786
		$hostapd = "/usr/sbin/hostapd";
2787
	}
2788
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
2789
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
2790
	} else {
2791
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2792
	}
2793
	$ifconfig = "/sbin/ifconfig";
2794
	$sysctl = "/sbin/sysctl";
2795
	$killall = "/usr/bin/killall";
2796

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

    
2799
	$wlcmd = array();
2800
	$wl_sysctl = array();
2801
	/* Set a/b/g standard */
2802
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2803
	/* skip mode entirely for "auto" */
2804
	if ($wlcfg['standard'] != "auto") {
2805
		$wlcmd[] = "mode " . escapeshellarg($standard);
2806
	}
2807

    
2808
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2809
	 * to prevent massive packet loss under certain conditions. */
2810
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2811
		$wlcmd[] = "-ampdu";
2812
	}
2813

    
2814
	/* Set ssid */
2815
	if ($wlcfg['ssid']) {
2816
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2817
	}
2818

    
2819
	/* Set 802.11g protection mode */
2820
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2821

    
2822
	/* set wireless channel value */
2823
	if (isset($wlcfg['channel'])) {
2824
		if ($wlcfg['channel'] == "0") {
2825
			$wlcmd[] = "channel any";
2826
		} else {
2827
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2828
		}
2829
	}
2830

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

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

    
2841
	/* Set rxantenna value */
2842
	if (isset($wlcfg['rxantenna'])) {
2843
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2844
	}
2845

    
2846
	/* set Distance value */
2847
	if ($wlcfg['distance']) {
2848
		$distance = escapeshellarg($wlcfg['distance']);
2849
	}
2850

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

    
2858
	/* Set wireless adhoc mode */
2859
	if ($wlcfg['mode'] == "adhoc") {
2860
		$wlcmd[] = "mediaopt adhoc";
2861
	} else {
2862
		$wlcmd[] = "-mediaopt adhoc";
2863
	}
2864

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

    
2867
	/* handle hide ssid option */
2868
	if (isset($wlcfg['hidessid']['enable'])) {
2869
		$wlcmd[] = "hidessid";
2870
	} else {
2871
		$wlcmd[] = "-hidessid";
2872
	}
2873

    
2874
	/* handle pureg (802.11g) only option */
2875
	if (isset($wlcfg['pureg']['enable'])) {
2876
		$wlcmd[] = "mode 11g pureg";
2877
	} else {
2878
		$wlcmd[] = "-pureg";
2879
	}
2880

    
2881
	/* handle puren (802.11n) only option */
2882
	if (isset($wlcfg['puren']['enable'])) {
2883
		$wlcmd[] = "puren";
2884
	} else {
2885
		$wlcmd[] = "-puren";
2886
	}
2887

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

    
2895
	/* handle turbo option */
2896
	if (isset($wlcfg['turbo']['enable'])) {
2897
		$wlcmd[] = "mediaopt turbo";
2898
	} else {
2899
		$wlcmd[] = "-mediaopt turbo";
2900
	}
2901

    
2902
	/* handle txpower setting */
2903
	// or don't. this has issues at the moment.
2904
	/*
2905
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2906
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2907
	}*/
2908

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

    
2916
	/* Enable wpa if it's configured. No WEP support anymore. */
2917
	if (isset($wlcfg['wpa']['enable'])) {
2918
		$wlcmd[] = "authmode wpa wepmode off ";
2919
	} else {
2920
		$wlcmd[] = "authmode open wepmode off ";
2921
	}
2922

    
2923
	kill_hostapd($if);
2924
	mwexec(kill_wpasupplicant("{$if}"));
2925

    
2926
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2927

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

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

    
2981
EOD;
2982

    
2983
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2984
					$wpa .= <<<EOD
2985
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
2986
rsn_preauth=1
2987
rsn_preauth_interfaces={$if}
2988

    
2989
EOD;
2990
				}
2991
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2992
					$wpa .= "ieee8021x=1\n";
2993

    
2994
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2995
						$auth_server_port = "1812";
2996
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2997
							$auth_server_port = intval($wlcfg['auth_server_port']);
2998
						}
2999
						$wpa .= <<<EOD
3000

    
3001
auth_server_addr={$wlcfg['auth_server_addr']}
3002
auth_server_port={$auth_server_port}
3003
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3004

    
3005
EOD;
3006
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3007
							$auth_server_port2 = "1812";
3008
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3009
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3010
							}
3011

    
3012
							$wpa .= <<<EOD
3013
auth_server_addr={$wlcfg['auth_server_addr2']}
3014
auth_server_port={$auth_server_port2}
3015
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3016

    
3017
EOD;
3018
						}
3019
					}
3020
				}
3021

    
3022
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3023
				unset($wpa);
3024
			}
3025
			break;
3026
	}
3027

    
3028
	/*
3029
	 *    all variables are set, lets start up everything
3030
	 */
3031

    
3032
	$baseif = interface_get_wireless_base($if);
3033
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3034
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3035

    
3036
	/* set sysctls for the wireless interface */
3037
	if (!empty($wl_sysctl)) {
3038
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3039
		foreach ($wl_sysctl as $wl_sysctl_line) {
3040
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3041
		}
3042
	}
3043

    
3044
	/* set ack timers according to users preference (if he/she has any) */
3045
	if ($distance) {
3046
		fwrite($fd_set, "# Enable ATH distance settings\n");
3047
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3048
	}
3049

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

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

    
3067
			/* add line to script to restore spoofed mac after running hostapd */
3068
			if ($wl['spoofmac']) {
3069
				$if_curmac = get_interface_mac($if);
3070
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3071
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3072
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3073
				}
3074
			}
3075
		}
3076
	}
3077

    
3078
	fclose($fd_set);
3079

    
3080
	/* Making sure regulatory settings have actually changed
3081
	 * before applying, because changing them requires bringing
3082
	 * down all wireless networks on the interface. */
3083
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3084
	$ifconfig_str = implode($output);
3085
	unset($output);
3086
	$reg_changing = false;
3087

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

    
3101
	if ($reg_changing) {
3102
		/* set regulatory domain */
3103
		if ($wlcfg['regdomain']) {
3104
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3105
		}
3106

    
3107
		/* set country */
3108
		if ($wlcfg['regcountry']) {
3109
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3110
		}
3111

    
3112
		/* set location */
3113
		if ($wlcfg['reglocation']) {
3114
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3115
		}
3116

    
3117
		$wlregcmd_args = implode(" ", $wlregcmd);
3118

    
3119
		/* build a complete list of the wireless clones for this interface */
3120
		$clone_list = array();
3121
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3122
			$clone_list[] = interface_get_wireless_clone($baseif);
3123
		}
3124
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3125
			foreach ($config['wireless']['clone'] as $clone) {
3126
				if ($clone['if'] == $baseif) {
3127
					$clone_list[] = $clone['cloneif'];
3128
				}
3129
			}
3130
		}
3131

    
3132
		/* find which clones are up and bring them down */
3133
		$clones_up = array();
3134
		foreach ($clone_list as $clone_if) {
3135
			$clone_status = pfSense_get_interface_addresses($clone_if);
3136
			if ($clone_status['status'] == 'up') {
3137
				$clones_up[] = $clone_if;
3138
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3139
			}
3140
		}
3141

    
3142
		/* apply the regulatory settings */
3143
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3144
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3145

    
3146
		/* bring the clones back up that were previously up */
3147
		foreach ($clones_up as $clone_if) {
3148
			interfaces_bring_up($clone_if);
3149

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

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

    
3175
	/* configure wireless */
3176
	$wlcmd_args = implode(" ", $wlcmd);
3177
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3178
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3179
	/* Bring the interface up only after setting up all the other parameters. */
3180
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3181
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3182
	fclose($wlan_setup_log);
3183

    
3184
	unset($wlcmd_args, $wlcmd);
3185

    
3186

    
3187
	sleep(1);
3188
	/* execute hostapd and wpa_supplicant if required in shell */
3189
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3190

    
3191
	return 0;
3192

    
3193
}
3194

    
3195
function kill_hostapd($interface) {
3196
	global $g;
3197

    
3198
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3199
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3200
	}
3201
}
3202

    
3203
function kill_wpasupplicant($interface) {
3204
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3205
}
3206

    
3207
function find_dhclient_process($interface) {
3208
	if ($interface) {
3209
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3210
	} else {
3211
		$pid = 0;
3212
	}
3213

    
3214
	return intval($pid);
3215
}
3216

    
3217
function kill_dhclient_process($interface) {
3218
	if (empty($interface) || !does_interface_exist($interface)) {
3219
		return;
3220
	}
3221

    
3222
	$i = 0;
3223
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3224
		/* 3rd time make it die for sure */
3225
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3226
		posix_kill($pid, $sig);
3227
		sleep(1);
3228
		$i++;
3229
	}
3230
	unset($i);
3231
}
3232

    
3233
function find_dhcp6c_process($interface) {
3234
	global $g;
3235

    
3236
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3237
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3238
	} else {
3239
		return(false);
3240
	}
3241

    
3242
	return intval($pid);
3243
}
3244

    
3245
function kill_dhcp6client_process($interface, $force, $release = false) {
3246
	global $g;
3247

    
3248
	$i = 0;
3249

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

    
3260
	/*********** Notes on signals for dhcp6c and this function *************
3261

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

    
3272
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3273
	exit quickly without sending release signals.
3274

    
3275
	If $Force is set to false and $release is also set to false dhcp6c will
3276
	follow the no-release flag.
3277

    
3278
	If $Force is set to false and $release is true then dhcp6c will send a 
3279
	release regardless of the no-release flag.
3280
	***********************************************************************/
3281

    
3282
	if ($force == true) {
3283
		$psig=SIGUSR1;
3284
	} else if ($release == false) {
3285
		$psig=SIGTERM;
3286
	} else {
3287
		$psig=SIGUSR2;
3288
	}
3289

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

    
3310
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3311
	global $g;
3312

    
3313
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3314
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3315

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

    
3340
function interface_virtual_create($interface) {
3341
	global $config;
3342

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

    
3382
function interface_vlan_mtu_configured($iface) {
3383
	global $config;
3384

    
3385
	$mtu = 0;
3386
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3387
		foreach ($config['vlans']['vlan'] as $vlan) {
3388

    
3389
			if ($vlan['vlanif'] != $iface)
3390
				continue;
3391

    
3392
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3393
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3394
				/* VLAN MTU */
3395
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3396
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3397
				/* Parent MTU */
3398
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3399
			}
3400
		}
3401
	}
3402

    
3403
	return $mtu;
3404
}
3405

    
3406
function interface_mtu_wanted_for_pppoe($realif) {
3407
	global $config;
3408

    
3409
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3410
		return 0;
3411

    
3412
	$mtu = 0;
3413
	foreach ($config['ppps']['ppp'] as $ppp) {
3414
		if ($ppp['type'] != "pppoe") {
3415
			continue;
3416
		}
3417

    
3418
		$mtus = array();
3419
		if (!empty($ppp['mtu'])) {
3420
			$mtus = explode(',', $ppp['mtu']);
3421
		}
3422
		$ports = explode(',', $ppp['ports']);
3423

    
3424
		foreach ($ports as $pid => $port) {
3425
			$parentifa = get_parent_interface($port);
3426
			$parentif = $parentifa[0];
3427
			if ($parentif != $realif)
3428
				continue;
3429

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

    
3446
	return $mtu;
3447
}
3448

    
3449
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3450
	global $config, $g;
3451
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3452
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3453

    
3454
	$wancfg = $config['interfaces'][$interface];
3455

    
3456
	if (!isset($wancfg['enable'])) {
3457
		return;
3458
	}
3459

    
3460
	$realif = get_real_interface($interface);
3461
	$realhwif_array = get_parent_interface($interface);
3462
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3463
	$realhwif = $realhwif_array[0];
3464

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

    
3486
		/* only bring down the interface when both v4 and v6 are set to NONE */
3487
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3488
			interface_bring_down($interface);
3489
		}
3490
	}
3491

    
3492
	$interface_to_check = $realif;
3493
	if (interface_isppp_type($interface)) {
3494
		$interface_to_check = $realhwif;
3495
	}
3496

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

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

    
3515
	$current_mac = get_interface_mac($realhwif);
3516
	$vendor_mac = get_interface_vendor_mac($realhwif);
3517
	/*
3518
	 * Do not change the MAC address if the interface does not store the original
3519
	 * vendor MAC address.
3520
	 */
3521
	if ($vendor_mac != NULL) {
3522
		/* Get the vendor MAC.  Use source dependent upon whether or not booting. */
3523
		if (platform_booting()) {
3524
			$vendor_mac = $current_mac;
3525
		}
3526
		$mac_addr = $wancfg['spoofmac'] ?: $vendor_mac;
3527
		/*
3528
		 * Don't try to reapply the MAC if it's already applied.
3529
		 * When ifconfig link is used, it cycles the interface down/up, which triggers
3530
		 * the interface config again, which attempts to apply the MAC again,
3531
		 * which cycles the link again...
3532
		 */
3533
		if (!empty($mac_addr) && ($mac_addr != $current_mac)) {
3534
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3535
				" link " . escapeshellarg($mac_addr));
3536
		}
3537
	} elseif ($current_mac == "ff:ff:ff:ff:ff:ff") {
3538
		/*   this is not a valid mac address.  generate a
3539
		 *   temporary mac address so the machine can get online.
3540
		 */
3541
		echo gettext("Generating new MAC address.");
3542
		$random_mac = generate_random_mac_address();
3543
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3544
			" link " . escapeshellarg($random_mac));
3545
		$wancfg['spoofmac'] = $random_mac;
3546
		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));
3547
		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");
3548
	}
3549

    
3550
	/* media */
3551
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3552
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3553
		if ($wancfg['media']) {
3554
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3555
		}
3556
		if ($wancfg['mediaopt']) {
3557
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3558
		}
3559
		mwexec($cmd);
3560
	}
3561

    
3562
	/* Apply hw offloading policies as configured */
3563
	enable_hardware_offloading($interface);
3564

    
3565
	/* invalidate interface/ip/sn cache */
3566
	get_interface_arr(true);
3567
	unset($interface_ip_arr_cache[$realif]);
3568
	unset($interface_sn_arr_cache[$realif]);
3569
	unset($interface_ipv6_arr_cache[$realif]);
3570
	unset($interface_snv6_arr_cache[$realif]);
3571

    
3572
	$tunnelif = substr($realif, 0, 3);
3573

    
3574
	$mtuif = $realif;
3575
	$mtuhwif = $realhwif;
3576

    
3577
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3578
	if (interface_isppp_type($interface)) {
3579
		$mtuif = $realhwif;
3580
		$mtuhwif_array = get_parent_interface($mtuif);
3581
		$mtuhwif = $mtuhwif_array[0];
3582
	}
3583

    
3584
	$wantedmtu = 0;
3585
	if (is_array($config['interfaces'])) {
3586
		foreach ($config['interfaces'] as $tmpinterface) {
3587
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3588
				$wantedmtu = $tmpinterface['mtu'];
3589
				break;
3590
			}
3591
		}
3592
	}
3593

    
3594
	/* MTU is not specified for interface, try the pppoe settings. */
3595
	if ($wantedmtu == 0) {
3596
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3597
	}
3598
	if ($wantedmtu == 0 && interface_is_vlan($mtuif) != NULL && interface_isppp_type($interface)) {
3599
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3600
	}
3601

    
3602
	/* Set the MTU to 1500 if no explicit MTU configured. */
3603
	if ($wantedmtu == 0) {
3604
		$wantedmtu = 1500; /* Default */
3605
	}
3606

    
3607
	if (interface_is_vlan($mtuif) != NULL) {
3608
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3609
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3610
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3611
			if ($wancfg['mtu'] > $parentmtu) {
3612
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3613
			}
3614
		}
3615

    
3616
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3617

    
3618
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3619
			$configuredmtu = $parentmtu;
3620
		if ($configuredmtu != 0)
3621
			$mtu = $configuredmtu;
3622
		else
3623
			$mtu = $wantedmtu;
3624

    
3625
		/* Set the parent MTU. */
3626
		if (get_interface_mtu($mtuhwif) < $mtu)
3627
			set_interface_mtu($mtuhwif, $mtu);
3628
		/* Set the VLAN MTU. */
3629
		if (get_interface_mtu($mtuif) != $mtu)
3630
			set_interface_mtu($mtuif, $mtu);
3631
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3632
		/* LAGG interface must be destroyed and re-created to change MTU */
3633
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3634
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3635
				foreach ($config['laggs']['lagg'] as $lagg) {
3636
					if ($lagg['laggif'] == $mtuif) {
3637
						interface_lagg_configure($lagg);
3638
						break;
3639
					}
3640
				}
3641
			}
3642
		}
3643
	} else {
3644
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3645
			pfSense_interface_mtu($mtuif, $wantedmtu);
3646
		}
3647
	}
3648
	/* XXX: What about gre/gif/.. ? */
3649

    
3650
	if (does_interface_exist($wancfg['if'])) {
3651
		interfaces_bring_up($wancfg['if']);
3652
	}
3653

    
3654
	switch ($wancfg['ipaddr']) {
3655
		case 'dhcp':
3656
			interface_dhcp_configure($interface);
3657
			break;
3658
		case 'pppoe':
3659
		case 'l2tp':
3660
		case 'pptp':
3661
		case 'ppp':
3662
			interface_ppps_configure($interface);
3663
			break;
3664
		default:
3665
			/* XXX: Kludge for now related to #3280 */
3666
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3667
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3668
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3669
				}
3670
			}
3671
			break;
3672
	}
3673

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

    
3708
	interface_netgraph_needed($interface);
3709

    
3710
	if (!platform_booting()) {
3711
		link_interface_to_vips($interface, "update");
3712

    
3713
		if ($tunnelif != 'gre') {
3714
			unset($gre);
3715
			$gre = link_interface_to_gre($interface);
3716
			if (!empty($gre)) {
3717
				array_walk($gre, 'interface_gre_configure');
3718
			}
3719
		}
3720

    
3721
		if ($tunnelif != 'gif') {
3722
			unset($gif);
3723
			$gif = link_interface_to_gif ($interface);
3724
			if (!empty($gif)) {
3725
				array_walk($gif, 'interface_gif_configure');
3726
			}
3727
		}
3728

    
3729
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3730
			unset($bridgetmp);
3731
			$bridgetmp = link_interface_to_bridge($interface);
3732
			if (!empty($bridgetmp)) {
3733
				interface_bridge_add_member($bridgetmp, $realif);
3734
			}
3735
		}
3736

    
3737
		$grouptmp = link_interface_to_group($interface);
3738
		if (!empty($grouptmp)) {
3739
			array_walk($grouptmp, 'interface_group_add_member');
3740
		}
3741

    
3742
		if ($interface == "lan") {
3743
			/* make new hosts file */
3744
			system_hosts_generate();
3745
		}
3746

    
3747
		if ($reloadall == true) {
3748

    
3749
			/* reconfigure static routes (kernel may have deleted them) */
3750
			system_routing_configure($interface);
3751

    
3752
			/* reload ipsec tunnels */
3753
			send_event("service reload ipsecdns");
3754

    
3755
			if (isset($config['dnsmasq']['enable'])) {
3756
				services_dnsmasq_configure();
3757
			}
3758

    
3759
			if (isset($config['unbound']['enable'])) {
3760
				services_unbound_configure();
3761
			}
3762

    
3763
			/* update dyndns */
3764
			send_event("service reload dyndns {$interface}");
3765

    
3766
			/* reload captive portal */
3767
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3768
				require_once('captiveportal.inc');
3769
			}
3770
			captiveportal_init_rules_byinterface($interface);
3771
		}
3772
	}
3773

    
3774
	interfaces_staticarp_configure($interface);
3775
	return 0;
3776
}
3777

    
3778
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3779
	global $config, $g;
3780

    
3781
	if (!is_array($wancfg)) {
3782
		return;
3783
	}
3784

    
3785
	if (!isset($wancfg['enable'])) {
3786
		return;
3787
	}
3788

    
3789
	/* If the interface is not configured via another, exit */
3790
	if (empty($wancfg['track6-interface'])) {
3791
		return;
3792
	}
3793

    
3794
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3795
	$realif = get_real_interface($interface);
3796
	$linklocal = find_interface_ipv6_ll($realif, true);
3797
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
3798
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3799
	}
3800
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3801
	/* XXX: Probably should remove? */
3802
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3803

    
3804
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3805
	if (!isset($trackcfg['enable'])) {
3806
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
3807
		return;
3808
	}
3809

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

    
3840
	if ($linkupevent == false && !platform_booting()) {
3841
		if (!function_exists('services_dhcpd_configure')) {
3842
			require_once("services.inc");
3843
		}
3844

    
3845
		/* restart dns servers (defering dhcpd reload) */
3846
		if (isset($config['unbound']['enable'])) {
3847
			services_unbound_configure(false);
3848
		}
3849
		if (isset($config['dnsmasq']['enable'])) {
3850
			services_dnsmasq_configure(false);
3851
		}
3852

    
3853
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
3854
		services_dhcpd_configure("inet6");
3855
	}
3856

    
3857
	return 0;
3858
}
3859

    
3860
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3861
	global $config, $g;
3862
	global $interface_ipv6_arr_cache;
3863
	global $interface_snv6_arr_cache;
3864

    
3865
	if (!is_array($lancfg)) {
3866
		return;
3867
	}
3868

    
3869
	/* If the interface is not configured via another, exit */
3870
	if (empty($lancfg['track6-interface'])) {
3871
		return;
3872
	}
3873

    
3874
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3875
	if (empty($wancfg)) {
3876
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3877
		return;
3878
	}
3879

    
3880
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3881
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3882
		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']));
3883
		return;
3884
	}
3885
	$hexwanv4 = return_hex_ipv4($ip4address);
3886

    
3887
	/* create the long prefix notation for math, save the prefix length */
3888
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3889
	$rd6prefixlen = $rd6prefix[1];
3890
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3891

    
3892
	/* binary presentation of the prefix for all 128 bits. */
3893
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3894

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

    
3900
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3901
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3902
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3903
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3904
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3905
	/* fill the rest out with zeros */
3906
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3907

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

    
3911
	$lanif = get_real_interface($interface);
3912
	$oip = find_interface_ipv6($lanif);
3913
	if (is_ipaddrv6($oip)) {
3914
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3915
	}
3916
	unset($interface_ipv6_arr_cache[$lanif]);
3917
	unset($interface_snv6_arr_cache[$lanif]);
3918
	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));
3919
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3920

    
3921
	return 0;
3922
}
3923

    
3924
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3925
	global $config, $g;
3926
	global $interface_ipv6_arr_cache;
3927
	global $interface_snv6_arr_cache;
3928

    
3929
	if (!is_array($lancfg)) {
3930
		return;
3931
	}
3932

    
3933
	/* If the interface is not configured via another, exit */
3934
	if (empty($lancfg['track6-interface'])) {
3935
		return;
3936
	}
3937

    
3938
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3939
	if (empty($wancfg)) {
3940
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3941
		return;
3942
	}
3943

    
3944
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3945
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3946
		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']));
3947
		return;
3948
	}
3949
	$hexwanv4 = return_hex_ipv4($ip4address);
3950

    
3951
	/* create the long prefix notation for math, save the prefix length */
3952
	$sixto4prefix = "2002::";
3953
	$sixto4prefixlen = 16;
3954
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3955

    
3956
	/* binary presentation of the prefix for all 128 bits. */
3957
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3958

    
3959
	/* just save the left prefix length bits */
3960
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3961
	/* add the v4 address */
3962
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3963
	/* add the custom prefix id */
3964
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3965
	/* fill the rest out with zeros */
3966
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3967

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

    
3971
	$lanif = get_real_interface($interface);
3972
	$oip = find_interface_ipv6($lanif);
3973
	if (is_ipaddrv6($oip)) {
3974
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3975
	}
3976
	unset($interface_ipv6_arr_cache[$lanif]);
3977
	unset($interface_snv6_arr_cache[$lanif]);
3978
	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));
3979
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3980

    
3981
	return 0;
3982
}
3983

    
3984
function interface_6rd_configure($interface = "wan", $wancfg) {
3985
	global $config, $g;
3986

    
3987
	/* because this is a tunnel interface we can only function
3988
	 *	with a public IPv4 address on the interface */
3989

    
3990
	if (!is_array($wancfg)) {
3991
		return;
3992
	}
3993

    
3994
	if (!is_module_loaded('if_stf.ko')) {
3995
		mwexec('/sbin/kldload if_stf.ko');
3996
	}
3997

    
3998
	$wanif = get_real_interface($interface);
3999
	$ip4address = find_interface_ip($wanif);
4000
	if (!is_ipaddrv4($ip4address)) {
4001
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4002
		return false;
4003
	}
4004
	$hexwanv4 = return_hex_ipv4($ip4address);
4005

    
4006
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4007
		$wancfg['prefix-6rd-v4plen'] = 0;
4008
	}
4009

    
4010
	/* create the long prefix notation for math, save the prefix length */
4011
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4012
	$rd6prefixlen = $rd6prefix[1];
4013
	$brgw = explode('.', $wancfg['gateway-6rd']);
4014
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4015
	$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);
4016
	if (strlen($rd6brgw) < 128) {
4017
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4018
	}
4019
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4020
	unset($brgw);
4021
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4022

    
4023
	/* binary presentation of the prefix for all 128 bits. */
4024
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4025

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

    
4033
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4034
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4035

    
4036

    
4037
	/* XXX: need to extend to support variable prefix size for v4 */
4038
	$stfiface = "{$interface}_stf";
4039
	if (does_interface_exist($stfiface)) {
4040
		pfSense_interface_destroy($stfiface);
4041
	}
4042
	$tmpstfiface = pfSense_interface_create("stf");
4043
	pfSense_interface_rename($tmpstfiface, $stfiface);
4044
	pfSense_interface_flags($stfiface, IFF_LINK2);
4045
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4046
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4047
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4048
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4049
	}
4050
	if ($g['debug']) {
4051
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4052
	}
4053

    
4054
	/* write out a default router file */
4055
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4056
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4057

    
4058
	$ip4gateway = get_interface_gateway($interface);
4059
	if (is_ipaddrv4($ip4gateway)) {
4060
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
4061
	}
4062

    
4063
	/* configure dependent interfaces */
4064
	if (!platform_booting()) {
4065
		link_interface_to_track6($interface, "update");
4066
	}
4067

    
4068
	return 0;
4069
}
4070

    
4071
function interface_6to4_configure($interface = "wan", $wancfg) {
4072
	global $config, $g;
4073

    
4074
	/* because this is a tunnel interface we can only function
4075
	 *	with a public IPv4 address on the interface */
4076

    
4077
	if (!is_array($wancfg)) {
4078
		return;
4079
	}
4080

    
4081
	$wanif = get_real_interface($interface);
4082
	$ip4address = find_interface_ip($wanif);
4083
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4084
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4085
		return false;
4086
	}
4087

    
4088
	/* create the long prefix notation for math, save the prefix length */
4089
	$stfprefixlen = 16;
4090
	$stfprefix = Net_IPv6::uncompress("2002::");
4091
	$stfarr = explode(":", $stfprefix);
4092
	$v4prefixlen = "0";
4093

    
4094
	/* we need the hex form of the interface IPv4 address */
4095
	$ip4arr = explode(".", $ip4address);
4096
	$hexwanv4 = "";
4097
	foreach ($ip4arr as $octet) {
4098
		$hexwanv4 .= sprintf("%02x", $octet);
4099
	}
4100

    
4101
	/* we need the hex form of the broker IPv4 address */
4102
	$ip4arr = explode(".", "192.88.99.1");
4103
	$hexbrv4 = "";
4104
	foreach ($ip4arr as $octet) {
4105
		$hexbrv4 .= sprintf("%02x", $octet);
4106
	}
4107

    
4108
	/* binary presentation of the prefix for all 128 bits. */
4109
	$stfprefixbin = "";
4110
	foreach ($stfarr as $element) {
4111
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4112
	}
4113
	/* just save the left prefix length bits */
4114
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4115

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

    
4120
	/* for the local subnet too. */
4121
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4122
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4123

    
4124
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4125
	$stfbrarr = array();
4126
	$stfbrbinarr = array();
4127
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4128
	foreach ($stfbrbinarr as $bin) {
4129
		$stfbrarr[] = dechex(bindec($bin));
4130
	}
4131
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4132

    
4133
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4134
	$stflanarr = array();
4135
	$stflanbinarr = array();
4136
	$stflanbinarr = str_split($stflanbin, 16);
4137
	foreach ($stflanbinarr as $bin) {
4138
		$stflanarr[] = dechex(bindec($bin));
4139
	}
4140
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4141
	$stflanarr[7] = 1;
4142
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4143

    
4144
	/* setup the stf interface */
4145
	if (!is_module_loaded("if_stf")) {
4146
		mwexec("/sbin/kldload if_stf.ko");
4147
	}
4148
	$stfiface = "{$interface}_stf";
4149
	if (does_interface_exist($stfiface)) {
4150
		pfSense_interface_destroy($stfiface);
4151
	}
4152
	$tmpstfiface = pfSense_interface_create("stf");
4153
	pfSense_interface_rename($tmpstfiface, $stfiface);
4154
	pfSense_interface_flags($stfiface, IFF_LINK2);
4155
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4156

    
4157
	if ($g['debug']) {
4158
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4159
	}
4160

    
4161
	/* write out a default router file */
4162
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4163
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4164

    
4165
	$ip4gateway = get_interface_gateway($interface);
4166
	if (is_ipaddrv4($ip4gateway)) {
4167
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
4168
	}
4169

    
4170
	if (!platform_booting()) {
4171
		link_interface_to_track6($interface, "update");
4172
	}
4173

    
4174
	return 0;
4175
}
4176

    
4177
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4178
	global $config, $g;
4179

    
4180
	if (!is_array($wancfg)) {
4181
		return;
4182
	}
4183

    
4184
	$wanif = get_real_interface($interface, "inet6");
4185
	$dhcp6cconf = "";
4186

    
4187
	if (!empty($config['system']['global-v6duid'])) {
4188
		// Write the DUID file
4189
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4190
		    log_error(gettext("Failed to write user DUID file!"));
4191
		}
4192
	}
4193
	
4194
	/* accept router advertisements for this interface                 */
4195
	/* Moved to early in the function as sometimes interface not ready */
4196
	/* RTSOLD fails as interface does not accept .....                 */
4197

    
4198
	log_error("Accept router advertisements on interface {$wanif} ");
4199
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4200

    
4201
	if ($wancfg['adv_dhcp6_config_file_override']) {
4202
		// DHCP6 Config File Override
4203
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4204
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4205
		// DHCP6 Config File Advanced
4206
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4207
	} else {
4208
		// DHCP6 Config File Basic
4209
		$dhcp6cconf .= "interface {$wanif} {\n";
4210

    
4211
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4212
		if ($wancfg['ipaddrv6'] == "slaac") {
4213
			$dhcp6cconf .= "\tinformation-only;\n";
4214
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4215
			$dhcp6cconf .= "\trequest domain-name;\n";
4216
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4217
			$dhcp6cconf .= "};\n";
4218
		} else {
4219
			$trackiflist = array();
4220
			$iflist = link_interface_to_track6($interface);
4221
			foreach ($iflist as $ifname => $ifcfg) {
4222
				if (is_numeric($ifcfg['track6-prefix-id'])) {
4223
					$trackiflist[$ifname] = $ifcfg;
4224
				}
4225
			}
4226

    
4227
			/* skip address request if this is set */
4228
			if (!isset($wancfg['dhcp6prefixonly'])) {
4229
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4230
			}
4231
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4232
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4233
			}
4234

    
4235
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4236
			$dhcp6cconf .= "\trequest domain-name;\n";
4237

    
4238
			/*
4239
			 * dhcp6c will run different scripts depending on
4240
			 * whether dhcpwithoutra is set or unset.
4241
			 */
4242
			if (isset($wancfg['dhcp6withoutra'])) {
4243
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4244
			} else {
4245
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4246
			}
4247
			$dhcp6cconf .= "};\n";
4248

    
4249
			if (!isset($wancfg['dhcp6prefixonly'])) {
4250
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4251
			}
4252

    
4253
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4254
				/* Setup the prefix delegation */
4255
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4256
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4257
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4258
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4259
				}
4260
				foreach ($trackiflist as $friendly => $ifcfg) {
4261
					if ($g['debug']) {
4262
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4263
					}
4264
					$realif = get_real_interface($friendly);
4265
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4266
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4267
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4268
					$dhcp6cconf .= "\t};\n";
4269
				}
4270
				unset($preflen, $iflist, $ifcfg, $ifname);
4271
				$dhcp6cconf .= "};\n";
4272
			}
4273
			unset($trackiflist);
4274
		}
4275
	}
4276

    
4277
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4278
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4279

    
4280
	/* wide-dhcp6c works for now. */
4281
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4282
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4283
		unset($dhcp6cconf);
4284
		return 1;
4285
	}
4286
	unset($dhcp6cconf);
4287

    
4288
	/*************** Script Debug Logging ***************************
4289
	Both dhcp6 scripts now have a logging message built in.
4290
	These logging messages ONLY appear if dhcp6c debug logging is set.
4291
	The logging messages appear in the dhcp section of the logs,
4292
	not in system.
4293

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

    
4347
	unset($dhcp6cscriptwithoutra);
4348
	@chmod(
4349
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4350
	    0755);
4351

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

    
4396
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4397
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4398
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4399
		unset($dhcp6cscript);
4400
		return 1;
4401
	}
4402
	unset($dhcp6cscript);
4403
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4404

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

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

    
4459
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4460
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4461
		log_error("Killing running rtsold process");
4462
		sleep(2);
4463
	}
4464

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

    
4506
	return 0;
4507
}
4508

    
4509
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4510
	global $g;
4511

    
4512
	$send_options = "";
4513
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4514
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4515
		foreach ($options as $option) {
4516
			$send_options .= "\tsend " . trim($option) . ";\n";
4517
		}
4518
	}
4519

    
4520
	$request_options = "";
4521
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4522
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4523
		foreach ($options as $option) {
4524
			$request_options .= "\trequest " . trim($option) . ";\n";
4525
		}
4526
	}
4527

    
4528
	$information_only = "";
4529
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4530
		$information_only = "\tinformation-only;\n";
4531
	}
4532

    
4533
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4534
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4535
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4536
	}
4537

    
4538
	$interface_statement  = "interface";
4539
	$interface_statement .= " {$wanif}";
4540
	$interface_statement .= " {\n";
4541
	$interface_statement .= "$send_options";
4542
	$interface_statement .= "$request_options";
4543
	$interface_statement .= "$information_only";
4544
	$interface_statement .= "$script";
4545
	$interface_statement .= "};\n";
4546

    
4547
	$id_assoc_statement_address = "";
4548
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4549
		$id_assoc_statement_address .= "id-assoc";
4550
		$id_assoc_statement_address .= " na";
4551
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4552
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4553
		}
4554
		$id_assoc_statement_address .= " { ";
4555

    
4556
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4557
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4558
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4559
			$id_assoc_statement_address .= "\n\taddress";
4560
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4561
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4562
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4563
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4564
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4565
			}
4566
			$id_assoc_statement_address .= ";\n";
4567
		}
4568

    
4569
		$id_assoc_statement_address .= "};\n";
4570
	}
4571

    
4572
	$id_assoc_statement_prefix = "";
4573
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4574
		$id_assoc_statement_prefix .= "id-assoc";
4575
		$id_assoc_statement_prefix .= " pd";
4576
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4577
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4578
		}
4579
		$id_assoc_statement_prefix .= " { ";
4580

    
4581
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4582
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4583
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4584
			$id_assoc_statement_prefix .= "\n\tprefix";
4585
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4586
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4587
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4588
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4589
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4590
			}
4591
			$id_assoc_statement_prefix .= ";";
4592
		}
4593
		
4594
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
4595
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4596
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4597
			$id_assoc_statement_prefix .= " {$realif}";
4598
			$id_assoc_statement_prefix .= " {\n";
4599
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4600
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4601
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4602
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4603
			}
4604
			$id_assoc_statement_prefix .= "\t};";
4605
		}
4606

    
4607
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4608
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4609
			$id_assoc_statement_prefix .= "\n";
4610
		}
4611

    
4612
		$id_assoc_statement_prefix .= "};\n";
4613
	}
4614

    
4615
	$authentication_statement = "";
4616
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4617
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4618
		$authentication_statement .= "authentication";
4619
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4620
		$authentication_statement .= " {\n";
4621
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4622
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4623
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4624
		}
4625
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4626
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4627
		}
4628
		$authentication_statement .= "};\n";
4629
	}
4630

    
4631
	$key_info_statement = "";
4632
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4633
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4634
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4635
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4636
		$key_info_statement .= "keyinfo";
4637
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4638
		$key_info_statement .= " {\n";
4639
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4640
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4641
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4642
		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'])) {
4643
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4644
		}
4645
		$key_info_statement .= "};\n";
4646
	}
4647

    
4648
	$dhcp6cconf  = $interface_statement;
4649
	$dhcp6cconf .= $id_assoc_statement_address;
4650
	$dhcp6cconf .= $id_assoc_statement_prefix;
4651
	$dhcp6cconf .= $authentication_statement;
4652
	$dhcp6cconf .= $key_info_statement;
4653

    
4654
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4655

    
4656
	return $dhcp6cconf;
4657
}
4658

    
4659

    
4660
function DHCP6_Config_File_Override($wancfg, $wanif) {
4661

    
4662
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4663

    
4664
	if ($dhcp6cconf === false) {
4665
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4666
		return '';
4667
	} else {
4668
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4669
	}
4670
}
4671

    
4672

    
4673
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4674

    
4675
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4676

    
4677
	return $dhcp6cconf;
4678
}
4679

    
4680

    
4681
function interface_dhcp_configure($interface = "wan") {
4682
	global $config, $g;
4683

    
4684
	$wancfg = $config['interfaces'][$interface];
4685
	$wanif = $wancfg['if'];
4686
	if (empty($wancfg)) {
4687
		$wancfg = array();
4688
	}
4689

    
4690
	/* generate dhclient_wan.conf */
4691
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4692
	if (!$fd) {
4693
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4694
		return 1;
4695
	}
4696

    
4697
	if ($wancfg['dhcphostname']) {
4698
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4699
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4700
	} else {
4701
		$dhclientconf_hostname = "";
4702
	}
4703

    
4704
	$wanif = get_real_interface($interface);
4705
	if (empty($wanif)) {
4706
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4707
		return 0;
4708
	}
4709
	$dhclientconf = "";
4710

    
4711
	$dhclientconf .= <<<EOD
4712
interface "{$wanif}" {
4713
timeout 60;
4714
retry 15;
4715
select-timeout 0;
4716
initial-interval 1;
4717
	{$dhclientconf_hostname}
4718
	script "/usr/local/sbin/pfSense-dhclient-script";
4719
EOD;
4720

    
4721
	if (validate_ipv4_list($wancfg['dhcprejectfrom'])) {
4722
		$dhclientconf .= <<<EOD
4723

    
4724
	reject {$wancfg['dhcprejectfrom']};
4725
EOD;
4726
	}
4727
	$dhclientconf .= <<<EOD
4728

    
4729
}
4730

    
4731
EOD;
4732

    
4733
	// DHCP Config File Advanced
4734
	if ($wancfg['adv_dhcp_config_advanced']) {
4735
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4736
	}
4737

    
4738
	if (is_ipaddr($wancfg['alias-address'])) {
4739
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4740
		$dhclientconf .= <<<EOD
4741
alias {
4742
	interface "{$wanif}";
4743
	fixed-address {$wancfg['alias-address']};
4744
	option subnet-mask {$subnetmask};
4745
}
4746

    
4747
EOD;
4748
	}
4749

    
4750
	// DHCP Config File Override
4751
	if ($wancfg['adv_dhcp_config_file_override']) {
4752
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4753
	}
4754

    
4755
	fwrite($fd, $dhclientconf);
4756
	fclose($fd);
4757

    
4758
	/* bring wan interface up before starting dhclient */
4759
	if ($wanif) {
4760
		interfaces_bring_up($wanif);
4761
	} else {
4762
		log_error(sprintf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4763
	}
4764

    
4765
	/* Make sure dhclient is not running */
4766
	kill_dhclient_process($wanif);
4767

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

    
4771
	return 0;
4772
}
4773

    
4774
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4775

    
4776
	$hostname = "";
4777
	if ($wancfg['dhcphostname'] != '') {
4778
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4779
	}
4780

    
4781
	/* DHCP Protocol Timings */
4782
	$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");
4783
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4784
		$pt_variable = "{$Protocol_Timing}";
4785
		${$pt_variable} = "";
4786
		if ($wancfg[$Protocol_Timing] != "") {
4787
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4788
		}
4789
	}
4790

    
4791
	$send_options = "";
4792
	if ($wancfg['adv_dhcp_send_options'] != '') {
4793
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp_send_options']);
4794
		foreach ($options as $option) {
4795
			$send_options .= "\tsend " . trim($option) . ";\n";
4796
		}
4797
	}
4798

    
4799
	$request_options = "";
4800
	if ($wancfg['adv_dhcp_request_options'] != '') {
4801
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4802
	}
4803

    
4804
	$required_options = "";
4805
	if ($wancfg['adv_dhcp_required_options'] != '') {
4806
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4807
	}
4808

    
4809
	$option_modifiers = "";
4810
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4811
		$modifiers = DHCP_Config_Option_Split($wancfg['adv_dhcp_option_modifiers']);
4812
		foreach ($modifiers as $modifier) {
4813
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4814
		}
4815
	}
4816

    
4817
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4818
	$dhclientconf .= "\n";
4819
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4820
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4821
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4822
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4823
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4824
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4825
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4826
	$dhclientconf .= "\n";
4827
	$dhclientconf .= "# DHCP Protocol Options\n";
4828
	$dhclientconf .= "{$hostname}";
4829
	$dhclientconf .= "{$send_options}";
4830
	$dhclientconf .= "{$request_options}";
4831
	$dhclientconf .= "{$required_options}";
4832
	$dhclientconf .= "{$option_modifiers}";
4833
	$dhclientconf .= "\n";
4834
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4835
		$dhclientconf .= "reject {$wancfg['dhcprejectfrom']};\n";
4836
	}
4837
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
4838
	$dhclientconf .= "}\n";
4839

    
4840
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4841

    
4842
	return $dhclientconf;
4843
}
4844

    
4845
function DHCP_Config_Option_Split($option_string) {
4846
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4847
	return $matches ? $matches[0] : [];
4848
}
4849

    
4850
function DHCP_Config_File_Override($wancfg, $wanif) {
4851

    
4852
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4853

    
4854
	if ($dhclientconf === false) {
4855
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $wancfg['adv_dhcp_config_file_override_path']));
4856
		return '';
4857
	} else {
4858
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4859
	}
4860
}
4861

    
4862

    
4863
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4864

    
4865
	/* Apply Interface Substitutions */
4866
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4867

    
4868
	/* Apply Hostname Substitutions */
4869
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4870

    
4871
	/* Arrays of MAC Address Types, Cases, Delimiters */
4872
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4873
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4874
	$various_mac_cases      = array("U", "L");
4875
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4876

    
4877
	/* Apply MAC Address Substitutions */
4878
	foreach ($various_mac_types as $various_mac_type) {
4879
		foreach ($various_mac_cases as $various_mac_case) {
4880
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4881

    
4882
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4883
				if ($res !== false) {
4884

    
4885
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4886
					if ("$various_mac_case" == "U") {
4887
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4888
					}
4889
					if ("$various_mac_case" == "L") {
4890
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4891
					}
4892

    
4893
					if ("$various_mac_type" == "mac_addr_hex") {
4894
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4895
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4896
						$dhcpclientconf_mac_hex = "";
4897
						$delimiter = "";
4898
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4899
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4900
							$delimiter = ":";
4901
						}
4902
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4903
					}
4904

    
4905
					/* MAC Address Delimiter Substitutions */
4906
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4907

    
4908
					/* Apply MAC Address Substitutions */
4909
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4910
				}
4911
			}
4912
		}
4913
	}
4914

    
4915
	return $dhclientconf;
4916
}
4917

    
4918
function interfaces_group_setup() {
4919
	global $config;
4920

    
4921
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4922
		return;
4923
	}
4924

    
4925
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4926
		interface_group_setup($groupar);
4927
	}
4928

    
4929
	return;
4930
}
4931

    
4932
function interface_group_setup(&$groupname /* The parameter is an array */) {
4933
	global $config;
4934

    
4935
	if (!is_array($groupname)) {
4936
		return;
4937
	}
4938
	$members = explode(" ", $groupname['members']);
4939
	foreach ($members as $ifs) {
4940
		$realif = get_real_interface($ifs);
4941
		if ($realif && does_interface_exist($realif)) {
4942
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4943
		}
4944
	}
4945

    
4946
	return;
4947
}
4948

    
4949
function is_interface_group($if) {
4950
	global $config;
4951

    
4952
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4953
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4954
			if ($groupentry['ifname'] === $if) {
4955
				return true;
4956
			}
4957
		}
4958
	}
4959

    
4960
	return false;
4961
}
4962

    
4963
function interface_group_add_member($interface, $groupname) {
4964
	$interface = get_real_interface($interface);
4965
	if (does_interface_exist($interface)) {
4966
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4967
	}
4968
}
4969

    
4970
/* COMPAT Function */
4971
function convert_friendly_interface_to_real_interface_name($interface) {
4972
	return get_real_interface($interface);
4973
}
4974

    
4975
/* COMPAT Function */
4976
function get_real_wan_interface($interface = "wan") {
4977
	return get_real_interface($interface);
4978
}
4979

    
4980
/* COMPAT Function */
4981
function get_current_wan_address($interface = "wan") {
4982
	return get_interface_ip($interface);
4983
}
4984

    
4985
/*
4986
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4987
 */
4988
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4989
	global $config;
4990

    
4991
	/* XXX: For speed reasons reference directly the interface array */
4992
	$ifdescrs = &$config['interfaces'];
4993
	//$ifdescrs = get_configured_interface_list(true);
4994

    
4995
	foreach ($ifdescrs as $if => $ifname) {
4996
		if ($if == $interface || $ifname['if'] == $interface) {
4997
			return $if;
4998
		}
4999

    
5000
		if (get_real_interface($if) == $interface) {
5001
			return $if;
5002
		}
5003

    
5004
		if ($checkparent == false) {
5005
			continue;
5006
		}
5007

    
5008
		$int = get_parent_interface($if, true);
5009
		if (is_array($int)) {
5010
			foreach ($int as $iface) {
5011
				if ($iface == $interface) {
5012
					return $if;
5013
				}
5014
			}
5015
		}
5016
	}
5017

    
5018
	if ($interface == "enc0") {
5019
		return 'IPsec';
5020
	}
5021
}
5022

    
5023
/* attempt to resolve interface to friendly descr */
5024
function convert_friendly_interface_to_friendly_descr($interface) {
5025
	global $config;
5026

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

    
5080
	return $ifdesc;
5081
}
5082

    
5083
function convert_real_interface_to_friendly_descr($interface) {
5084

    
5085
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5086

    
5087
	if (!empty($ifdesc)) {
5088
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5089
	}
5090

    
5091
	return $interface;
5092
}
5093

    
5094
/*
5095
 *  get_parent_interface($interface):
5096
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5097
 *				or virtual interface (i.e. vlan)
5098
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5099
 *			-- returns $interface passed in if $interface parent is not found
5100
 *			-- returns empty array if an invalid interface is passed
5101
 *	(Only handles ppps and vlans now.)
5102
 */
5103
function get_parent_interface($interface, $avoidrecurse = false) {
5104
	global $config;
5105

    
5106
	$parents = array();
5107
	//Check that we got a valid interface passed
5108
	$realif = get_real_interface($interface);
5109
	if ($realif == NULL) {
5110
		return $parents;
5111
	}
5112

    
5113
	// If we got a real interface, find it's friendly assigned name
5114
	if ($interface == $realif && $avoidrecurse == false) {
5115
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5116
	}
5117

    
5118
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5119
		$ifcfg = $config['interfaces'][$interface];
5120
		switch ($ifcfg['ipaddr']) {
5121
			case "ppp":
5122
			case "pppoe":
5123
			case "pptp":
5124
			case "l2tp":
5125
				if (empty($parents)) {
5126
					if (is_array($config['ppps']['ppp'])) {
5127
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5128
							if ($ifcfg['if'] == $ppp['if']) {
5129
								$ports = explode(',', $ppp['ports']);
5130
								foreach ($ports as $pid => $parent_if) {
5131
									$parents[$pid] = get_real_interface($parent_if);
5132
								}
5133
								break;
5134
							}
5135
						}
5136
					}
5137
				}
5138
				break;
5139
			case "dhcp":
5140
			case "static":
5141
			default:
5142
				// Handle _vlans
5143
				$vlan = interface_is_vlan($ifcfg['if']);
5144
				if ($vlan != NULL) {
5145
					$parents[0] = $vlan['if'];
5146
				}
5147
				break;
5148
		}
5149
	}
5150

    
5151
	if (empty($parents)) {
5152
		// Handle _vlans not assigned to an interface
5153
		$vlan = interface_is_vlan($realif);
5154
		if ($vlan != NULL) {
5155
			$parents[0] = $vlan['if'];
5156
		}
5157
	}
5158

    
5159
	if (empty($parents)) {
5160
		$parents[0] = $realif;
5161
	}
5162

    
5163
	return $parents;
5164
}
5165

    
5166
/*
5167
 *  get_parent_physical_interface($interface):
5168
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5169
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5170
 */
5171
function get_parent_physical_interface($interface) {
5172
	global $config;
5173

    
5174
	$realif = get_parent_interface($interface);
5175

    
5176
	if (substr($realif[0], 0, 4) == "lagg") {
5177
		foreach ($config['laggs']['lagg'] as $lagg) {
5178
			if ($realif[0] == $lagg['laggif']) {
5179
				return explode(",", $lagg['members']);
5180
			}
5181
		}
5182
	} else {
5183
		return $realif;
5184
	}
5185
}
5186

    
5187
function interface_is_wireless_clone($wlif) {
5188
	if (!stristr($wlif, "_wlan")) {
5189
		return false;
5190
	} else {
5191
		return true;
5192
	}
5193
}
5194

    
5195
function interface_get_wireless_base($wlif) {
5196
	if (!stristr($wlif, "_wlan")) {
5197
		return $wlif;
5198
	} else {
5199
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5200
	}
5201
}
5202

    
5203
function interface_get_wireless_clone($wlif) {
5204
	if (!stristr($wlif, "_wlan")) {
5205
		return $wlif . "_wlan0";
5206
	} else {
5207
		return $wlif;
5208
	}
5209
}
5210

    
5211
function interface_list_wireless() {
5212
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5213

    
5214
	$result = array();
5215
	foreach ($portlist as $port) {
5216
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5217
			continue;
5218
		}
5219

    
5220
		$desc = $port . " ( " . get_single_sysctl(
5221
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5222

    
5223
		$result[] = array(
5224
		    "if" => $port,
5225
		    "descr" => $desc
5226
		);
5227
	}
5228

    
5229
	return $result;
5230
}
5231

    
5232
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
5233
	global $config, $g;
5234

    
5235
	$wanif = NULL;
5236

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

    
5279
			if (empty($config['interfaces'][$interface])) {
5280
				break;
5281
			}
5282

    
5283
			$cfg = &$config['interfaces'][$interface];
5284

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

    
5342
	return $wanif;
5343
}
5344

    
5345
/* Guess the physical interface by providing a IP address */
5346
function guess_interface_from_ip($ipaddress) {
5347

    
5348
	$family = '';
5349
	if (is_ipaddrv4($ipaddress)) {
5350
		$family = 'inet';
5351
	}
5352
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5353
		$family = 'inet6';
5354
	}
5355

    
5356
	if (empty($family)) {
5357
		return false;
5358
	}
5359

    
5360
	/* create a route table we can search */
5361
	$output = '';
5362
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
5363
	$output[0] = trim($output[0], " \n");
5364
	if (!empty($output[0])) {
5365
		return $output[0];
5366
	}
5367

    
5368
	return false;
5369
}
5370

    
5371
/*
5372
 * find_ip_interface($ip): return the interface where an ip is defined
5373
 *   (or if $bits is specified, where an IP within the subnet is defined)
5374
 */
5375
function find_ip_interface($ip, $bits = null) {
5376
	if (!is_ipaddr($ip)) {
5377
		return false;
5378
	}
5379

    
5380
	$isv6ip = is_ipaddrv6($ip);
5381

    
5382
	/* if list */
5383
	$ifdescrs = get_configured_interface_list();
5384

    
5385
	foreach ($ifdescrs as $ifdescr => $ifname) {
5386
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
5387
		if (is_null($ifip)) {
5388
			continue;
5389
		}
5390
		if (is_null($bits)) {
5391
			if ($ip == $ifip) {
5392
				$int = get_real_interface($ifname);
5393
				return $int;
5394
			}
5395
		} else {
5396
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
5397
				$int = get_real_interface($ifname);
5398
				return $int;
5399
			}
5400
		}
5401
	}
5402

    
5403
	return false;
5404
}
5405

    
5406
/*
5407
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5408
 *   (or if $bits is specified, where an IP within the subnet is found)
5409
 */
5410
function find_virtual_ip_alias($ip, $bits = null) {
5411
	global $config;
5412

    
5413
	if (!is_array($config['virtualip']['vip'])) {
5414
		return false;
5415
	}
5416
	if (!is_ipaddr($ip)) {
5417
		return false;
5418
	}
5419

    
5420
	$isv6ip = is_ipaddrv6($ip);
5421

    
5422
	foreach ($config['virtualip']['vip'] as $vip) {
5423
		if ($vip['mode'] === "ipalias") {
5424
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
5425
				continue;
5426
			}
5427
			if (is_null($bits)) {
5428
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
5429
					return $vip;
5430
				}
5431
			} else {
5432
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5433
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5434
					return $vip;
5435
				}
5436
			}
5437
		}
5438
	}
5439
	return false;
5440
}
5441

    
5442
function link_interface_to_track6($int, $action = "") {
5443
	global $config;
5444

    
5445
	if (empty($int)) {
5446
		return;
5447
	}
5448

    
5449
	if (is_array($config['interfaces'])) {
5450
		$list = array();
5451
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5452
			if (!isset($ifcfg['enable'])) {
5453
				continue;
5454
			}
5455
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5456
				if ($action == "update") {
5457
					interface_track6_configure($ifname, $ifcfg);
5458
				} else if ($action == "") {
5459
					$list[$ifname] = $ifcfg;
5460
				}
5461
			}
5462
		}
5463
		return $list;
5464
	}
5465
}
5466

    
5467
function interface_find_child_cfgmtu($realiface) {
5468
	global $config;
5469

    
5470
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5471
	$vlans = link_interface_to_vlans($realiface);
5472
	$qinqs = link_interface_to_qinqs($realiface);
5473
	$bridge = link_interface_to_bridge($realiface);
5474
	if (!empty($interface)) {
5475
		$gifs = link_interface_to_gif($interface);
5476
		$gres = link_interface_to_gre($interface);
5477
	} else {
5478
		$gifs = array();
5479
		$gres = array();
5480
	}
5481

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

    
5543
	return $mtu;
5544
}
5545

    
5546
function link_interface_to_vlans($int, $action = "") {
5547
	global $config;
5548

    
5549
	if (empty($int)) {
5550
		return;
5551
	}
5552

    
5553
	if (is_array($config['vlans']['vlan'])) {
5554
		$ifaces = array();
5555
		foreach ($config['vlans']['vlan'] as $vlan) {
5556
			if ($int == $vlan['if']) {
5557
				if ($action == "update") {
5558
					interfaces_bring_up($int);
5559
				} else {
5560
					$ifaces[$vlan['tag']] = $vlan;
5561
				}
5562
			}
5563
		}
5564
		if (!empty($ifaces)) {
5565
			return $ifaces;
5566
		}
5567
	}
5568
}
5569

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

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

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

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

    
5597
	$updatevips = false;
5598
	if (is_array($config['virtualip']['vip'])) {
5599
		$result = array();
5600
		foreach ($config['virtualip']['vip'] as $vip) {
5601
			if (substr($vip['interface'], 0, 4) == "_vip") {
5602
				$iface = get_configured_vip_interface($vip['interface']);
5603
			} else {
5604
				$iface = $vip['interface'];
5605
			}
5606
			if ($int != $iface) {
5607
				continue;
5608
			}
5609
			if ($action == "update") {
5610
				$updatevips = true;
5611
			} else {
5612
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5613
				    substr($vip['interface'], 0, 4) == "_vip") {
5614
					$result[] = $vip;
5615
				}
5616
			}
5617
		}
5618
		if ($updatevips === true) {
5619
			interfaces_vips_configure($int);
5620
		}
5621
		return $result;
5622
	}
5623

    
5624
	return NULL;
5625
}
5626

    
5627
/****f* interfaces/link_interface_to_bridge
5628
 * NAME
5629
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5630
 * INPUTS
5631
 *   $ip
5632
 * RESULT
5633
 *   bridge[0-99]
5634
 ******/
5635
function link_interface_to_bridge($int) {
5636
	global $config;
5637

    
5638
	if (is_array($config['bridges']['bridged'])) {
5639
		foreach ($config['bridges']['bridged'] as $bridge) {
5640
			if (in_array($int, explode(',', $bridge['members']))) {
5641
				return "{$bridge['bridgeif']}";
5642
			}
5643
		}
5644
	}
5645
}
5646

    
5647
function link_interface_to_group($int) {
5648
	global $config;
5649

    
5650
	$result = array();
5651

    
5652
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5653
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5654
			if (in_array($int, explode(" ", $group['members']))) {
5655
				$result[$group['ifname']] = $int;
5656
			}
5657
		}
5658
	}
5659

    
5660
	return $result;
5661
}
5662

    
5663
function link_interface_to_gre($interface) {
5664
	global $config;
5665

    
5666
	$result = array();
5667

    
5668
	if (is_array($config['gres']['gre'])) {
5669
		foreach ($config['gres']['gre'] as $gre) {
5670
			if ($gre['if'] == $interface) {
5671
				$result[] = $gre;
5672
			}
5673
		}
5674
	}
5675

    
5676
	return $result;
5677
}
5678

    
5679
function link_interface_to_gif($interface) {
5680
	global $config;
5681

    
5682
	$result = array();
5683

    
5684
	if (is_array($config['gifs']['gif'])) {
5685
		foreach ($config['gifs']['gif'] as $gif) {
5686
			if ($gif['if'] == $interface) {
5687
				$result[] = $gif;
5688
			}
5689
		}
5690
	}
5691

    
5692
	return $result;
5693
}
5694

    
5695
/*
5696
 * find_interface_ip($interface): return the interface ip (first found)
5697
 */
5698
function find_interface_ip($interface, $flush = false) {
5699
	global $interface_ip_arr_cache;
5700
	global $interface_sn_arr_cache;
5701

    
5702
	$interface = str_replace("\n", "", $interface);
5703

    
5704
	if (!does_interface_exist($interface)) {
5705
		return;
5706
	}
5707

    
5708
	/* Setup IP cache */
5709
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5710
		if (file_exists("/var/db/${interface}_ip")) {
5711
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
5712
			$ifaddrs = pfSense_getall_interface_addresses($interface);
5713
			foreach ($ifaddrs as $ifaddr) {
5714
				list($ip, $mask) = explode("/", $ifaddr);
5715
				if ($ip == $ifip) {
5716
					$interface_ip_arr_cache[$interface] = $ip;
5717
					$interface_sn_arr_cache[$interface] = $mask;
5718
					break;
5719
				}
5720
			}
5721
		}
5722
		if (!isset($interface_ip_arr_cache[$interface])) {
5723
			$ifinfo = pfSense_get_interface_addresses($interface);
5724
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5725
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5726
		}
5727
	}
5728

    
5729
	return $interface_ip_arr_cache[$interface];
5730
}
5731

    
5732
/*
5733
 * find_interface_ipv6($interface): return the interface ip (first found)
5734
 */
5735
function find_interface_ipv6($interface, $flush = false) {
5736
	global $interface_ipv6_arr_cache;
5737
	global $interface_snv6_arr_cache;
5738
	global $config;
5739

    
5740
	$interface = trim($interface);
5741
	$interface = get_real_interface($interface);
5742

    
5743
	if (!does_interface_exist($interface)) {
5744
		return;
5745
	}
5746

    
5747
	/* Setup IP cache */
5748
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5749
		$ifinfo = pfSense_get_interface_addresses($interface);
5750
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5751
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5752
	}
5753

    
5754
	return $interface_ipv6_arr_cache[$interface];
5755
}
5756

    
5757
/*
5758
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5759
 */
5760
function find_interface_ipv6_ll($interface, $flush = false) {
5761
	global $interface_llv6_arr_cache;
5762
	global $config;
5763

    
5764
	$interface = str_replace("\n", "", $interface);
5765

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

    
5770
	/* Setup IP cache */
5771
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5772
		$ifinfo = pfSense_getall_interface_addresses($interface);
5773
		foreach ($ifinfo as $line) {
5774
			if (strstr($line, ":")) {
5775
				$parts = explode("/", $line);
5776
				if (is_linklocal($parts[0])) {
5777
					$ifinfo['linklocal'] = $parts[0];
5778
				}
5779
			}
5780
		}
5781
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5782
	}
5783
	return $interface_llv6_arr_cache[$interface];
5784
}
5785

    
5786
function find_interface_subnet($interface, $flush = false) {
5787
	global $interface_sn_arr_cache;
5788
	global $interface_ip_arr_cache;
5789

    
5790
	$interface = str_replace("\n", "", $interface);
5791
	if (does_interface_exist($interface) == false) {
5792
		return;
5793
	}
5794

    
5795
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5796
		$ifinfo = pfSense_get_interface_addresses($interface);
5797
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5798
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5799
	}
5800

    
5801
	return $interface_sn_arr_cache[$interface];
5802
}
5803

    
5804
function find_interface_subnetv6($interface, $flush = false) {
5805
	global $interface_snv6_arr_cache;
5806
	global $interface_ipv6_arr_cache;
5807

    
5808
	$interface = str_replace("\n", "", $interface);
5809
	if (does_interface_exist($interface) == false) {
5810
		return;
5811
	}
5812

    
5813
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5814
		$ifinfo = pfSense_get_interface_addresses($interface);
5815
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5816
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5817
	}
5818

    
5819
	return $interface_snv6_arr_cache[$interface];
5820
}
5821

    
5822
function ip_in_interface_alias_subnet($interface, $ipalias) {
5823
	global $config;
5824

    
5825
	if (empty($interface) || !is_ipaddr($ipalias)) {
5826
		return false;
5827
	}
5828
	if (is_array($config['virtualip']['vip'])) {
5829
		foreach ($config['virtualip']['vip'] as $vip) {
5830
			switch ($vip['mode']) {
5831
				case "ipalias":
5832
					if ($vip['interface'] <> $interface) {
5833
						break;
5834
					}
5835
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5836
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5837
						return true;
5838
					}
5839
					break;
5840
			}
5841
		}
5842
	}
5843

    
5844
	return false;
5845
}
5846

    
5847
function get_possible_listen_ips($include_ipv6_link_local=false) {
5848

    
5849
	$interfaces = get_configured_interface_with_descr();
5850
	foreach ($interfaces as $iface => $ifacename) {
5851
		if ($include_ipv6_link_local) {
5852
			/* This is to avoid going though added ll below */
5853
			if (substr($iface, 0, 5) == '_lloc') {
5854
				continue;
5855
			}
5856
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5857
			if (!empty($llip)) {
5858
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5859
			}
5860
		}
5861
	}
5862
	$viplist = get_configured_vip_list();
5863
	foreach ($viplist as $vip => $address) {
5864
		$interfaces[$vip] = $address;
5865
		if (get_vip_descr($address)) {
5866
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5867
		}
5868
	}
5869

    
5870
	$interfaces['lo0'] = 'Localhost';
5871

    
5872
	return $interfaces;
5873
}
5874

    
5875
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5876
	global $config;
5877

    
5878
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5879
	foreach (array('server', 'client') as $mode) {
5880
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5881
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5882
				if (!isset($setting['disable'])) {
5883
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5884
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5885
				}
5886
			}
5887
		}
5888
	}
5889
	return $sourceips;
5890
}
5891

    
5892
function get_interface_ip($interface = "wan") {
5893
	global $config;
5894
	
5895
	if (substr($interface, 0, 4) == '_vip') {
5896
		return get_configured_vip_ipv4($interface);
5897
	} else if (substr($interface, 0, 5) == '_lloc') {
5898
		/* No link-local address for v4. */
5899
		return null;
5900
	}
5901

    
5902
	$realif = get_failover_interface($interface, 'inet');
5903
	if (!$realif) {
5904
		return null;
5905
	}
5906

    
5907
	if (substr($realif, 0, 4) == '_vip') {
5908
		return get_configured_vip_ipv4($realif);
5909
	} else if (substr($realif, 0, 5) == '_lloc') {
5910
		/* No link-local address for v4. */
5911
		return null;
5912
	}
5913

    
5914
	if (is_array($config['interfaces'][$interface]) &&
5915
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5916
		return ($config['interfaces'][$interface]['ipaddr']);
5917
	}
5918

    
5919
	/*
5920
	 * Beaware that find_interface_ip() is our last option, it will
5921
	 * return the first IP it find on interface, not necessarily the
5922
	 * main IP address.
5923
	 */
5924
	$curip = find_interface_ip($realif);
5925
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5926
		return $curip;
5927
	} else {
5928
		return null;
5929
	}
5930
}
5931

    
5932
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5933
	global $config;
5934

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

    
5941
	$realif = get_failover_interface($interface, 'inet6');
5942
	if (!$realif) {
5943
		return null;
5944
	}
5945

    
5946
	if (substr($realif, 0, 4) == '_vip') {
5947
		return get_configured_vip_ipv6($realif);
5948
	} else if (substr($realif, 0, 5) == '_lloc') {
5949
		return get_interface_linklocal($realif);
5950
	}
5951

    
5952
	if (is_array($config['interfaces'][$interface])) {
5953
		switch ($config['interfaces'][$interface]['ipaddr']) {
5954
			case 'pppoe':
5955
			case 'l2tp':
5956
			case 'pptp':
5957
			case 'ppp':
5958
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5959
					$realif = get_real_interface($interface, 'inet6', false);
5960
				}
5961
				break;
5962
		}
5963
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5964
			return ($config['interfaces'][$interface]['ipaddrv6']);
5965
		}
5966
	}
5967

    
5968
	/*
5969
	 * Beaware that find_interface_ip() is our last option, it will
5970
	 * return the first IP it find on interface, not necessarily the
5971
	 * main IP address.
5972
	 */
5973
	$curip = find_interface_ipv6($realif, $flush);
5974
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5975
		return $curip;
5976
	} else {
5977
		/*
5978
		 * NOTE: On the case when only the prefix is requested,
5979
		 * the communication on WAN will be done over link-local.
5980
		 */
5981
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
5982
			$curip = find_interface_ipv6_ll($realif, $flush);
5983
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5984
				return $curip;
5985
			}
5986
		}
5987
	}
5988
	return null;
5989
}
5990

    
5991
function get_interface_linklocal($interface = "wan") {
5992

    
5993
	$realif = get_failover_interface($interface, 'inet6');
5994
	if (!$realif) {
5995
		return null;
5996
	}
5997

    
5998
	if (substr($interface, 0, 4) == '_vip') {
5999
		$realif = get_real_interface($interface);
6000
	} else if (substr($interface, 0, 5) == '_lloc') {
6001
		$realif = get_real_interface(substr($interface, 5));
6002
	}
6003

    
6004
	$curip = find_interface_ipv6_ll($realif);
6005
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6006
		return $curip;
6007
	} else {
6008
		return null;
6009
	}
6010
}
6011

    
6012
function get_interface_subnet($interface = "wan") {
6013

    
6014
	if (substr($interface, 0, 4) == '_vip') {
6015
		return (get_configured_vip_subnetv4($interface));
6016
	}
6017

    
6018
	$realif = get_real_interface($interface);
6019
	if (!$realif) {
6020
		return (NULL);
6021
	}
6022

    
6023
	$cursn = find_interface_subnet($realif);
6024
	if (!empty($cursn)) {
6025
		return ($cursn);
6026
	}
6027

    
6028
	return (NULL);
6029
}
6030

    
6031
function get_interface_subnetv6($interface = "wan") {
6032

    
6033
	if (substr($interface, 0, 4) == '_vip') {
6034
		return (get_configured_vip_subnetv6($interface));
6035
	} else if (substr($interface, 0, 5) == '_lloc') {
6036
		$interface = substr($interface, 5);
6037
	}
6038

    
6039
	$realif = get_real_interface($interface, 'inet6');
6040
	if (!$realif) {
6041
		return (NULL);
6042
	}
6043

    
6044
	$cursn = find_interface_subnetv6($realif);
6045
	if (!empty($cursn)) {
6046
		return ($cursn);
6047
	}
6048

    
6049
	return (NULL);
6050
}
6051

    
6052
/* return outside interfaces with a gateway */
6053
function get_interfaces_with_gateway() {
6054
	global $config;
6055

    
6056
	$ints = array();
6057

    
6058
	/* loop interfaces, check config for outbound */
6059
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6060
		switch ($ifname['ipaddr']) {
6061
			case "dhcp":
6062
			case "pppoe":
6063
			case "pptp":
6064
			case "l2tp":
6065
			case "ppp":
6066
				$ints[$ifdescr] = $ifdescr;
6067
				break;
6068
			default:
6069
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6070
				    !empty($ifname['gateway'])) {
6071
					$ints[$ifdescr] = $ifdescr;
6072
				}
6073
				break;
6074
		}
6075
	}
6076
	return $ints;
6077
}
6078

    
6079
/* return true if interface has a gateway */
6080
function interface_has_gateway($friendly) {
6081
	global $config;
6082

    
6083
	if (!empty($config['interfaces'][$friendly])) {
6084
		$ifname = &$config['interfaces'][$friendly];
6085
		switch ($ifname['ipaddr']) {
6086
			case "dhcp":
6087
			case "pppoe":
6088
			case "pptp":
6089
			case "l2tp":
6090
			case "ppp":
6091
				return true;
6092
			break;
6093
			default:
6094
				if (substr($ifname['if'], 0, 4) == "ovpn") {
6095
					return true;
6096
				}
6097
				$tunnelif = substr($ifname['if'], 0, 3);
6098
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6099
					if (find_interface_ip($ifname['if'])) {
6100
						return true;
6101
					}
6102
				}
6103
				if (!empty($ifname['gateway'])) {
6104
					return true;
6105
				}
6106
			break;
6107
		}
6108
	}
6109

    
6110
	return false;
6111
}
6112

    
6113
/* return true if interface has a gateway */
6114
function interface_has_gatewayv6($friendly) {
6115
	global $config;
6116

    
6117
	if (!empty($config['interfaces'][$friendly])) {
6118
		$ifname = &$config['interfaces'][$friendly];
6119
		switch ($ifname['ipaddrv6']) {
6120
			case "slaac":
6121
			case "dhcp6":
6122
			case "6to4":
6123
			case "6rd":
6124
				return true;
6125
				break;
6126
			default:
6127
				if (substr($ifname['if'], 0, 4) == "ovpn") {
6128
					return true;
6129
				}
6130
				$tunnelif = substr($ifname['if'], 0, 3);
6131
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6132
					if (find_interface_ipv6($ifname['if'])) {
6133
						return true;
6134
					}
6135
				}
6136
				if (!empty($ifname['gatewayv6'])) {
6137
					return true;
6138
				}
6139
				break;
6140
		}
6141
	}
6142

    
6143
	return false;
6144
}
6145

    
6146
/****f* interfaces/is_altq_capable
6147
 * NAME
6148
 *   is_altq_capable - Test if interface is capable of using ALTQ
6149
 * INPUTS
6150
 *   $int            - string containing interface name
6151
 * RESULT
6152
 *   boolean         - true or false
6153
 ******/
6154

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

    
6170
	$int_family = remove_ifindex($int);
6171

    
6172
	if (in_array($int_family, $capable)) {
6173
		return true;
6174
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6175
		return true;
6176
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6177
		return true;
6178
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6179
		return true;
6180
	} else {
6181
		return false;
6182
	}
6183
}
6184

    
6185
/****f* interfaces/is_interface_wireless
6186
 * NAME
6187
 *   is_interface_wireless - Returns if an interface is wireless
6188
 * RESULT
6189
 *   $tmp       - Returns if an interface is wireless
6190
 ******/
6191
function is_interface_wireless($interface) {
6192
	global $config, $g;
6193

    
6194
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6195
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6196
		if (preg_match($g['wireless_regex'], $interface)) {
6197
			if (isset($config['interfaces'][$friendly])) {
6198
				$config['interfaces'][$friendly]['wireless'] = array();
6199
			}
6200
			return true;
6201
		}
6202
		return false;
6203
	} else {
6204
		return true;
6205
	}
6206
}
6207

    
6208
function get_wireless_modes($interface) {
6209
	/* return wireless modes and channels */
6210
	$wireless_modes = array();
6211

    
6212
	$cloned_interface = get_real_interface($interface);
6213

    
6214
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6215
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6216
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6217
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6218

    
6219
		$interface_channels = "";
6220
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6221
		$interface_channel_count = count($interface_channels);
6222

    
6223
		$c = 0;
6224
		while ($c < $interface_channel_count) {
6225
			$channel_line = explode(",", $interface_channels["$c"]);
6226
			$wireless_mode = trim($channel_line[0]);
6227
			$wireless_channel = trim($channel_line[1]);
6228
			if (trim($wireless_mode) != "") {
6229
				/* if we only have 11g also set 11b channels */
6230
				if ($wireless_mode == "11g") {
6231
					if (!isset($wireless_modes["11b"])) {
6232
						$wireless_modes["11b"] = array();
6233
					}
6234
				} else if ($wireless_mode == "11g ht") {
6235
					if (!isset($wireless_modes["11b"])) {
6236
						$wireless_modes["11b"] = array();
6237
					}
6238
					if (!isset($wireless_modes["11g"])) {
6239
						$wireless_modes["11g"] = array();
6240
					}
6241
					$wireless_mode = "11ng";
6242
				} else if ($wireless_mode == "11a ht") {
6243
					if (!isset($wireless_modes["11a"])) {
6244
						$wireless_modes["11a"] = array();
6245
					}
6246
					$wireless_mode = "11na";
6247
				}
6248
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6249
			}
6250
			$c++;
6251
		}
6252
	}
6253
	return($wireless_modes);
6254
}
6255

    
6256
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6257
function get_wireless_channel_info($interface) {
6258
	$wireless_channels = array();
6259

    
6260
	$cloned_interface = get_real_interface($interface);
6261

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

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

    
6270
		foreach ($interface_channels as $channel_line) {
6271
			$channel_line = explode(",", $channel_line);
6272
			if (!isset($wireless_channels[$channel_line[0]])) {
6273
				$wireless_channels[$channel_line[0]] = $channel_line;
6274
			}
6275
		}
6276
	}
6277
	return($wireless_channels);
6278
}
6279

    
6280
function set_interface_mtu($interface, $mtu) {
6281

    
6282
	/* LAGG interface must be destroyed and re-created to change MTU */
6283
	if (substr($interface, 0, 4) == 'lagg') {
6284
		if (isset($config['laggs']['lagg']) &&
6285
		    is_array($config['laggs']['lagg'])) {
6286
			foreach ($config['laggs']['lagg'] as $lagg) {
6287
				if ($lagg['laggif'] == $interface) {
6288
					interface_lagg_configure($lagg);
6289
					break;
6290
				}
6291
			}
6292
		}
6293
	} else {
6294
		pfSense_interface_mtu($interface, $mtu);
6295
	}
6296
}
6297

    
6298
/****f* interfaces/get_interface_mtu
6299
 * NAME
6300
 *   get_interface_mtu - Return the mtu of an interface
6301
 * RESULT
6302
 *   $tmp       - Returns the mtu of an interface
6303
 ******/
6304
function get_interface_mtu($interface) {
6305
	$mtu = pfSense_interface_getmtu($interface);
6306
	return $mtu['mtu'];
6307
}
6308

    
6309
function get_interface_mac($interface) {
6310
	$macinfo = pfSense_get_interface_addresses($interface);
6311
	return $macinfo["macaddr"];
6312
}
6313

    
6314
function get_interface_vendor_mac($interface) {
6315
	$macinfo = pfSense_get_interface_addresses($interface);
6316
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] != "00:00:00:00:00:00") {
6317
		return ($macinfo["hwaddr"]);
6318
	}
6319
	return (NULL); 
6320
}
6321

    
6322
/****f* pfsense-utils/generate_random_mac_address
6323
 * NAME
6324
 *   generate_random_mac - generates a random mac address
6325
 * INPUTS
6326
 *   none
6327
 * RESULT
6328
 *   $mac - a random mac address
6329
 ******/
6330
function generate_random_mac_address() {
6331
	$mac = "02";
6332
	for ($x = 0; $x < 5; $x++) {
6333
		$mac .= ":" . dechex(rand(16, 255));
6334
	}
6335
	return $mac;
6336
}
6337

    
6338
/****f* interfaces/is_jumbo_capable
6339
 * NAME
6340
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
6341
 * INPUTS
6342
 *   $int             - string containing interface name
6343
 * RESULT
6344
 *   boolean          - true or false
6345
 ******/
6346
function is_jumbo_capable($iface) {
6347
	$iface = trim($iface);
6348
	$capable = pfSense_get_interface_addresses($iface);
6349

    
6350
	if (isset($capable['caps']['vlanmtu'])) {
6351
		return true;
6352
	}
6353

    
6354
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
6355
	if (substr($iface, 0, 4) == "lagg") {
6356
		return true;
6357
	}
6358

    
6359
	return false;
6360
}
6361

    
6362
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6363
	global $g;
6364

    
6365
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6366

    
6367
	if (!empty($iface) && !empty($pppif)) {
6368
		$cron_cmd = <<<EOD
6369
#!/bin/sh
6370
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
6371
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
6372

    
6373
EOD;
6374

    
6375
		@file_put_contents($cron_file, $cron_cmd);
6376
		chmod($cron_file, 0755);
6377
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
6378
	} else {
6379
		unlink_if_exists($cron_file);
6380
	}
6381
}
6382

    
6383
function get_interface_default_mtu($type = "ethernet") {
6384
	switch ($type) {
6385
		case "gre":
6386
			return 1476;
6387
			break;
6388
		case "gif":
6389
			return 1280;
6390
			break;
6391
		case "tun":
6392
		case "vlan":
6393
		case "tap":
6394
		case "ethernet":
6395
		default:
6396
			return 1500;
6397
			break;
6398
	}
6399

    
6400
	/* Never reached */
6401
	return 1500;
6402
}
6403

    
6404
function get_vip_descr($ipaddress) {
6405
	global $config;
6406

    
6407
	foreach ($config['virtualip']['vip'] as $vip) {
6408
		if ($vip['subnet'] == $ipaddress) {
6409
			return ($vip['descr']);
6410
		}
6411
	}
6412
	return "";
6413
}
6414

    
6415
function interfaces_staticarp_configure($if) {
6416
	global $config, $g;
6417
	if (isset($config['system']['developerspew'])) {
6418
		$mt = microtime();
6419
		echo "interfaces_staticarp_configure($if) being called $mt\n";
6420
	}
6421

    
6422
	$ifcfg = $config['interfaces'][$if];
6423

    
6424
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
6425
		return 0;
6426
	}
6427

    
6428
	/* Enable staticarp, if enabled */
6429
	if (isset($config['dhcpd'][$if]['staticarp'])) {
6430
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
6431
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6432
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
6433
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6434
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6435
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6436
				}
6437
			}
6438
		}
6439
	} else {
6440
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
6441
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6442
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
6443
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6444
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6445
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6446
				}
6447
			}
6448
		}
6449
	}
6450

    
6451
	return 0;
6452
}
6453

    
6454
function get_failover_interface($interface, $family = "all") {
6455
	global $config;
6456

    
6457
	/* shortcut to get_real_interface if we find it in the config */
6458
	if (is_array($config['interfaces'][$interface])) {
6459
		return get_real_interface($interface, $family);
6460
	}
6461

    
6462
	/* compare against gateway groups */
6463
	$a_groups = return_gateway_groups_array();
6464
	if (is_array($a_groups[$interface])) {
6465
		/* we found a gateway group, fetch the interface or vip */
6466
		if (!empty($a_groups[$interface][0]['vip'])) {
6467
			return $a_groups[$interface][0]['vip'];
6468
		} else {
6469
			return $a_groups[$interface][0]['int'];
6470
		}
6471
	}
6472
	/* fall through to get_real_interface */
6473
	/* XXX: Really needed? */
6474
	return get_real_interface($interface, $family);
6475
}
6476

    
6477
/****f* interfaces/interface_has_dhcp
6478
 * NAME
6479
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6480
 * INPUTS
6481
 *   interface or gateway group name
6482
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6483
 * RESULT
6484
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6485
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6486
 ******/
6487
function interface_has_dhcp($interface, $family = 4) {
6488
	global $config;
6489

    
6490
	if ($config['interfaces'][$interface]) {
6491
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6492
			return true;
6493
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6494
			return true;
6495
		} else {
6496
			return false;
6497
		}
6498
	}
6499

    
6500
	if (!is_array($config['gateways']['gateway_group'])) {
6501
		return false;
6502
	}
6503

    
6504
	if ($family == 6) {
6505
		$dhcp_string = "_DHCP6";
6506
	} else {
6507
		$dhcp_string = "_DHCP";
6508
	}
6509

    
6510
	foreach ($config['gateways']['gateway_group'] as $group) {
6511
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6512
			continue;
6513
		}
6514
		foreach ($group['item'] as $item) {
6515
			$item_data = explode("|", $item);
6516
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6517
				return true;
6518
			}
6519
		}
6520
	}
6521

    
6522
	return false;
6523
}
6524

    
6525
function remove_ifindex($ifname) {
6526
	return preg_replace("/[0-9]+$/", "", $ifname);
6527
}
6528

    
6529
?>
(20-20/54)