Project

General

Profile

Download (166 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	interfaces.inc
4
	Copyright (C) 2004-2008 Scott Ullrich
5
	Copyright (C) 2008-2009 Ermal Luçi
6
	All rights reserved.
7

    
8
	function interfaces_wireless_configure is
9
	Copyright (C) 2005 Espen Johansen
10
	All rights reserved.
11

    
12
	originally part of m0n0wall (http://m0n0.ch/wall)
13
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
14
	All rights reserved.
15

    
16
	Redistribution and use in source and binary forms, with or without
17
	modification, are permitted provided that the following conditions are met:
18

    
19
	1. Redistributions of source code must retain the above copyright notices,
20
	   this list of conditions and the following disclaimer.
21

    
22
	2. Redistributions in binary form must reproduce the above copyright
23
	   notices, this list of conditions and the following disclaimer in the
24
	   documentation and/or other materials provided with the distribution.
25

    
26
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
27
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
28
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
	POSSIBILITY OF SUCH DAMAGE.
36

    
37
	pfSense_BUILDER_BINARIES:	/sbin/dhclient	/bin/sh	/usr/bin/grep	/usr/bin/xargs	/usr/bin/awk	/usr/local/sbin/choparp
38
	pfSense_BUILDER_BINARIES:	/sbin/ifconfig	/sbin/route	/usr/sbin/ngctl	/usr/sbin/arp	/bin/kill	/usr/local/sbin/mpd5
39
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/dhcp6c
40
	pfSense_MODULE:	interfaces
41

    
42
*/
43

    
44
/* include all configuration functions */
45
require_once("globals.inc");
46
require_once("util.inc");
47
require_once("gwlb.inc");
48

    
49
function interfaces_bring_up($interface) {
50
	if (!$interface) {
51
		log_error(gettext("interfaces_bring_up() was called but no variable defined."));
52
		log_error("Backtrace: " . debug_backtrace());
53
		return;
54
	}
55
	pfSense_interface_flags($interface, IFF_UP);
56
}
57

    
58
/*
59
 * Return the interface array
60
 */
61
function get_interface_arr($flush = false) {
62
	global $interface_arr_cache;
63

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

    
69
	return $interface_arr_cache;
70
}
71

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

    
79
	if (!$interface) {
80
		return false;
81
	}
82

    
83
	$ints = get_interface_arr($flush);
84
	if (in_array($interface, $ints)) {
85
		return true;
86
	} else {
87
		return false;
88
	}
89
}
90

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

    
98
	if (!$vip) {
99
		return false;
100
	}
101

    
102

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

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

    
125
	return false;
126
}
127

    
128
function interface_netgraph_needed($interface = "wan") {
129
	global $config;
130

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

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

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

    
186
function interfaces_loopback_configure() {
187
	global $g;
188

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

    
200
function interfaces_vlan_configure($realif = "") {
201
	global $config, $g;
202
	if (platform_booting()) {
203
		echo gettext("Configuring VLAN interfaces...");
204
	}
205
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
206
		foreach ($config['vlans']['vlan'] as $vlan) {
207
			if (empty($vlan['vlanif'])) {
208
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
209
			}
210
			if (!empty($realif) && $realif != $vlan['vlanif']) {
211
				continue;
212
			}
213

    
214
			/* XXX: Maybe we should report any errors?! */
215
			interface_vlan_configure($vlan);
216
		}
217
	}
218
	if (platform_booting()) {
219
		echo gettext("done.") . "\n";
220
	}
221
}
222

    
223
function interface_vlan_configure(&$vlan) {
224
	global $config, $g;
225

    
226
	if (!is_array($vlan)) {
227
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
228
		return;
229
	}
230
	$if = $vlan['if'];
231
	$vlanif = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
232
	$tag = $vlan['tag'];
233

    
234
	if (empty($if)) {
235
		log_error(gettext("interface_vlan_configure called with if undefined."));
236
		return;
237
	}
238

    
239
	/* make sure the parent interface is up */
240
	interfaces_bring_up($if);
241
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
242
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
243

    
244
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
245
		interface_bring_down($vlanif, true);
246
	} else {
247
		$tmpvlanif = pfSense_interface_create("vlan");
248
		pfSense_interface_rename($tmpvlanif, $vlanif);
249
		pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
250
	}
251

    
252
	pfSense_vlan_create($vlanif, $if, $tag);
253

    
254
	interfaces_bring_up($vlanif);
255

    
256
	/* invalidate interface cache */
257
	get_interface_arr(true);
258

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

    
262
	return $vlanif;
263
}
264

    
265
function interface_qinq_configure(&$vlan, $fd = NULL) {
266
	global $config, $g;
267

    
268
	if (!is_array($vlan)) {
269
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
270
		return;
271
	}
272

    
273
	$qinqif = $vlan['if'];
274
	$tag = $vlan['tag'];
275
	if (empty($qinqif)) {
276
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
277
		return;
278
	}
279

    
280
	if (!does_interface_exist($qinqif)) {
281
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
282
		return;
283
	}
284

    
285
	$vlanif = interface_vlan_configure($vlan);
286

    
287
	if ($fd == NULL) {
288
		$exec = true;
289
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
290
	} else {
291
		$exec = false;
292
	}
293
	/* make sure the parent is converted to ng_vlan(4) and is up */
294
	interfaces_bring_up($qinqif);
295

    
296
	pfSense_ngctl_attach(".", $qinqif);
297
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
298
		fwrite($fd, "shutdown {$qinqif}qinq:\n");
299
		exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
300
		if (empty($result)) {
301
			fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
302
			fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
303
			fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
304
		}
305
	} else {
306
		fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
307
		fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
308
		fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
309
	}
310

    
311
	/* invalidate interface cache */
312
	get_interface_arr(true);
313

    
314
	if (!stristr($qinqif, "_vlan")) {
315
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
316
	}
317

    
318
	$macaddr = get_interface_mac($qinqif);
319
	if (!empty($vlan['members'])) {
320
		$members = explode(" ", $vlan['members']);
321
		foreach ($members as $qtag) {
322
			$qinq = array();
323
			$qinq['tag'] = $qtag;
324
			$qinq['if'] = $vlanif;
325
			interface_qinq2_configure($qinq, $fd, $macaddr);
326
		}
327
	}
328
	if ($exec == true) {
329
		fclose($fd);
330
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
331
	}
332

    
333
	interfaces_bring_up($qinqif);
334
	if (!empty($vlan['members'])) {
335
		$members = explode(" ", $vlan['members']);
336
		foreach ($members as $qif) {
337
			interfaces_bring_up("{$vlanif}_{$qif}");
338
		}
339
	}
340

    
341
	return $vlanif;
342
}
343

    
344
function interfaces_qinq_configure() {
345
	global $config, $g;
346
	if (platform_booting()) {
347
		echo gettext("Configuring QinQ interfaces...");
348
	}
349
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
350
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
351
			/* XXX: Maybe we should report any errors?! */
352
			interface_qinq_configure($qinq);
353
		}
354
	}
355
	if (platform_booting()) {
356
		echo gettext("done.") . "\n";
357
	}
358
}
359

    
360
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
361
	global $config, $g;
362

    
363
	if (!is_array($qinq)) {
364
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
365
		return;
366
	}
367

    
368
	$if = $qinq['if'];
369
	$tag = $qinq['tag'];
370
	$vlanif = "{$if}_{$tag}";
371
	if (empty($if)) {
372
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
373
		return;
374
	}
375

    
376
	fwrite($fd, "shutdown {$if}h{$tag}:\n");
377
	fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
378
	fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
379
	fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
380
	fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
381
	fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
382

    
383
	/* invalidate interface cache */
384
	get_interface_arr(true);
385

    
386
	return $vlanif;
387
}
388

    
389
function interfaces_create_wireless_clones() {
390
	global $config, $g;
391

    
392
	if (platform_booting()) {
393
		echo gettext("Creating wireless clone interfaces...");
394
	}
395

    
396
	$iflist = get_configured_interface_list();
397

    
398
	foreach ($iflist as $if) {
399
		$realif = $config['interfaces'][$if]['if'];
400
		if (is_interface_wireless($realif)) {
401
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
402
		}
403
	}
404

    
405
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
406
		foreach ($config['wireless']['clone'] as $clone) {
407
			if (empty($clone['cloneif'])) {
408
				continue;
409
			}
410
			if (does_interface_exist($clone['cloneif'])) {
411
				continue;
412
			}
413
			/* XXX: Maybe we should report any errors?! */
414
			interface_wireless_clone($clone['cloneif'], $clone);
415
		}
416
	}
417
	if (platform_booting()) {
418
		echo gettext("done.") . "\n";
419
	}
420

    
421
}
422

    
423
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
424
	global $config;
425

    
426
	$i = 0;
427
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
428
		foreach ($config['bridges']['bridged'] as $bridge) {
429
			if (empty($bridge['bridgeif'])) {
430
				$bridge['bridgeif'] = "bridge{$i}";
431
			}
432
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
433
				continue;
434
			}
435

    
436
			if ($checkmember == 1) {
437
				/* XXX: It should not be possible no? */
438
				if (strstr($bridge['if'], '_vip')) {
439
					continue;
440
				}
441
				$members = explode(',', $bridge['members']);
442
				foreach ($members as $member) {
443
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6") {
444
						continue 2;
445
					}
446
				}
447
			}
448
			else if ($checkmember == 2) {
449
				$members = explode(',', $bridge['members']);
450
				foreach ($members as $member) {
451
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6") {
452
						continue 2;
453
					}
454
				}
455
			}
456
			/* XXX: Maybe we should report any errors?! */
457
			interface_bridge_configure($bridge, $checkmember);
458
			$i++;
459
		}
460
	}
461
}
462

    
463
function interface_bridge_configure(&$bridge, $checkmember = 0) {
464
	global $config, $g;
465

    
466
	if (!is_array($bridge)) {
467
		return;
468
	}
469

    
470
	if (empty($bridge['members'])) {
471
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
472
		return;
473
	}
474

    
475
	$members = explode(',', $bridge['members']);
476
	if (!count($members)) {
477
		return;
478
	}
479

    
480
	/* Calculate smaller mtu and enforce it */
481
	$smallermtu = 0;
482
	$commonrx = true;
483
	$commontx = true;
484
	$foundgif = false;
485
	foreach ($members as $member) {
486
		$realif = get_real_interface($member);
487
		$mtu = get_interface_mtu($realif);
488
		if (substr($realif, 0, 3) == "gif") {
489
			$foundgif = true;
490
			if ($checkmember == 1) {
491
				return;
492
			}
493
			if ($mtu <= 1500) {
494
				continue;
495
			}
496
		}
497
		if ($smallermtu == 0 && !empty($mtu)) {
498
			$smallermtu = $mtu;
499
		} else if (!empty($mtu) && $mtu < $smallermtu) {
500
			$smallermtu = $mtu;
501
		}
502
	}
503
	if ($foundgif == false && $checkmember == 2) {
504
		return;
505
	}
506

    
507
	/* Just in case anything is not working well */
508
	if ($smallermtu == 0) {
509
		$smallermtu = 1500;
510
	}
511

    
512
	if (platform_booting() || !empty($bridge['bridgeif'])) {
513
		pfSense_interface_destroy($bridge['bridgeif']);
514
		pfSense_interface_create($bridge['bridgeif']);
515
		$bridgeif = escapeshellarg($bridge['bridgeif']);
516
	} else {
517
		$bridgeif = pfSense_interface_create("bridge");
518
		$bridge['bridgeif'] = $bridgeif;
519
	}
520

    
521
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
522
	if ($bridgemtu > $smallermtu) {
523
		$smallermtu = $bridgemtu;
524
	}
525

    
526
	$checklist = get_configured_interface_list();
527

    
528
	/* Add interfaces to bridge */
529
	foreach ($members as $member) {
530
		if (empty($checklist[$member])) {
531
			continue;
532
		}
533
		$realif = get_real_interface($member);
534
		if (!$realif) {
535
			log_error(gettext("realif not defined in interfaces bridge - up"));
536
			continue;
537
		}
538
		/* make sure the parent interface is up */
539
		pfSense_interface_mtu($realif, $smallermtu);
540
		interfaces_bring_up($realif);
541
		enable_hardware_offloading($member);
542
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
543
	}
544

    
545
	if (isset($bridge['enablestp'])) {
546
		/* Choose spanning tree proto */
547
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
548

    
549
		if (!empty($bridge['stp'])) {
550
			$stpifs = explode(',', $bridge['stp']);
551
			foreach ($stpifs as $stpif) {
552
				$realif = get_real_interface($stpif);
553
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
554
			}
555
		}
556
		if (!empty($bridge['maxage'])) {
557
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
558
		}
559
		if (!empty($bridge['fwdelay'])) {
560
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
561
		}
562
		if (!empty($bridge['hellotime'])) {
563
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
564
		}
565
		if (!empty($bridge['priority'])) {
566
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
567
		}
568
		if (!empty($bridge['holdcnt'])) {
569
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
570
		}
571
		if (!empty($bridge['ifpriority'])) {
572
			$pconfig = explode(",", $bridge['ifpriority']);
573
			$ifpriority = array();
574
			foreach ($pconfig as $cfg) {
575
				$embcfg = explode_assoc(":", $cfg);
576
				foreach ($embcfg as $key => $value) {
577
					$ifpriority[$key] = $value;
578
				}
579
			}
580
			foreach ($ifpriority as $key => $value) {
581
				$realif = get_real_interface($key);
582
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
583
			}
584
		}
585
		if (!empty($bridge['ifpathcost'])) {
586
			$pconfig = explode(",", $bridge['ifpathcost']);
587
			$ifpathcost = array();
588
			foreach ($pconfig as $cfg) {
589
				$embcfg = explode_assoc(":", $cfg);
590
				foreach ($embcfg as $key => $value) {
591
					$ifpathcost[$key] = $value;
592
				}
593
			}
594
			foreach ($ifpathcost as $key => $value) {
595
				$realif = get_real_interface($key);
596
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
597
			}
598
		}
599
	}
600

    
601
	if ($bridge['maxaddr'] <> "") {
602
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
603
	}
604
	if ($bridge['timeout'] <> "") {
605
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
606
	}
607
	if ($bridge['span'] <> "") {
608
		$realif = get_real_interface($bridge['span']);
609
		mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
610
	}
611
	if (!empty($bridge['edge'])) {
612
		$edgeifs = explode(',', $bridge['edge']);
613
		foreach ($edgeifs as $edgeif) {
614
			$realif = get_real_interface($edgeif);
615
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
616
		}
617
	}
618
	if (!empty($bridge['autoedge'])) {
619
		$edgeifs = explode(',', $bridge['autoedge']);
620
		foreach ($edgeifs as $edgeif) {
621
			$realif = get_real_interface($edgeif);
622
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
623
		}
624
	}
625
	if (!empty($bridge['ptp'])) {
626
		$ptpifs = explode(',', $bridge['ptp']);
627
		foreach ($ptpifs as $ptpif) {
628
			$realif = get_real_interface($ptpif);
629
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
630
		}
631
	}
632
	if (!empty($bridge['autoptp'])) {
633
		$ptpifs = explode(',', $bridge['autoptp']);
634
		foreach ($ptpifs as $ptpif) {
635
			$realif = get_real_interface($ptpif);
636
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
637
		}
638
	}
639
	if (!empty($bridge['static'])) {
640
		$stickyifs = explode(',', $bridge['static']);
641
		foreach ($stickyifs as $stickyif) {
642
			$realif = get_real_interface($stickyif);
643
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
644
		}
645
	}
646
	if (!empty($bridge['private'])) {
647
		$privateifs = explode(',', $bridge['private']);
648
		foreach ($privateifs as $privateif) {
649
			$realif = get_real_interface($privateif);
650
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
651
		}
652
	}
653

    
654
	if ($bridge['bridgeif']) {
655
		interfaces_bring_up($bridge['bridgeif']);
656
	} else {
657
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
658
	}
659
}
660

    
661
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
662

    
663
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
664
		return;
665
	}
666

    
667
	if ($flagsapplied == false) {
668
		$mtu = get_interface_mtu($bridgeif);
669
		$mtum = get_interface_mtu($interface);
670
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
671
			pfSense_interface_mtu($interface, $mtu);
672
		}
673

    
674
		hardware_offloading_applyflags($interface);
675
		interfaces_bring_up($interface);
676
	}
677

    
678
	pfSense_bridge_add_member($bridgeif, $interface);
679
}
680

    
681
function interfaces_lagg_configure($realif = "") {
682
	global $config, $g;
683
	if (platform_booting()) {
684
		echo gettext("Configuring LAGG interfaces...");
685
	}
686
	$i = 0;
687
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
688
		foreach ($config['laggs']['lagg'] as $lagg) {
689
			if (empty($lagg['laggif'])) {
690
				$lagg['laggif'] = "lagg{$i}";
691
			}
692
			if (!empty($realif) && $realif != $lagg['laggif']) {
693
				continue;
694
			}
695
			/* XXX: Maybe we should report any errors?! */
696
			interface_lagg_configure($lagg);
697
			$i++;
698
		}
699
	}
700
	if (platform_booting()) {
701
		echo gettext("done.") . "\n";
702
	}
703
}
704

    
705
function interface_lagg_configure($lagg) {
706
	global $config, $g;
707

    
708
	if (!is_array($lagg)) {
709
		return -1;
710
	}
711

    
712
	$members = explode(',', $lagg['members']);
713
	if (!count($members)) {
714
		return -1;
715
	}
716

    
717
	if (platform_booting() || !(empty($lagg['laggif']))) {
718
		pfSense_interface_destroy($lagg['laggif']);
719
		pfSense_interface_create($lagg['laggif']);
720
		$laggif = $lagg['laggif'];
721
	} else {
722
		$laggif = pfSense_interface_create("lagg");
723
	}
724

    
725
	/* Check if MTU was defined for this lagg interface */
726
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
727
	if ($lagg_mtu == 0) {
728
		/* Calculate smaller mtu and enforce it */
729
		$smallermtu = 0;
730
		foreach ($members as $member) {
731
			$mtu = get_interface_mtu($member);
732
			if ($smallermtu == 0 && !empty($mtu)) {
733
				$smallermtu = $mtu;
734
			} else if (!empty($mtu) && $mtu < $smallermtu) {
735
				$smallermtu = $mtu;
736
			}
737
		}
738
		$lagg_mtu = $smallermtu;
739
	}
740

    
741
	/* Just in case anything is not working well */
742
	if ($lagg_mtu == 0) {
743
		$lagg_mtu = 1500;
744
	}
745

    
746
	foreach ($members as $member) {
747
		if (!does_interface_exist($member)) {
748
			continue;
749
		}
750
		/* make sure the parent interface is up */
751
		pfSense_interface_mtu($member, $lagg_mtu);
752
		interfaces_bring_up($member);
753
		hardware_offloading_applyflags($member);
754
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
755
	}
756
	pfSense_interface_capabilities($laggif, -$flags_off);
757
	pfSense_interface_capabilities($laggif, $flags_on);
758

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

    
761
	interfaces_bring_up($laggif);
762

    
763
	return $laggif;
764
}
765

    
766
function interfaces_gre_configure($checkparent = 0, $realif = "") {
767
	global $config;
768

    
769
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
770
		foreach ($config['gres']['gre'] as $i => $gre) {
771
			if (empty($gre['greif'])) {
772
				$gre['greif'] = "gre{$i}";
773
			}
774
			if (!empty($realif) && $realif != $gre['greif']) {
775
				continue;
776
			}
777

    
778
			if ($checkparent == 1) {
779
				if (substr($gre['if'], 0, 4) == '_vip') {
780
					continue;
781
				}
782
				if (substr($gre['if'], 0, 5) == '_lloc') {
783
					continue;
784
				}
785
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6") {
786
					continue;
787
				}
788
			} else if ($checkparent == 2) {
789
				if ((substr($gre['if'], 0, 4) != '_vip' && substr($gre['if'], 0, 5) != '_lloc') &&
790
				    (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")) {
791
					continue;
792
				}
793
			}
794
			/* XXX: Maybe we should report any errors?! */
795
			interface_gre_configure($gre);
796
		}
797
	}
798
}
799

    
800
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
801
function interface_gre_configure(&$gre, $grekey = "") {
802
	global $config, $g;
803

    
804
	if (!is_array($gre)) {
805
		return -1;
806
	}
807

    
808
	$realif = get_real_interface($gre['if']);
809
	$realifip = get_interface_ip($gre['if']);
810

    
811
	/* make sure the parent interface is up */
812
	interfaces_bring_up($realif);
813

    
814
	if (platform_booting() || !(empty($gre['greif']))) {
815
		pfSense_interface_destroy($gre['greif']);
816
		pfSense_interface_create($gre['greif']);
817
		$greif = $gre['greif'];
818
	} else {
819
		$greif = pfSense_interface_create("gre");
820
	}
821

    
822
	/* Do not change the order here for more see gre(4) NOTES section. */
823
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
824
	if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
825
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
826
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
827
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
828
	} else {
829
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
830
	}
831
	if (isset($gre['link0'])) {
832
		pfSense_interface_flags($greif, IFF_LINK0);
833
	}
834
	if (isset($gre['link1'])) {
835
		pfSense_interface_flags($greif, IFF_LINK1);
836
	}
837
	if (isset($gre['link2'])) {
838
		pfSense_interface_flags($greif, IFF_LINK2);
839
	}
840

    
841
	if ($greif) {
842
		interfaces_bring_up($greif);
843
	} else {
844
		log_error(gettext("Could not bring greif up -- variable not defined."));
845
	}
846

    
847
	if (isset($gre['link1']) && $gre['link1']) {
848
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
849
	}
850
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
851
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
852
	}
853
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
854
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
855
	}
856

    
857
	interfaces_bring_up($greif);
858

    
859
	return $greif;
860
}
861

    
862
function interfaces_gif_configure($checkparent = 0, $realif = "") {
863
	global $config;
864

    
865
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
866
		foreach ($config['gifs']['gif'] as $i => $gif) {
867
			if (empty($gif['gifif'])) {
868
				$gre['gifif'] = "gif{$i}";
869
			}
870
			if (!empty($realif) && $realif != $gif['gifif']) {
871
				continue;
872
			}
873

    
874
			if ($checkparent == 1) {
875
				if (substr($gif['if'], 0, 4) == '_vip') {
876
					continue;
877
				}
878
				if (substr($gif['if'], 0, 5) == '_lloc') {
879
					continue;
880
				}
881
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
882
					continue;
883
				}
884
			}
885
			else if ($checkparent == 2) {
886
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
887
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
888
					continue;
889
				}
890
			}
891
			/* XXX: Maybe we should report any errors?! */
892
			interface_gif_configure($gif);
893
		}
894
	}
895
}
896

    
897
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
898
function interface_gif_configure(&$gif, $gifkey = "") {
899
	global $config, $g;
900

    
901
	if (!is_array($gif)) {
902
		return -1;
903
	}
904

    
905
	$realif = get_real_interface($gif['if']);
906
	$ipaddr = get_interface_ip($gif['if']);
907

    
908
	if (is_ipaddrv4($gif['remote-addr'])) {
909
		if (is_ipaddrv4($ipaddr)) {
910
			$realifip = $ipaddr;
911
		} else {
912
			$realifip = get_interface_ip($gif['if']);
913
		}
914
		$realifgw = get_interface_gateway($gif['if']);
915
	} else if (is_ipaddrv6($gif['remote-addr'])) {
916
		if (is_ipaddrv6($ipaddr)) {
917
			$realifip = $ipaddr;
918
		} else {
919
			$realifip = get_interface_ipv6($gif['if']);
920
		}
921
		$realifgw = get_interface_gateway_v6($gif['if']);
922
	}
923
	/* make sure the parent interface is up */
924
	if ($realif) {
925
		interfaces_bring_up($realif);
926
	} else {
927
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
928
	}
929

    
930
	if (platform_booting() || !(empty($gif['gifif']))) {
931
		pfSense_interface_destroy($gif['gifif']);
932
		pfSense_interface_create($gif['gifif']);
933
		$gifif = $gif['gifif'];
934
	} else {
935
		$gifif = pfSense_interface_create("gif");
936
	}
937

    
938
	/* Do not change the order here for more see gif(4) NOTES section. */
939
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
940
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
941
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
942
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
943
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
944
	} else {
945
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
946
	}
947
	if (isset($gif['link0'])) {
948
		pfSense_interface_flags($gifif, IFF_LINK0);
949
	}
950
	if (isset($gif['link1'])) {
951
		pfSense_interface_flags($gifif, IFF_LINK1);
952
	}
953
	if ($gifif) {
954
		interfaces_bring_up($gifif);
955
	} else {
956
		log_error(gettext("could not bring gifif up -- variable not defined"));
957
	}
958

    
959
	if (!platform_booting()) {
960
		$iflist = get_configured_interface_list();
961
		foreach ($iflist as $ifname) {
962
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
963
				if (get_interface_gateway($ifname)) {
964
					system_routing_configure($ifname);
965
					break;
966
				}
967
				if (get_interface_gateway_v6($ifname)) {
968
					system_routing_configure($ifname);
969
					break;
970
				}
971
			}
972
		}
973
	}
974

    
975

    
976
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
977
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
978
	}
979
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
980
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
981
	}
982

    
983
	if (is_ipaddrv4($realifgw)) {
984
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
985
	}
986
	if (is_ipaddrv6($realifgw)) {
987
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
988
	}
989

    
990
	interfaces_bring_up($gifif);
991

    
992
	return $gifif;
993
}
994

    
995
function interfaces_configure() {
996
	global $config, $g;
997

    
998
	/* Set up our loopback interface */
999
	interfaces_loopback_configure();
1000

    
1001
	/* create the unconfigured wireless clones */
1002
	interfaces_create_wireless_clones();
1003

    
1004
	/* set up LAGG virtual interfaces */
1005
	interfaces_lagg_configure();
1006

    
1007
	/* set up VLAN virtual interfaces */
1008
	interfaces_vlan_configure();
1009

    
1010
	interfaces_qinq_configure();
1011

    
1012
	$iflist = get_configured_interface_with_descr();
1013
	$delayed_list = array();
1014
	$bridge_list = array();
1015
	$track6_list = array();
1016

    
1017
	/* This is needed to speedup interfaces on bootup. */
1018
	$reload = false;
1019
	if (!platform_booting()) {
1020
		$reload = true;
1021
	}
1022

    
1023
	foreach ($iflist as $if => $ifname) {
1024
		$realif = $config['interfaces'][$if]['if'];
1025
		if (strstr($realif, "bridge")) {
1026
			$bridge_list[$if] = $ifname;
1027
		} else if (strstr($realif, "gre")) {
1028
			$delayed_list[$if] = $ifname;
1029
		} else if (strstr($realif, "gif")) {
1030
			$delayed_list[$if] = $ifname;
1031
		} else if (strstr($realif, "ovpn")) {
1032
			//echo "Delaying OpenVPN interface configuration...done.\n";
1033
			continue;
1034
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1035
			$track6_list[$if] = $ifname;
1036
		} else {
1037
			if (platform_booting()) {
1038
				printf(gettext("Configuring %s interface..."), $ifname);
1039
			}
1040

    
1041
			if ($g['debug']) {
1042
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1043
			}
1044
			interface_configure($if, $reload);
1045
			if (platform_booting()) {
1046
				echo gettext("done.") . "\n";
1047
			}
1048
		}
1049
	}
1050

    
1051
	/*
1052
	 * NOTE: The following function parameter consists of
1053
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1054
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1055
	 */
1056

    
1057
	/* set up GRE virtual interfaces */
1058
	interfaces_gre_configure(1);
1059

    
1060
	/* set up GIF virtual interfaces */
1061
	interfaces_gif_configure(1);
1062

    
1063
	/* set up BRIDGe virtual interfaces */
1064
	interfaces_bridge_configure(1);
1065

    
1066
	foreach ($track6_list as $if => $ifname) {
1067
		if (platform_booting()) {
1068
			printf(gettext("Configuring %s interface..."), $ifname);
1069
		}
1070
		if ($g['debug']) {
1071
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1072
		}
1073

    
1074
		interface_configure($if, $reload);
1075

    
1076
		if (platform_booting()) {
1077
			echo gettext("done.") . "\n";
1078
		}
1079
	}
1080

    
1081
	/* bring up vip interfaces */
1082
	interfaces_vips_configure();
1083

    
1084
	/* set up GRE virtual interfaces */
1085
	interfaces_gre_configure(2);
1086

    
1087
	/* set up GIF virtual interfaces */
1088
	interfaces_gif_configure(2);
1089

    
1090
	foreach ($delayed_list as $if => $ifname) {
1091
		if (platform_booting()) {
1092
			printf(gettext("Configuring %s interface..."), $ifname);
1093
		}
1094
		if ($g['debug']) {
1095
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1096
		}
1097

    
1098
		interface_configure($if, $reload);
1099

    
1100
		if (platform_booting()) {
1101
			echo gettext("done.") . "\n";
1102
		}
1103
	}
1104

    
1105
	/* set up BRIDGe virtual interfaces */
1106
	interfaces_bridge_configure(2);
1107

    
1108
	foreach ($bridge_list as $if => $ifname) {
1109
		if (platform_booting()) {
1110
			printf(gettext("Configuring %s interface..."), $ifname);
1111
		}
1112
		if ($g['debug']) {
1113
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1114
		}
1115

    
1116
		interface_configure($if, $reload);
1117

    
1118
		if (platform_booting()) {
1119
			echo gettext("done.") . "\n";
1120
		}
1121
	}
1122

    
1123
	/* configure interface groups */
1124
	interfaces_group_setup();
1125

    
1126
	if (!platform_booting()) {
1127
		/* reconfigure static routes (kernel may have deleted them) */
1128
		system_routing_configure();
1129

    
1130
		/* reload IPsec tunnels */
1131
		vpn_ipsec_configure();
1132

    
1133
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1134
		services_dhcpd_configure();
1135

    
1136
		/* restart dnsmasq or unbound */
1137
		if (isset($config['dnsmasq']['enable'])) {
1138
			services_dnsmasq_configure();
1139
		} elseif (isset($config['unbound']['enable'])) {
1140
			services_unbound_configure();
1141
		}
1142
	}
1143

    
1144
	return 0;
1145
}
1146

    
1147
function interface_reconfigure($interface = "wan", $reloadall = false) {
1148
	interface_bring_down($interface);
1149
	interface_configure($interface, $reloadall);
1150
}
1151

    
1152
function interface_vip_bring_down($vip) {
1153
	global $g;
1154

    
1155
	if (strpos($vip['interface'], '_vip')) {
1156
		if (is_ipaddrv6($vip['subnet'])) {
1157
			$family = 'inet6';
1158
		} else {
1159
			$family = 'inet';
1160
		}
1161

    
1162
		$carpvip = get_configured_carp_interface_list($vip['interface'], $family, 'vip');
1163
		$iface = $carpvip['interface'];
1164
	} else {
1165
		$iface = $vip['interface'];
1166
	}
1167

    
1168
	$vipif = get_real_interface($iface);
1169
	switch ($vip['mode']) {
1170
		case "proxyarp":
1171
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1172
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1173
			}
1174
			break;
1175
		case "ipalias":
1176
			if (does_interface_exist($vipif)) {
1177
				if (is_ipaddrv6($vip['subnet'])) {
1178
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1179
				} else {
1180
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1181
				}
1182
			}
1183
			break;
1184
		case "carp":
1185
			/* XXX: Is enough to delete ip address? */
1186
			if (does_interface_exist($vipif)) {
1187
				if (is_ipaddrv6($vip['subnet'])) {
1188
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1189
				} else {
1190
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1191
				}
1192
			}
1193
			break;
1194
	}
1195
}
1196

    
1197
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1198
	global $config, $g;
1199

    
1200
	if (!isset($config['interfaces'][$interface])) {
1201
		return;
1202
	}
1203

    
1204
	if ($g['debug']) {
1205
		log_error("Calling interface down for interface {$interface}, destroy is " . (($destroy) ? 'true' : 'false'));
1206
	}
1207

    
1208
	/*
1209
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1210
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1211
	 * Keep this in mind while doing changes here!
1212
	 */
1213
	if ($ifacecfg === false) {
1214
		$ifcfg = $config['interfaces'][$interface];
1215
		$ppps = $config['ppps']['ppp'];
1216
		$realif = get_real_interface($interface);
1217
		$realifv6 = get_real_interface($interface, "inet6", true);
1218
	} elseif (!is_array($ifacecfg)) {
1219
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1220
		$ifcfg = $config['interfaces'][$interface];
1221
		$ppps = $config['ppps']['ppp'];
1222
		$realif = get_real_interface($interface);
1223
		$realifv6 = get_real_interface($interface, "inet6", true);
1224
	} else {
1225
		$ifcfg = $ifacecfg['ifcfg'];
1226
		$ppps = $ifacecfg['ppps'];
1227
		if (isset($ifacecfg['ifcfg']['realif'])) {
1228
			$realif = $ifacecfg['ifcfg']['realif'];
1229
			/* XXX: Any better way? */
1230
			$realifv6 = $realif;
1231
		} else {
1232
			$realif = get_real_interface($interface);
1233
			$realifv6 = get_real_interface($interface, "inet6", true);
1234
		}
1235
	}
1236

    
1237
	switch ($ifcfg['ipaddr']) {
1238
		case "ppp":
1239
		case "pppoe":
1240
		case "pptp":
1241
		case "l2tp":
1242
			if (is_array($ppps) && count($ppps)) {
1243
				foreach ($ppps as $pppid => $ppp) {
1244
					if ($realif == $ppp['if']) {
1245
						if (isset($ppp['ondemand']) && !$destroy) {
1246
							send_event("interface reconfigure {$interface}");
1247
							break;
1248
						}
1249
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1250
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1251
							sleep(2);
1252
						}
1253
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1254
						break;
1255
					}
1256
				}
1257
			}
1258
			break;
1259
		case "dhcp":
1260
			kill_dhclient_process($realif);
1261
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1262
			if (does_interface_exist("$realif")) {
1263
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1264
				interface_ipalias_cleanup($interface);
1265
				if ($destroy == true) {
1266
					pfSense_interface_flags($realif, -IFF_UP);
1267
				}
1268
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1269
			}
1270
			break;
1271
		default:
1272
			if (does_interface_exist("$realif")) {
1273
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1274
				interface_ipalias_cleanup($interface);
1275
				if ($destroy == true) {
1276
					pfSense_interface_flags($realif, -IFF_UP);
1277
				}
1278
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1279
			}
1280
			break;
1281
	}
1282

    
1283
	$track6 = array();
1284
	switch ($ifcfg['ipaddrv6']) {
1285
		case "slaac":
1286
		case "dhcp6":
1287
			$pidv6 = find_dhcp6c_process($realif);
1288
			if ($pidv6) {
1289
				posix_kill($pidv6, SIGTERM);
1290
			}
1291
			sleep(3);
1292
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1293
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1294
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1295
			if (does_interface_exist($realifv6)) {
1296
				$ip6 = find_interface_ipv6($realifv6);
1297
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1298
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1299
				}
1300
				interface_ipalias_cleanup($interface, "inet6");
1301
				if ($destroy == true) {
1302
					pfSense_interface_flags($realif, -IFF_UP);
1303
				}
1304
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1305
			}
1306
			$track6 = link_interface_to_track6($interface);
1307
			break;
1308
		case "6rd":
1309
		case "6to4":
1310
			$realif = "{$interface}_stf";
1311
			if (does_interface_exist("$realif")) {
1312
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1313
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1314
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1315
					$destroy = true;
1316
				} else {
1317
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1318
					$ip6 = get_interface_ipv6($interface);
1319
					if (is_ipaddrv6($ip6)) {
1320
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1321
					}
1322
				}
1323
				interface_ipalias_cleanup($interface, "inet6");
1324
				if ($destroy == true) {
1325
					pfSense_interface_flags($realif, -IFF_UP);
1326
				}
1327
			}
1328
			$track6 = link_interface_to_track6($interface);
1329
			break;
1330
		default:
1331
			if (does_interface_exist("$realif")) {
1332
				$ip6 = get_interface_ipv6($interface);
1333
				if (is_ipaddrv6($ip6)) {
1334
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1335
				}
1336
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1337
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1338
				}
1339
				interface_ipalias_cleanup($interface, "inet6");
1340
				if ($destroy == true) {
1341
					pfSense_interface_flags($realif, -IFF_UP);
1342
				}
1343
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1344
			}
1345
			$track6 = link_interface_to_track6($interface);
1346
			break;
1347
	}
1348

    
1349
	if (!empty($track6) && is_array($track6)) {
1350
		if (!function_exists('services_dhcpd_configure')) {
1351
			require_once('services.inc');
1352
		}
1353
		/* Bring down radvd and dhcp6 on these interfaces */
1354
		services_dhcpd_configure('inet6', $track6);
1355
	}
1356

    
1357
	$old_router = '';
1358
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1359
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1360
	}
1361

    
1362
	/* remove interface up file if it exists */
1363
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1364
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1365
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1366
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1367
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1368
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1369
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1370

    
1371
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1372
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1373
	if (is_array($ifcfg['wireless'])) {
1374
		kill_hostapd($realif);
1375
		mwexec(kill_wpasupplicant($realif));
1376
	}
1377

    
1378
	if ($destroy == true) {
1379
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1380
			pfSense_interface_destroy($realif);
1381
		}
1382
	}
1383

    
1384
	return;
1385
}
1386

    
1387
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1388
	global $config;
1389
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1390
		unset($config["virtualip_carp_maintenancemode"]);
1391
		write_config("Leave CARP maintenance mode");
1392
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1393
		$config["virtualip_carp_maintenancemode"] = true;
1394
		write_config("Enter CARP maintenance mode");
1395
	}
1396

    
1397
	$viparr = &$config['virtualip']['vip'];
1398
	foreach ($viparr as $vip) {
1399
		if ($vip['mode'] == "carp") {
1400
			interface_carp_configure($vip);
1401
		}
1402
	}
1403
}
1404

    
1405
function interface_isppp_type($interface) {
1406
	global $config;
1407

    
1408
	if (!is_array($config['interfaces'][$interface])) {
1409
		return false;
1410
	}
1411

    
1412
	switch ($config['interfaces'][$interface]['ipaddr']) {
1413
		case 'pptp':
1414
		case 'l2tp':
1415
		case 'pppoe':
1416
		case 'ppp':
1417
			return true;
1418
			break;
1419
		default:
1420
			return false;
1421
			break;
1422
	}
1423
}
1424

    
1425
function interfaces_ptpid_used($ptpid) {
1426
	global $config;
1427

    
1428
	if (is_array($config['ppps']['ppp'])) {
1429
		foreach ($config['ppps']['ppp'] as & $settings) {
1430
			if ($ptpid == $settings['ptpid']) {
1431
				return true;
1432
			}
1433
		}
1434
	}
1435

    
1436
	return false;
1437
}
1438

    
1439
function interfaces_ptpid_next() {
1440

    
1441
	$ptpid = 0;
1442
	while (interfaces_ptpid_used($ptpid)) {
1443
		$ptpid++;
1444
	}
1445

    
1446
	return $ptpid;
1447
}
1448

    
1449
function getMPDCRONSettings($pppif) {
1450
	global $config;
1451

    
1452
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1453
	if (is_array($config['cron']['item'])) {
1454
		foreach ($config['cron']['item'] as $i => $item) {
1455
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1456
				return array("ID" => $i, "ITEM" => $item);
1457
			}
1458
		}
1459
	}
1460

    
1461
	return NULL;
1462
}
1463

    
1464
function handle_pppoe_reset($post_array) {
1465
	global $config, $g;
1466

    
1467
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1468
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1469

    
1470
	if (!is_array($config['cron']['item'])) {
1471
		$config['cron']['item'] = array();
1472
	}
1473

    
1474
	$itemhash = getMPDCRONSettings($pppif);
1475

    
1476
	// reset cron items if necessary and return
1477
	if (empty($post_array['pppoe-reset-type'])) {
1478
		if (isset($itemhash)) {
1479
			unset($config['cron']['item'][$itemhash['ID']]);
1480
		}
1481
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1482
		return;
1483
	}
1484

    
1485
	if (empty($itemhash)) {
1486
		$itemhash = array();
1487
	}
1488
	$item = array();
1489
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1490
		$item['minute'] = $post_array['pppoe_resetminute'];
1491
		$item['hour'] = $post_array['pppoe_resethour'];
1492
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1493
			$date = explode("/", $post_array['pppoe_resetdate']);
1494
			$item['mday'] = $date[1];
1495
			$item['month'] = $date[0];
1496
		} else {
1497
			$item['mday'] = "*";
1498
			$item['month'] = "*";
1499
		}
1500
		$item['wday'] = "*";
1501
		$item['who'] = "root";
1502
		$item['command'] = $cron_cmd_file;
1503
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1504
		switch ($post_array['pppoe_pr_preset_val']) {
1505
			case "monthly":
1506
				$item['minute'] = "0";
1507
				$item['hour'] = "0";
1508
				$item['mday'] = "1";
1509
				$item['month'] = "*";
1510
				$item['wday'] = "*";
1511
				break;
1512
			case "weekly":
1513
				$item['minute'] = "0";
1514
				$item['hour'] = "0";
1515
				$item['mday'] = "*";
1516
				$item['month'] = "*";
1517
				$item['wday'] = "0";
1518
				break;
1519
			case "daily":
1520
				$item['minute'] = "0";
1521
				$item['hour'] = "0";
1522
				$item['mday'] = "*";
1523
				$item['month'] = "*";
1524
				$item['wday'] = "*";
1525
				break;
1526
			case "hourly":
1527
				$item['minute'] = "0";
1528
				$item['hour'] = "*";
1529
				$item['mday'] = "*";
1530
				$item['month'] = "*";
1531
				$item['wday'] = "*";
1532
				break;
1533
		} // end switch
1534
		$item['who'] = "root";
1535
		$item['command'] = $cron_cmd_file;
1536
	}
1537
	if (empty($item)) {
1538
		return;
1539
	}
1540
	if (isset($itemhash['ID'])) {
1541
		$config['cron']['item'][$itemhash['ID']] = $item;
1542
	} else {
1543
		$config['cron']['item'][] = $item;
1544
	}
1545
}
1546

    
1547
/*
1548
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1549
 * It writes the mpd config file to /var/etc every time the link is opened.
1550
 */
1551
function interface_ppps_configure($interface) {
1552
	global $config, $g;
1553

    
1554
	/* Return for unassigned interfaces. This is a minimum requirement. */
1555
	if (empty($config['interfaces'][$interface])) {
1556
		return 0;
1557
	}
1558
	$ifcfg = $config['interfaces'][$interface];
1559
	if (!isset($ifcfg['enable'])) {
1560
		return 0;
1561
	}
1562

    
1563
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1564
	if (!is_dir("/var/spool/lock")) {
1565
		mkdir("/var/spool/lock", 0777, true);
1566
	}
1567
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1568
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1569
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1570
	}
1571

    
1572
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1573
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1574
			if ($ifcfg['if'] == $ppp['if']) {
1575
				break;
1576
			}
1577
		}
1578
	}
1579
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
1580
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1581
		return 0;
1582
	}
1583
	$pppif = $ifcfg['if'];
1584
	if ($ppp['type'] == "ppp") {
1585
		$type = "modem";
1586
	} else {
1587
		$type = $ppp['type'];
1588
	}
1589
	$upper_type = strtoupper($ppp['type']);
1590

    
1591
	/* XXX: This does not make sense and may create trouble
1592
	 * comment it for now to be removed later on.
1593
	if (platform_booting()) {
1594
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1595
		echo "starting {$pppif} link...";
1596
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1597
			return 0;
1598
	}
1599
	*/
1600

    
1601
	$ports = explode(',', $ppp['ports']);
1602
	if ($type != "modem") {
1603
		foreach ($ports as $pid => $port) {
1604
			$ports[$pid] = get_real_interface($port);
1605
			if (empty($ports[$pid])) {
1606
				return 0;
1607
			}
1608
		}
1609
	}
1610
	$localips = explode(',', $ppp['localip']);
1611
	$gateways = explode(',', $ppp['gateway']);
1612
	$subnets = explode(',', $ppp['subnet']);
1613

    
1614
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1615
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1616
	 */
1617
	foreach ($ports as $pid => $port) {
1618
		switch ($ppp['type']) {
1619
			case "pppoe":
1620
				/* Bring the parent interface up */
1621
				interfaces_bring_up($port);
1622
				pfSense_ngctl_attach(".", $port);
1623
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1624
				mwexec("ngctl msg {$port}: setautosrc 1");
1625
				break;
1626
			case "pptp":
1627
			case "l2tp":
1628
				/* configure interface */
1629
				if (is_ipaddr($localips[$pid])) {
1630
					// Manually configure interface IP/subnet
1631
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1632
					interfaces_bring_up($port);
1633
				} else if (empty($localips[$pid])) {
1634
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1635
				}
1636

    
1637
				if (!is_ipaddr($localips[$pid])) {
1638
					log_error("Could not get a Local IP address for PPTP/L2TP link on {$port} in interfaces_ppps_configure. Using 0.0.0.0 ip!");
1639
					$localips[$pid] = "0.0.0.0";
1640
				}
1641
				if (!is_ipaddr($gateways[$pid])) {
1642
					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));
1643
					return 0;
1644
				}
1645
				pfSense_ngctl_attach(".", $port);
1646
				break;
1647
			case "ppp":
1648
				if (!file_exists("{$port}")) {
1649
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1650
					return 0;
1651
				}
1652
				break;
1653
			default:
1654
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1655
				break;
1656
		}
1657
	}
1658

    
1659
	if (is_array($ports) && count($ports) > 1) {
1660
		$multilink = "enable";
1661
	} else {
1662
		$multilink = "disable";
1663
	}
1664

    
1665
	if ($type == "modem") {
1666
		if (is_ipaddr($ppp['localip'])) {
1667
			$localip = $ppp['localip'];
1668
		} else {
1669
			$localip = '0.0.0.0';
1670
		}
1671

    
1672
		if (is_ipaddr($ppp['gateway'])) {
1673
			$gateway = $ppp['gateway'];
1674
		} else {
1675
			$gateway = "10.64.64.{$pppid}";
1676
		}
1677
		$ranges = "{$localip}/0 {$gateway}/0";
1678

    
1679
		if (empty($ppp['apnum'])) {
1680
			$ppp['apnum'] = 1;
1681
		}
1682
	} else {
1683
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1684
	}
1685

    
1686
	if (isset($ppp['ondemand'])) {
1687
		$ondemand = "enable";
1688
	} else {
1689
		$ondemand = "disable";
1690
	}
1691
	if (!isset($ppp['idletimeout'])) {
1692
		$ppp['idletimeout'] = 0;
1693
	}
1694

    
1695
	if (empty($ppp['username']) && $type == "modem") {
1696
		$ppp['username'] = "user";
1697
		$ppp['password'] = "none";
1698
	}
1699
	if (empty($ppp['password']) && $type == "modem") {
1700
		$passwd = "none";
1701
	} else {
1702
		$passwd = base64_decode($ppp['password']);
1703
	}
1704

    
1705
	$bandwidths = explode(',', $ppp['bandwidth']);
1706
	$defaultmtu = "1492";
1707
	if (!empty($ifcfg['mtu'])) {
1708
		$defaultmtu = intval($ifcfg['mtu']);
1709
	}
1710
	$mtus = explode(',', $ppp['mtu']);
1711
	$mrus = explode(',', $ppp['mru']);
1712

    
1713
	if (isset($ppp['mrru'])) {
1714
		$mrrus = explode(',', $ppp['mrru']);
1715
	}
1716

    
1717
	// Construct the mpd.conf file
1718
	$mpdconf = <<<EOD
1719
startup:
1720
	# configure the console
1721
	set console close
1722
	# configure the web server
1723
	set web close
1724

    
1725
default:
1726
{$ppp['type']}client:
1727
	create bundle static {$interface}
1728
	set bundle enable ipv6cp
1729
	set iface name {$pppif}
1730

    
1731
EOD;
1732
	$setdefaultgw = false;
1733
	$founddefaultgw = false;
1734
	if (is_array($config['gateways']['gateway_item'])) {
1735
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1736
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1737
				$setdefaultgw = true;
1738
				break;
1739
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1740
				$founddefaultgw = true;
1741
				break;
1742
			}
1743
		}
1744
	}
1745

    
1746
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1747
		$setdefaultgw = true;
1748
		$mpdconf .= <<<EOD
1749
	set iface route default
1750

    
1751
EOD;
1752
	}
1753
	$mpdconf .= <<<EOD
1754
	set iface {$ondemand} on-demand
1755
	set iface idle {$ppp['idletimeout']}
1756

    
1757
EOD;
1758

    
1759
	if (isset($ppp['ondemand'])) {
1760
		$mpdconf .= <<<EOD
1761
	set iface addrs 10.10.1.1 10.10.1.2
1762

    
1763
EOD;
1764
	}
1765

    
1766
	if (isset($ppp['tcpmssfix'])) {
1767
		$tcpmss = "disable";
1768
	} else {
1769
		$tcpmss = "enable";
1770
	}
1771
	$mpdconf .= <<<EOD
1772
	set iface {$tcpmss} tcpmssfix
1773

    
1774
EOD;
1775

    
1776
	$mpdconf .= <<<EOD
1777
	set iface up-script /usr/local/sbin/ppp-linkup
1778
	set iface down-script /usr/local/sbin/ppp-linkdown
1779
	set ipcp ranges {$ranges}
1780

    
1781
EOD;
1782
	if (isset($ppp['vjcomp'])) {
1783
		$mpdconf .= <<<EOD
1784
	set ipcp no vjcomp
1785

    
1786
EOD;
1787
	}
1788

    
1789
	if (isset($config['system']['dnsallowoverride'])) {
1790
		$mpdconf .= <<<EOD
1791
	set ipcp enable req-pri-dns
1792
	set ipcp enable req-sec-dns
1793

    
1794
EOD;
1795
	}
1796

    
1797
	if (!isset($ppp['verbose_log'])) {
1798
		$mpdconf .= <<<EOD
1799
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1800

    
1801
EOD;
1802
	}
1803

    
1804
	foreach ($ports as $pid => $port) {
1805
		$port = get_real_interface($port);
1806
		$mpdconf .= <<<EOD
1807

    
1808
	create link static {$interface}_link{$pid} {$type}
1809
	set link action bundle {$interface}
1810
	set link {$multilink} multilink
1811
	set link keep-alive 10 60
1812
	set link max-redial 0
1813

    
1814
EOD;
1815
		if (isset($ppp['shortseq'])) {
1816
			$mpdconf .= <<<EOD
1817
	set link no shortseq
1818

    
1819
EOD;
1820
		}
1821

    
1822
		if (isset($ppp['acfcomp'])) {
1823
			$mpdconf .= <<<EOD
1824
	set link no acfcomp
1825

    
1826
EOD;
1827
		}
1828

    
1829
		if (isset($ppp['protocomp'])) {
1830
			$mpdconf .= <<<EOD
1831
	set link no protocomp
1832

    
1833
EOD;
1834
		}
1835

    
1836
		$mpdconf .= <<<EOD
1837
	set link disable chap pap
1838
	set link accept chap pap eap
1839
	set link disable incoming
1840

    
1841
EOD;
1842

    
1843

    
1844
		if (!empty($bandwidths[$pid])) {
1845
			$mpdconf .= <<<EOD
1846
	set link bandwidth {$bandwidths[$pid]}
1847

    
1848
EOD;
1849
		}
1850

    
1851
		if (empty($mtus[$pid])) {
1852
			$mtus[$pid] = $defaultmtu;
1853
		}
1854
		$mpdconf .= <<<EOD
1855
	set link mtu {$mtus[$pid]}
1856

    
1857
EOD;
1858

    
1859
		if (!empty($mrus[$pid])) {
1860
			$mpdconf .= <<<EOD
1861
	set link mru {$mrus[$pid]}
1862

    
1863
EOD;
1864
		}
1865

    
1866
		if (!empty($mrrus[$pid])) {
1867
			$mpdconf .= <<<EOD
1868
	set link mrru {$mrrus[$pid]}
1869

    
1870
EOD;
1871
		}
1872

    
1873
		$mpdconf .= <<<EOD
1874
	set auth authname "{$ppp['username']}"
1875
	set auth password {$passwd}
1876

    
1877
EOD;
1878
		if ($type == "modem") {
1879
			$mpdconf .= <<<EOD
1880
	set modem device {$ppp['ports']}
1881
	set modem script DialPeer
1882
	set modem idle-script Ringback
1883
	set modem watch -cd
1884
	set modem var \$DialPrefix "DT"
1885
	set modem var \$Telephone "{$ppp['phone']}"
1886

    
1887
EOD;
1888
		}
1889
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1890
			$mpdconf .= <<<EOD
1891
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1892

    
1893
EOD;
1894
		}
1895
		if (isset($ppp['initstr']) && $type == "modem") {
1896
			$initstr = base64_decode($ppp['initstr']);
1897
			$mpdconf .= <<<EOD
1898
	set modem var \$InitString "{$initstr}"
1899

    
1900
EOD;
1901
		}
1902
		if (isset($ppp['simpin']) && $type == "modem") {
1903
			if ($ppp['pin-wait'] == "") {
1904
				$ppp['pin-wait'] = 0;
1905
			}
1906
			$mpdconf .= <<<EOD
1907
	set modem var \$SimPin "{$ppp['simpin']}"
1908
	set modem var \$PinWait "{$ppp['pin-wait']}"
1909

    
1910
EOD;
1911
		}
1912
		if (isset($ppp['apn']) && $type == "modem") {
1913
			$mpdconf .= <<<EOD
1914
	set modem var \$APN "{$ppp['apn']}"
1915
	set modem var \$APNum "{$ppp['apnum']}"
1916

    
1917
EOD;
1918
		}
1919
		if ($type == "pppoe") {
1920
			// Send a null service name if none is set.
1921
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1922
			$mpdconf .= <<<EOD
1923
	set pppoe service "{$provider}"
1924

    
1925
EOD;
1926
		}
1927
		if ($type == "pppoe") {
1928
			$mpdconf .= <<<EOD
1929
	set pppoe iface {$port}
1930

    
1931
EOD;
1932
		}
1933

    
1934
		if ($type == "pptp" || $type == "l2tp") {
1935
			$mpdconf .= <<<EOD
1936
	set {$type} self {$localips[$pid]}
1937
	set {$type} peer {$gateways[$pid]}
1938

    
1939
EOD;
1940
		}
1941

    
1942
		$mpdconf .= "\topen\n";
1943
	} //end foreach ($port)
1944

    
1945

    
1946
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1947
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
1948
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1949
	} else {
1950
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1951
		if (!$fd) {
1952
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1953
			return 0;
1954
		}
1955
		// Write out mpd_ppp.conf
1956
		fwrite($fd, $mpdconf);
1957
		fclose($fd);
1958
		unset($mpdconf);
1959
	}
1960

    
1961
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1962
	if (isset($ppp['uptime'])) {
1963
		if (!file_exists("/conf/{$pppif}.log")) {
1964
			conf_mount_rw();
1965
			file_put_contents("/conf/{$pppif}.log", '');
1966
			conf_mount_ro();
1967
		}
1968
	} else {
1969
		if (file_exists("/conf/{$pppif}.log")) {
1970
			conf_mount_rw();
1971
			@unlink("/conf/{$pppif}.log");
1972
			conf_mount_ro();
1973
		}
1974
	}
1975

    
1976
	/* clean up old lock files */
1977
	foreach ($ports as $port) {
1978
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
1979
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1980
		}
1981
	}
1982

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

    
1987
	// Check for PPPoE periodic reset request
1988
	if ($type == "pppoe") {
1989
		if (!empty($ppp['pppoe-reset-type'])) {
1990
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1991
		} else {
1992
			interface_setup_pppoe_reset_file($ppp['if']);
1993
		}
1994
	}
1995
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1996
	$i = 0;
1997
	while ($i < 3) {
1998
		sleep(10);
1999
		if (does_interface_exist($ppp['if'], true)) {
2000
			break;
2001
		}
2002
		$i++;
2003
	}
2004

    
2005
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2006
	/* We should be able to launch the right version for each modem */
2007
	/* We can also guess the mondev from the manufacturer */
2008
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
2009
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
2010
	foreach ($ports as $port) {
2011
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2012
			$mondev = substr(basename($port), 0, -1);
2013
			$devlist = glob("/dev/{$mondev}?");
2014
			$mondev = basename(end($devlist));
2015
		}
2016
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2017
			$mondev = substr(basename($port), 0, -1) . "1";
2018
		}
2019
		if ($mondev != '') {
2020
			log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
2021
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2022
		}
2023
	}
2024

    
2025
	return 1;
2026
}
2027

    
2028
function interfaces_sync_setup() {
2029
	global $g, $config;
2030

    
2031
	if (isset($config['system']['developerspew'])) {
2032
		$mt = microtime();
2033
		echo "interfaces_sync_setup() being called $mt\n";
2034
	}
2035

    
2036
	if (platform_booting()) {
2037
		echo gettext("Configuring CARP settings...");
2038
		mute_kernel_msgs();
2039
	}
2040

    
2041
	/* suck in configuration items */
2042
	if ($config['hasync']) {
2043
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2044
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2045
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2046
	} else {
2047
		unset($pfsyncinterface);
2048
		unset($pfsyncenabled);
2049
	}
2050

    
2051
	set_sysctl(array(
2052
		"net.inet.carp.preempt" => "1",
2053
		"net.inet.carp.log" => "1")
2054
	);
2055

    
2056
	if (!empty($pfsyncinterface)) {
2057
		$carp_sync_int = get_real_interface($pfsyncinterface);
2058
	} else {
2059
		unset($carp_sync_int);
2060
	}
2061

    
2062
	/* setup pfsync interface */
2063
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2064
		if (is_ipaddr($pfsyncpeerip)) {
2065
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2066
		} else {
2067
			$syncpeer = "-syncpeer";
2068
		}
2069

    
2070
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2071
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2072

    
2073
		sleep(1);
2074

    
2075
		/* 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
2076
		 * for existing sessions.
2077
		 */
2078
		log_error("waiting for pfsync...");
2079
		$i = 0;
2080
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2081
			$i++;
2082
			sleep(1);
2083
		}
2084
		log_error("pfsync done in $i seconds.");
2085
		log_error("Configuring CARP settings finalize...");
2086
	} else {
2087
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2088
	}
2089

    
2090
	if ($config['virtualip']['vip']) {
2091
		set_single_sysctl("net.inet.carp.allow", "1");
2092
	} else {
2093
		set_single_sysctl("net.inet.carp.allow", "0");
2094
	}
2095

    
2096
	if (platform_booting()) {
2097
		unmute_kernel_msgs();
2098
		echo gettext("done.") . "\n";
2099
	}
2100
}
2101

    
2102
function interface_proxyarp_configure($interface = "") {
2103
	global $config, $g;
2104
	if (isset($config['system']['developerspew'])) {
2105
		$mt = microtime();
2106
		echo "interface_proxyarp_configure() being called $mt\n";
2107
	}
2108

    
2109
	/* kill any running choparp */
2110
	if (empty($interface)) {
2111
		killbyname("choparp");
2112
	} else {
2113
		$vipif = get_real_interface($interface);
2114
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2115
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2116
		}
2117
	}
2118

    
2119
	$paa = array();
2120
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2121

    
2122
		/* group by interface */
2123
		foreach ($config['virtualip']['vip'] as $vipent) {
2124
			if ($vipent['mode'] === "proxyarp") {
2125
				if ($vipent['interface']) {
2126
					$proxyif = $vipent['interface'];
2127
				} else {
2128
					$proxyif = "wan";
2129
				}
2130

    
2131
				if (!empty($interface) && $interface != $proxyif) {
2132
					continue;
2133
				}
2134

    
2135
				if (!is_array($paa[$proxyif])) {
2136
					$paa[$proxyif] = array();
2137
				}
2138

    
2139
				$paa[$proxyif][] = $vipent;
2140
			}
2141
		}
2142
	}
2143

    
2144
	if (!empty($interface)) {
2145
		if (is_array($paa[$interface])) {
2146
			$paaifip = get_interface_ip($interface);
2147
			if (!is_ipaddr($paaifip)) {
2148
				return;
2149
			}
2150
			$args = get_real_interface($interface) . " auto";
2151
			foreach ($paa[$interface] as $paent) {
2152
				if (isset($paent['subnet'])) {
2153
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2154
				} else if (isset($paent['range'])) {
2155
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2156
				}
2157
			}
2158
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2159
		}
2160
	} else if (count($paa) > 0) {
2161
		foreach ($paa as $paif => $paents) {
2162
			$paaifip = get_interface_ip($paif);
2163
			if (!is_ipaddr($paaifip)) {
2164
				continue;
2165
			}
2166
			$args = get_real_interface($paif) . " auto";
2167
			foreach ($paents as $paent) {
2168
				if (isset($paent['subnet'])) {
2169
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2170
				} else if (isset($paent['range'])) {
2171
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2172
				}
2173
			}
2174
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2175
		}
2176
	}
2177
}
2178

    
2179
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2180
	global $g, $config;
2181

    
2182
	if (is_array($config['virtualip']['vip'])) {
2183
		foreach ($config['virtualip']['vip'] as $vip) {
2184
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2185
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet'])) {
2186
					interface_vip_bring_down($vip);
2187
				} else if ($inet == "inet4" && is_ipaddrv4($vip['subnet'])) {
2188
					interface_vip_bring_down($vip);
2189
				}
2190
			}
2191
		}
2192
	}
2193
}
2194

    
2195
function interfaces_vips_configure($interface = "") {
2196
	global $g, $config;
2197
	if (isset($config['system']['developerspew'])) {
2198
		$mt = microtime();
2199
		echo "interfaces_vips_configure() being called $mt\n";
2200
	}
2201
	$paa = array();
2202
	if (is_array($config['virtualip']['vip'])) {
2203
		$carp_setuped = false;
2204
		$anyproxyarp = false;
2205
		foreach ($config['virtualip']['vip'] as $vip) {
2206
			switch ($vip['mode']) {
2207
				case "proxyarp":
2208
					/* nothing it is handled on interface_proxyarp_configure() */
2209
					if ($interface <> "" && $vip['interface'] <> $interface) {
2210
						continue;
2211
					}
2212
					$anyproxyarp = true;
2213
					break;
2214
				case "ipalias":
2215
					if ($interface <> "" && $vip['interface'] <> $interface) {
2216
						continue;
2217
					}
2218
					interface_ipalias_configure($vip);
2219
					break;
2220
				case "carp":
2221
					if ($interface <> "" && $vip['interface'] <> $interface) {
2222
						continue;
2223
					}
2224
					if ($carp_setuped == false) {
2225
						$carp_setuped = true;
2226
					}
2227
					interface_carp_configure($vip);
2228
					break;
2229
			}
2230
		}
2231
		if ($carp_setuped == true) {
2232
			interfaces_sync_setup();
2233
		}
2234
		if ($anyproxyarp == true) {
2235
			interface_proxyarp_configure();
2236
		}
2237
	}
2238
}
2239

    
2240
function interface_ipalias_configure(&$vip) {
2241
	global $config;
2242

    
2243
	if ($vip['mode'] != 'ipalias') {
2244
		return;
2245
	}
2246

    
2247
	if ($vip['interface'] != 'lo0' && stripos($vip['interface'], '_vip') === false) {
2248
		if (!isset($config['interfaces'][$vip['interface']])) {
2249
			return;
2250
		}
2251

    
2252
		if (!isset($config['interfaces'][$vip['interface']]['enable'])) {
2253
			return;
2254
		}
2255
	}
2256

    
2257
	$af = 'inet';
2258
	if (is_ipaddrv6($vip['subnet'])) {
2259
		$af = 'inet6';
2260
	}
2261
	$iface = $vip['interface'];
2262
	$vipadd = '';
2263
	if (strpos($vip['interface'], '_vip')) {
2264
		$carpvip = get_configured_carp_interface_list($vip['interface'], $af, 'vip');
2265
		$iface = $carpvip['interface'];
2266
		$vipadd = "vhid {$carpvip['vhid']}";
2267
	}
2268
	$if = get_real_interface($iface);
2269
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vipadd}");
2270
	unset($iface, $af, $if, $carpvip, $vipadd);
2271
}
2272

    
2273
function interface_reload_carps($cif) {
2274
	global $config;
2275

    
2276
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2277
	if (empty($carpifs)) {
2278
		return;
2279
	}
2280

    
2281
	$carps = explode(" ", $carpifs);
2282
	if (is_array($config['virtualip']['vip'])) {
2283
		$viparr = &$config['virtualip']['vip'];
2284
		foreach ($viparr as $vip) {
2285
			if (in_array($vip['carpif'], $carps)) {
2286
				switch ($vip['mode']) {
2287
					case "carp":
2288
						interface_vip_bring_down($vip);
2289
						sleep(1);
2290
						interface_carp_configure($vip);
2291
						break;
2292
					case "ipalias":
2293
						interface_vip_bring_down($vip);
2294
						sleep(1);
2295
						interface_ipalias_configure($vip);
2296
						break;
2297
				}
2298
			}
2299
		}
2300
	}
2301
}
2302

    
2303
function interface_carp_configure(&$vip) {
2304
	global $config, $g;
2305
	if (isset($config['system']['developerspew'])) {
2306
		$mt = microtime();
2307
		echo "interface_carp_configure() being called $mt\n";
2308
	}
2309

    
2310
	if ($vip['mode'] != "carp") {
2311
		return;
2312
	}
2313

    
2314
	/* NOTE: Maybe its useless nowadays */
2315
	$realif = get_real_interface($vip['interface']);
2316
	if (!does_interface_exist($realif)) {
2317
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2318
		return;
2319
	}
2320

    
2321
	$vip_password = $vip['password'];
2322
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2323
	if ($vip['password'] != "") {
2324
		$password = " pass {$vip_password}";
2325
	}
2326

    
2327
	$advbase = "";
2328
	if (!empty($vip['advbase'])) {
2329
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2330
	}
2331

    
2332
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2333
	if ($carp_maintenancemode) {
2334
		$advskew = "advskew 254";
2335
	} else {
2336
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2337
	}
2338

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

    
2341
	if (is_ipaddrv4($vip['subnet'])) {
2342
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2343
	} else if (is_ipaddrv6($vip['subnet'])) {
2344
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2345
	}
2346

    
2347
	return $realif;
2348
}
2349

    
2350
function interface_wireless_clone($realif, $wlcfg) {
2351
	global $config, $g;
2352
	/*   Check to see if interface has been cloned as of yet.
2353
	 *   If it has not been cloned then go ahead and clone it.
2354
	 */
2355
	$needs_clone = false;
2356
	if (is_array($wlcfg['wireless'])) {
2357
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2358
	} else {
2359
		$wlcfg_mode = $wlcfg['mode'];
2360
	}
2361
	switch ($wlcfg_mode) {
2362
		case "hostap":
2363
			$mode = "wlanmode hostap";
2364
			break;
2365
		case "adhoc":
2366
			$mode = "wlanmode adhoc";
2367
			break;
2368
		default:
2369
			$mode = "";
2370
			break;
2371
	}
2372
	$baseif = interface_get_wireless_base($wlcfg['if']);
2373
	if (does_interface_exist($realif)) {
2374
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2375
		$ifconfig_str = implode($output);
2376
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2377
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2378
			$needs_clone = true;
2379
		}
2380
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2381
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2382
			$needs_clone = true;
2383
		}
2384
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2385
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2386
			$needs_clone = true;
2387
		}
2388
	} else {
2389
		$needs_clone = true;
2390
	}
2391

    
2392
	if ($needs_clone == true) {
2393
		/* remove previous instance if it exists */
2394
		if (does_interface_exist($realif)) {
2395
			pfSense_interface_destroy($realif);
2396
		}
2397

    
2398
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2399
		// Create the new wlan interface. FreeBSD returns the new interface name.
2400
		// example:  wlan2
2401
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2402
		if ($ret <> 0) {
2403
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2404
			return false;
2405
		}
2406
		$newif = trim($out[0]);
2407
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2408
		pfSense_interface_rename($newif, $realif);
2409
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2410
	}
2411
	return true;
2412
}
2413

    
2414
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2415
	global $config, $g;
2416

    
2417
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2418
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2419
				 'regdomain', 'regcountry', 'reglocation');
2420

    
2421
	if (!is_interface_wireless($ifcfg['if'])) {
2422
		return;
2423
	}
2424

    
2425
	$baseif = interface_get_wireless_base($ifcfg['if']);
2426

    
2427
	// Sync shared settings for assigned clones
2428
	$iflist = get_configured_interface_list(false, true);
2429
	foreach ($iflist as $if) {
2430
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2431
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2432
				foreach ($shared_settings as $setting) {
2433
					if ($sync_changes) {
2434
						if (isset($ifcfg['wireless'][$setting])) {
2435
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2436
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2437
							unset($config['interfaces'][$if]['wireless'][$setting]);
2438
						}
2439
					} else {
2440
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2441
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2442
						} else if (isset($ifcfg['wireless'][$setting])) {
2443
							unset($ifcfg['wireless'][$setting]);
2444
						}
2445
					}
2446
				}
2447
				if (!$sync_changes) {
2448
					break;
2449
				}
2450
			}
2451
		}
2452
	}
2453

    
2454
	// Read or write settings at shared area
2455
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2456
		foreach ($shared_settings as $setting) {
2457
			if ($sync_changes) {
2458
				if (isset($ifcfg['wireless'][$setting])) {
2459
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2460
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2461
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2462
				}
2463
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2464
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2465
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2466
				} else if (isset($ifcfg['wireless'][$setting])) {
2467
					unset($ifcfg['wireless'][$setting]);
2468
				}
2469
			}
2470
		}
2471
	}
2472

    
2473
	// Sync the mode on the clone creation page with the configured mode on the interface
2474
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2475
		foreach ($config['wireless']['clone'] as &$clone) {
2476
			if ($clone['cloneif'] == $ifcfg['if']) {
2477
				if ($sync_changes) {
2478
					$clone['mode'] = $ifcfg['wireless']['mode'];
2479
				} else {
2480
					$ifcfg['wireless']['mode'] = $clone['mode'];
2481
				}
2482
				break;
2483
			}
2484
		}
2485
		unset($clone);
2486
	}
2487
}
2488

    
2489
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2490
	global $config, $g;
2491

    
2492
	/*    open up a shell script that will be used to output the commands.
2493
	 *    since wireless is changing a lot, these series of commands are fragile
2494
	 *    and will sometimes need to be verified by a operator by executing the command
2495
	 *    and returning the output of the command to the developers for inspection.  please
2496
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2497
	 */
2498

    
2499
	// Remove script file
2500
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2501

    
2502
	// Clone wireless nic if needed.
2503
	interface_wireless_clone($if, $wl);
2504

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

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

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

    
2514
	/* set values for /path/program */
2515
	$hostapd = "/usr/sbin/hostapd";
2516
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2517
	$ifconfig = "/sbin/ifconfig";
2518
	$sysctl = "/sbin/sysctl";
2519
	$killall = "/usr/bin/killall";
2520

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

    
2523
	$wlcmd = array();
2524
	$wl_sysctl = array();
2525
	/* Make sure it's up */
2526
	$wlcmd[] = "up";
2527
	/* Set a/b/g standard */
2528
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2529
	/* skip mode entirely for "auto" */
2530
	if ($wlcfg['standard'] != "auto") {
2531
		$wlcmd[] = "mode " . escapeshellarg($standard);
2532
	}
2533

    
2534
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2535
	 * to prevent massive packet loss under certain conditions. */
2536
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2537
		$wlcmd[] = "-ampdu";
2538
	}
2539

    
2540
	/* Set ssid */
2541
	if ($wlcfg['ssid']) {
2542
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2543
	}
2544

    
2545
	/* Set 802.11g protection mode */
2546
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2547

    
2548
	/* set wireless channel value */
2549
	if (isset($wlcfg['channel'])) {
2550
		if ($wlcfg['channel'] == "0") {
2551
			$wlcmd[] = "channel any";
2552
		} else {
2553
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2554
		}
2555
	}
2556

    
2557
	/* Set antenna diversity value */
2558
	if (isset($wlcfg['diversity'])) {
2559
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2560
	}
2561

    
2562
	/* Set txantenna value */
2563
	if (isset($wlcfg['txantenna'])) {
2564
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2565
	}
2566

    
2567
	/* Set rxantenna value */
2568
	if (isset($wlcfg['rxantenna'])) {
2569
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2570
	}
2571

    
2572
	/* set Distance value */
2573
	if ($wlcfg['distance']) {
2574
		$distance = escapeshellarg($wlcfg['distance']);
2575
	}
2576

    
2577
	/* Set wireless hostap mode */
2578
	if ($wlcfg['mode'] == "hostap") {
2579
		$wlcmd[] = "mediaopt hostap";
2580
	} else {
2581
		$wlcmd[] = "-mediaopt hostap";
2582
	}
2583

    
2584
	/* Set wireless adhoc mode */
2585
	if ($wlcfg['mode'] == "adhoc") {
2586
		$wlcmd[] = "mediaopt adhoc";
2587
	} else {
2588
		$wlcmd[] = "-mediaopt adhoc";
2589
	}
2590

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

    
2593
	/* handle hide ssid option */
2594
	if (isset($wlcfg['hidessid']['enable'])) {
2595
		$wlcmd[] = "hidessid";
2596
	} else {
2597
		$wlcmd[] = "-hidessid";
2598
	}
2599

    
2600
	/* handle pureg (802.11g) only option */
2601
	if (isset($wlcfg['pureg']['enable'])) {
2602
		$wlcmd[] = "mode 11g pureg";
2603
	} else {
2604
		$wlcmd[] = "-pureg";
2605
	}
2606

    
2607
	/* handle puren (802.11n) only option */
2608
	if (isset($wlcfg['puren']['enable'])) {
2609
		$wlcmd[] = "puren";
2610
	} else {
2611
		$wlcmd[] = "-puren";
2612
	}
2613

    
2614
	/* enable apbridge option */
2615
	if (isset($wlcfg['apbridge']['enable'])) {
2616
		$wlcmd[] = "apbridge";
2617
	} else {
2618
		$wlcmd[] = "-apbridge";
2619
	}
2620

    
2621
	/* handle turbo option */
2622
	if (isset($wlcfg['turbo']['enable'])) {
2623
		$wlcmd[] = "mediaopt turbo";
2624
	} else {
2625
		$wlcmd[] = "-mediaopt turbo";
2626
	}
2627

    
2628
	/* handle txpower setting */
2629
	// or don't. this has issues at the moment.
2630
	/*
2631
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2632
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2633
	}*/
2634

    
2635
	/* handle wme option */
2636
	if (isset($wlcfg['wme']['enable'])) {
2637
		$wlcmd[] = "wme";
2638
	} else {
2639
		$wlcmd[] = "-wme";
2640
	}
2641

    
2642
	/* set up wep if enabled */
2643
	$wepset = "";
2644
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2645
		switch ($wlcfg['wpa']['auth_algs']) {
2646
			case "1":
2647
				$wepset .= "authmode open wepmode on ";
2648
				break;
2649
			case "2":
2650
				$wepset .= "authmode shared wepmode on ";
2651
				break;
2652
			case "3":
2653
				$wepset .= "authmode mixed wepmode on ";
2654
		}
2655
		$i = 1;
2656
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2657
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2658
			if (isset($wepkey['txkey'])) {
2659
				$wlcmd[] = "weptxkey {$i} ";
2660
			}
2661
			$i++;
2662
		}
2663
		$wlcmd[] = $wepset;
2664
	} else if (isset($wlcfg['wpa']['enable'])) {
2665
		$wlcmd[] = "authmode wpa wepmode off ";
2666
	} else {
2667
		$wlcmd[] = "authmode open wepmode off ";
2668
	}
2669

    
2670
	kill_hostapd($if);
2671
	mwexec(kill_wpasupplicant("{$if}"));
2672

    
2673
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2674
	conf_mount_rw();
2675

    
2676
	switch ($wlcfg['mode']) {
2677
		case 'bss':
2678
			if (isset($wlcfg['wpa']['enable'])) {
2679
				$wpa .= <<<EOD
2680
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2681
ctrl_interface_group=0
2682
ap_scan=1
2683
#fast_reauth=1
2684
network={
2685
ssid="{$wlcfg['ssid']}"
2686
scan_ssid=1
2687
priority=5
2688
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2689
psk="{$wlcfg['wpa']['passphrase']}"
2690
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2691
group={$wlcfg['wpa']['wpa_pairwise']}
2692
}
2693
EOD;
2694

    
2695
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2696
				unset($wpa);
2697
			}
2698
			break;
2699
		case 'hostap':
2700
			if (!empty($wlcfg['wpa']['passphrase'])) {
2701
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2702
			} else {
2703
				$wpa_passphrase = "";
2704
			}
2705
			if (isset($wlcfg['wpa']['enable'])) {
2706
				$wpa .= <<<EOD
2707
interface={$if}
2708
driver=bsd
2709
logger_syslog=-1
2710
logger_syslog_level=0
2711
logger_stdout=-1
2712
logger_stdout_level=0
2713
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2714
ctrl_interface={$g['varrun_path']}/hostapd
2715
ctrl_interface_group=wheel
2716
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2717
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2718
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2719
ssid={$wlcfg['ssid']}
2720
debug={$wlcfg['wpa']['debug_mode']}
2721
auth_algs={$wlcfg['wpa']['auth_algs']}
2722
wpa={$wlcfg['wpa']['wpa_mode']}
2723
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2724
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2725
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2726
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2727
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2728
{$wpa_passphrase}
2729

    
2730
EOD;
2731

    
2732
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2733
					$wpa .= <<<EOD
2734
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2735
rsn_preauth=1
2736
rsn_preauth_interfaces={$if}
2737

    
2738
EOD;
2739
				}
2740
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2741
					$wpa .= "ieee8021x=1\n";
2742

    
2743
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2744
						$auth_server_port = "1812";
2745
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2746
							$auth_server_port = intval($wlcfg['auth_server_port']);
2747
						}
2748
						$wpa .= <<<EOD
2749

    
2750
auth_server_addr={$wlcfg['auth_server_addr']}
2751
auth_server_port={$auth_server_port}
2752
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2753

    
2754
EOD;
2755
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2756
							$auth_server_port2 = "1812";
2757
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2758
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2759
							}
2760

    
2761
							$wpa .= <<<EOD
2762
auth_server_addr={$wlcfg['auth_server_addr2']}
2763
auth_server_port={$auth_server_port2}
2764
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2765

    
2766
EOD;
2767
						}
2768
					}
2769
				}
2770

    
2771
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2772
				unset($wpa);
2773
			}
2774
			break;
2775
	}
2776

    
2777
	/*
2778
	 *    all variables are set, lets start up everything
2779
	 */
2780

    
2781
	$baseif = interface_get_wireless_base($if);
2782
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2783
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2784

    
2785
	/* set sysctls for the wireless interface */
2786
	if (!empty($wl_sysctl)) {
2787
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2788
		foreach ($wl_sysctl as $wl_sysctl_line) {
2789
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2790
		}
2791
	}
2792

    
2793
	/* set ack timers according to users preference (if he/she has any) */
2794
	if ($distance) {
2795
		fwrite($fd_set, "# Enable ATH distance settings\n");
2796
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2797
	}
2798

    
2799
	if (isset($wlcfg['wpa']['enable'])) {
2800
		if ($wlcfg['mode'] == "bss") {
2801
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2802
		}
2803
		if ($wlcfg['mode'] == "hostap") {
2804
			/* add line to script to restore old mac to make hostapd happy */
2805
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2806
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2807
				if (is_macaddr($if_oldmac)) {
2808
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2809
						" link " . escapeshellarg($if_oldmac) . "\n");
2810
				}
2811
			}
2812

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

    
2815
			/* add line to script to restore spoofed mac after running hostapd */
2816
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2817
				if ($wl['spoofmac']) {
2818
					$if_curmac = $wl['spoofmac'];
2819
				} else {
2820
					$if_curmac = get_interface_mac($if);
2821
				}
2822
				if (is_macaddr($if_curmac)) {
2823
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2824
						" link " . escapeshellarg($if_curmac) . "\n");
2825
				}
2826
			}
2827
		}
2828
	}
2829

    
2830
	fclose($fd_set);
2831
	conf_mount_ro();
2832

    
2833
	/* Making sure regulatory settings have actually changed
2834
	 * before applying, because changing them requires bringing
2835
	 * down all wireless networks on the interface. */
2836
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2837
	$ifconfig_str = implode($output);
2838
	unset($output);
2839
	$reg_changing = false;
2840

    
2841
	/* special case for the debug country code */
2842
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
2843
		$reg_changing = true;
2844
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
2845
		$reg_changing = true;
2846
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
2847
		$reg_changing = true;
2848
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
2849
		$reg_changing = true;
2850
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
2851
		$reg_changing = true;
2852
	}
2853

    
2854
	if ($reg_changing) {
2855
		/* set regulatory domain */
2856
		if ($wlcfg['regdomain']) {
2857
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2858
		}
2859

    
2860
		/* set country */
2861
		if ($wlcfg['regcountry']) {
2862
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2863
		}
2864

    
2865
		/* set location */
2866
		if ($wlcfg['reglocation']) {
2867
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2868
		}
2869

    
2870
		$wlregcmd_args = implode(" ", $wlregcmd);
2871

    
2872
		/* build a complete list of the wireless clones for this interface */
2873
		$clone_list = array();
2874
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2875
			$clone_list[] = interface_get_wireless_clone($baseif);
2876
		}
2877
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2878
			foreach ($config['wireless']['clone'] as $clone) {
2879
				if ($clone['if'] == $baseif) {
2880
					$clone_list[] = $clone['cloneif'];
2881
				}
2882
			}
2883
		}
2884

    
2885
		/* find which clones are up and bring them down */
2886
		$clones_up = array();
2887
		foreach ($clone_list as $clone_if) {
2888
			$clone_status = pfSense_get_interface_addresses($clone_if);
2889
			if ($clone_status['status'] == 'up') {
2890
				$clones_up[] = $clone_if;
2891
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2892
			}
2893
		}
2894

    
2895
		/* apply the regulatory settings */
2896
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2897
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2898

    
2899
		/* bring the clones back up that were previously up */
2900
		foreach ($clones_up as $clone_if) {
2901
			interfaces_bring_up($clone_if);
2902

    
2903
			/*
2904
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2905
			 * is in infrastructure mode, and WPA is enabled.
2906
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2907
			 */
2908
			if ($clone_if != $if) {
2909
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2910
				if ((!empty($friendly_if)) &&
2911
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
2912
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
2913
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2914
				}
2915
			}
2916
		}
2917
	}
2918

    
2919
	/* 20150318 cmb - Note: the below no longer appears to be true on FreeBSD 10.x, so don't set
2920
	 * mode twice (for now at least). This can be removed entirely in the future if no problems are found
2921

    
2922
	 * The mode must be specified in a separate command before ifconfig
2923
	 * will allow the mode and channel at the same time in the next. */
2924
	//mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2925
	//fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
2926

    
2927
	/* configure wireless */
2928
	$wlcmd_args = implode(" ", $wlcmd);
2929
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2930
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
2931
	fclose($wlan_setup_log);
2932

    
2933
	unset($wlcmd_args, $wlcmd);
2934

    
2935

    
2936
	sleep(1);
2937
	/* execute hostapd and wpa_supplicant if required in shell */
2938
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2939

    
2940
	return 0;
2941

    
2942
}
2943

    
2944
function kill_hostapd($interface) {
2945
	global $g;
2946

    
2947
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
2948
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2949
	}
2950
}
2951

    
2952
function kill_wpasupplicant($interface) {
2953
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2954
}
2955

    
2956
function find_dhclient_process($interface) {
2957
	if ($interface) {
2958
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2959
	} else {
2960
		$pid = 0;
2961
	}
2962

    
2963
	return intval($pid);
2964
}
2965

    
2966
function kill_dhclient_process($interface) {
2967
	if (empty($interface) || !does_interface_exist($interface)) {
2968
		return;
2969
	}
2970

    
2971
	$i = 0;
2972
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2973
		/* 3rd time make it die for sure */
2974
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2975
		posix_kill($pid, $sig);
2976
		sleep(1);
2977
		$i++;
2978
	}
2979
	unset($i);
2980
}
2981

    
2982
function find_dhcp6c_process($interface) {
2983
	global $g;
2984

    
2985
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
2986
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2987
	} else {
2988
		return(false);
2989
	}
2990

    
2991
	return intval($pid);
2992
}
2993

    
2994
function interface_virtual_create($interface) {
2995
	global $config;
2996

    
2997
	if (strstr($interface, "_vlan")) {
2998
		interfaces_vlan_configure($vlan);
2999
	} else if (substr($interface, 0, 3) == "gre") {
3000
		interfaces_gre_configure(0, $interface);
3001
	} else if (substr($interface, 0, 3) == "gif") {
3002
		interfaces_gif_configure(0, $interface);
3003
	} else if (substr($interface, 0, 5) == "ovpns") {
3004
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3005
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3006
				if ($interface == "ovpns{$server['vpnid']}") {
3007
					if (!function_exists('openvpn_resync')) {
3008
						require_once('openvpn.inc');
3009
					}
3010
					log_error("OpenVPN: Resync server {$server['description']}");
3011
					openvpn_resync('server', $server);
3012
				}
3013
			}
3014
			unset($server);
3015
		}
3016
	} else if (substr($interface, 0, 5) == "ovpnc") {
3017
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3018
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3019
				if ($interface == "ovpnc{$client['vpnid']}") {
3020
					if (!function_exists('openvpn_resync')) {
3021
						require_once('openvpn.inc');
3022
					}
3023
					log_error("OpenVPN: Resync server {$client['description']}");
3024
					openvpn_resync('client', $client);
3025
				}
3026
			}
3027
			unset($client);
3028
		}
3029
	} else if (substr($interface, 0, 4) == "lagg") {
3030
		interfaces_lagg_configure($interface);
3031
	} else if (substr($interface, 0, 6) == "bridge") {
3032
		interfaces_bridge_configure(0, $interface);
3033
	}
3034
}
3035

    
3036
function interface_vlan_mtu_configured($realhwif, $mtu) {
3037
	global $config;
3038

    
3039
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3040
		foreach ($config['vlans']['vlan'] as $vlan) {
3041
			if ($vlan['if'] != $realhwif) {
3042
				continue;
3043
			}
3044
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3045
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3046
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu) {
3047
					$mtu = $config['interfaces'][$assignedport]['mtu'];
3048
				}
3049
			}
3050
		}
3051
	}
3052

    
3053
	return $mtu;
3054
}
3055

    
3056
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
3057
	global $config;
3058

    
3059
	if (!is_array($vlanifs)) {
3060
		return;
3061
	}
3062

    
3063
	/* All vlans need to use the same mtu value as their parent. */
3064
	foreach ($vlanifs as $vlan) {
3065
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3066
		if (!empty($assignedport)) {
3067
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
3068
				pfSense_interface_mtu($vlan['vlanif'], $config['interfaces'][$assignedport]['mtu']);
3069
			} else {
3070
				if (get_interface_mtu($vlan['vlanif']) != $mtu) {
3071
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
3072
				}
3073
			}
3074
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu) {
3075
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
3076
		}
3077
	}
3078
}
3079

    
3080
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3081
	global $config, $g;
3082
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3083
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3084

    
3085
	$wancfg = $config['interfaces'][$interface];
3086

    
3087
	if (!isset($wancfg['enable'])) {
3088
		return;
3089
	}
3090

    
3091
	$realif = get_real_interface($interface);
3092
	$realhwif_array = get_parent_interface($interface);
3093
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3094
	$realhwif = $realhwif_array[0];
3095

    
3096
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3097
		/* remove all IPv4 and IPv6 addresses */
3098
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3099
		if (is_array($tmpifaces)) {
3100
			foreach ($tmpifaces as $tmpiface) {
3101
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3102
					if (!is_linklocal($tmpiface)) {
3103
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3104
					}
3105
				} else {
3106
					if (is_subnetv4($tmpiface)) {
3107
						$tmpip = explode('/', $tmpiface);
3108
						$tmpip = $tmpip[0];
3109
					} else {
3110
						$tmpip = $tmpiface;
3111
					}
3112
					pfSense_interface_deladdress($realif, $tmpip);
3113
				}
3114
			}
3115
		}
3116

    
3117
		/* only bring down the interface when both v4 and v6 are set to NONE */
3118
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3119
			interface_bring_down($interface);
3120
		}
3121
	}
3122

    
3123
	$interface_to_check = $realif;
3124
	if (interface_isppp_type($interface)) {
3125
		$interface_to_check = $realhwif;
3126
	}
3127

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

    
3133
	/* Disable Accepting router advertisements unless specifically requested */
3134
	if ($g['debug']) {
3135
		log_error("Deny router advertisements for interface {$interface}");
3136
	}
3137
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3138

    
3139
	/* wireless configuration? */
3140
	if (is_array($wancfg['wireless'])) {
3141
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3142
	}
3143

    
3144
	$mac = get_interface_mac($realhwif);
3145
	/*
3146
	 * Don't try to reapply the spoofed MAC if it's already applied.
3147
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3148
	 * the interface config again, which attempts to spoof the MAC again,
3149
	 * which cycles the link again...
3150
	 */
3151
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
3152
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3153
			" link " . escapeshellarg($wancfg['spoofmac']));
3154
	} else {
3155

    
3156
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3157
			/*   this is not a valid mac address.  generate a
3158
			 *   temporary mac address so the machine can get online.
3159
			 */
3160
			echo gettext("Generating new MAC address.");
3161
			$random_mac = generate_random_mac_address();
3162
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3163
				" link " . escapeshellarg($random_mac));
3164
			$wancfg['spoofmac'] = $random_mac;
3165
			write_config();
3166
			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");
3167
		}
3168
	}
3169

    
3170
	/* media */
3171
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3172
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3173
		if ($wancfg['media']) {
3174
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3175
		}
3176
		if ($wancfg['mediaopt']) {
3177
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3178
		}
3179
		mwexec($cmd);
3180
	}
3181

    
3182
	/* Apply hw offloading policies as configured */
3183
	enable_hardware_offloading($interface);
3184

    
3185
	/* invalidate interface/ip/sn cache */
3186
	get_interface_arr(true);
3187
	unset($interface_ip_arr_cache[$realif]);
3188
	unset($interface_sn_arr_cache[$realif]);
3189
	unset($interface_ipv6_arr_cache[$realif]);
3190
	unset($interface_snv6_arr_cache[$realif]);
3191

    
3192
	$tunnelif = substr($realif, 0, 3);
3193

    
3194
	if (does_interface_exist($wancfg['if'])) {
3195
		interfaces_bring_up($wancfg['if']);
3196
	}
3197

    
3198
	if (!empty($wancfg['mtu'])) {
3199
		if (stristr($realif, "_vlan")) {
3200
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3201
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3202
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3203
				if ($wancfg['mtu'] > $parentmtu) {
3204
					log_error("There is a conflict on MTU between parent {$realhwif} and VLAN({$realif})");
3205
				}
3206
			} else {
3207
				$parentmtu = 0;
3208
			}
3209

    
3210
			$parentmtu = interface_vlan_mtu_configured($realhwif, $parentmtu);
3211

    
3212
			if (get_interface_mtu($realhwif) != $parentmtu) {
3213
				pfSense_interface_mtu($realhwif, $parentmtu);
3214
			}
3215

    
3216
			/* All vlans need to use the same mtu value as their parent. */
3217
			interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $parentmtu);
3218
		} else if (substr($realif, 0, 4) == 'lagg') {
3219
			/* LAGG interface must be destroyed and re-created to change MTU */
3220
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3221
				if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3222
					foreach ($config['laggs']['lagg'] as $lagg) {
3223
						if ($lagg['laggif'] == $realif) {
3224
							interface_lagg_configure($lagg);
3225
							break;
3226
						}
3227
					}
3228
				}
3229
			}
3230
		} else {
3231
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3232
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3233
			}
3234

    
3235
			/* This case is needed when the parent of vlans is being configured */
3236
			$vlans = link_interface_to_vlans($realif);
3237
			if (is_array($vlans)) {
3238
				interface_vlan_adapt_mtu($vlans, $wancfg['mtu']);
3239
			}
3240
			unset($vlans);
3241
		}
3242
		/* XXX: What about gre/gif/.. ? */
3243
	}
3244

    
3245
	switch ($wancfg['ipaddr']) {
3246
		case 'dhcp':
3247
			interface_dhcp_configure($interface);
3248
			break;
3249
		case 'pppoe':
3250
		case 'l2tp':
3251
		case 'pptp':
3252
		case 'ppp':
3253
			interface_ppps_configure($interface);
3254
			break;
3255
		default:
3256
			/* XXX: Kludge for now related to #3280 */
3257
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3258
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3259
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3260
				}
3261
			}
3262
			break;
3263
	}
3264

    
3265
	switch ($wancfg['ipaddrv6']) {
3266
		case 'slaac':
3267
		case 'dhcp6':
3268
			interface_dhcpv6_configure($interface, $wancfg);
3269
			break;
3270
		case '6rd':
3271
			interface_6rd_configure($interface, $wancfg);
3272
			break;
3273
		case '6to4':
3274
			interface_6to4_configure($interface, $wancfg);
3275
			break;
3276
		case 'track6':
3277
			interface_track6_configure($interface, $wancfg, $linkupevent);
3278
			break;
3279
		default:
3280
			/* XXX: Kludge for now related to #3280 */
3281
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3282
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3283
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3284
					// FIXME: Add IPv6 Support to the pfSense module
3285
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3286
				}
3287
			}
3288
			break;
3289
	}
3290

    
3291
	interface_netgraph_needed($interface);
3292

    
3293
	if (!platform_booting()) {
3294
		link_interface_to_vips($interface, "update");
3295

    
3296
		if ($tunnelif != 'gre') {
3297
			unset($gre);
3298
			$gre = link_interface_to_gre($interface);
3299
			if (!empty($gre)) {
3300
				array_walk($gre, 'interface_gre_configure');
3301
			}
3302
		}
3303

    
3304
		if ($tunnelif != 'gif') {
3305
			unset($gif);
3306
			$gif = link_interface_to_gif ($interface);
3307
			if (!empty($gif)) {
3308
				array_walk($gif, 'interface_gif_configure');
3309
			}
3310
		}
3311

    
3312
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3313
			unset($bridgetmp);
3314
			$bridgetmp = link_interface_to_bridge($interface);
3315
			if (!empty($bridgetmp)) {
3316
				interface_bridge_add_member($bridgetmp, $realif);
3317
			}
3318
		}
3319

    
3320
		$grouptmp = link_interface_to_group($interface);
3321
		if (!empty($grouptmp)) {
3322
			array_walk($grouptmp, 'interface_group_add_member');
3323
		}
3324

    
3325
		if ($interface == "lan") {
3326
			/* make new hosts file */
3327
			system_hosts_generate();
3328
		}
3329

    
3330
		if ($reloadall == true) {
3331

    
3332
			/* reconfigure static routes (kernel may have deleted them) */
3333
			system_routing_configure($interface);
3334

    
3335
			/* reload ipsec tunnels */
3336
			send_event("service reload ipsecdns");
3337

    
3338
			/* restart dnsmasq or unbound */
3339
			if (isset($config['dnsmasq']['enable'])) {
3340
				services_dnsmasq_configure();
3341
			} elseif (isset($config['unbound']['enable'])) {
3342
				services_unbound_configure();
3343
			}
3344

    
3345
			/* update dyndns */
3346
			send_event("service reload dyndns {$interface}");
3347

    
3348
			/* reload captive portal */
3349
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3350
				require_once('captiveportal.inc');
3351
			}
3352
			captiveportal_init_rules_byinterface($interface);
3353
		}
3354
	}
3355

    
3356
	interfaces_staticarp_configure($interface);
3357
	return 0;
3358
}
3359

    
3360
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3361
	global $config, $g;
3362

    
3363
	if (!is_array($wancfg)) {
3364
		return;
3365
	}
3366

    
3367
	if (!isset($wancfg['enable'])) {
3368
		return;
3369
	}
3370

    
3371
	/* If the interface is not configured via another, exit */
3372
	if (empty($wancfg['track6-interface'])) {
3373
		return;
3374
	}
3375

    
3376
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3377
	$realif = get_real_interface($interface);
3378
	$linklocal = find_interface_ipv6_ll($realif);
3379
	if (!empty($linklocal)) {
3380
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3381
	}
3382
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3383
	/* XXX: Probably should remove? */
3384
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3385

    
3386
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3387
	if (!isset($trackcfg['enable'])) {
3388
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3389
		return;
3390
	}
3391

    
3392
	switch ($trackcfg['ipaddrv6']) {
3393
		case "6to4":
3394
			if ($g['debug']) {
3395
				log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3396
			}
3397
			interface_track6_6to4_configure($interface, $wancfg);
3398
			break;
3399
		case "6rd":
3400
			if ($g['debug']) {
3401
				log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3402
			}
3403
			interface_track6_6rd_configure($interface, $wancfg);
3404
			break;
3405
		case "dhcp6":
3406
			if ($linkupevent == true) {
3407
				/*
3408
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
3409
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3410
				 *
3411
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
3412
				 */
3413
				$parentrealif = get_real_interface($wancfg['track6-interface']);
3414
				$pidv6 = find_dhcp6c_process($parentrealif);
3415
				if ($pidv6) {
3416
					posix_kill($pidv6, SIGHUP);
3417
				}
3418
			}
3419
			break;
3420
	}
3421

    
3422
	if ($linkupevent == false) {
3423
		if (!function_exists('services_dhcpd_configure')) {
3424
			require_once("services.inc");
3425
		}
3426

    
3427
		if (isset($config['unbound']['enable'])) {
3428
			services_unbound_configure();
3429
		}
3430

    
3431
		services_dhcpd_configure("inet6");
3432
	}
3433

    
3434
	return 0;
3435
}
3436

    
3437
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3438
	global $config, $g;
3439
	global $interface_ipv6_arr_cache;
3440
	global $interface_snv6_arr_cache;
3441

    
3442
	if (!is_array($lancfg)) {
3443
		return;
3444
	}
3445

    
3446
	/* If the interface is not configured via another, exit */
3447
	if (empty($lancfg['track6-interface'])) {
3448
		return;
3449
	}
3450

    
3451
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3452
	if (empty($wancfg)) {
3453
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3454
		return;
3455
	}
3456

    
3457
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3458
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3459
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not valid, not configuring 6RD tunnel");
3460
		return;
3461
	}
3462
	$hexwanv4 = return_hex_ipv4($ip4address);
3463

    
3464
	/* create the long prefix notation for math, save the prefix length */
3465
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3466
	$rd6prefixlen = $rd6prefix[1];
3467
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3468

    
3469
	/* binary presentation of the prefix for all 128 bits. */
3470
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3471

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

    
3477
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3478
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3479
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3480
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3481
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3482
	/* fill the rest out with zeros */
3483
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3484

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

    
3488
	$lanif = get_real_interface($interface);
3489
	$oip = find_interface_ipv6($lanif);
3490
	if (is_ipaddrv6($oip)) {
3491
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3492
	}
3493
	unset($interface_ipv6_arr_cache[$lanif]);
3494
	unset($interface_snv6_arr_cache[$lanif]);
3495
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3496
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3497

    
3498
	return 0;
3499
}
3500

    
3501
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3502
	global $config, $g;
3503
	global $interface_ipv6_arr_cache;
3504
	global $interface_snv6_arr_cache;
3505

    
3506
	if (!is_array($lancfg)) {
3507
		return;
3508
	}
3509

    
3510
	/* If the interface is not configured via another, exit */
3511
	if (empty($lancfg['track6-interface'])) {
3512
		return;
3513
	}
3514

    
3515
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3516
	if (empty($wancfg)) {
3517
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3518
		return;
3519
	}
3520

    
3521
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3522
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3523
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3524
		return;
3525
	}
3526
	$hexwanv4 = return_hex_ipv4($ip4address);
3527

    
3528
	/* create the long prefix notation for math, save the prefix length */
3529
	$sixto4prefix = "2002::";
3530
	$sixto4prefixlen = 16;
3531
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3532

    
3533
	/* binary presentation of the prefix for all 128 bits. */
3534
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3535

    
3536
	/* just save the left prefix length bits */
3537
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3538
	/* add the v4 address */
3539
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3540
	/* add the custom prefix id */
3541
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3542
	/* fill the rest out with zeros */
3543
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3544

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

    
3548
	$lanif = get_real_interface($interface);
3549
	$oip = find_interface_ipv6($lanif);
3550
	if (is_ipaddrv6($oip)) {
3551
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3552
	}
3553
	unset($interface_ipv6_arr_cache[$lanif]);
3554
	unset($interface_snv6_arr_cache[$lanif]);
3555
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3556
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3557

    
3558
	return 0;
3559
}
3560

    
3561
function interface_6rd_configure($interface = "wan", $wancfg) {
3562
	global $config, $g;
3563

    
3564
	/* because this is a tunnel interface we can only function
3565
	 *	with a public IPv4 address on the interface */
3566

    
3567
	if (!is_array($wancfg)) {
3568
		return;
3569
	}
3570

    
3571
	if (!is_module_loaded('if_stf.ko')) {
3572
		mwexec('/sbin/kldload if_stf.ko');
3573
	}
3574

    
3575
	$wanif = get_real_interface($interface);
3576
	$ip4address = find_interface_ip($wanif);
3577
	if (!is_ipaddrv4($ip4address)) {
3578
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3579
		return false;
3580
	}
3581
	$hexwanv4 = return_hex_ipv4($ip4address);
3582

    
3583
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3584
		$wancfg['prefix-6rd-v4plen'] = 0;
3585
	}
3586

    
3587
	/* create the long prefix notation for math, save the prefix length */
3588
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3589
	$rd6prefixlen = $rd6prefix[1];
3590
	$brgw = explode('.', $wancfg['gateway-6rd']);
3591
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3592
	$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);
3593
	if (strlen($rd6brgw) < 128) {
3594
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3595
	}
3596
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3597
	unset($brgw);
3598
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3599

    
3600
	/* binary presentation of the prefix for all 128 bits. */
3601
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3602

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

    
3610
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3611
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3612

    
3613

    
3614
	/* XXX: need to extend to support variable prefix size for v4 */
3615
	if (!is_module_loaded("if_stf")) {
3616
		mwexec("/sbin/kldload if_stf.ko");
3617
	}
3618
	$stfiface = "{$interface}_stf";
3619
	if (does_interface_exist($stfiface)) {
3620
		pfSense_interface_destroy($stfiface);
3621
	}
3622
	$tmpstfiface = pfSense_interface_create("stf");
3623
	pfSense_interface_rename($tmpstfiface, $stfiface);
3624
	pfSense_interface_flags($stfiface, IFF_LINK2);
3625
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3626
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3627
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3628
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3629
	}
3630
	if ($g['debug']) {
3631
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3632
	}
3633

    
3634
	/* write out a default router file */
3635
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3636
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3637

    
3638
	$ip4gateway = get_interface_gateway($interface);
3639
	if (is_ipaddrv4($ip4gateway)) {
3640
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3641
	}
3642

    
3643
	/* configure dependent interfaces */
3644
	if (!platform_booting()) {
3645
		link_interface_to_track6($interface, "update");
3646
	}
3647

    
3648
	return 0;
3649
}
3650

    
3651
function interface_6to4_configure($interface = "wan", $wancfg) {
3652
	global $config, $g;
3653

    
3654
	/* because this is a tunnel interface we can only function
3655
	 *	with a public IPv4 address on the interface */
3656

    
3657
	if (!is_array($wancfg)) {
3658
		return;
3659
	}
3660

    
3661
	$wanif = get_real_interface($interface);
3662
	$ip4address = find_interface_ip($wanif);
3663
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3664
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3665
		return false;
3666
	}
3667

    
3668
	/* create the long prefix notation for math, save the prefix length */
3669
	$stfprefixlen = 16;
3670
	$stfprefix = Net_IPv6::uncompress("2002::");
3671
	$stfarr = explode(":", $stfprefix);
3672
	$v4prefixlen = "0";
3673

    
3674
	/* we need the hex form of the interface IPv4 address */
3675
	$ip4arr = explode(".", $ip4address);
3676
	$hexwanv4 = "";
3677
	foreach ($ip4arr as $octet) {
3678
		$hexwanv4 .= sprintf("%02x", $octet);
3679
	}
3680

    
3681
	/* we need the hex form of the broker IPv4 address */
3682
	$ip4arr = explode(".", "192.88.99.1");
3683
	$hexbrv4 = "";
3684
	foreach ($ip4arr as $octet) {
3685
		$hexbrv4 .= sprintf("%02x", $octet);
3686
	}
3687

    
3688
	/* binary presentation of the prefix for all 128 bits. */
3689
	$stfprefixbin = "";
3690
	foreach ($stfarr as $element) {
3691
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3692
	}
3693
	/* just save the left prefix length bits */
3694
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3695

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

    
3700
	/* for the local subnet too. */
3701
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3702
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3703

    
3704
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3705
	$stfbrarr = array();
3706
	$stfbrbinarr = array();
3707
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3708
	foreach ($stfbrbinarr as $bin) {
3709
		$stfbrarr[] = dechex(bindec($bin));
3710
	}
3711
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3712

    
3713
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3714
	$stflanarr = array();
3715
	$stflanbinarr = array();
3716
	$stflanbinarr = str_split($stflanbin, 16);
3717
	foreach ($stflanbinarr as $bin) {
3718
		$stflanarr[] = dechex(bindec($bin));
3719
	}
3720
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3721
	$stflanarr[7] = 1;
3722
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3723

    
3724
	/* setup the stf interface */
3725
	if (!is_module_loaded("if_stf")) {
3726
		mwexec("/sbin/kldload if_stf.ko");
3727
	}
3728
	$stfiface = "{$interface}_stf";
3729
	if (does_interface_exist($stfiface)) {
3730
		pfSense_interface_destroy($stfiface);
3731
	}
3732
	$tmpstfiface = pfSense_interface_create("stf");
3733
	pfSense_interface_rename($tmpstfiface, $stfiface);
3734
	pfSense_interface_flags($stfiface, IFF_LINK2);
3735
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3736

    
3737
	if ($g['debug']) {
3738
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3739
	}
3740

    
3741
	/* write out a default router file */
3742
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3743
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3744

    
3745
	$ip4gateway = get_interface_gateway($interface);
3746
	if (is_ipaddrv4($ip4gateway)) {
3747
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3748
	}
3749

    
3750
	if (!platform_booting()) {
3751
		link_interface_to_track6($interface, "update");
3752
	}
3753

    
3754
	return 0;
3755
}
3756

    
3757
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3758
	global $config, $g;
3759

    
3760
	if (!is_array($wancfg)) {
3761
		return;
3762
	}
3763

    
3764
	$wanif = get_real_interface($interface, "inet6");
3765
	$dhcp6cconf = "";
3766

    
3767
	if ($wancfg['adv_dhcp6_config_file_override']) {
3768
		// DHCP6 Config File Override
3769
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3770
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3771
		// DHCP6 Config File Advanced
3772
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3773
	} else {
3774
		// DHCP6 Config File Basic
3775
		$dhcp6cconf .= "interface {$wanif} {\n";
3776

    
3777
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3778
		if ($wancfg['ipaddrv6'] == "slaac") {
3779
			$dhcp6cconf .= "\tinformation-only;\n";
3780
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3781
			$dhcp6cconf .= "\trequest domain-name;\n";
3782
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3783
			$dhcp6cconf .= "};\n";
3784
		} else {
3785
			$trackiflist = array();
3786
			$iflist = link_interface_to_track6($interface);
3787
			foreach ($iflist as $ifname => $ifcfg) {
3788
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3789
					$trackiflist[$ifname] = $ifcfg;
3790
				}
3791
			}
3792

    
3793
			/* skip address request if this is set */
3794
			if (!isset($wancfg['dhcp6prefixonly'])) {
3795
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3796
			}
3797
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3798
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3799
			}
3800

    
3801
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3802
			$dhcp6cconf .= "\trequest domain-name;\n";
3803
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3804
			$dhcp6cconf .= "};\n";
3805

    
3806
			if (!isset($wancfg['dhcp6prefixonly'])) {
3807
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3808
			}
3809

    
3810
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3811
				/* Setup the prefix delegation */
3812
				$dhcp6cconf .= "id-assoc pd 0 {\n";
3813
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3814
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
3815
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
3816
				}
3817
				foreach ($trackiflist as $friendly => $ifcfg) {
3818
					if ($g['debug']) {
3819
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3820
					}
3821
					$realif = get_real_interface($friendly);
3822
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
3823
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
3824
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3825
					$dhcp6cconf .= "\t};\n";
3826
				}
3827
				unset($preflen, $iflist, $ifcfg, $ifname);
3828
				$dhcp6cconf .= "};\n";
3829
			}
3830
			unset($trackiflist);
3831
		}
3832
	}
3833

    
3834
	/* wide-dhcp6c works for now. */
3835
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3836
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3837
		unset($dhcp6cconf);
3838
		return 1;
3839
	}
3840
	unset($dhcp6cconf);
3841

    
3842
	$dhcp6cscript = "#!/bin/sh\n";
3843
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3844
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3845
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3846
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3847
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3848
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3849
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3850
		unset($dhcp6cscript);
3851
		return 1;
3852
	}
3853
	unset($dhcp6cscript);
3854
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3855

    
3856
	$rtsoldscript = "#!/bin/sh\n";
3857
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3858
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3859
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3860
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Recieved RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
3861
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3862
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3863
	$rtsoldscript .= "\t/bin/sleep 1\n";
3864
	$rtsoldscript .= "fi\n";
3865
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3866
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3867
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3868
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3869
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3870
		unset($rtsoldscript);
3871
		return 1;
3872
	}
3873
	unset($rtsoldscript);
3874
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3875

    
3876
	/* accept router advertisements for this interface */
3877
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3878
	log_error("Accept router advertisements on interface {$wanif} ");
3879
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3880

    
3881
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3882
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3883
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3884
		sleep(2);
3885
	}
3886
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3887

    
3888
	/* NOTE: will be called from rtsold invoked script
3889
	 * link_interface_to_track6($interface, "update");
3890
	 */
3891

    
3892
	return 0;
3893
}
3894

    
3895
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3896
	global $g;
3897

    
3898
	$send_options = "";
3899
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3900
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_send_options']);
3901
		foreach ($options as $option) {
3902
			$send_options .= "\tsend " . trim($option) . ";\n";
3903
		}
3904
	}
3905

    
3906
	$request_options = "";
3907
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3908
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_request_options']);
3909
		foreach ($options as $option) {
3910
			$request_options .= "\trequest " . trim($option) . ";\n";
3911
		}
3912
	}
3913

    
3914
	$information_only = "";
3915
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
3916
		$information_only = "\tinformation-only;\n";
3917
	}
3918

    
3919
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3920
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
3921
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3922
	}
3923

    
3924
	$interface_statement  = "interface";
3925
	$interface_statement .= " {$wanif}";
3926
	$interface_statement .= " {\n";
3927
	$interface_statement .= "$send_options";
3928
	$interface_statement .= "$request_options";
3929
	$interface_statement .= "$information_only";
3930
	$interface_statement .= "$script";
3931
	$interface_statement .= "};\n";
3932

    
3933
	$id_assoc_statement_address = "";
3934
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3935
		$id_assoc_statement_address .= "id-assoc";
3936
		$id_assoc_statement_address .= " na";
3937
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
3938
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3939
		}
3940
		$id_assoc_statement_address .= " { ";
3941

    
3942
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
3943
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
3944
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
3945
			$id_assoc_statement_address .= "\n\taddress";
3946
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3947
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3948
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
3949
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
3950
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3951
			}
3952
			$id_assoc_statement_address .= ";\n";
3953
		}
3954

    
3955
		$id_assoc_statement_address .= "};\n";
3956
	}
3957

    
3958
	$id_assoc_statement_prefix = "";
3959
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3960
		$id_assoc_statement_prefix .= "id-assoc";
3961
		$id_assoc_statement_prefix .= " pd";
3962
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
3963
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3964
		}
3965
		$id_assoc_statement_prefix .= " { ";
3966

    
3967
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
3968
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
3969
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
3970
			$id_assoc_statement_prefix .= "\n\tprefix";
3971
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3972
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3973
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
3974
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
3975
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3976
			}
3977
			$id_assoc_statement_prefix .= ";";
3978
		}
3979

    
3980
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3981
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3982
			$id_assoc_statement_prefix .= " {$wanif}";
3983
			$id_assoc_statement_prefix .= " {\n";
3984
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3985
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
3986
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
3987
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3988
			}
3989
			$id_assoc_statement_prefix .= "\t};";
3990
		}
3991

    
3992
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
3993
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
3994
			$id_assoc_statement_prefix .= "\n";
3995
		}
3996

    
3997
		$id_assoc_statement_prefix .= "};\n";
3998
	}
3999

    
4000
	$authentication_statement = "";
4001
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4002
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4003
		$authentication_statement .= "authentication";
4004
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4005
		$authentication_statement .= " {\n";
4006
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4007
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4008
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4009
		}
4010
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4011
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4012
		}
4013
		$authentication_statement .= "};\n";
4014
	}
4015

    
4016
	$key_info_statement = "";
4017
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4018
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4019
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4020
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4021
		$key_info_statement .= "keyinfo";
4022
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4023
		$key_info_statement .= " {\n";
4024
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4025
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4026
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4027
		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'])) {
4028
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4029
		}
4030
		$key_info_statement .= "};\n";
4031
	}
4032

    
4033
	$dhcp6cconf  = $interface_statement;
4034
	$dhcp6cconf .= $id_assoc_statement_address;
4035
	$dhcp6cconf .= $id_assoc_statement_prefix;
4036
	$dhcp6cconf .= $authentication_statement;
4037
	$dhcp6cconf .= $key_info_statement;
4038

    
4039
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4040

    
4041
	return $dhcp6cconf;
4042
}
4043

    
4044

    
4045
function DHCP6_Config_File_Override($wancfg, $wanif) {
4046

    
4047
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4048

    
4049
	if ($dhcp6cconf === false) {
4050
		log_error("Error: cannot open {$wancfg['adv_dhcp6_config_file_override_path']} in DHCP6_Config_File_Override() for reading.\n");
4051
		return '';
4052
	} else {
4053
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4054
	}
4055
}
4056

    
4057

    
4058
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4059

    
4060
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4061

    
4062
	return $dhcp6cconf;
4063
}
4064

    
4065

    
4066
function interface_dhcp_configure($interface = "wan") {
4067
	global $config, $g;
4068

    
4069
	$wancfg = $config['interfaces'][$interface];
4070
	$wanif = $wancfg['if'];
4071
	if (empty($wancfg)) {
4072
		$wancfg = array();
4073
	}
4074

    
4075
	/* generate dhclient_wan.conf */
4076
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4077
	if (!$fd) {
4078
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
4079
		return 1;
4080
	}
4081

    
4082
	if ($wancfg['dhcphostname']) {
4083
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4084
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4085
	} else {
4086
		$dhclientconf_hostname = "";
4087
	}
4088

    
4089
	$wanif = get_real_interface($interface);
4090
	if (empty($wanif)) {
4091
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4092
		return 0;
4093
	}
4094
	$dhclientconf = "";
4095

    
4096
	$dhclientconf .= <<<EOD
4097
interface "{$wanif}" {
4098
timeout 60;
4099
retry 15;
4100
select-timeout 0;
4101
initial-interval 1;
4102
	{$dhclientconf_hostname}
4103
	script "/sbin/dhclient-script";
4104
EOD;
4105

    
4106
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4107
		$dhclientconf .= <<<EOD
4108

    
4109
	reject {$wancfg['dhcprejectfrom']};
4110
EOD;
4111
	}
4112
	$dhclientconf .= <<<EOD
4113

    
4114
}
4115

    
4116
EOD;
4117

    
4118
	// DHCP Config File Advanced
4119
	if ($wancfg['adv_dhcp_config_advanced']) {
4120
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4121
	}
4122

    
4123
	if (is_ipaddr($wancfg['alias-address'])) {
4124
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4125
		$dhclientconf .= <<<EOD
4126
alias {
4127
	interface "{$wanif}";
4128
	fixed-address {$wancfg['alias-address']};
4129
	option subnet-mask {$subnetmask};
4130
}
4131

    
4132
EOD;
4133
	}
4134

    
4135
	// DHCP Config File Override
4136
	if ($wancfg['adv_dhcp_config_file_override']) {
4137
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4138
	}
4139

    
4140
	fwrite($fd, $dhclientconf);
4141
	fclose($fd);
4142

    
4143
	/* bring wan interface up before starting dhclient */
4144
	if ($wanif) {
4145
		interfaces_bring_up($wanif);
4146
	} else {
4147
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4148
	}
4149

    
4150
	/* Make sure dhclient is not running */
4151
	kill_dhclient_process($wanif);
4152

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

    
4156
	return 0;
4157
}
4158

    
4159
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4160

    
4161
	$hostname = "";
4162
	if ($wancfg['dhcphostname'] != '') {
4163
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4164
	}
4165

    
4166
	/* DHCP Protocol Timings */
4167
	$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");
4168
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4169
		$pt_variable = "{$Protocol_Timing}";
4170
		${$pt_variable} = "";
4171
		if ($wancfg[$Protocol_Timing] != "") {
4172
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4173
		}
4174
	}
4175

    
4176
	$send_options = "";
4177
	if ($wancfg['adv_dhcp_send_options'] != '') {
4178
		$options = explode(',', $wancfg['adv_dhcp_send_options']);
4179
		foreach ($options as $option) {
4180
			$send_options .= "\tsend " . trim($option) . ";\n";
4181
		}
4182
	}
4183

    
4184
	$request_options = "";
4185
	if ($wancfg['adv_dhcp_request_options'] != '') {
4186
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4187
	}
4188

    
4189
	$required_options = "";
4190
	if ($wancfg['adv_dhcp_required_options'] != '') {
4191
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4192
	}
4193

    
4194
	$option_modifiers = "";
4195
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4196
		$modifiers = explode(',', $wancfg['adv_dhcp_option_modifiers']);
4197
		foreach ($modifiers as $modifier) {
4198
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4199
		}
4200
	}
4201

    
4202
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4203
	$dhclientconf .= "\n";
4204
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4205
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4206
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4207
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4208
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4209
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4210
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4211
	$dhclientconf .= "\n";
4212
	$dhclientconf .= "# DHCP Protocol Options\n";
4213
	$dhclientconf .= "{$hostname}";
4214
	$dhclientconf .= "{$send_options}";
4215
	$dhclientconf .= "{$request_options}";
4216
	$dhclientconf .= "{$required_options}";
4217
	$dhclientconf .= "{$option_modifiers}";
4218
	$dhclientconf .= "\n";
4219
	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4220
	$dhclientconf .= "}\n";
4221

    
4222
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4223

    
4224
	return $dhclientconf;
4225
}
4226

    
4227

    
4228
function DHCP_Config_File_Override($wancfg, $wanif) {
4229

    
4230
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4231

    
4232
	if ($dhclientconf === false) {
4233
		log_error("Error: cannot open {$wancfg['adv_dhcp_config_file_override_path']} in DHCP_Config_File_Override() for reading.\n");
4234
		return '';
4235
	} else {
4236
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4237
	}
4238
}
4239

    
4240

    
4241
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4242

    
4243
	/* Apply Interface Substitutions */
4244
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4245

    
4246
	/* Apply Hostname Substitutions */
4247
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4248

    
4249
	/* Arrays of MAC Address Types, Cases, Delimiters */
4250
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4251
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4252
	$various_mac_cases      = array("U", "L");
4253
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4254

    
4255
	/* Apply MAC Address Substitutions */
4256
	foreach ($various_mac_types as $various_mac_type) {
4257
		foreach ($various_mac_cases as $various_mac_case) {
4258
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4259

    
4260
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4261
				if ($res !== false) {
4262

    
4263
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4264
					if ("$various_mac_case" == "U") {
4265
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4266
					}
4267
					if ("$various_mac_case" == "L") {
4268
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4269
					}
4270

    
4271
					if ("$various_mac_type" == "mac_addr_hex") {
4272
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4273
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4274
						$dhcpclientconf_mac_hex = "";
4275
						$delimiter = "";
4276
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4277
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4278
							$delimiter = ":";
4279
						}
4280
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4281
					}
4282

    
4283
					/* MAC Address Delimiter Substitutions */
4284
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4285

    
4286
					/* Apply MAC Address Substitutions */
4287
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4288
				}
4289
			}
4290
		}
4291
	}
4292

    
4293
	return $dhclientconf;
4294
}
4295

    
4296
function interfaces_group_setup() {
4297
	global $config;
4298

    
4299
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4300
		return;
4301
	}
4302

    
4303
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4304
		interface_group_setup($groupar);
4305
	}
4306

    
4307
	return;
4308
}
4309

    
4310
function interface_group_setup(&$groupname /* The parameter is an array */) {
4311
	global $config;
4312

    
4313
	if (!is_array($groupname)) {
4314
		return;
4315
	}
4316
	$members = explode(" ", $groupname['members']);
4317
	foreach ($members as $ifs) {
4318
		$realif = get_real_interface($ifs);
4319
		if ($realif && does_interface_exist($realif)) {
4320
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4321
		}
4322
	}
4323

    
4324
	return;
4325
}
4326

    
4327
function is_interface_group($if) {
4328
	global $config;
4329

    
4330
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4331
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4332
			if ($groupentry['ifname'] === $if) {
4333
				return true;
4334
			}
4335
		}
4336
	}
4337

    
4338
	return false;
4339
}
4340

    
4341
function interface_group_add_member($interface, $groupname) {
4342
	$interface = get_real_interface($interface);
4343
	if (does_interface_exist($interface)) {
4344
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4345
	}
4346
}
4347

    
4348
/* COMPAT Function */
4349
function convert_friendly_interface_to_real_interface_name($interface) {
4350
	return get_real_interface($interface);
4351
}
4352

    
4353
/* COMPAT Function */
4354
function get_real_wan_interface($interface = "wan") {
4355
	return get_real_interface($interface);
4356
}
4357

    
4358
/* COMPAT Function */
4359
function get_current_wan_address($interface = "wan") {
4360
	return get_interface_ip($interface);
4361
}
4362

    
4363
/*
4364
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4365
 */
4366
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4367
	global $config;
4368

    
4369
	if (stripos($interface, "_vip")) {
4370
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
4371
			if ($vip['mode'] == "carp") {
4372
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}") {
4373
					return $vip['interface'];
4374
				}
4375
			}
4376
		}
4377
	}
4378

    
4379
	/* XXX: For speed reasons reference directly the interface array */
4380
	$ifdescrs = &$config['interfaces'];
4381
	//$ifdescrs = get_configured_interface_list(false, true);
4382

    
4383
	foreach ($ifdescrs as $if => $ifname) {
4384
		if ($if == $interface || $ifname['if'] == $interface) {
4385
			return $if;
4386
		}
4387

    
4388
		if (get_real_interface($if) == $interface) {
4389
			return $if;
4390
		}
4391

    
4392
		if ($checkparent == false) {
4393
			continue;
4394
		}
4395

    
4396
		$int = get_parent_interface($if, true);
4397
		if (is_array($int)) {
4398
			foreach ($int as $iface) {
4399
				if ($iface == $interface) {
4400
					return $if;
4401
				}
4402
			}
4403
		}
4404
	}
4405

    
4406
	if ($interface == "enc0") {
4407
		return 'IPsec';
4408
	}
4409
}
4410

    
4411
/* attempt to resolve interface to friendly descr */
4412
function convert_friendly_interface_to_friendly_descr($interface) {
4413
	global $config;
4414

    
4415
	switch ($interface) {
4416
		case "l2tp":
4417
			$ifdesc = "L2TP";
4418
			break;
4419
		case "pptp":
4420
			$ifdesc = "PPTP";
4421
			break;
4422
		case "pppoe":
4423
			$ifdesc = "PPPoE";
4424
			break;
4425
		case "openvpn":
4426
			$ifdesc = "OpenVPN";
4427
			break;
4428
		case "enc0":
4429
		case "ipsec":
4430
		case "IPsec":
4431
			$ifdesc = "IPsec";
4432
			break;
4433
		default:
4434
			if (isset($config['interfaces'][$interface])) {
4435
				if (empty($config['interfaces'][$interface]['descr'])) {
4436
					$ifdesc = strtoupper($interface);
4437
				} else {
4438
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4439
				}
4440
				break;
4441
			} else if (substr($interface, 0, 4) == '_vip') {
4442
				if (is_array($config['virtualip']['vip'])) {
4443
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
4444
						if ($vip['mode'] == "carp") {
4445
							if ($interface == "{$vip['interface']}_vip{$vip['vhid']}") {
4446
								return "{$vip['subnet']} - {$vip['descr']}";
4447
							}
4448
						}
4449
					}
4450
				}
4451
			} else if (substr($interface, 0, 5) == '_lloc') {
4452
				return get_interface_linklocal($interface);
4453
			} else {
4454
				/* if list */
4455
				$ifdescrs = get_configured_interface_with_descr(false, true);
4456
				foreach ($ifdescrs as $if => $ifname) {
4457
					if ($if == $interface || $ifname == $interface) {
4458
						return $ifname;
4459
					}
4460
				}
4461
			}
4462
			break;
4463
	}
4464

    
4465
	return $ifdesc;
4466
}
4467

    
4468
function convert_real_interface_to_friendly_descr($interface) {
4469

    
4470
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4471

    
4472
	if (!empty($ifdesc)) {
4473
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4474
	}
4475

    
4476
	return $interface;
4477
}
4478

    
4479
/*
4480
 *  get_parent_interface($interface):
4481
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4482
 *				or virtual interface (i.e. vlan)
4483
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4484
 *			-- returns $interface passed in if $interface parent is not found
4485
 *			-- returns empty array if an invalid interface is passed
4486
 *	(Only handles ppps and vlans now.)
4487
 */
4488
function get_parent_interface($interface, $avoidrecurse = false) {
4489
	global $config;
4490

    
4491
	$parents = array();
4492
	//Check that we got a valid interface passed
4493
	$realif = get_real_interface($interface);
4494
	if ($realif == NULL) {
4495
		return $parents;
4496
	}
4497

    
4498
	// If we got a real interface, find it's friendly assigned name
4499
	if ($interface == $realif && $avoidrecurse == false) {
4500
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4501
	}
4502

    
4503
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4504
		$ifcfg = $config['interfaces'][$interface];
4505
		switch ($ifcfg['ipaddr']) {
4506
			case "ppp":
4507
			case "pppoe":
4508
			case "pptp":
4509
			case "l2tp":
4510
				if (empty($parents)) {
4511
					if (is_array($config['ppps']['ppp'])) {
4512
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4513
							if ($ifcfg['if'] == $ppp['if']) {
4514
								$ports = explode(',', $ppp['ports']);
4515
								foreach ($ports as $pid => $parent_if) {
4516
									$parents[$pid] = get_real_interface($parent_if);
4517
								}
4518
								break;
4519
							}
4520
						}
4521
					}
4522
				}
4523
				break;
4524
			case "dhcp":
4525
			case "static":
4526
			default:
4527
				// Handle _vlans
4528
				if (strpos($realif, '_vlan') !== FALSE) {
4529
					if (is_array($config['vlans']['vlan'])) {
4530
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4531
							if ($ifcfg['if'] == $vlan['vlanif']) {
4532
								$parents[0] = $vlan['if'];
4533
								break;
4534
							}
4535
						}
4536
					}
4537
				}
4538
				break;
4539
		}
4540
	}
4541

    
4542
	if (empty($parents)) {
4543
		$parents[0] = $realif;
4544
	}
4545

    
4546
	return $parents;
4547
}
4548

    
4549
function interface_is_wireless_clone($wlif) {
4550
	if (!stristr($wlif, "_wlan")) {
4551
		return false;
4552
	} else {
4553
		return true;
4554
	}
4555
}
4556

    
4557
function interface_get_wireless_base($wlif) {
4558
	if (!stristr($wlif, "_wlan")) {
4559
		return $wlif;
4560
	} else {
4561
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4562
	}
4563
}
4564

    
4565
function interface_get_wireless_clone($wlif) {
4566
	if (!stristr($wlif, "_wlan")) {
4567
		return $wlif . "_wlan0";
4568
	} else {
4569
		return $wlif;
4570
	}
4571
}
4572

    
4573
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4574
	global $config, $g;
4575

    
4576
	$wanif = NULL;
4577

    
4578
	switch ($interface) {
4579
		case "l2tp":
4580
			$wanif = "l2tp";
4581
			break;
4582
		case "pptp":
4583
			$wanif = "pptp";
4584
			break;
4585
		case "pppoe":
4586
			$wanif = "pppoe";
4587
			break;
4588
		case "openvpn":
4589
			$wanif = "openvpn";
4590
			break;
4591
		case "ipsec":
4592
		case "enc0":
4593
			$wanif = "enc0";
4594
			break;
4595
		case "ppp":
4596
			$wanif = "ppp";
4597
			break;
4598
		default:
4599
			if (substr($interface, 0, 4) == '_vip') {
4600
				$wanif = get_configured_carp_interface_list($interface, '', 'iface');
4601
				if (!empty($wanif)) {
4602
					$wanif = get_real_interface($wanif, $family);
4603
				}
4604
				break;
4605
			} else if (substr($interface, 0, 5) == '_lloc') {
4606
				$interface = substr($interface, 5);
4607
			} else if (does_interface_exist($interface, $flush)) {
4608
				/*
4609
				 * If a real interface was already passed simply
4610
				 * pass the real interface back.  This encourages
4611
				 * the usage of this function in more cases so that
4612
				 * we can combine logic for more flexibility.
4613
				 */
4614
				$wanif = $interface;
4615
				break;
4616
			}
4617

    
4618
			if (empty($config['interfaces'][$interface])) {
4619
				break;
4620
			}
4621

    
4622
			$cfg = &$config['interfaces'][$interface];
4623

    
4624
			if ($family == "inet6") {
4625
				switch ($cfg['ipaddrv6']) {
4626
					case "6rd":
4627
					case "6to4":
4628
						$wanif = "{$interface}_stf";
4629
						break;
4630
					case 'pppoe':
4631
					case 'ppp':
4632
					case 'l2tp':
4633
					case 'pptp':
4634
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4635
							$wanif = interface_get_wireless_clone($cfg['if']);
4636
						} else {
4637
							$wanif = $cfg['if'];
4638
						}
4639
						break;
4640
					default:
4641
						switch ($cfg['ipaddr']) {
4642
							case 'pppoe':
4643
							case 'ppp':
4644
							case 'l2tp':
4645
							case 'pptp':
4646
								if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false) {
4647
									$wanif = $cfg['if'];
4648
								} else {
4649
									$parents = get_parent_interface($interface);
4650
									if (!empty($parents[0])) {
4651
										$wanif = $parents[0];
4652
									} else {
4653
										$wanif = $cfg['if'];
4654
									}
4655
								}
4656
								break;
4657
							default:
4658
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4659
									$wanif = interface_get_wireless_clone($cfg['if']);
4660
								} else {
4661
									$wanif = $cfg['if'];
4662
								}
4663
								break;
4664
						}
4665
						break;
4666
				}
4667
			} else {
4668
				// Wireless cloned NIC support (FreeBSD 8+)
4669
				// interface name format: $parentnic_wlanparentnic#
4670
				// example: ath0_wlan0
4671
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4672
					$wanif = interface_get_wireless_clone($cfg['if']);
4673
				} else {
4674
					$wanif = $cfg['if'];
4675
				}
4676
			}
4677
			break;
4678
	}
4679

    
4680
	return $wanif;
4681
}
4682

    
4683
/* Guess the physical interface by providing a IP address */
4684
function guess_interface_from_ip($ipaddress) {
4685

    
4686
	$family = '';
4687
	if (is_ipaddrv4($ipaddress)) {
4688
		$family = 'inet';
4689
	}
4690
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4691
		$family = 'inet6';
4692
	}
4693

    
4694
	if (empty($family)) {
4695
		return false;
4696
	}
4697

    
4698
	/* create a route table we can search */
4699
	$output = '';
4700
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4701
	$output[0] = trim($output[0], " \n");
4702
	if (!empty($output[0])) {
4703
		return $output[0];
4704
	}
4705

    
4706
	return false;
4707
}
4708

    
4709
/*
4710
 * find_ip_interface($ip): return the interface where an ip is defined
4711
 *   (or if $bits is specified, where an IP within the subnet is defined)
4712
 */
4713
function find_ip_interface($ip, $bits = null) {
4714
	if (!is_ipaddr($ip)) {
4715
		return false;
4716
	}
4717

    
4718
	$isv6ip = is_ipaddrv6($ip);
4719

    
4720
	/* if list */
4721
	$ifdescrs = get_configured_interface_list();
4722

    
4723
	foreach ($ifdescrs as $ifdescr => $ifname) {
4724
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4725
		if (is_null($ifip)) {
4726
			continue;
4727
		}
4728
		if (is_null($bits)) {
4729
			if ($ip == $ifip) {
4730
				$int = get_real_interface($ifname);
4731
				return $int;
4732
			}
4733
		} else {
4734
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4735
				$int = get_real_interface($ifname);
4736
				return $int;
4737
			}
4738
		}
4739
	}
4740

    
4741
	return false;
4742
}
4743

    
4744
/*
4745
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4746
 *   (or if $bits is specified, where an IP within the subnet is found)
4747
 */
4748
function find_virtual_ip_alias($ip, $bits = null) {
4749
	global $config;
4750

    
4751
	if (!is_array($config['virtualip']['vip'])) {
4752
		return false;
4753
	}
4754
	if (!is_ipaddr($ip)) {
4755
		return false;
4756
	}
4757

    
4758
	$isv6ip = is_ipaddrv6($ip);
4759

    
4760
	foreach ($config['virtualip']['vip'] as $vip) {
4761
		if ($vip['mode'] === "ipalias") {
4762
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
4763
				continue;
4764
			}
4765
			if (is_null($bits)) {
4766
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4767
					return $vip;
4768
				}
4769
			} else {
4770
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
4771
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4772
					return $vip;
4773
				}
4774
			}
4775
		}
4776
	}
4777
	return false;
4778
}
4779

    
4780
/*
4781
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4782
 */
4783
function find_number_of_created_carp_interfaces() {
4784
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4785
}
4786

    
4787
/*
4788
 * find_carp_interface($ip): return the carp interface where an ip is defined
4789
 */
4790
function find_carp_interface($ip) {
4791
	global $config;
4792
	if (is_array($config['virtualip']['vip'])) {
4793
		foreach ($config['virtualip']['vip'] as $vip) {
4794
			if ($vip['mode'] == "carp") {
4795
				if (is_ipaddrv4($ip)) {
4796
					$carp_ip = get_interface_ip($vip['interface']);
4797
				}
4798
				if (is_ipaddrv6($ip)) {
4799
					$carp_ip = get_interface_ipv6($vip['interface']);
4800
				}
4801
				exec("/sbin/ifconfig", $output, $return);
4802
				foreach ($output as $line) {
4803
					$elements = preg_split("/[ ]+/i", $line);
4804
					if (strstr($elements[0], "vip")) {
4805
						$curif = str_replace(":", "", $elements[0]);
4806
					}
4807
					if (stristr($line, $ip)) {
4808
						$if = $curif;
4809
						continue;
4810
					}
4811
				}
4812

    
4813
				if ($if) {
4814
					return $if;
4815
				}
4816
			}
4817
		}
4818
	}
4819
}
4820

    
4821
function link_carp_interface_to_parent($interface) {
4822
	global $config;
4823

    
4824
	if (empty($interface)) {
4825
		return;
4826
	}
4827

    
4828
	$carp_ip = get_interface_ip($interface);
4829
	$carp_ipv6 = get_interface_ipv6($interface);
4830

    
4831
	if ((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6))) {
4832
		return;
4833
	}
4834

    
4835
	/* if list */
4836
	$ifdescrs = get_configured_interface_list();
4837
	foreach ($ifdescrs as $ifdescr => $ifname) {
4838
		/* check IPv4 */
4839
		if (is_ipaddrv4($carp_ip)) {
4840
			$interfaceip = get_interface_ip($ifname);
4841
			$subnet_bits = get_interface_subnet($ifname);
4842
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4843
			if (ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}")) {
4844
				return $ifname;
4845
			}
4846
		}
4847
		/* Check IPv6 */
4848
		if (is_ipaddrv6($carp_ipv6)) {
4849
			$interfaceipv6 = get_interface_ipv6($ifname);
4850
			$prefixlen = get_interface_subnetv6($ifname);
4851
			if (ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}")) {
4852
				return $ifname;
4853
			}
4854
		}
4855
	}
4856
	return "";
4857
}
4858

    
4859

    
4860
/****f* interfaces/link_ip_to_carp_interface
4861
 * NAME
4862
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4863
 * INPUTS
4864
 *   $ip
4865
 * RESULT
4866
 *   $carp_ints
4867
 ******/
4868
function link_ip_to_carp_interface($ip) {
4869
	global $config;
4870

    
4871
	if (!is_ipaddr($ip)) {
4872
		return;
4873
	}
4874

    
4875
	$carp_ints = "";
4876
	if (is_array($config['virtualip']['vip'])) {
4877
		$first = 0;
4878
		$carp_int = array();
4879
		foreach ($config['virtualip']['vip'] as $vip) {
4880
			if ($vip['mode'] == "carp") {
4881
				$carp_ip = $vip['subnet'];
4882
				$carp_sn = $vip['subnet_bits'];
4883
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4884
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4885
					$carp_int[] = get_real_interface($vip['interface']);
4886
				}
4887
			}
4888
		}
4889
		if (!empty($carp_int)) {
4890
			$carp_ints = implode(" ", array_unique($carp_int));
4891
		}
4892
	}
4893

    
4894
	return $carp_ints;
4895
}
4896

    
4897
function link_interface_to_track6($int, $action = "") {
4898
	global $config;
4899

    
4900
	if (empty($int)) {
4901
		return;
4902
	}
4903

    
4904
	if (is_array($config['interfaces'])) {
4905
		$list = array();
4906
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4907
			if (!isset($ifcfg['enable'])) {
4908
				continue;
4909
			}
4910
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4911
				if ($action == "update") {
4912
					interface_track6_configure($ifname, $ifcfg);
4913
				} else if ($action == "") {
4914
					$list[$ifname] = $ifcfg;
4915
				}
4916
			}
4917
		}
4918
		return $list;
4919
	}
4920
}
4921

    
4922
function interface_find_child_cfgmtu($realiface) {
4923
	global $config;
4924

    
4925
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
4926
	$vlans = link_interface_to_vlans($realiface);
4927
	$bridge = link_interface_to_bridge($realiface);
4928
	if (!empty($interface)) {
4929
		$gifs = link_interface_to_gif($interface);
4930
		$gres = link_interface_to_gre($interface);
4931
	} else {
4932
		$gifs = array();
4933
		$gres = array();
4934
	}
4935

    
4936
	$mtu = 0;
4937
	if (is_array($vlans)) {
4938
		foreach ($vlans as $vlan) {
4939
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4940
			if (empty($ifass)) {
4941
				continue;
4942
			}
4943
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4944
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4945
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4946
				}
4947
			}
4948
		}
4949
	}
4950
	if (is_array($gifs)) {
4951
		foreach ($gifs as $vlan) {
4952
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['gifif']);
4953
			if (empty($ifass)) {
4954
				continue;
4955
			}
4956
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4957
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4958
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4959
				}
4960
			}
4961
		}
4962
	}
4963
	if (is_array($gres)) {
4964
		foreach ($gres as $vlan) {
4965
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['greif']);
4966
			if (empty($ifass)) {
4967
				continue;
4968
			}
4969
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4970
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4971
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4972
				}
4973
			}
4974
		}
4975
	}
4976
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
4977
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
4978
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4979
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
4980
		}
4981
	}
4982
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
4983

    
4984
	return $mtu;
4985
}
4986

    
4987
function link_interface_to_vlans($int, $action = "") {
4988
	global $config;
4989

    
4990
	if (empty($int)) {
4991
		return;
4992
	}
4993

    
4994
	if (is_array($config['vlans']['vlan'])) {
4995
		$ifaces = array();
4996
		foreach ($config['vlans']['vlan'] as $vlan) {
4997
			if ($int == $vlan['if']) {
4998
				if ($action == "update") {
4999
					interfaces_bring_up($int);
5000
				} else {
5001
					$ifaces[$vlan['tag']] = $vlan;
5002
				}
5003
			}
5004
		}
5005
		if (!empty($ifaces)) {
5006
			return $ifaces;
5007
		}
5008
	}
5009
}
5010

    
5011
function link_interface_to_vips($int, $action = "", $vhid = '') {
5012
	global $config;
5013

    
5014
	if (is_array($config['virtualip']['vip'])) {
5015
		$result = array();
5016
		foreach ($config['virtualip']['vip'] as $vip) {
5017
			if ($int == $vip['interface']) {
5018
				if ($action == "update") {
5019
					interfaces_vips_configure($int);
5020
				} else {
5021
					if (empty($vhid) || ($vhid == $vip['vhid'])) {
5022
						$result[] = $vip;
5023
					}
5024
				}
5025
			}
5026
		}
5027
		return $result;
5028
	}
5029
}
5030

    
5031
/****f* interfaces/link_interface_to_bridge
5032
 * NAME
5033
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5034
 * INPUTS
5035
 *   $ip
5036
 * RESULT
5037
 *   bridge[0-99]
5038
 ******/
5039
function link_interface_to_bridge($int) {
5040
	global $config;
5041

    
5042
	if (is_array($config['bridges']['bridged'])) {
5043
		foreach ($config['bridges']['bridged'] as $bridge) {
5044
			if (in_array($int, explode(',', $bridge['members']))) {
5045
				return "{$bridge['bridgeif']}";
5046
			}
5047
		}
5048
	}
5049
}
5050

    
5051
function link_interface_to_group($int) {
5052
	global $config;
5053

    
5054
	$result = array();
5055

    
5056
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5057
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5058
			if (in_array($int, explode(" ", $group['members']))) {
5059
				$result[$group['ifname']] = $int;
5060
			}
5061
		}
5062
	}
5063

    
5064
	return $result;
5065
}
5066

    
5067
function link_interface_to_gre($interface) {
5068
	global $config;
5069

    
5070
	$result = array();
5071

    
5072
	if (is_array($config['gres']['gre'])) {
5073
		foreach ($config['gres']['gre'] as $gre) {
5074
			if ($gre['if'] == $interface) {
5075
				$result[] = $gre;
5076
			}
5077
		}
5078
	}
5079

    
5080
	return $result;
5081
}
5082

    
5083
function link_interface_to_gif($interface) {
5084
	global $config;
5085

    
5086
	$result = array();
5087

    
5088
	if (is_array($config['gifs']['gif'])) {
5089
		foreach ($config['gifs']['gif'] as $gif) {
5090
			if ($gif['if'] == $interface) {
5091
				$result[] = $gif;
5092
			}
5093
		}
5094
	}
5095

    
5096
	return $result;
5097
}
5098

    
5099
/*
5100
 * find_interface_ip($interface): return the interface ip (first found)
5101
 */
5102
function find_interface_ip($interface, $flush = false) {
5103
	global $interface_ip_arr_cache;
5104
	global $interface_sn_arr_cache;
5105

    
5106
	$interface = str_replace("\n", "", $interface);
5107

    
5108
	if (!does_interface_exist($interface)) {
5109
		return;
5110
	}
5111

    
5112
	/* Setup IP cache */
5113
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5114
		$ifinfo = pfSense_get_interface_addresses($interface);
5115
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5116
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5117
	}
5118

    
5119
	return $interface_ip_arr_cache[$interface];
5120
}
5121

    
5122
/*
5123
 * find_interface_ipv6($interface): return the interface ip (first found)
5124
 */
5125
function find_interface_ipv6($interface, $flush = false) {
5126
	global $interface_ipv6_arr_cache;
5127
	global $interface_snv6_arr_cache;
5128
	global $config;
5129

    
5130
	$interface = trim($interface);
5131
	$interface = get_real_interface($interface);
5132

    
5133
	if (!does_interface_exist($interface)) {
5134
		return;
5135
	}
5136

    
5137
	/* Setup IP cache */
5138
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5139
		$ifinfo = pfSense_get_interface_addresses($interface);
5140
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5141
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5142
	}
5143

    
5144
	return $interface_ipv6_arr_cache[$interface];
5145
}
5146

    
5147
/*
5148
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5149
 */
5150
function find_interface_ipv6_ll($interface, $flush = false) {
5151
	global $interface_llv6_arr_cache;
5152
	global $config;
5153

    
5154
	$interface = str_replace("\n", "", $interface);
5155

    
5156
	if (!does_interface_exist($interface)) {
5157
		return;
5158
	}
5159

    
5160
	/* Setup IP cache */
5161
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5162
		$ifinfo = pfSense_getall_interface_addresses($interface);
5163
		foreach ($ifinfo as $line) {
5164
			if (strstr($line, ":")) {
5165
				$parts = explode("/", $line);
5166
				if (is_linklocal($parts[0])) {
5167
					$ifinfo['linklocal'] = $parts[0];
5168
				}
5169
			}
5170
		}
5171
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5172
	}
5173
	return $interface_llv6_arr_cache[$interface];
5174
}
5175

    
5176
function find_interface_subnet($interface, $flush = false) {
5177
	global $interface_sn_arr_cache;
5178
	global $interface_ip_arr_cache;
5179

    
5180
	$interface = str_replace("\n", "", $interface);
5181
	if (does_interface_exist($interface) == false) {
5182
		return;
5183
	}
5184

    
5185
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5186
		$ifinfo = pfSense_get_interface_addresses($interface);
5187
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5188
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5189
	}
5190

    
5191
	return $interface_sn_arr_cache[$interface];
5192
}
5193

    
5194
function find_interface_subnetv6($interface, $flush = false) {
5195
	global $interface_snv6_arr_cache;
5196
	global $interface_ipv6_arr_cache;
5197

    
5198
	$interface = str_replace("\n", "", $interface);
5199
	if (does_interface_exist($interface) == false) {
5200
		return;
5201
	}
5202

    
5203
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5204
		$ifinfo = pfSense_get_interface_addresses($interface);
5205
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5206
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5207
	}
5208

    
5209
	return $interface_snv6_arr_cache[$interface];
5210
}
5211

    
5212
function ip_in_interface_alias_subnet($interface, $ipalias) {
5213
	global $config;
5214

    
5215
	if (empty($interface) || !is_ipaddr($ipalias)) {
5216
		return false;
5217
	}
5218
	if (is_array($config['virtualip']['vip'])) {
5219
		foreach ($config['virtualip']['vip'] as $vip) {
5220
			switch ($vip['mode']) {
5221
				case "ipalias":
5222
					if ($vip['interface'] <> $interface) {
5223
						break;
5224
					}
5225
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5226
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5227
						return true;
5228
					}
5229
					break;
5230
			}
5231
		}
5232
	}
5233

    
5234
	return false;
5235
}
5236

    
5237
function get_possible_listen_ips($include_ipv6_link_local=false) {
5238

    
5239
	$interfaces = get_configured_interface_with_descr();
5240
	foreach ($interfaces as $iface => $ifacename) {
5241
		if ($include_ipv6_link_local) {
5242
			/* This is to avoid going though added ll below */
5243
			if (substr($iface, 0, 5) == '_lloc') {
5244
				continue;
5245
			}
5246
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5247
			if (!empty($llip)) {
5248
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5249
			}
5250
		}
5251
	}
5252
	/* XXX: Maybe use array_merge below? */
5253
	$carplist = get_configured_carp_interface_list();
5254
	foreach ($carplist as $cif => $carpip) {
5255
		$interfaces[$cif] = $carpip . ' (' . get_vip_descr($carpip) . ')';
5256
	}
5257
	$aliaslist = get_configured_ip_aliases_list();
5258
	foreach ($aliaslist as $aliasip => $aliasif) {
5259
		$interfaces[$aliasip] = $aliasip . ' (' . get_vip_descr($aliasip) . ')';
5260
	}
5261

    
5262
	$interfaces['lo0'] = 'Localhost';
5263

    
5264
	return $interfaces;
5265
}
5266

    
5267
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5268
	global $config;
5269

    
5270
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5271
	foreach (array('server', 'client') as $mode) {
5272
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5273
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5274
				if (!isset($setting['disable'])) {
5275
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5276
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " ".$mode.": ".htmlspecialchars($setting['description']);
5277
				}
5278
			}
5279
		}
5280
	}
5281
	return $sourceips;
5282
}
5283

    
5284
function get_interface_ip($interface = "wan") {
5285

    
5286
	$realif = get_failover_interface($interface);
5287
	if (!$realif) {
5288
		return null;
5289
	}
5290

    
5291
	if (substr($realif, 0, 4) == '_vip') {
5292
		return get_configured_carp_interface_list($realif, 'inet', 'ip');
5293
	}
5294

    
5295
	if (strstr($realif, "_vip")) {
5296
		return get_configured_carp_interface_list($realif);
5297
	}
5298

    
5299
	$curip = find_interface_ip($realif);
5300
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5301
		return $curip;
5302
	} else {
5303
		return null;
5304
	}
5305
}
5306

    
5307
function get_interface_ipv6($interface = "wan", $flush = false) {
5308
	global $config;
5309

    
5310
	$realif = get_failover_interface($interface, 'inet6');
5311
	if (!$realif) {
5312
		return null;
5313
	}
5314

    
5315
	if (substr($realif, 0, 4) == '_vip') {
5316
		return get_configured_carp_interface_list($realif, 'inet6', 'ip');
5317
	} else if (substr($realif, 0, 5) == '_lloc') {
5318
		return get_interface_linklocal($interface);
5319
	}
5320

    
5321
	if (is_array($config['interfaces'][$interface])) {
5322
		switch ($config['interfaces'][$interface]['ipaddr']) {
5323
			case 'pppoe':
5324
			case 'l2tp':
5325
			case 'pptp':
5326
			case 'ppp':
5327
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5328
					$realif = get_real_interface($interface, 'inet6', false);
5329
				}
5330
				break;
5331
		}
5332
	}
5333

    
5334
	$curip = find_interface_ipv6($realif, $flush);
5335
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5336
		return $curip;
5337
	} else {
5338
		/*
5339
		 * NOTE: On the case when only the prefix is requested,
5340
		 * the communication on WAN will be done over link-local.
5341
		 */
5342
		if (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
5343
			$curip = find_interface_ipv6_ll($realif, $flush);
5344
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5345
				return $curip;
5346
			}
5347
		}
5348
	}
5349
	return null;
5350
}
5351

    
5352
function get_interface_linklocal($interface = "wan") {
5353

    
5354
	$realif = get_failover_interface($interface, 'inet6');
5355
	if (!$realif) {
5356
		return null;
5357
	}
5358

    
5359
	if (substr($interface, 0, 4) == '_vip') {
5360
		$realif = get_real_interface($interface);
5361
	} else if (substr($interface, 0, 5) == '_lloc') {
5362
		$realif = get_real_interface(substr($interface, 5));
5363
	}
5364

    
5365
	$curip = find_interface_ipv6_ll($realif);
5366
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5367
		return $curip;
5368
	} else {
5369
		return null;
5370
	}
5371
}
5372

    
5373
function get_interface_subnet($interface = "wan") {
5374

    
5375
	if (substr($interface, 0, 4) == '_vip') {
5376
		return get_configured_carp_interface_list($interface, 'inet', 'subnet');
5377
	}
5378

    
5379
	$realif = get_real_interface($interface);
5380
	if (!$realif) {
5381
		return null;
5382
	}
5383

    
5384
	$cursn = find_interface_subnet($realif);
5385
	if (!empty($cursn)) {
5386
		return $cursn;
5387
	}
5388

    
5389
	return null;
5390
}
5391

    
5392
function get_interface_subnetv6($interface = "wan") {
5393

    
5394
	if (substr($interface, 0, 4) == '_vip') {
5395
		return get_configured_carp_interface_list($interface, 'inet6', 'subnet');
5396
	} else if (substr($interface, 0, 5) == '_lloc') {
5397
		$interface = substr($interface, 5);
5398
	}
5399

    
5400
	$realif = get_real_interface($interface, 'inet6');
5401
	if (!$realif) {
5402
		return null;
5403
	}
5404

    
5405
	$cursn = find_interface_subnetv6($realif);
5406
	if (!empty($cursn)) {
5407
		return $cursn;
5408
	}
5409

    
5410
	return null;
5411
}
5412

    
5413
/* return outside interfaces with a gateway */
5414
function get_interfaces_with_gateway() {
5415
	global $config;
5416

    
5417
	$ints = array();
5418

    
5419
	/* loop interfaces, check config for outbound */
5420
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5421
		switch ($ifname['ipaddr']) {
5422
			case "dhcp":
5423
			case "pppoe":
5424
			case "pptp":
5425
			case "l2tp":
5426
			case "ppp":
5427
				$ints[$ifdescr] = $ifdescr;
5428
				break;
5429
			default:
5430
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5431
				    !empty($ifname['gateway'])) {
5432
					$ints[$ifdescr] = $ifdescr;
5433
				}
5434
				break;
5435
		}
5436
	}
5437
	return $ints;
5438
}
5439

    
5440
/* return true if interface has a gateway */
5441
function interface_has_gateway($friendly) {
5442
	global $config;
5443

    
5444
	if (!empty($config['interfaces'][$friendly])) {
5445
		$ifname = &$config['interfaces'][$friendly];
5446
		switch ($ifname['ipaddr']) {
5447
			case "dhcp":
5448
			case "pppoe":
5449
			case "pptp":
5450
			case "l2tp":
5451
			case "ppp":
5452
				return true;
5453
			break;
5454
			default:
5455
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5456
					return true;
5457
				}
5458
				$tunnelif = substr($ifname['if'], 0, 3);
5459
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5460
					return true;
5461
				}
5462
				if (!empty($ifname['gateway'])) {
5463
					return true;
5464
				}
5465
			break;
5466
		}
5467
	}
5468

    
5469
	return false;
5470
}
5471

    
5472
/* return true if interface has a gateway */
5473
function interface_has_gatewayv6($friendly) {
5474
	global $config;
5475

    
5476
	if (!empty($config['interfaces'][$friendly])) {
5477
		$ifname = &$config['interfaces'][$friendly];
5478
		switch ($ifname['ipaddrv6']) {
5479
			case "slaac":
5480
			case "dhcp6":
5481
			case "6to4":
5482
			case "6rd":
5483
				return true;
5484
				break;
5485
			default:
5486
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5487
					return true;
5488
				}
5489
				$tunnelif = substr($ifname['if'], 0, 3);
5490
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5491
					return true;
5492
				}
5493
				if (!empty($ifname['gatewayv6'])) {
5494
					return true;
5495
				}
5496
				break;
5497
		}
5498
	}
5499

    
5500
	return false;
5501
}
5502

    
5503
/****f* interfaces/is_altq_capable
5504
 * NAME
5505
 *   is_altq_capable - Test if interface is capable of using ALTQ
5506
 * INPUTS
5507
 *   $int            - string containing interface name
5508
 * RESULT
5509
 *   boolean         - true or false
5510
 ******/
5511

    
5512
function is_altq_capable($int) {
5513
	/* Per:
5514
	 * http://www.freebsd.org/cgi/man.cgi?query=altq&apropos=0&sektion=0&manpath=FreeBSD+8.3-RELEASE&arch=default&format=html
5515
	 * Only the following drivers have ALTQ support
5516
	 * 20150328 - removed wireless drivers - ath, awi, bwn, iwi, ipw, ral, rum, run, wi - for now. redmine #4406
5517
	 */
5518
	$capable = array("ae", "age", "alc", "ale", "an", "aue", "axe", "bce",
5519
			"bfe", "bge", "bridge", "cas", "dc", "de", "ed", "em", "ep", "epair", "et", "fxp", "gem",
5520
			"hme", "hn", "igb", "ixgbe", "jme", "le", "lem", "msk", "mxge", "my", "nfe",
5521
			"nge", "npe", "nve", "re", "rl", "sf", "sge", "sis", "sk",
5522
			"ste", "stge", "ti", "txp", "udav", "ural", "vge", "vmx", "vr", "vte", "xl",
5523
			"ndis", "tun", "ovpns", "ovpnc", "vlan", "pppoe", "pptp", "ng",
5524
			"l2tp", "ppp", "vtnet");
5525

    
5526
	$int_family = remove_ifindex($int);
5527

    
5528
	if (in_array($int_family, $capable)) {
5529
		return true;
5530
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5531
		return true;
5532
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5533
		return true;
5534
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5535
		return true;
5536
	} else {
5537
		return false;
5538
	}
5539
}
5540

    
5541
/****f* interfaces/is_interface_wireless
5542
 * NAME
5543
 *   is_interface_wireless - Returns if an interface is wireless
5544
 * RESULT
5545
 *   $tmp       - Returns if an interface is wireless
5546
 ******/
5547
function is_interface_wireless($interface) {
5548
	global $config, $g;
5549

    
5550
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5551
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5552
		if (preg_match($g['wireless_regex'], $interface)) {
5553
			if (isset($config['interfaces'][$friendly])) {
5554
				$config['interfaces'][$friendly]['wireless'] = array();
5555
			}
5556
			return true;
5557
		}
5558
		return false;
5559
	} else {
5560
		return true;
5561
	}
5562
}
5563

    
5564
function get_wireless_modes($interface) {
5565
	/* return wireless modes and channels */
5566
	$wireless_modes = array();
5567

    
5568
	$cloned_interface = get_real_interface($interface);
5569

    
5570
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5571
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5572
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5573
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5574

    
5575
		$interface_channels = "";
5576
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5577
		$interface_channel_count = count($interface_channels);
5578

    
5579
		$c = 0;
5580
		while ($c < $interface_channel_count) {
5581
			$channel_line = explode(",", $interface_channels["$c"]);
5582
			$wireless_mode = trim($channel_line[0]);
5583
			$wireless_channel = trim($channel_line[1]);
5584
			if (trim($wireless_mode) != "") {
5585
				/* if we only have 11g also set 11b channels */
5586
				if ($wireless_mode == "11g") {
5587
					if (!isset($wireless_modes["11b"])) {
5588
						$wireless_modes["11b"] = array();
5589
					}
5590
				} else if ($wireless_mode == "11g ht") {
5591
					if (!isset($wireless_modes["11b"])) {
5592
						$wireless_modes["11b"] = array();
5593
					}
5594
					if (!isset($wireless_modes["11g"])) {
5595
						$wireless_modes["11g"] = array();
5596
					}
5597
					$wireless_mode = "11ng";
5598
				} else if ($wireless_mode == "11a ht") {
5599
					if (!isset($wireless_modes["11a"])) {
5600
						$wireless_modes["11a"] = array();
5601
					}
5602
					$wireless_mode = "11na";
5603
				}
5604
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5605
			}
5606
			$c++;
5607
		}
5608
	}
5609
	return($wireless_modes);
5610
}
5611

    
5612
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5613
function get_wireless_channel_info($interface) {
5614
	$wireless_channels = array();
5615

    
5616
	$cloned_interface = get_real_interface($interface);
5617

    
5618
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5619
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5620
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5621
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5622

    
5623
		$interface_channels = "";
5624
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5625

    
5626
		foreach ($interface_channels as $channel_line) {
5627
			$channel_line = explode(",", $channel_line);
5628
			if (!isset($wireless_channels[$channel_line[0]])) {
5629
				$wireless_channels[$channel_line[0]] = $channel_line;
5630
			}
5631
		}
5632
	}
5633
	return($wireless_channels);
5634
}
5635

    
5636
/****f* interfaces/get_interface_mtu
5637
 * NAME
5638
 *   get_interface_mtu - Return the mtu of an interface
5639
 * RESULT
5640
 *   $tmp       - Returns the mtu of an interface
5641
 ******/
5642
function get_interface_mtu($interface) {
5643
	$mtu = pfSense_interface_getmtu($interface);
5644
	return $mtu['mtu'];
5645
}
5646

    
5647
function get_interface_mac($interface) {
5648

    
5649
	$macinfo = pfSense_get_interface_addresses($interface);
5650
	return $macinfo["macaddr"];
5651
}
5652

    
5653
/****f* pfsense-utils/generate_random_mac_address
5654
 * NAME
5655
 *   generate_random_mac - generates a random mac address
5656
 * INPUTS
5657
 *   none
5658
 * RESULT
5659
 *   $mac - a random mac address
5660
 ******/
5661
function generate_random_mac_address() {
5662
	$mac = "02";
5663
	for ($x = 0; $x < 5; $x++) {
5664
		$mac .= ":" . dechex(rand(16, 255));
5665
	}
5666
	return $mac;
5667
}
5668

    
5669
/****f* interfaces/is_jumbo_capable
5670
 * NAME
5671
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5672
 * INPUTS
5673
 *   $int             - string containing interface name
5674
 * RESULT
5675
 *   boolean          - true or false
5676
 ******/
5677
function is_jumbo_capable($iface) {
5678
	$iface = trim($iface);
5679
	$capable = pfSense_get_interface_addresses($iface);
5680

    
5681
	if (isset($capable['caps']['vlanmtu'])) {
5682
		return true;
5683
	}
5684

    
5685
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5686
	if (substr($iface, 0, 4) == "lagg") {
5687
		return true;
5688
	}
5689

    
5690
	return false;
5691
}
5692

    
5693
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5694
	global $g;
5695

    
5696
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5697

    
5698
	if (!empty($iface) && !empty($pppif)) {
5699
		$cron_cmd = <<<EOD
5700
#!/bin/sh
5701
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5702
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5703

    
5704
EOD;
5705

    
5706
		@file_put_contents($cron_file, $cron_cmd);
5707
		chmod($cron_file, 0755);
5708
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5709
	} else {
5710
		unlink_if_exists($cron_file);
5711
	}
5712
}
5713

    
5714
function get_interface_default_mtu($type = "ethernet") {
5715
	switch ($type) {
5716
		case "gre":
5717
			return 1476;
5718
			break;
5719
		case "gif":
5720
			return 1280;
5721
			break;
5722
		case "tun":
5723
		case "vlan":
5724
		case "tap":
5725
		case "ethernet":
5726
		default:
5727
			return 1500;
5728
			break;
5729
	}
5730

    
5731
	/* Never reached */
5732
	return 1500;
5733
}
5734

    
5735
function get_vip_descr($ipaddress) {
5736
	global $config;
5737

    
5738
	foreach ($config['virtualip']['vip'] as $vip) {
5739
		if ($vip['subnet'] == $ipaddress) {
5740
			return ($vip['descr']);
5741
		}
5742
	}
5743
	return "";
5744
}
5745

    
5746
function interfaces_staticarp_configure($if) {
5747
	global $config, $g;
5748
	if (isset($config['system']['developerspew'])) {
5749
		$mt = microtime();
5750
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5751
	}
5752

    
5753
	$ifcfg = $config['interfaces'][$if];
5754

    
5755
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5756
		return 0;
5757
	}
5758

    
5759
	/* Enable staticarp, if enabled */
5760
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5761
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5762
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5763
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5764
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5765
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5766
			}
5767
		}
5768
	} else {
5769
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5770
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5771
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5772
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5773
				if (isset($arpent['arp_table_static_entry'])) {
5774
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5775
				}
5776
			}
5777
		}
5778
	}
5779

    
5780
	return 0;
5781
}
5782

    
5783
function get_failover_interface($interface, $family = "all") {
5784
	global $config;
5785

    
5786
	/* shortcut to get_real_interface if we find it in the config */
5787
	if (is_array($config['interfaces'][$interface])) {
5788
		return get_real_interface($interface, $family);
5789
	}
5790

    
5791
	/* compare against gateway groups */
5792
	$a_groups = return_gateway_groups_array();
5793
	if (is_array($a_groups[$interface])) {
5794
		/* we found a gateway group, fetch the interface or vip */
5795
		if (!empty($a_groups[$interface][0]['vip'])) {
5796
			return $a_groups[$interface][0]['vip'];
5797
		} else {
5798
			return $a_groups[$interface][0]['int'];
5799
		}
5800
	}
5801
	/* fall through to get_real_interface */
5802
	/* XXX: Really needed? */
5803
	return get_real_interface($interface, $family);
5804
}
5805

    
5806
function remove_ifindex($ifname) {
5807
	return preg_replace("/[0-9]+$/", "", $ifname);
5808
}
5809

    
5810
?>
(26-26/68)