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
	if (empty($if)) {
232
		log_error(gettext("interface_vlan_configure called with if undefined."));
233
		return;
234
	}
235

    
236
	$vlanif = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
237
	$tag = $vlan['tag'];
238
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
239

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

    
245
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
246
		pfSense_interface_destroy($vlanif);
247
	}
248

    
249
	$tmpvlanif = pfSense_interface_create("vlan");
250
	pfSense_interface_rename($tmpvlanif, $vlanif);
251
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
252

    
253
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
254

    
255
	interfaces_bring_up($vlanif);
256

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

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

    
263
	return $vlanif;
264
}
265

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

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

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

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

    
286
	$vlanif = interface_vlan_configure($vlan);
287

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

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

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

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

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

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

    
342
	return $vlanif;
343
}
344

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

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

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

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

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

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

    
387
	return $vlanif;
388
}
389

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

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

    
397
	$iflist = get_configured_interface_list();
398

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

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

    
422
}
423

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

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

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

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

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

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

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

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

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

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

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

    
527
	$checklist = get_configured_interface_list();
528

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
762
	interfaces_bring_up($laggif);
763

    
764
	return $laggif;
765
}
766

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

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

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

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

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

    
809
	$realif = get_real_interface($gre['if']);
810
	$realifip = get_interface_ip($gre['if']);
811
	$realifip6 = get_interface_ipv6($gre['if']);
812

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

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

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

    
847
	if ($greif) {
848
		interfaces_bring_up($greif);
849
	} else {
850
		log_error(gettext("Could not bring greif up -- variable not defined."));
851
	}
852

    
853
	if (isset($gre['link1']) && $gre['link1']) {
854
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
855
	}
856
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
857
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
858
	}
859
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
860
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
861
	}
862

    
863
	interfaces_bring_up($greif);
864

    
865
	return $greif;
866
}
867

    
868
function interfaces_gif_configure($checkparent = 0, $realif = "") {
869
	global $config;
870

    
871
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
872
		foreach ($config['gifs']['gif'] as $i => $gif) {
873
			if (empty($gif['gifif'])) {
874
				$gre['gifif'] = "gif{$i}";
875
			}
876
			if (!empty($realif) && $realif != $gif['gifif']) {
877
				continue;
878
			}
879

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

    
903
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
904
function interface_gif_configure(&$gif, $gifkey = "") {
905
	global $config, $g;
906

    
907
	if (!is_array($gif)) {
908
		return -1;
909
	}
910

    
911
	$realif = get_real_interface($gif['if']);
912
	$ipaddr = get_interface_ip($gif['if']);
913

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

    
936
	if (platform_booting() || !(empty($gif['gifif']))) {
937
		pfSense_interface_destroy($gif['gifif']);
938
		pfSense_interface_create($gif['gifif']);
939
		$gifif = $gif['gifif'];
940
	} else {
941
		$gifif = pfSense_interface_create("gif");
942
	}
943

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

    
969
	if (!platform_booting()) {
970
		$iflist = get_configured_interface_list();
971
		foreach ($iflist as $ifname) {
972
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
973
				if (get_interface_gateway($ifname)) {
974
					system_routing_configure($ifname);
975
					break;
976
				}
977
				if (get_interface_gateway_v6($ifname)) {
978
					system_routing_configure($ifname);
979
					break;
980
				}
981
			}
982
		}
983
	}
984

    
985

    
986
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
987
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
988
	}
989
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
990
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
991
	}
992

    
993
	if (is_ipaddrv4($realifgw)) {
994
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
995
	}
996
	if (is_ipaddrv6($realifgw)) {
997
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
998
	}
999

    
1000
	interfaces_bring_up($gifif);
1001

    
1002
	return $gifif;
1003
}
1004

    
1005
function interfaces_configure() {
1006
	global $config, $g;
1007

    
1008
	/* Set up our loopback interface */
1009
	interfaces_loopback_configure();
1010

    
1011
	/* create the unconfigured wireless clones */
1012
	interfaces_create_wireless_clones();
1013

    
1014
	/* set up LAGG virtual interfaces */
1015
	interfaces_lagg_configure();
1016

    
1017
	/* set up VLAN virtual interfaces */
1018
	interfaces_vlan_configure();
1019

    
1020
	interfaces_qinq_configure();
1021

    
1022
	$iflist = get_configured_interface_with_descr();
1023
	$delayed_list = array();
1024
	$bridge_list = array();
1025
	$track6_list = array();
1026

    
1027
	/* This is needed to speedup interfaces on bootup. */
1028
	$reload = false;
1029
	if (!platform_booting()) {
1030
		$reload = true;
1031
	}
1032

    
1033
	foreach ($iflist as $if => $ifname) {
1034
		$realif = $config['interfaces'][$if]['if'];
1035
		if (strstr($realif, "bridge")) {
1036
			$bridge_list[$if] = $ifname;
1037
		} else if (strstr($realif, "gre")) {
1038
			$delayed_list[$if] = $ifname;
1039
		} else if (strstr($realif, "gif")) {
1040
			$delayed_list[$if] = $ifname;
1041
		} else if (strstr($realif, "ovpn")) {
1042
			//echo "Delaying OpenVPN interface configuration...done.\n";
1043
			continue;
1044
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1045
			$track6_list[$if] = $ifname;
1046
		} else {
1047
			if (platform_booting()) {
1048
				printf(gettext("Configuring %s interface..."), $ifname);
1049
			}
1050

    
1051
			if ($g['debug']) {
1052
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1053
			}
1054
			interface_configure($if, $reload);
1055
			if (platform_booting()) {
1056
				echo gettext("done.") . "\n";
1057
			}
1058
		}
1059
	}
1060

    
1061
	/*
1062
	 * NOTE: The following function parameter consists of
1063
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1064
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1065
	 */
1066

    
1067
	/* set up GRE virtual interfaces */
1068
	interfaces_gre_configure(1);
1069

    
1070
	/* set up GIF virtual interfaces */
1071
	interfaces_gif_configure(1);
1072

    
1073
	/* set up BRIDGe virtual interfaces */
1074
	interfaces_bridge_configure(1);
1075

    
1076
	foreach ($track6_list as $if => $ifname) {
1077
		if (platform_booting()) {
1078
			printf(gettext("Configuring %s interface..."), $ifname);
1079
		}
1080
		if ($g['debug']) {
1081
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1082
		}
1083

    
1084
		interface_configure($if, $reload);
1085

    
1086
		if (platform_booting()) {
1087
			echo gettext("done.") . "\n";
1088
		}
1089
	}
1090

    
1091
	/* bring up vip interfaces */
1092
	interfaces_vips_configure();
1093

    
1094
	/* set up GRE virtual interfaces */
1095
	interfaces_gre_configure(2);
1096

    
1097
	/* set up GIF virtual interfaces */
1098
	interfaces_gif_configure(2);
1099

    
1100
	foreach ($delayed_list as $if => $ifname) {
1101
		if (platform_booting()) {
1102
			printf(gettext("Configuring %s interface..."), $ifname);
1103
		}
1104
		if ($g['debug']) {
1105
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1106
		}
1107

    
1108
		interface_configure($if, $reload);
1109

    
1110
		if (platform_booting()) {
1111
			echo gettext("done.") . "\n";
1112
		}
1113
	}
1114

    
1115
	/* set up BRIDGe virtual interfaces */
1116
	interfaces_bridge_configure(2);
1117

    
1118
	foreach ($bridge_list as $if => $ifname) {
1119
		if (platform_booting()) {
1120
			printf(gettext("Configuring %s interface..."), $ifname);
1121
		}
1122
		if ($g['debug']) {
1123
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1124
		}
1125

    
1126
		interface_configure($if, $reload);
1127

    
1128
		if (platform_booting()) {
1129
			echo gettext("done.") . "\n";
1130
		}
1131
	}
1132

    
1133
	/* configure interface groups */
1134
	interfaces_group_setup();
1135

    
1136
	if (!platform_booting()) {
1137
		/* reconfigure static routes (kernel may have deleted them) */
1138
		system_routing_configure();
1139

    
1140
		/* reload IPsec tunnels */
1141
		vpn_ipsec_configure();
1142

    
1143
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1144
		services_dhcpd_configure();
1145

    
1146
		/* restart dnsmasq or unbound */
1147
		if (isset($config['dnsmasq']['enable'])) {
1148
			services_dnsmasq_configure();
1149
		} elseif (isset($config['unbound']['enable'])) {
1150
			services_unbound_configure();
1151
		}
1152
	}
1153

    
1154
	return 0;
1155
}
1156

    
1157
function interface_reconfigure($interface = "wan", $reloadall = false) {
1158
	interface_bring_down($interface);
1159
	interface_configure($interface, $reloadall);
1160
}
1161

    
1162
function interface_vip_bring_down($vip) {
1163
	global $g;
1164

    
1165
	if (strpos($vip['interface'], '_vip')) {
1166
		if (is_ipaddrv6($vip['subnet'])) {
1167
			$family = 'inet6';
1168
		} else {
1169
			$family = 'inet';
1170
		}
1171

    
1172
		$carpvip = get_configured_carp_interface_list($vip['interface'], $family, 'vip');
1173
		$iface = $carpvip['interface'];
1174
	} else {
1175
		$iface = $vip['interface'];
1176
	}
1177

    
1178
	$vipif = get_real_interface($iface);
1179
	switch ($vip['mode']) {
1180
		case "proxyarp":
1181
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1182
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1183
			}
1184
			break;
1185
		case "ipalias":
1186
			if (does_interface_exist($vipif)) {
1187
				if (is_ipaddrv6($vip['subnet'])) {
1188
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1189
				} else {
1190
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1191
				}
1192
			}
1193
			break;
1194
		case "carp":
1195
			/* XXX: Is enough to delete ip address? */
1196
			if (does_interface_exist($vipif)) {
1197
				if (is_ipaddrv6($vip['subnet'])) {
1198
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1199
				} else {
1200
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1201
				}
1202
			}
1203
			break;
1204
	}
1205
}
1206

    
1207
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1208
	global $config, $g;
1209

    
1210
	if (!isset($config['interfaces'][$interface])) {
1211
		return;
1212
	}
1213

    
1214
	if ($g['debug']) {
1215
		log_error("Calling interface down for interface {$interface}, destroy is " . (($destroy) ? 'true' : 'false'));
1216
	}
1217

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

    
1247
	switch ($ifcfg['ipaddr']) {
1248
		case "ppp":
1249
		case "pppoe":
1250
		case "pptp":
1251
		case "l2tp":
1252
			if (is_array($ppps) && count($ppps)) {
1253
				foreach ($ppps as $pppid => $ppp) {
1254
					if ($realif == $ppp['if']) {
1255
						if (isset($ppp['ondemand']) && !$destroy) {
1256
							send_event("interface reconfigure {$interface}");
1257
							break;
1258
						}
1259
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1260
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1261
							sleep(2);
1262
						}
1263
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1264
						break;
1265
					}
1266
				}
1267
			}
1268
			break;
1269
		case "dhcp":
1270
			kill_dhclient_process($realif);
1271
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
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
		default:
1282
			if (does_interface_exist("$realif")) {
1283
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1284
				interface_ipalias_cleanup($interface);
1285
				if ($destroy == true) {
1286
					pfSense_interface_flags($realif, -IFF_UP);
1287
				}
1288
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1289
			}
1290
			break;
1291
	}
1292

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

    
1359
	if (!empty($track6) && is_array($track6)) {
1360
		if (!function_exists('services_dhcpd_configure')) {
1361
			require_once('services.inc');
1362
		}
1363
		/* Bring down radvd and dhcp6 on these interfaces */
1364
		services_dhcpd_configure('inet6', $track6);
1365
	}
1366

    
1367
	$old_router = '';
1368
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1369
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1370
	}
1371

    
1372
	/* remove interface up file if it exists */
1373
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1374
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1375
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1376
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1377
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1378
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1379
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1380

    
1381
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1382
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1383
	if (is_array($ifcfg['wireless'])) {
1384
		kill_hostapd($realif);
1385
		mwexec(kill_wpasupplicant($realif));
1386
	}
1387

    
1388
	if ($destroy == true) {
1389
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1390
			pfSense_interface_destroy($realif);
1391
		}
1392
	}
1393

    
1394
	return;
1395
}
1396

    
1397
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1398
	global $config;
1399
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1400
		unset($config["virtualip_carp_maintenancemode"]);
1401
		write_config("Leave CARP maintenance mode");
1402
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1403
		$config["virtualip_carp_maintenancemode"] = true;
1404
		write_config("Enter CARP maintenance mode");
1405
	}
1406

    
1407
	$viparr = &$config['virtualip']['vip'];
1408
	foreach ($viparr as $vip) {
1409
		if ($vip['mode'] == "carp") {
1410
			interface_carp_configure($vip);
1411
		}
1412
	}
1413
}
1414

    
1415
function interface_isppp_type($interface) {
1416
	global $config;
1417

    
1418
	if (!is_array($config['interfaces'][$interface])) {
1419
		return false;
1420
	}
1421

    
1422
	switch ($config['interfaces'][$interface]['ipaddr']) {
1423
		case 'pptp':
1424
		case 'l2tp':
1425
		case 'pppoe':
1426
		case 'ppp':
1427
			return true;
1428
			break;
1429
		default:
1430
			return false;
1431
			break;
1432
	}
1433
}
1434

    
1435
function interfaces_ptpid_used($ptpid) {
1436
	global $config;
1437

    
1438
	if (is_array($config['ppps']['ppp'])) {
1439
		foreach ($config['ppps']['ppp'] as & $settings) {
1440
			if ($ptpid == $settings['ptpid']) {
1441
				return true;
1442
			}
1443
		}
1444
	}
1445

    
1446
	return false;
1447
}
1448

    
1449
function interfaces_ptpid_next() {
1450

    
1451
	$ptpid = 0;
1452
	while (interfaces_ptpid_used($ptpid)) {
1453
		$ptpid++;
1454
	}
1455

    
1456
	return $ptpid;
1457
}
1458

    
1459
function getMPDCRONSettings($pppif) {
1460
	global $config;
1461

    
1462
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1463
	if (is_array($config['cron']['item'])) {
1464
		foreach ($config['cron']['item'] as $i => $item) {
1465
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1466
				return array("ID" => $i, "ITEM" => $item);
1467
			}
1468
		}
1469
	}
1470

    
1471
	return NULL;
1472
}
1473

    
1474
function handle_pppoe_reset($post_array) {
1475
	global $config, $g;
1476

    
1477
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1478
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1479

    
1480
	if (!is_array($config['cron']['item'])) {
1481
		$config['cron']['item'] = array();
1482
	}
1483

    
1484
	$itemhash = getMPDCRONSettings($pppif);
1485

    
1486
	// reset cron items if necessary and return
1487
	if (empty($post_array['pppoe-reset-type'])) {
1488
		if (isset($itemhash)) {
1489
			unset($config['cron']['item'][$itemhash['ID']]);
1490
		}
1491
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1492
		return;
1493
	}
1494

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

    
1557
/*
1558
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1559
 * It writes the mpd config file to /var/etc every time the link is opened.
1560
 */
1561
function interface_ppps_configure($interface) {
1562
	global $config, $g;
1563

    
1564
	/* Return for unassigned interfaces. This is a minimum requirement. */
1565
	if (empty($config['interfaces'][$interface])) {
1566
		return 0;
1567
	}
1568
	$ifcfg = $config['interfaces'][$interface];
1569
	if (!isset($ifcfg['enable'])) {
1570
		return 0;
1571
	}
1572

    
1573
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1574
	if (!is_dir("/var/spool/lock")) {
1575
		mkdir("/var/spool/lock", 0777, true);
1576
	}
1577
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1578
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1579
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1580
	}
1581

    
1582
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1583
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1584
			if ($ifcfg['if'] == $ppp['if']) {
1585
				break;
1586
			}
1587
		}
1588
	}
1589
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
1590
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1591
		return 0;
1592
	}
1593
	$pppif = $ifcfg['if'];
1594
	if ($ppp['type'] == "ppp") {
1595
		$type = "modem";
1596
	} else {
1597
		$type = $ppp['type'];
1598
	}
1599
	$upper_type = strtoupper($ppp['type']);
1600

    
1601
	/* XXX: This does not make sense and may create trouble
1602
	 * comment it for now to be removed later on.
1603
	if (platform_booting()) {
1604
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1605
		echo "starting {$pppif} link...";
1606
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1607
			return 0;
1608
	}
1609
	*/
1610

    
1611
	$ports = explode(',', $ppp['ports']);
1612
	if ($type != "modem") {
1613
		foreach ($ports as $pid => $port) {
1614
			$ports[$pid] = get_real_interface($port);
1615
			if (empty($ports[$pid])) {
1616
				return 0;
1617
			}
1618
		}
1619
	}
1620
	$localips = explode(',', $ppp['localip']);
1621
	$gateways = explode(',', $ppp['gateway']);
1622
	$subnets = explode(',', $ppp['subnet']);
1623

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

    
1647
				if (!is_ipaddr($localips[$pid])) {
1648
					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!");
1649
					$localips[$pid] = "0.0.0.0";
1650
				}
1651
				if (!is_ipaddr($gateways[$pid])) {
1652
					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));
1653
					return 0;
1654
				}
1655
				pfSense_ngctl_attach(".", $port);
1656
				break;
1657
			case "ppp":
1658
				if (!file_exists("{$port}")) {
1659
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1660
					return 0;
1661
				}
1662
				break;
1663
			default:
1664
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1665
				break;
1666
		}
1667
	}
1668

    
1669
	if (is_array($ports) && count($ports) > 1) {
1670
		$multilink = "enable";
1671
	} else {
1672
		$multilink = "disable";
1673
	}
1674

    
1675
	if ($type == "modem") {
1676
		if (is_ipaddr($ppp['localip'])) {
1677
			$localip = $ppp['localip'];
1678
		} else {
1679
			$localip = '0.0.0.0';
1680
		}
1681

    
1682
		if (is_ipaddr($ppp['gateway'])) {
1683
			$gateway = $ppp['gateway'];
1684
		} else {
1685
			$gateway = "10.64.64.{$pppid}";
1686
		}
1687
		$ranges = "{$localip}/0 {$gateway}/0";
1688

    
1689
		if (empty($ppp['apnum'])) {
1690
			$ppp['apnum'] = 1;
1691
		}
1692
	} else {
1693
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1694
	}
1695

    
1696
	if (isset($ppp['ondemand'])) {
1697
		$ondemand = "enable";
1698
	} else {
1699
		$ondemand = "disable";
1700
	}
1701
	if (!isset($ppp['idletimeout'])) {
1702
		$ppp['idletimeout'] = 0;
1703
	}
1704

    
1705
	if (empty($ppp['username']) && $type == "modem") {
1706
		$ppp['username'] = "user";
1707
		$ppp['password'] = "none";
1708
	}
1709
	if (empty($ppp['password']) && $type == "modem") {
1710
		$passwd = "none";
1711
	} else {
1712
		$passwd = base64_decode($ppp['password']);
1713
	}
1714

    
1715
	$bandwidths = explode(',', $ppp['bandwidth']);
1716
	$defaultmtu = "1492";
1717
	if (!empty($ifcfg['mtu'])) {
1718
		$defaultmtu = intval($ifcfg['mtu']);
1719
	}
1720
	$mtus = explode(',', $ppp['mtu']);
1721
	$mrus = explode(',', $ppp['mru']);
1722

    
1723
	if (isset($ppp['mrru'])) {
1724
		$mrrus = explode(',', $ppp['mrru']);
1725
	}
1726

    
1727
	// Construct the mpd.conf file
1728
	$mpdconf = <<<EOD
1729
startup:
1730
	# configure the console
1731
	set console close
1732
	# configure the web server
1733
	set web close
1734

    
1735
default:
1736
{$ppp['type']}client:
1737
	create bundle static {$interface}
1738
	set bundle enable ipv6cp
1739
	set iface name {$pppif}
1740

    
1741
EOD;
1742
	$setdefaultgw = false;
1743
	$founddefaultgw = false;
1744
	if (is_array($config['gateways']['gateway_item'])) {
1745
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1746
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1747
				$setdefaultgw = true;
1748
				break;
1749
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1750
				$founddefaultgw = true;
1751
				break;
1752
			}
1753
		}
1754
	}
1755

    
1756
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1757
		$setdefaultgw = true;
1758
		$mpdconf .= <<<EOD
1759
	set iface route default
1760

    
1761
EOD;
1762
	}
1763
	$mpdconf .= <<<EOD
1764
	set iface {$ondemand} on-demand
1765
	set iface idle {$ppp['idletimeout']}
1766

    
1767
EOD;
1768

    
1769
	if (isset($ppp['ondemand'])) {
1770
		$mpdconf .= <<<EOD
1771
	set iface addrs 10.10.1.1 10.10.1.2
1772

    
1773
EOD;
1774
	}
1775

    
1776
	if (isset($ppp['tcpmssfix'])) {
1777
		$tcpmss = "disable";
1778
	} else {
1779
		$tcpmss = "enable";
1780
	}
1781
	$mpdconf .= <<<EOD
1782
	set iface {$tcpmss} tcpmssfix
1783

    
1784
EOD;
1785

    
1786
	$mpdconf .= <<<EOD
1787
	set iface up-script /usr/local/sbin/ppp-linkup
1788
	set iface down-script /usr/local/sbin/ppp-linkdown
1789
	set ipcp ranges {$ranges}
1790

    
1791
EOD;
1792
	if (isset($ppp['vjcomp'])) {
1793
		$mpdconf .= <<<EOD
1794
	set ipcp no vjcomp
1795

    
1796
EOD;
1797
	}
1798

    
1799
	if (isset($config['system']['dnsallowoverride'])) {
1800
		$mpdconf .= <<<EOD
1801
	set ipcp enable req-pri-dns
1802
	set ipcp enable req-sec-dns
1803

    
1804
EOD;
1805
	}
1806

    
1807
	if (!isset($ppp['verbose_log'])) {
1808
		$mpdconf .= <<<EOD
1809
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1810

    
1811
EOD;
1812
	}
1813

    
1814
	foreach ($ports as $pid => $port) {
1815
		$port = get_real_interface($port);
1816
		$mpdconf .= <<<EOD
1817

    
1818
	create link static {$interface}_link{$pid} {$type}
1819
	set link action bundle {$interface}
1820
	set link {$multilink} multilink
1821
	set link keep-alive 10 60
1822
	set link max-redial 0
1823

    
1824
EOD;
1825
		if (isset($ppp['shortseq'])) {
1826
			$mpdconf .= <<<EOD
1827
	set link no shortseq
1828

    
1829
EOD;
1830
		}
1831

    
1832
		if (isset($ppp['acfcomp'])) {
1833
			$mpdconf .= <<<EOD
1834
	set link no acfcomp
1835

    
1836
EOD;
1837
		}
1838

    
1839
		if (isset($ppp['protocomp'])) {
1840
			$mpdconf .= <<<EOD
1841
	set link no protocomp
1842

    
1843
EOD;
1844
		}
1845

    
1846
		$mpdconf .= <<<EOD
1847
	set link disable chap pap
1848
	set link accept chap pap eap
1849
	set link disable incoming
1850

    
1851
EOD;
1852

    
1853

    
1854
		if (!empty($bandwidths[$pid])) {
1855
			$mpdconf .= <<<EOD
1856
	set link bandwidth {$bandwidths[$pid]}
1857

    
1858
EOD;
1859
		}
1860

    
1861
		if (empty($mtus[$pid])) {
1862
			$mtus[$pid] = $defaultmtu;
1863
		}
1864
		$mpdconf .= <<<EOD
1865
	set link mtu {$mtus[$pid]}
1866

    
1867
EOD;
1868

    
1869
		if (!empty($mrus[$pid])) {
1870
			$mpdconf .= <<<EOD
1871
	set link mru {$mrus[$pid]}
1872

    
1873
EOD;
1874
		}
1875

    
1876
		if (!empty($mrrus[$pid])) {
1877
			$mpdconf .= <<<EOD
1878
	set link mrru {$mrrus[$pid]}
1879

    
1880
EOD;
1881
		}
1882

    
1883
		$mpdconf .= <<<EOD
1884
	set auth authname "{$ppp['username']}"
1885
	set auth password {$passwd}
1886

    
1887
EOD;
1888
		if ($type == "modem") {
1889
			$mpdconf .= <<<EOD
1890
	set modem device {$ppp['ports']}
1891
	set modem script DialPeer
1892
	set modem idle-script Ringback
1893
	set modem watch -cd
1894
	set modem var \$DialPrefix "DT"
1895
	set modem var \$Telephone "{$ppp['phone']}"
1896

    
1897
EOD;
1898
		}
1899
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1900
			$mpdconf .= <<<EOD
1901
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1902

    
1903
EOD;
1904
		}
1905
		if (isset($ppp['initstr']) && $type == "modem") {
1906
			$initstr = base64_decode($ppp['initstr']);
1907
			$mpdconf .= <<<EOD
1908
	set modem var \$InitString "{$initstr}"
1909

    
1910
EOD;
1911
		}
1912
		if (isset($ppp['simpin']) && $type == "modem") {
1913
			if ($ppp['pin-wait'] == "") {
1914
				$ppp['pin-wait'] = 0;
1915
			}
1916
			$mpdconf .= <<<EOD
1917
	set modem var \$SimPin "{$ppp['simpin']}"
1918
	set modem var \$PinWait "{$ppp['pin-wait']}"
1919

    
1920
EOD;
1921
		}
1922
		if (isset($ppp['apn']) && $type == "modem") {
1923
			$mpdconf .= <<<EOD
1924
	set modem var \$APN "{$ppp['apn']}"
1925
	set modem var \$APNum "{$ppp['apnum']}"
1926

    
1927
EOD;
1928
		}
1929
		if ($type == "pppoe") {
1930
			// Send a null service name if none is set.
1931
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1932
			$mpdconf .= <<<EOD
1933
	set pppoe service "{$provider}"
1934

    
1935
EOD;
1936
		}
1937
		if ($type == "pppoe") {
1938
			$mpdconf .= <<<EOD
1939
	set pppoe iface {$port}
1940

    
1941
EOD;
1942
		}
1943

    
1944
		if ($type == "pptp" || $type == "l2tp") {
1945
			$mpdconf .= <<<EOD
1946
	set {$type} self {$localips[$pid]}
1947
	set {$type} peer {$gateways[$pid]}
1948

    
1949
EOD;
1950
		}
1951

    
1952
		$mpdconf .= "\topen\n";
1953
	} //end foreach ($port)
1954

    
1955

    
1956
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1957
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
1958
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1959
	} else {
1960
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1961
		if (!$fd) {
1962
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1963
			return 0;
1964
		}
1965
		// Write out mpd_ppp.conf
1966
		fwrite($fd, $mpdconf);
1967
		fclose($fd);
1968
		unset($mpdconf);
1969
	}
1970

    
1971
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1972
	if (isset($ppp['uptime'])) {
1973
		if (!file_exists("/conf/{$pppif}.log")) {
1974
			conf_mount_rw();
1975
			file_put_contents("/conf/{$pppif}.log", '');
1976
			conf_mount_ro();
1977
		}
1978
	} else {
1979
		if (file_exists("/conf/{$pppif}.log")) {
1980
			conf_mount_rw();
1981
			@unlink("/conf/{$pppif}.log");
1982
			conf_mount_ro();
1983
		}
1984
	}
1985

    
1986
	/* clean up old lock files */
1987
	foreach ($ports as $port) {
1988
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
1989
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1990
		}
1991
	}
1992

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

    
1997
	// Check for PPPoE periodic reset request
1998
	if ($type == "pppoe") {
1999
		if (!empty($ppp['pppoe-reset-type'])) {
2000
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2001
		} else {
2002
			interface_setup_pppoe_reset_file($ppp['if']);
2003
		}
2004
	}
2005
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
2006
	$i = 0;
2007
	while ($i < 3) {
2008
		sleep(10);
2009
		if (does_interface_exist($ppp['if'], true)) {
2010
			break;
2011
		}
2012
		$i++;
2013
	}
2014

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

    
2035
	return 1;
2036
}
2037

    
2038
function interfaces_sync_setup() {
2039
	global $g, $config;
2040

    
2041
	if (isset($config['system']['developerspew'])) {
2042
		$mt = microtime();
2043
		echo "interfaces_sync_setup() being called $mt\n";
2044
	}
2045

    
2046
	if (platform_booting()) {
2047
		echo gettext("Configuring CARP settings...");
2048
		mute_kernel_msgs();
2049
	}
2050

    
2051
	/* suck in configuration items */
2052
	if ($config['hasync']) {
2053
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2054
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2055
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2056
	} else {
2057
		unset($pfsyncinterface);
2058
		unset($pfsyncenabled);
2059
	}
2060

    
2061
	set_sysctl(array(
2062
		"net.inet.carp.preempt" => "1",
2063
		"net.inet.carp.log" => "1")
2064
	);
2065

    
2066
	if (!empty($pfsyncinterface)) {
2067
		$carp_sync_int = get_real_interface($pfsyncinterface);
2068
	} else {
2069
		unset($carp_sync_int);
2070
	}
2071

    
2072
	/* setup pfsync interface */
2073
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2074
		if (is_ipaddr($pfsyncpeerip)) {
2075
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2076
		} else {
2077
			$syncpeer = "-syncpeer";
2078
		}
2079

    
2080
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2081
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2082

    
2083
		sleep(1);
2084

    
2085
		/* 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
2086
		 * for existing sessions.
2087
		 */
2088
		log_error("waiting for pfsync...");
2089
		$i = 0;
2090
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2091
			$i++;
2092
			sleep(1);
2093
		}
2094
		log_error("pfsync done in $i seconds.");
2095
		log_error("Configuring CARP settings finalize...");
2096
	} else {
2097
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2098
	}
2099

    
2100
	if ($config['virtualip']['vip']) {
2101
		set_single_sysctl("net.inet.carp.allow", "1");
2102
	} else {
2103
		set_single_sysctl("net.inet.carp.allow", "0");
2104
	}
2105

    
2106
	if (platform_booting()) {
2107
		unmute_kernel_msgs();
2108
		echo gettext("done.") . "\n";
2109
	}
2110
}
2111

    
2112
function interface_proxyarp_configure($interface = "") {
2113
	global $config, $g;
2114
	if (isset($config['system']['developerspew'])) {
2115
		$mt = microtime();
2116
		echo "interface_proxyarp_configure() being called $mt\n";
2117
	}
2118

    
2119
	/* kill any running choparp */
2120
	if (empty($interface)) {
2121
		killbyname("choparp");
2122
	} else {
2123
		$vipif = get_real_interface($interface);
2124
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2125
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2126
		}
2127
	}
2128

    
2129
	$paa = array();
2130
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2131

    
2132
		/* group by interface */
2133
		foreach ($config['virtualip']['vip'] as $vipent) {
2134
			if ($vipent['mode'] === "proxyarp") {
2135
				if ($vipent['interface']) {
2136
					$proxyif = $vipent['interface'];
2137
				} else {
2138
					$proxyif = "wan";
2139
				}
2140

    
2141
				if (!empty($interface) && $interface != $proxyif) {
2142
					continue;
2143
				}
2144

    
2145
				if (!is_array($paa[$proxyif])) {
2146
					$paa[$proxyif] = array();
2147
				}
2148

    
2149
				$paa[$proxyif][] = $vipent;
2150
			}
2151
		}
2152
	}
2153

    
2154
	if (!empty($interface)) {
2155
		if (is_array($paa[$interface])) {
2156
			$paaifip = get_interface_ip($interface);
2157
			if (!is_ipaddr($paaifip)) {
2158
				return;
2159
			}
2160
			$args = get_real_interface($interface) . " auto";
2161
			foreach ($paa[$interface] as $paent) {
2162
				if (isset($paent['subnet'])) {
2163
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2164
				} else if (isset($paent['range'])) {
2165
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2166
				}
2167
			}
2168
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2169
		}
2170
	} else if (count($paa) > 0) {
2171
		foreach ($paa as $paif => $paents) {
2172
			$paaifip = get_interface_ip($paif);
2173
			if (!is_ipaddr($paaifip)) {
2174
				continue;
2175
			}
2176
			$args = get_real_interface($paif) . " auto";
2177
			foreach ($paents as $paent) {
2178
				if (isset($paent['subnet'])) {
2179
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2180
				} else if (isset($paent['range'])) {
2181
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2182
				}
2183
			}
2184
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2185
		}
2186
	}
2187
}
2188

    
2189
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2190
	global $g, $config;
2191

    
2192
	if (is_array($config['virtualip']['vip'])) {
2193
		foreach ($config['virtualip']['vip'] as $vip) {
2194
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2195
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet'])) {
2196
					interface_vip_bring_down($vip);
2197
				} else if ($inet == "inet4" && is_ipaddrv4($vip['subnet'])) {
2198
					interface_vip_bring_down($vip);
2199
				}
2200
			}
2201
		}
2202
	}
2203
}
2204

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

    
2250
function interface_ipalias_configure(&$vip) {
2251
	global $config;
2252

    
2253
	if ($vip['mode'] != 'ipalias') {
2254
		return;
2255
	}
2256

    
2257
	if ($vip['interface'] != 'lo0' && stripos($vip['interface'], '_vip') === false) {
2258
		if (!isset($config['interfaces'][$vip['interface']])) {
2259
			return;
2260
		}
2261

    
2262
		if (!isset($config['interfaces'][$vip['interface']]['enable'])) {
2263
			return;
2264
		}
2265
	}
2266

    
2267
	$af = 'inet';
2268
	if (is_ipaddrv6($vip['subnet'])) {
2269
		$af = 'inet6';
2270
	}
2271
	$iface = $vip['interface'];
2272
	$vipadd = '';
2273
	if (strpos($vip['interface'], '_vip')) {
2274
		$carpvip = get_configured_carp_interface_list($vip['interface'], $af, 'vip');
2275
		$iface = $carpvip['interface'];
2276
		$vipadd = "vhid {$carpvip['vhid']}";
2277
	}
2278
	$if = get_real_interface($iface);
2279
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vipadd}");
2280
	unset($iface, $af, $if, $carpvip, $vipadd);
2281
}
2282

    
2283
function interface_reload_carps($cif) {
2284
	global $config;
2285

    
2286
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2287
	if (empty($carpifs)) {
2288
		return;
2289
	}
2290

    
2291
	$carps = explode(" ", $carpifs);
2292
	if (is_array($config['virtualip']['vip'])) {
2293
		$viparr = &$config['virtualip']['vip'];
2294
		foreach ($viparr as $vip) {
2295
			if (in_array($vip['carpif'], $carps)) {
2296
				switch ($vip['mode']) {
2297
					case "carp":
2298
						interface_vip_bring_down($vip);
2299
						sleep(1);
2300
						interface_carp_configure($vip);
2301
						break;
2302
					case "ipalias":
2303
						interface_vip_bring_down($vip);
2304
						sleep(1);
2305
						interface_ipalias_configure($vip);
2306
						break;
2307
				}
2308
			}
2309
		}
2310
	}
2311
}
2312

    
2313
function interface_carp_configure(&$vip) {
2314
	global $config, $g;
2315
	if (isset($config['system']['developerspew'])) {
2316
		$mt = microtime();
2317
		echo "interface_carp_configure() being called $mt\n";
2318
	}
2319

    
2320
	if ($vip['mode'] != "carp") {
2321
		return;
2322
	}
2323

    
2324
	/* NOTE: Maybe its useless nowadays */
2325
	$realif = get_real_interface($vip['interface']);
2326
	if (!does_interface_exist($realif)) {
2327
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2328
		return;
2329
	}
2330

    
2331
	$vip_password = $vip['password'];
2332
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2333
	if ($vip['password'] != "") {
2334
		$password = " pass {$vip_password}";
2335
	}
2336

    
2337
	$advbase = "";
2338
	if (!empty($vip['advbase'])) {
2339
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2340
	}
2341

    
2342
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2343
	if ($carp_maintenancemode) {
2344
		$advskew = "advskew 254";
2345
	} else {
2346
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2347
	}
2348

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

    
2351
	if (is_ipaddrv4($vip['subnet'])) {
2352
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2353
	} else if (is_ipaddrv6($vip['subnet'])) {
2354
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2355
	}
2356

    
2357
	return $realif;
2358
}
2359

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

    
2402
	if ($needs_clone == true) {
2403
		/* remove previous instance if it exists */
2404
		if (does_interface_exist($realif)) {
2405
			pfSense_interface_destroy($realif);
2406
		}
2407

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

    
2424
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2425
	global $config, $g;
2426

    
2427
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2428
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2429
				 'regdomain', 'regcountry', 'reglocation');
2430

    
2431
	if (!is_interface_wireless($ifcfg['if'])) {
2432
		return;
2433
	}
2434

    
2435
	$baseif = interface_get_wireless_base($ifcfg['if']);
2436

    
2437
	// Sync shared settings for assigned clones
2438
	$iflist = get_configured_interface_list(false, true);
2439
	foreach ($iflist as $if) {
2440
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2441
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2442
				foreach ($shared_settings as $setting) {
2443
					if ($sync_changes) {
2444
						if (isset($ifcfg['wireless'][$setting])) {
2445
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2446
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2447
							unset($config['interfaces'][$if]['wireless'][$setting]);
2448
						}
2449
					} else {
2450
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2451
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2452
						} else if (isset($ifcfg['wireless'][$setting])) {
2453
							unset($ifcfg['wireless'][$setting]);
2454
						}
2455
					}
2456
				}
2457
				if (!$sync_changes) {
2458
					break;
2459
				}
2460
			}
2461
		}
2462
	}
2463

    
2464
	// Read or write settings at shared area
2465
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2466
		foreach ($shared_settings as $setting) {
2467
			if ($sync_changes) {
2468
				if (isset($ifcfg['wireless'][$setting])) {
2469
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2470
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2471
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2472
				}
2473
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2474
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2475
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2476
				} else if (isset($ifcfg['wireless'][$setting])) {
2477
					unset($ifcfg['wireless'][$setting]);
2478
				}
2479
			}
2480
		}
2481
	}
2482

    
2483
	// Sync the mode on the clone creation page with the configured mode on the interface
2484
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2485
		foreach ($config['wireless']['clone'] as &$clone) {
2486
			if ($clone['cloneif'] == $ifcfg['if']) {
2487
				if ($sync_changes) {
2488
					$clone['mode'] = $ifcfg['wireless']['mode'];
2489
				} else {
2490
					$ifcfg['wireless']['mode'] = $clone['mode'];
2491
				}
2492
				break;
2493
			}
2494
		}
2495
		unset($clone);
2496
	}
2497
}
2498

    
2499
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2500
	global $config, $g;
2501

    
2502
	/*    open up a shell script that will be used to output the commands.
2503
	 *    since wireless is changing a lot, these series of commands are fragile
2504
	 *    and will sometimes need to be verified by a operator by executing the command
2505
	 *    and returning the output of the command to the developers for inspection.  please
2506
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2507
	 */
2508

    
2509
	// Remove script file
2510
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2511

    
2512
	// Clone wireless nic if needed.
2513
	interface_wireless_clone($if, $wl);
2514

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

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

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

    
2524
	/* set values for /path/program */
2525
	$hostapd = "/usr/sbin/hostapd";
2526
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2527
	$ifconfig = "/sbin/ifconfig";
2528
	$sysctl = "/sbin/sysctl";
2529
	$killall = "/usr/bin/killall";
2530

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

    
2533
	$wlcmd = array();
2534
	$wl_sysctl = array();
2535
	/* Make sure it's up */
2536
	$wlcmd[] = "up";
2537
	/* Set a/b/g standard */
2538
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2539
	/* skip mode entirely for "auto" */
2540
	if ($wlcfg['standard'] != "auto") {
2541
		$wlcmd[] = "mode " . escapeshellarg($standard);
2542
	}
2543

    
2544
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2545
	 * to prevent massive packet loss under certain conditions. */
2546
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2547
		$wlcmd[] = "-ampdu";
2548
	}
2549

    
2550
	/* Set ssid */
2551
	if ($wlcfg['ssid']) {
2552
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2553
	}
2554

    
2555
	/* Set 802.11g protection mode */
2556
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2557

    
2558
	/* set wireless channel value */
2559
	if (isset($wlcfg['channel'])) {
2560
		if ($wlcfg['channel'] == "0") {
2561
			$wlcmd[] = "channel any";
2562
		} else {
2563
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2564
		}
2565
	}
2566

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

    
2572
	/* Set txantenna value */
2573
	if (isset($wlcfg['txantenna'])) {
2574
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2575
	}
2576

    
2577
	/* Set rxantenna value */
2578
	if (isset($wlcfg['rxantenna'])) {
2579
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2580
	}
2581

    
2582
	/* set Distance value */
2583
	if ($wlcfg['distance']) {
2584
		$distance = escapeshellarg($wlcfg['distance']);
2585
	}
2586

    
2587
	/* Set wireless hostap mode */
2588
	if ($wlcfg['mode'] == "hostap") {
2589
		$wlcmd[] = "mediaopt hostap";
2590
	} else {
2591
		$wlcmd[] = "-mediaopt hostap";
2592
	}
2593

    
2594
	/* Set wireless adhoc mode */
2595
	if ($wlcfg['mode'] == "adhoc") {
2596
		$wlcmd[] = "mediaopt adhoc";
2597
	} else {
2598
		$wlcmd[] = "-mediaopt adhoc";
2599
	}
2600

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

    
2603
	/* handle hide ssid option */
2604
	if (isset($wlcfg['hidessid']['enable'])) {
2605
		$wlcmd[] = "hidessid";
2606
	} else {
2607
		$wlcmd[] = "-hidessid";
2608
	}
2609

    
2610
	/* handle pureg (802.11g) only option */
2611
	if (isset($wlcfg['pureg']['enable'])) {
2612
		$wlcmd[] = "mode 11g pureg";
2613
	} else {
2614
		$wlcmd[] = "-pureg";
2615
	}
2616

    
2617
	/* handle puren (802.11n) only option */
2618
	if (isset($wlcfg['puren']['enable'])) {
2619
		$wlcmd[] = "puren";
2620
	} else {
2621
		$wlcmd[] = "-puren";
2622
	}
2623

    
2624
	/* enable apbridge option */
2625
	if (isset($wlcfg['apbridge']['enable'])) {
2626
		$wlcmd[] = "apbridge";
2627
	} else {
2628
		$wlcmd[] = "-apbridge";
2629
	}
2630

    
2631
	/* handle turbo option */
2632
	if (isset($wlcfg['turbo']['enable'])) {
2633
		$wlcmd[] = "mediaopt turbo";
2634
	} else {
2635
		$wlcmd[] = "-mediaopt turbo";
2636
	}
2637

    
2638
	/* handle txpower setting */
2639
	// or don't. this has issues at the moment.
2640
	/*
2641
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2642
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2643
	}*/
2644

    
2645
	/* handle wme option */
2646
	if (isset($wlcfg['wme']['enable'])) {
2647
		$wlcmd[] = "wme";
2648
	} else {
2649
		$wlcmd[] = "-wme";
2650
	}
2651

    
2652
	/* Enable wpa if it's configured. No WEP support anymore. */
2653
	if (isset($wlcfg['wpa']['enable'])) {
2654
		$wlcmd[] = "authmode wpa wepmode off ";
2655
	} else {
2656
		$wlcmd[] = "authmode open wepmode off ";
2657
	}
2658

    
2659
	kill_hostapd($if);
2660
	mwexec(kill_wpasupplicant("{$if}"));
2661

    
2662
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2663
	conf_mount_rw();
2664

    
2665
	switch ($wlcfg['mode']) {
2666
		case 'bss':
2667
			if (isset($wlcfg['wpa']['enable'])) {
2668
				$wpa .= <<<EOD
2669
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2670
ctrl_interface_group=0
2671
ap_scan=1
2672
#fast_reauth=1
2673
network={
2674
ssid="{$wlcfg['ssid']}"
2675
scan_ssid=1
2676
priority=5
2677
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2678
psk="{$wlcfg['wpa']['passphrase']}"
2679
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2680
group={$wlcfg['wpa']['wpa_pairwise']}
2681
}
2682
EOD;
2683

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

    
2718
EOD;
2719

    
2720
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2721
					$wpa .= <<<EOD
2722
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2723
rsn_preauth=1
2724
rsn_preauth_interfaces={$if}
2725

    
2726
EOD;
2727
				}
2728
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2729
					$wpa .= "ieee8021x=1\n";
2730

    
2731
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2732
						$auth_server_port = "1812";
2733
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2734
							$auth_server_port = intval($wlcfg['auth_server_port']);
2735
						}
2736
						$wpa .= <<<EOD
2737

    
2738
auth_server_addr={$wlcfg['auth_server_addr']}
2739
auth_server_port={$auth_server_port}
2740
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2741

    
2742
EOD;
2743
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2744
							$auth_server_port2 = "1812";
2745
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2746
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2747
							}
2748

    
2749
							$wpa .= <<<EOD
2750
auth_server_addr={$wlcfg['auth_server_addr2']}
2751
auth_server_port={$auth_server_port2}
2752
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2753

    
2754
EOD;
2755
						}
2756
					}
2757
				}
2758

    
2759
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2760
				unset($wpa);
2761
			}
2762
			break;
2763
	}
2764

    
2765
	/*
2766
	 *    all variables are set, lets start up everything
2767
	 */
2768

    
2769
	$baseif = interface_get_wireless_base($if);
2770
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2771
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2772

    
2773
	/* set sysctls for the wireless interface */
2774
	if (!empty($wl_sysctl)) {
2775
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2776
		foreach ($wl_sysctl as $wl_sysctl_line) {
2777
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2778
		}
2779
	}
2780

    
2781
	/* set ack timers according to users preference (if he/she has any) */
2782
	if ($distance) {
2783
		fwrite($fd_set, "# Enable ATH distance settings\n");
2784
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2785
	}
2786

    
2787
	if (isset($wlcfg['wpa']['enable'])) {
2788
		if ($wlcfg['mode'] == "bss") {
2789
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2790
		}
2791
		if ($wlcfg['mode'] == "hostap") {
2792
			/* add line to script to restore old mac to make hostapd happy */
2793
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2794
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2795
				if (is_macaddr($if_oldmac)) {
2796
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2797
						" link " . escapeshellarg($if_oldmac) . "\n");
2798
				}
2799
			}
2800

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

    
2803
			/* add line to script to restore spoofed mac after running hostapd */
2804
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2805
				if ($wl['spoofmac']) {
2806
					$if_curmac = $wl['spoofmac'];
2807
				} else {
2808
					$if_curmac = get_interface_mac($if);
2809
				}
2810
				if (is_macaddr($if_curmac)) {
2811
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2812
						" link " . escapeshellarg($if_curmac) . "\n");
2813
				}
2814
			}
2815
		}
2816
	}
2817

    
2818
	fclose($fd_set);
2819
	conf_mount_ro();
2820

    
2821
	/* Making sure regulatory settings have actually changed
2822
	 * before applying, because changing them requires bringing
2823
	 * down all wireless networks on the interface. */
2824
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2825
	$ifconfig_str = implode($output);
2826
	unset($output);
2827
	$reg_changing = false;
2828

    
2829
	/* special case for the debug country code */
2830
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
2831
		$reg_changing = true;
2832
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
2833
		$reg_changing = true;
2834
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
2835
		$reg_changing = true;
2836
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
2837
		$reg_changing = true;
2838
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
2839
		$reg_changing = true;
2840
	}
2841

    
2842
	if ($reg_changing) {
2843
		/* set regulatory domain */
2844
		if ($wlcfg['regdomain']) {
2845
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2846
		}
2847

    
2848
		/* set country */
2849
		if ($wlcfg['regcountry']) {
2850
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2851
		}
2852

    
2853
		/* set location */
2854
		if ($wlcfg['reglocation']) {
2855
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2856
		}
2857

    
2858
		$wlregcmd_args = implode(" ", $wlregcmd);
2859

    
2860
		/* build a complete list of the wireless clones for this interface */
2861
		$clone_list = array();
2862
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2863
			$clone_list[] = interface_get_wireless_clone($baseif);
2864
		}
2865
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2866
			foreach ($config['wireless']['clone'] as $clone) {
2867
				if ($clone['if'] == $baseif) {
2868
					$clone_list[] = $clone['cloneif'];
2869
				}
2870
			}
2871
		}
2872

    
2873
		/* find which clones are up and bring them down */
2874
		$clones_up = array();
2875
		foreach ($clone_list as $clone_if) {
2876
			$clone_status = pfSense_get_interface_addresses($clone_if);
2877
			if ($clone_status['status'] == 'up') {
2878
				$clones_up[] = $clone_if;
2879
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2880
			}
2881
		}
2882

    
2883
		/* apply the regulatory settings */
2884
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2885
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2886

    
2887
		/* bring the clones back up that were previously up */
2888
		foreach ($clones_up as $clone_if) {
2889
			interfaces_bring_up($clone_if);
2890

    
2891
			/*
2892
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2893
			 * is in infrastructure mode, and WPA is enabled.
2894
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2895
			 */
2896
			if ($clone_if != $if) {
2897
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2898
				if ((!empty($friendly_if)) &&
2899
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
2900
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
2901
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2902
				}
2903
			}
2904
		}
2905
	}
2906

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

    
2910
	 * The mode must be specified in a separate command before ifconfig
2911
	 * will allow the mode and channel at the same time in the next. */
2912
	//mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2913
	//fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
2914

    
2915
	/* configure wireless */
2916
	$wlcmd_args = implode(" ", $wlcmd);
2917
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2918
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
2919
	fclose($wlan_setup_log);
2920

    
2921
	unset($wlcmd_args, $wlcmd);
2922

    
2923

    
2924
	sleep(1);
2925
	/* execute hostapd and wpa_supplicant if required in shell */
2926
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2927

    
2928
	return 0;
2929

    
2930
}
2931

    
2932
function kill_hostapd($interface) {
2933
	global $g;
2934

    
2935
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
2936
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2937
	}
2938
}
2939

    
2940
function kill_wpasupplicant($interface) {
2941
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2942
}
2943

    
2944
function find_dhclient_process($interface) {
2945
	if ($interface) {
2946
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2947
	} else {
2948
		$pid = 0;
2949
	}
2950

    
2951
	return intval($pid);
2952
}
2953

    
2954
function kill_dhclient_process($interface) {
2955
	if (empty($interface) || !does_interface_exist($interface)) {
2956
		return;
2957
	}
2958

    
2959
	$i = 0;
2960
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2961
		/* 3rd time make it die for sure */
2962
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2963
		posix_kill($pid, $sig);
2964
		sleep(1);
2965
		$i++;
2966
	}
2967
	unset($i);
2968
}
2969

    
2970
function find_dhcp6c_process($interface) {
2971
	global $g;
2972

    
2973
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
2974
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2975
	} else {
2976
		return(false);
2977
	}
2978

    
2979
	return intval($pid);
2980
}
2981

    
2982
function interface_virtual_create($interface) {
2983
	global $config;
2984

    
2985
	if (strstr($interface, "_vlan")) {
2986
		interfaces_vlan_configure($vlan);
2987
	} else if (substr($interface, 0, 3) == "gre") {
2988
		interfaces_gre_configure(0, $interface);
2989
	} else if (substr($interface, 0, 3) == "gif") {
2990
		interfaces_gif_configure(0, $interface);
2991
	} else if (substr($interface, 0, 5) == "ovpns") {
2992
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
2993
			foreach ($config['openvpn']['openvpn-server'] as $server) {
2994
				if ($interface == "ovpns{$server['vpnid']}") {
2995
					if (!function_exists('openvpn_resync')) {
2996
						require_once('openvpn.inc');
2997
					}
2998
					log_error("OpenVPN: Resync server {$server['description']}");
2999
					openvpn_resync('server', $server);
3000
				}
3001
			}
3002
			unset($server);
3003
		}
3004
	} else if (substr($interface, 0, 5) == "ovpnc") {
3005
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3006
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3007
				if ($interface == "ovpnc{$client['vpnid']}") {
3008
					if (!function_exists('openvpn_resync')) {
3009
						require_once('openvpn.inc');
3010
					}
3011
					log_error("OpenVPN: Resync server {$client['description']}");
3012
					openvpn_resync('client', $client);
3013
				}
3014
			}
3015
			unset($client);
3016
		}
3017
	} else if (substr($interface, 0, 4) == "lagg") {
3018
		interfaces_lagg_configure($interface);
3019
	} else if (substr($interface, 0, 6) == "bridge") {
3020
		interfaces_bridge_configure(0, $interface);
3021
	}
3022
}
3023

    
3024
function interface_vlan_mtu_configured($realhwif, $mtu) {
3025
	global $config;
3026

    
3027
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3028
		foreach ($config['vlans']['vlan'] as $vlan) {
3029
			if ($vlan['if'] != $realhwif) {
3030
				continue;
3031
			}
3032
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3033
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3034
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu) {
3035
					$mtu = $config['interfaces'][$assignedport]['mtu'];
3036
				}
3037
			}
3038
		}
3039
	}
3040

    
3041
	return $mtu;
3042
}
3043

    
3044
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
3045
	global $config;
3046

    
3047
	if (!is_array($vlanifs)) {
3048
		return;
3049
	}
3050

    
3051
	/* All vlans need to use the same mtu value as their parent. */
3052
	foreach ($vlanifs as $vlan) {
3053
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3054
		if (!empty($assignedport)) {
3055
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
3056
				pfSense_interface_mtu($vlan['vlanif'], $config['interfaces'][$assignedport]['mtu']);
3057
			} else {
3058
				if (get_interface_mtu($vlan['vlanif']) != $mtu) {
3059
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
3060
				}
3061
			}
3062
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu) {
3063
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
3064
		}
3065
	}
3066
}
3067

    
3068
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3069
	global $config, $g;
3070
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3071
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3072

    
3073
	$wancfg = $config['interfaces'][$interface];
3074

    
3075
	if (!isset($wancfg['enable'])) {
3076
		return;
3077
	}
3078

    
3079
	$realif = get_real_interface($interface);
3080
	$realhwif_array = get_parent_interface($interface);
3081
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3082
	$realhwif = $realhwif_array[0];
3083

    
3084
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3085
		/* remove all IPv4 and IPv6 addresses */
3086
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3087
		if (is_array($tmpifaces)) {
3088
			foreach ($tmpifaces as $tmpiface) {
3089
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3090
					if (!is_linklocal($tmpiface)) {
3091
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3092
					}
3093
				} else {
3094
					if (is_subnetv4($tmpiface)) {
3095
						$tmpip = explode('/', $tmpiface);
3096
						$tmpip = $tmpip[0];
3097
					} else {
3098
						$tmpip = $tmpiface;
3099
					}
3100
					pfSense_interface_deladdress($realif, $tmpip);
3101
				}
3102
			}
3103
		}
3104

    
3105
		/* only bring down the interface when both v4 and v6 are set to NONE */
3106
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3107
			interface_bring_down($interface);
3108
		}
3109
	}
3110

    
3111
	$interface_to_check = $realif;
3112
	if (interface_isppp_type($interface)) {
3113
		$interface_to_check = $realhwif;
3114
	}
3115

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

    
3121
	/* Disable Accepting router advertisements unless specifically requested */
3122
	if ($g['debug']) {
3123
		log_error("Deny router advertisements for interface {$interface}");
3124
	}
3125
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3126

    
3127
	/* wireless configuration? */
3128
	if (is_array($wancfg['wireless'])) {
3129
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3130
	}
3131

    
3132
	$mac = get_interface_mac($realhwif);
3133
	/*
3134
	 * Don't try to reapply the spoofed MAC if it's already applied.
3135
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3136
	 * the interface config again, which attempts to spoof the MAC again,
3137
	 * which cycles the link again...
3138
	 */
3139
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
3140
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3141
			" link " . escapeshellarg($wancfg['spoofmac']));
3142
	} else {
3143

    
3144
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3145
			/*   this is not a valid mac address.  generate a
3146
			 *   temporary mac address so the machine can get online.
3147
			 */
3148
			echo gettext("Generating new MAC address.");
3149
			$random_mac = generate_random_mac_address();
3150
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3151
				" link " . escapeshellarg($random_mac));
3152
			$wancfg['spoofmac'] = $random_mac;
3153
			write_config();
3154
			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");
3155
		}
3156
	}
3157

    
3158
	/* media */
3159
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3160
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3161
		if ($wancfg['media']) {
3162
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3163
		}
3164
		if ($wancfg['mediaopt']) {
3165
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3166
		}
3167
		mwexec($cmd);
3168
	}
3169

    
3170
	/* Apply hw offloading policies as configured */
3171
	enable_hardware_offloading($interface);
3172

    
3173
	/* invalidate interface/ip/sn cache */
3174
	get_interface_arr(true);
3175
	unset($interface_ip_arr_cache[$realif]);
3176
	unset($interface_sn_arr_cache[$realif]);
3177
	unset($interface_ipv6_arr_cache[$realif]);
3178
	unset($interface_snv6_arr_cache[$realif]);
3179

    
3180
	$tunnelif = substr($realif, 0, 3);
3181

    
3182
	if (does_interface_exist($wancfg['if'])) {
3183
		interfaces_bring_up($wancfg['if']);
3184
	}
3185

    
3186
	if (!empty($wancfg['mtu'])) {
3187
		if (stristr($realif, "_vlan")) {
3188
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3189
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3190
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3191
				if ($wancfg['mtu'] > $parentmtu) {
3192
					log_error("There is a conflict on MTU between parent {$realhwif} and VLAN({$realif})");
3193
				}
3194
			} else {
3195
				$parentmtu = 0;
3196
			}
3197

    
3198
			$parentmtu = interface_vlan_mtu_configured($realhwif, $parentmtu);
3199

    
3200
			if (get_interface_mtu($realhwif) != $parentmtu) {
3201
				pfSense_interface_mtu($realhwif, $parentmtu);
3202
			}
3203

    
3204
			/* All vlans need to use the same mtu value as their parent. */
3205
			interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $parentmtu);
3206
		} else if (substr($realif, 0, 4) == 'lagg') {
3207
			/* LAGG interface must be destroyed and re-created to change MTU */
3208
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3209
				if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3210
					foreach ($config['laggs']['lagg'] as $lagg) {
3211
						if ($lagg['laggif'] == $realif) {
3212
							interface_lagg_configure($lagg);
3213
							break;
3214
						}
3215
					}
3216
				}
3217
			}
3218
		} else {
3219
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3220
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3221
			}
3222

    
3223
			/* This case is needed when the parent of vlans is being configured */
3224
			$vlans = link_interface_to_vlans($realif);
3225
			if (is_array($vlans)) {
3226
				interface_vlan_adapt_mtu($vlans, $wancfg['mtu']);
3227
			}
3228
			unset($vlans);
3229
		}
3230
		/* XXX: What about gre/gif/.. ? */
3231
	}
3232

    
3233
	switch ($wancfg['ipaddr']) {
3234
		case 'dhcp':
3235
			interface_dhcp_configure($interface);
3236
			break;
3237
		case 'pppoe':
3238
		case 'l2tp':
3239
		case 'pptp':
3240
		case 'ppp':
3241
			interface_ppps_configure($interface);
3242
			break;
3243
		default:
3244
			/* XXX: Kludge for now related to #3280 */
3245
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3246
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3247
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3248
				}
3249
			}
3250
			break;
3251
	}
3252

    
3253
	switch ($wancfg['ipaddrv6']) {
3254
		case 'slaac':
3255
		case 'dhcp6':
3256
			interface_dhcpv6_configure($interface, $wancfg);
3257
			break;
3258
		case '6rd':
3259
			interface_6rd_configure($interface, $wancfg);
3260
			break;
3261
		case '6to4':
3262
			interface_6to4_configure($interface, $wancfg);
3263
			break;
3264
		case 'track6':
3265
			interface_track6_configure($interface, $wancfg, $linkupevent);
3266
			break;
3267
		default:
3268
			/* XXX: Kludge for now related to #3280 */
3269
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3270
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3271
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3272
					// FIXME: Add IPv6 Support to the pfSense module
3273
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3274
				}
3275
			}
3276
			break;
3277
	}
3278

    
3279
	interface_netgraph_needed($interface);
3280

    
3281
	if (!platform_booting()) {
3282
		link_interface_to_vips($interface, "update");
3283

    
3284
		if ($tunnelif != 'gre') {
3285
			unset($gre);
3286
			$gre = link_interface_to_gre($interface);
3287
			if (!empty($gre)) {
3288
				array_walk($gre, 'interface_gre_configure');
3289
			}
3290
		}
3291

    
3292
		if ($tunnelif != 'gif') {
3293
			unset($gif);
3294
			$gif = link_interface_to_gif ($interface);
3295
			if (!empty($gif)) {
3296
				array_walk($gif, 'interface_gif_configure');
3297
			}
3298
		}
3299

    
3300
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3301
			unset($bridgetmp);
3302
			$bridgetmp = link_interface_to_bridge($interface);
3303
			if (!empty($bridgetmp)) {
3304
				interface_bridge_add_member($bridgetmp, $realif);
3305
			}
3306
		}
3307

    
3308
		$grouptmp = link_interface_to_group($interface);
3309
		if (!empty($grouptmp)) {
3310
			array_walk($grouptmp, 'interface_group_add_member');
3311
		}
3312

    
3313
		if ($interface == "lan") {
3314
			/* make new hosts file */
3315
			system_hosts_generate();
3316
		}
3317

    
3318
		if ($reloadall == true) {
3319

    
3320
			/* reconfigure static routes (kernel may have deleted them) */
3321
			system_routing_configure($interface);
3322

    
3323
			/* reload ipsec tunnels */
3324
			send_event("service reload ipsecdns");
3325

    
3326
			/* restart dnsmasq or unbound */
3327
			if (isset($config['dnsmasq']['enable'])) {
3328
				services_dnsmasq_configure();
3329
			} elseif (isset($config['unbound']['enable'])) {
3330
				services_unbound_configure();
3331
			}
3332

    
3333
			/* update dyndns */
3334
			send_event("service reload dyndns {$interface}");
3335

    
3336
			/* reload captive portal */
3337
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3338
				require_once('captiveportal.inc');
3339
			}
3340
			captiveportal_init_rules_byinterface($interface);
3341
		}
3342
	}
3343

    
3344
	interfaces_staticarp_configure($interface);
3345
	return 0;
3346
}
3347

    
3348
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3349
	global $config, $g;
3350

    
3351
	if (!is_array($wancfg)) {
3352
		return;
3353
	}
3354

    
3355
	if (!isset($wancfg['enable'])) {
3356
		return;
3357
	}
3358

    
3359
	/* If the interface is not configured via another, exit */
3360
	if (empty($wancfg['track6-interface'])) {
3361
		return;
3362
	}
3363

    
3364
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3365
	$realif = get_real_interface($interface);
3366
	$linklocal = find_interface_ipv6_ll($realif);
3367
	if (!empty($linklocal)) {
3368
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3369
	}
3370
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3371
	/* XXX: Probably should remove? */
3372
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3373

    
3374
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3375
	if (!isset($trackcfg['enable'])) {
3376
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3377
		return;
3378
	}
3379

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

    
3410
	if ($linkupevent == false) {
3411
		if (!function_exists('services_dhcpd_configure')) {
3412
			require_once("services.inc");
3413
		}
3414

    
3415
		if (isset($config['unbound']['enable'])) {
3416
			services_unbound_configure();
3417
		}
3418

    
3419
		services_dhcpd_configure("inet6");
3420
	}
3421

    
3422
	return 0;
3423
}
3424

    
3425
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3426
	global $config, $g;
3427
	global $interface_ipv6_arr_cache;
3428
	global $interface_snv6_arr_cache;
3429

    
3430
	if (!is_array($lancfg)) {
3431
		return;
3432
	}
3433

    
3434
	/* If the interface is not configured via another, exit */
3435
	if (empty($lancfg['track6-interface'])) {
3436
		return;
3437
	}
3438

    
3439
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3440
	if (empty($wancfg)) {
3441
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3442
		return;
3443
	}
3444

    
3445
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3446
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3447
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not valid, not configuring 6RD tunnel");
3448
		return;
3449
	}
3450
	$hexwanv4 = return_hex_ipv4($ip4address);
3451

    
3452
	/* create the long prefix notation for math, save the prefix length */
3453
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3454
	$rd6prefixlen = $rd6prefix[1];
3455
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3456

    
3457
	/* binary presentation of the prefix for all 128 bits. */
3458
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3459

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

    
3465
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3466
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3467
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3468
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3469
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3470
	/* fill the rest out with zeros */
3471
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3472

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

    
3476
	$lanif = get_real_interface($interface);
3477
	$oip = find_interface_ipv6($lanif);
3478
	if (is_ipaddrv6($oip)) {
3479
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3480
	}
3481
	unset($interface_ipv6_arr_cache[$lanif]);
3482
	unset($interface_snv6_arr_cache[$lanif]);
3483
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3484
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3485

    
3486
	return 0;
3487
}
3488

    
3489
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3490
	global $config, $g;
3491
	global $interface_ipv6_arr_cache;
3492
	global $interface_snv6_arr_cache;
3493

    
3494
	if (!is_array($lancfg)) {
3495
		return;
3496
	}
3497

    
3498
	/* If the interface is not configured via another, exit */
3499
	if (empty($lancfg['track6-interface'])) {
3500
		return;
3501
	}
3502

    
3503
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3504
	if (empty($wancfg)) {
3505
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3506
		return;
3507
	}
3508

    
3509
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3510
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3511
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3512
		return;
3513
	}
3514
	$hexwanv4 = return_hex_ipv4($ip4address);
3515

    
3516
	/* create the long prefix notation for math, save the prefix length */
3517
	$sixto4prefix = "2002::";
3518
	$sixto4prefixlen = 16;
3519
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3520

    
3521
	/* binary presentation of the prefix for all 128 bits. */
3522
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3523

    
3524
	/* just save the left prefix length bits */
3525
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3526
	/* add the v4 address */
3527
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3528
	/* add the custom prefix id */
3529
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3530
	/* fill the rest out with zeros */
3531
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3532

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

    
3536
	$lanif = get_real_interface($interface);
3537
	$oip = find_interface_ipv6($lanif);
3538
	if (is_ipaddrv6($oip)) {
3539
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3540
	}
3541
	unset($interface_ipv6_arr_cache[$lanif]);
3542
	unset($interface_snv6_arr_cache[$lanif]);
3543
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3544
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3545

    
3546
	return 0;
3547
}
3548

    
3549
function interface_6rd_configure($interface = "wan", $wancfg) {
3550
	global $config, $g;
3551

    
3552
	/* because this is a tunnel interface we can only function
3553
	 *	with a public IPv4 address on the interface */
3554

    
3555
	if (!is_array($wancfg)) {
3556
		return;
3557
	}
3558

    
3559
	if (!is_module_loaded('if_stf.ko')) {
3560
		mwexec('/sbin/kldload if_stf.ko');
3561
	}
3562

    
3563
	$wanif = get_real_interface($interface);
3564
	$ip4address = find_interface_ip($wanif);
3565
	if (!is_ipaddrv4($ip4address)) {
3566
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3567
		return false;
3568
	}
3569
	$hexwanv4 = return_hex_ipv4($ip4address);
3570

    
3571
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3572
		$wancfg['prefix-6rd-v4plen'] = 0;
3573
	}
3574

    
3575
	/* create the long prefix notation for math, save the prefix length */
3576
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3577
	$rd6prefixlen = $rd6prefix[1];
3578
	$brgw = explode('.', $wancfg['gateway-6rd']);
3579
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3580
	$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);
3581
	if (strlen($rd6brgw) < 128) {
3582
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3583
	}
3584
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3585
	unset($brgw);
3586
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3587

    
3588
	/* binary presentation of the prefix for all 128 bits. */
3589
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3590

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

    
3598
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3599
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3600

    
3601

    
3602
	/* XXX: need to extend to support variable prefix size for v4 */
3603
	if (!is_module_loaded("if_stf")) {
3604
		mwexec("/sbin/kldload if_stf.ko");
3605
	}
3606
	$stfiface = "{$interface}_stf";
3607
	if (does_interface_exist($stfiface)) {
3608
		pfSense_interface_destroy($stfiface);
3609
	}
3610
	$tmpstfiface = pfSense_interface_create("stf");
3611
	pfSense_interface_rename($tmpstfiface, $stfiface);
3612
	pfSense_interface_flags($stfiface, IFF_LINK2);
3613
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3614
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3615
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3616
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3617
	}
3618
	if ($g['debug']) {
3619
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3620
	}
3621

    
3622
	/* write out a default router file */
3623
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3624
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3625

    
3626
	$ip4gateway = get_interface_gateway($interface);
3627
	if (is_ipaddrv4($ip4gateway)) {
3628
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3629
	}
3630

    
3631
	/* configure dependent interfaces */
3632
	if (!platform_booting()) {
3633
		link_interface_to_track6($interface, "update");
3634
	}
3635

    
3636
	return 0;
3637
}
3638

    
3639
function interface_6to4_configure($interface = "wan", $wancfg) {
3640
	global $config, $g;
3641

    
3642
	/* because this is a tunnel interface we can only function
3643
	 *	with a public IPv4 address on the interface */
3644

    
3645
	if (!is_array($wancfg)) {
3646
		return;
3647
	}
3648

    
3649
	$wanif = get_real_interface($interface);
3650
	$ip4address = find_interface_ip($wanif);
3651
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3652
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3653
		return false;
3654
	}
3655

    
3656
	/* create the long prefix notation for math, save the prefix length */
3657
	$stfprefixlen = 16;
3658
	$stfprefix = Net_IPv6::uncompress("2002::");
3659
	$stfarr = explode(":", $stfprefix);
3660
	$v4prefixlen = "0";
3661

    
3662
	/* we need the hex form of the interface IPv4 address */
3663
	$ip4arr = explode(".", $ip4address);
3664
	$hexwanv4 = "";
3665
	foreach ($ip4arr as $octet) {
3666
		$hexwanv4 .= sprintf("%02x", $octet);
3667
	}
3668

    
3669
	/* we need the hex form of the broker IPv4 address */
3670
	$ip4arr = explode(".", "192.88.99.1");
3671
	$hexbrv4 = "";
3672
	foreach ($ip4arr as $octet) {
3673
		$hexbrv4 .= sprintf("%02x", $octet);
3674
	}
3675

    
3676
	/* binary presentation of the prefix for all 128 bits. */
3677
	$stfprefixbin = "";
3678
	foreach ($stfarr as $element) {
3679
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3680
	}
3681
	/* just save the left prefix length bits */
3682
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3683

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

    
3688
	/* for the local subnet too. */
3689
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3690
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3691

    
3692
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3693
	$stfbrarr = array();
3694
	$stfbrbinarr = array();
3695
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3696
	foreach ($stfbrbinarr as $bin) {
3697
		$stfbrarr[] = dechex(bindec($bin));
3698
	}
3699
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3700

    
3701
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3702
	$stflanarr = array();
3703
	$stflanbinarr = array();
3704
	$stflanbinarr = str_split($stflanbin, 16);
3705
	foreach ($stflanbinarr as $bin) {
3706
		$stflanarr[] = dechex(bindec($bin));
3707
	}
3708
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3709
	$stflanarr[7] = 1;
3710
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3711

    
3712
	/* setup the stf interface */
3713
	if (!is_module_loaded("if_stf")) {
3714
		mwexec("/sbin/kldload if_stf.ko");
3715
	}
3716
	$stfiface = "{$interface}_stf";
3717
	if (does_interface_exist($stfiface)) {
3718
		pfSense_interface_destroy($stfiface);
3719
	}
3720
	$tmpstfiface = pfSense_interface_create("stf");
3721
	pfSense_interface_rename($tmpstfiface, $stfiface);
3722
	pfSense_interface_flags($stfiface, IFF_LINK2);
3723
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3724

    
3725
	if ($g['debug']) {
3726
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3727
	}
3728

    
3729
	/* write out a default router file */
3730
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3731
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3732

    
3733
	$ip4gateway = get_interface_gateway($interface);
3734
	if (is_ipaddrv4($ip4gateway)) {
3735
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3736
	}
3737

    
3738
	if (!platform_booting()) {
3739
		link_interface_to_track6($interface, "update");
3740
	}
3741

    
3742
	return 0;
3743
}
3744

    
3745
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3746
	global $config, $g;
3747

    
3748
	if (!is_array($wancfg)) {
3749
		return;
3750
	}
3751

    
3752
	$wanif = get_real_interface($interface, "inet6");
3753
	$dhcp6cconf = "";
3754

    
3755
	if ($wancfg['adv_dhcp6_config_file_override']) {
3756
		// DHCP6 Config File Override
3757
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3758
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3759
		// DHCP6 Config File Advanced
3760
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3761
	} else {
3762
		// DHCP6 Config File Basic
3763
		$dhcp6cconf .= "interface {$wanif} {\n";
3764

    
3765
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3766
		if ($wancfg['ipaddrv6'] == "slaac") {
3767
			$dhcp6cconf .= "\tinformation-only;\n";
3768
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3769
			$dhcp6cconf .= "\trequest domain-name;\n";
3770
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3771
			$dhcp6cconf .= "};\n";
3772
		} else {
3773
			$trackiflist = array();
3774
			$iflist = link_interface_to_track6($interface);
3775
			foreach ($iflist as $ifname => $ifcfg) {
3776
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3777
					$trackiflist[$ifname] = $ifcfg;
3778
				}
3779
			}
3780

    
3781
			/* skip address request if this is set */
3782
			if (!isset($wancfg['dhcp6prefixonly'])) {
3783
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3784
			}
3785
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3786
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3787
			}
3788

    
3789
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3790
			$dhcp6cconf .= "\trequest domain-name;\n";
3791
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3792
			$dhcp6cconf .= "};\n";
3793

    
3794
			if (!isset($wancfg['dhcp6prefixonly'])) {
3795
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3796
			}
3797

    
3798
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3799
				/* Setup the prefix delegation */
3800
				$dhcp6cconf .= "id-assoc pd 0 {\n";
3801
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3802
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
3803
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
3804
				}
3805
				foreach ($trackiflist as $friendly => $ifcfg) {
3806
					if ($g['debug']) {
3807
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3808
					}
3809
					$realif = get_real_interface($friendly);
3810
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
3811
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
3812
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3813
					$dhcp6cconf .= "\t};\n";
3814
				}
3815
				unset($preflen, $iflist, $ifcfg, $ifname);
3816
				$dhcp6cconf .= "};\n";
3817
			}
3818
			unset($trackiflist);
3819
		}
3820
	}
3821

    
3822
	/* wide-dhcp6c works for now. */
3823
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3824
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3825
		unset($dhcp6cconf);
3826
		return 1;
3827
	}
3828
	unset($dhcp6cconf);
3829

    
3830
	$dhcp6cscript = "#!/bin/sh\n";
3831
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3832
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3833
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3834
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3835
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3836
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3837
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3838
		unset($dhcp6cscript);
3839
		return 1;
3840
	}
3841
	unset($dhcp6cscript);
3842
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3843

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

    
3864
	/* accept router advertisements for this interface */
3865
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3866
	log_error("Accept router advertisements on interface {$wanif} ");
3867
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3868

    
3869
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3870
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3871
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3872
		sleep(2);
3873
	}
3874
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3875

    
3876
	/* NOTE: will be called from rtsold invoked script
3877
	 * link_interface_to_track6($interface, "update");
3878
	 */
3879

    
3880
	return 0;
3881
}
3882

    
3883
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3884
	global $g;
3885

    
3886
	$send_options = "";
3887
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3888
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_send_options']);
3889
		foreach ($options as $option) {
3890
			$send_options .= "\tsend " . trim($option) . ";\n";
3891
		}
3892
	}
3893

    
3894
	$request_options = "";
3895
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3896
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_request_options']);
3897
		foreach ($options as $option) {
3898
			$request_options .= "\trequest " . trim($option) . ";\n";
3899
		}
3900
	}
3901

    
3902
	$information_only = "";
3903
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
3904
		$information_only = "\tinformation-only;\n";
3905
	}
3906

    
3907
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3908
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
3909
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3910
	}
3911

    
3912
	$interface_statement  = "interface";
3913
	$interface_statement .= " {$wanif}";
3914
	$interface_statement .= " {\n";
3915
	$interface_statement .= "$send_options";
3916
	$interface_statement .= "$request_options";
3917
	$interface_statement .= "$information_only";
3918
	$interface_statement .= "$script";
3919
	$interface_statement .= "};\n";
3920

    
3921
	$id_assoc_statement_address = "";
3922
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3923
		$id_assoc_statement_address .= "id-assoc";
3924
		$id_assoc_statement_address .= " na";
3925
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
3926
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3927
		}
3928
		$id_assoc_statement_address .= " { ";
3929

    
3930
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
3931
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
3932
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
3933
			$id_assoc_statement_address .= "\n\taddress";
3934
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3935
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3936
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
3937
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
3938
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3939
			}
3940
			$id_assoc_statement_address .= ";\n";
3941
		}
3942

    
3943
		$id_assoc_statement_address .= "};\n";
3944
	}
3945

    
3946
	$id_assoc_statement_prefix = "";
3947
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3948
		$id_assoc_statement_prefix .= "id-assoc";
3949
		$id_assoc_statement_prefix .= " pd";
3950
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
3951
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3952
		}
3953
		$id_assoc_statement_prefix .= " { ";
3954

    
3955
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
3956
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
3957
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
3958
			$id_assoc_statement_prefix .= "\n\tprefix";
3959
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3960
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3961
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
3962
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
3963
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3964
			}
3965
			$id_assoc_statement_prefix .= ";";
3966
		}
3967

    
3968
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3969
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3970
			$id_assoc_statement_prefix .= " {$wanif}";
3971
			$id_assoc_statement_prefix .= " {\n";
3972
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3973
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
3974
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
3975
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3976
			}
3977
			$id_assoc_statement_prefix .= "\t};";
3978
		}
3979

    
3980
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
3981
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
3982
			$id_assoc_statement_prefix .= "\n";
3983
		}
3984

    
3985
		$id_assoc_statement_prefix .= "};\n";
3986
	}
3987

    
3988
	$authentication_statement = "";
3989
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
3990
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
3991
		$authentication_statement .= "authentication";
3992
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
3993
		$authentication_statement .= " {\n";
3994
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
3995
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
3996
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
3997
		}
3998
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
3999
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4000
		}
4001
		$authentication_statement .= "};\n";
4002
	}
4003

    
4004
	$key_info_statement = "";
4005
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4006
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4007
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4008
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4009
		$key_info_statement .= "keyinfo";
4010
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4011
		$key_info_statement .= " {\n";
4012
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4013
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4014
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4015
		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'])) {
4016
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4017
		}
4018
		$key_info_statement .= "};\n";
4019
	}
4020

    
4021
	$dhcp6cconf  = $interface_statement;
4022
	$dhcp6cconf .= $id_assoc_statement_address;
4023
	$dhcp6cconf .= $id_assoc_statement_prefix;
4024
	$dhcp6cconf .= $authentication_statement;
4025
	$dhcp6cconf .= $key_info_statement;
4026

    
4027
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4028

    
4029
	return $dhcp6cconf;
4030
}
4031

    
4032

    
4033
function DHCP6_Config_File_Override($wancfg, $wanif) {
4034

    
4035
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4036

    
4037
	if ($dhcp6cconf === false) {
4038
		log_error("Error: cannot open {$wancfg['adv_dhcp6_config_file_override_path']} in DHCP6_Config_File_Override() for reading.\n");
4039
		return '';
4040
	} else {
4041
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4042
	}
4043
}
4044

    
4045

    
4046
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4047

    
4048
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4049

    
4050
	return $dhcp6cconf;
4051
}
4052

    
4053

    
4054
function interface_dhcp_configure($interface = "wan") {
4055
	global $config, $g;
4056

    
4057
	$wancfg = $config['interfaces'][$interface];
4058
	$wanif = $wancfg['if'];
4059
	if (empty($wancfg)) {
4060
		$wancfg = array();
4061
	}
4062

    
4063
	/* generate dhclient_wan.conf */
4064
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4065
	if (!$fd) {
4066
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
4067
		return 1;
4068
	}
4069

    
4070
	if ($wancfg['dhcphostname']) {
4071
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4072
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4073
	} else {
4074
		$dhclientconf_hostname = "";
4075
	}
4076

    
4077
	$wanif = get_real_interface($interface);
4078
	if (empty($wanif)) {
4079
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4080
		return 0;
4081
	}
4082
	$dhclientconf = "";
4083

    
4084
	$dhclientconf .= <<<EOD
4085
interface "{$wanif}" {
4086
timeout 60;
4087
retry 15;
4088
select-timeout 0;
4089
initial-interval 1;
4090
	{$dhclientconf_hostname}
4091
	script "/sbin/dhclient-script";
4092
EOD;
4093

    
4094
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4095
		$dhclientconf .= <<<EOD
4096

    
4097
	reject {$wancfg['dhcprejectfrom']};
4098
EOD;
4099
	}
4100
	$dhclientconf .= <<<EOD
4101

    
4102
}
4103

    
4104
EOD;
4105

    
4106
	// DHCP Config File Advanced
4107
	if ($wancfg['adv_dhcp_config_advanced']) {
4108
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4109
	}
4110

    
4111
	if (is_ipaddr($wancfg['alias-address'])) {
4112
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4113
		$dhclientconf .= <<<EOD
4114
alias {
4115
	interface "{$wanif}";
4116
	fixed-address {$wancfg['alias-address']};
4117
	option subnet-mask {$subnetmask};
4118
}
4119

    
4120
EOD;
4121
	}
4122

    
4123
	// DHCP Config File Override
4124
	if ($wancfg['adv_dhcp_config_file_override']) {
4125
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4126
	}
4127

    
4128
	fwrite($fd, $dhclientconf);
4129
	fclose($fd);
4130

    
4131
	/* bring wan interface up before starting dhclient */
4132
	if ($wanif) {
4133
		interfaces_bring_up($wanif);
4134
	} else {
4135
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4136
	}
4137

    
4138
	/* Make sure dhclient is not running */
4139
	kill_dhclient_process($wanif);
4140

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

    
4144
	return 0;
4145
}
4146

    
4147
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4148

    
4149
	$hostname = "";
4150
	if ($wancfg['dhcphostname'] != '') {
4151
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4152
	}
4153

    
4154
	/* DHCP Protocol Timings */
4155
	$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");
4156
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4157
		$pt_variable = "{$Protocol_Timing}";
4158
		${$pt_variable} = "";
4159
		if ($wancfg[$Protocol_Timing] != "") {
4160
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4161
		}
4162
	}
4163

    
4164
	$send_options = "";
4165
	if ($wancfg['adv_dhcp_send_options'] != '') {
4166
		$options = explode(',', $wancfg['adv_dhcp_send_options']);
4167
		foreach ($options as $option) {
4168
			$send_options .= "\tsend " . trim($option) . ";\n";
4169
		}
4170
	}
4171

    
4172
	$request_options = "";
4173
	if ($wancfg['adv_dhcp_request_options'] != '') {
4174
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4175
	}
4176

    
4177
	$required_options = "";
4178
	if ($wancfg['adv_dhcp_required_options'] != '') {
4179
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4180
	}
4181

    
4182
	$option_modifiers = "";
4183
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4184
		$modifiers = explode(',', $wancfg['adv_dhcp_option_modifiers']);
4185
		foreach ($modifiers as $modifier) {
4186
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4187
		}
4188
	}
4189

    
4190
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4191
	$dhclientconf .= "\n";
4192
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4193
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4194
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4195
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4196
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4197
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4198
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4199
	$dhclientconf .= "\n";
4200
	$dhclientconf .= "# DHCP Protocol Options\n";
4201
	$dhclientconf .= "{$hostname}";
4202
	$dhclientconf .= "{$send_options}";
4203
	$dhclientconf .= "{$request_options}";
4204
	$dhclientconf .= "{$required_options}";
4205
	$dhclientconf .= "{$option_modifiers}";
4206
	$dhclientconf .= "\n";
4207
	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4208
	$dhclientconf .= "}\n";
4209

    
4210
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4211

    
4212
	return $dhclientconf;
4213
}
4214

    
4215

    
4216
function DHCP_Config_File_Override($wancfg, $wanif) {
4217

    
4218
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4219

    
4220
	if ($dhclientconf === false) {
4221
		log_error("Error: cannot open {$wancfg['adv_dhcp_config_file_override_path']} in DHCP_Config_File_Override() for reading.\n");
4222
		return '';
4223
	} else {
4224
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4225
	}
4226
}
4227

    
4228

    
4229
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4230

    
4231
	/* Apply Interface Substitutions */
4232
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4233

    
4234
	/* Apply Hostname Substitutions */
4235
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4236

    
4237
	/* Arrays of MAC Address Types, Cases, Delimiters */
4238
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4239
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4240
	$various_mac_cases      = array("U", "L");
4241
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4242

    
4243
	/* Apply MAC Address Substitutions */
4244
	foreach ($various_mac_types as $various_mac_type) {
4245
		foreach ($various_mac_cases as $various_mac_case) {
4246
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4247

    
4248
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4249
				if ($res !== false) {
4250

    
4251
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4252
					if ("$various_mac_case" == "U") {
4253
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4254
					}
4255
					if ("$various_mac_case" == "L") {
4256
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4257
					}
4258

    
4259
					if ("$various_mac_type" == "mac_addr_hex") {
4260
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4261
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4262
						$dhcpclientconf_mac_hex = "";
4263
						$delimiter = "";
4264
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4265
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4266
							$delimiter = ":";
4267
						}
4268
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4269
					}
4270

    
4271
					/* MAC Address Delimiter Substitutions */
4272
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4273

    
4274
					/* Apply MAC Address Substitutions */
4275
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4276
				}
4277
			}
4278
		}
4279
	}
4280

    
4281
	return $dhclientconf;
4282
}
4283

    
4284
function interfaces_group_setup() {
4285
	global $config;
4286

    
4287
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4288
		return;
4289
	}
4290

    
4291
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4292
		interface_group_setup($groupar);
4293
	}
4294

    
4295
	return;
4296
}
4297

    
4298
function interface_group_setup(&$groupname /* The parameter is an array */) {
4299
	global $config;
4300

    
4301
	if (!is_array($groupname)) {
4302
		return;
4303
	}
4304
	$members = explode(" ", $groupname['members']);
4305
	foreach ($members as $ifs) {
4306
		$realif = get_real_interface($ifs);
4307
		if ($realif && does_interface_exist($realif)) {
4308
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4309
		}
4310
	}
4311

    
4312
	return;
4313
}
4314

    
4315
function is_interface_group($if) {
4316
	global $config;
4317

    
4318
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4319
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4320
			if ($groupentry['ifname'] === $if) {
4321
				return true;
4322
			}
4323
		}
4324
	}
4325

    
4326
	return false;
4327
}
4328

    
4329
function interface_group_add_member($interface, $groupname) {
4330
	$interface = get_real_interface($interface);
4331
	if (does_interface_exist($interface)) {
4332
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4333
	}
4334
}
4335

    
4336
/* COMPAT Function */
4337
function convert_friendly_interface_to_real_interface_name($interface) {
4338
	return get_real_interface($interface);
4339
}
4340

    
4341
/* COMPAT Function */
4342
function get_real_wan_interface($interface = "wan") {
4343
	return get_real_interface($interface);
4344
}
4345

    
4346
/* COMPAT Function */
4347
function get_current_wan_address($interface = "wan") {
4348
	return get_interface_ip($interface);
4349
}
4350

    
4351
/*
4352
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4353
 */
4354
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4355
	global $config;
4356

    
4357
	if (stripos($interface, "_vip")) {
4358
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
4359
			if ($vip['mode'] == "carp") {
4360
				if ($interface == "_vip{$vip['uniqid']}") {
4361
					return $vip['interface'];
4362
				}
4363
			}
4364
		}
4365
	}
4366

    
4367
	/* XXX: For speed reasons reference directly the interface array */
4368
	$ifdescrs = &$config['interfaces'];
4369
	//$ifdescrs = get_configured_interface_list(false, true);
4370

    
4371
	foreach ($ifdescrs as $if => $ifname) {
4372
		if ($if == $interface || $ifname['if'] == $interface) {
4373
			return $if;
4374
		}
4375

    
4376
		if (get_real_interface($if) == $interface) {
4377
			return $if;
4378
		}
4379

    
4380
		if ($checkparent == false) {
4381
			continue;
4382
		}
4383

    
4384
		$int = get_parent_interface($if, true);
4385
		if (is_array($int)) {
4386
			foreach ($int as $iface) {
4387
				if ($iface == $interface) {
4388
					return $if;
4389
				}
4390
			}
4391
		}
4392
	}
4393

    
4394
	if ($interface == "enc0") {
4395
		return 'IPsec';
4396
	}
4397
}
4398

    
4399
/* attempt to resolve interface to friendly descr */
4400
function convert_friendly_interface_to_friendly_descr($interface) {
4401
	global $config;
4402

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

    
4453
	return $ifdesc;
4454
}
4455

    
4456
function convert_real_interface_to_friendly_descr($interface) {
4457

    
4458
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4459

    
4460
	if (!empty($ifdesc)) {
4461
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4462
	}
4463

    
4464
	return $interface;
4465
}
4466

    
4467
/*
4468
 *  get_parent_interface($interface):
4469
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4470
 *				or virtual interface (i.e. vlan)
4471
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4472
 *			-- returns $interface passed in if $interface parent is not found
4473
 *			-- returns empty array if an invalid interface is passed
4474
 *	(Only handles ppps and vlans now.)
4475
 */
4476
function get_parent_interface($interface, $avoidrecurse = false) {
4477
	global $config;
4478

    
4479
	$parents = array();
4480
	//Check that we got a valid interface passed
4481
	$realif = get_real_interface($interface);
4482
	if ($realif == NULL) {
4483
		return $parents;
4484
	}
4485

    
4486
	// If we got a real interface, find it's friendly assigned name
4487
	if ($interface == $realif && $avoidrecurse == false) {
4488
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4489
	}
4490

    
4491
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4492
		$ifcfg = $config['interfaces'][$interface];
4493
		switch ($ifcfg['ipaddr']) {
4494
			case "ppp":
4495
			case "pppoe":
4496
			case "pptp":
4497
			case "l2tp":
4498
				if (empty($parents)) {
4499
					if (is_array($config['ppps']['ppp'])) {
4500
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4501
							if ($ifcfg['if'] == $ppp['if']) {
4502
								$ports = explode(',', $ppp['ports']);
4503
								foreach ($ports as $pid => $parent_if) {
4504
									$parents[$pid] = get_real_interface($parent_if);
4505
								}
4506
								break;
4507
							}
4508
						}
4509
					}
4510
				}
4511
				break;
4512
			case "dhcp":
4513
			case "static":
4514
			default:
4515
				// Handle _vlans
4516
				if (strpos($realif, '_vlan') !== FALSE) {
4517
					if (is_array($config['vlans']['vlan'])) {
4518
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4519
							if ($ifcfg['if'] == $vlan['vlanif']) {
4520
								$parents[0] = $vlan['if'];
4521
								break;
4522
							}
4523
						}
4524
					}
4525
				}
4526
				break;
4527
		}
4528
	}
4529

    
4530
	if (empty($parents)) {
4531
		$parents[0] = $realif;
4532
	}
4533

    
4534
	return $parents;
4535
}
4536

    
4537
function interface_is_wireless_clone($wlif) {
4538
	if (!stristr($wlif, "_wlan")) {
4539
		return false;
4540
	} else {
4541
		return true;
4542
	}
4543
}
4544

    
4545
function interface_get_wireless_base($wlif) {
4546
	if (!stristr($wlif, "_wlan")) {
4547
		return $wlif;
4548
	} else {
4549
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4550
	}
4551
}
4552

    
4553
function interface_get_wireless_clone($wlif) {
4554
	if (!stristr($wlif, "_wlan")) {
4555
		return $wlif . "_wlan0";
4556
	} else {
4557
		return $wlif;
4558
	}
4559
}
4560

    
4561
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4562
	global $config, $g;
4563

    
4564
	$wanif = NULL;
4565

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

    
4607
			if (empty($config['interfaces'][$interface])) {
4608
				break;
4609
			}
4610

    
4611
			$cfg = &$config['interfaces'][$interface];
4612

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

    
4669
	return $wanif;
4670
}
4671

    
4672
/* Guess the physical interface by providing a IP address */
4673
function guess_interface_from_ip($ipaddress) {
4674

    
4675
	$family = '';
4676
	if (is_ipaddrv4($ipaddress)) {
4677
		$family = 'inet';
4678
	}
4679
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4680
		$family = 'inet6';
4681
	}
4682

    
4683
	if (empty($family)) {
4684
		return false;
4685
	}
4686

    
4687
	/* create a route table we can search */
4688
	$output = '';
4689
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4690
	$output[0] = trim($output[0], " \n");
4691
	if (!empty($output[0])) {
4692
		return $output[0];
4693
	}
4694

    
4695
	return false;
4696
}
4697

    
4698
/*
4699
 * find_ip_interface($ip): return the interface where an ip is defined
4700
 *   (or if $bits is specified, where an IP within the subnet is defined)
4701
 */
4702
function find_ip_interface($ip, $bits = null) {
4703
	if (!is_ipaddr($ip)) {
4704
		return false;
4705
	}
4706

    
4707
	$isv6ip = is_ipaddrv6($ip);
4708

    
4709
	/* if list */
4710
	$ifdescrs = get_configured_interface_list();
4711

    
4712
	foreach ($ifdescrs as $ifdescr => $ifname) {
4713
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4714
		if (is_null($ifip)) {
4715
			continue;
4716
		}
4717
		if (is_null($bits)) {
4718
			if ($ip == $ifip) {
4719
				$int = get_real_interface($ifname);
4720
				return $int;
4721
			}
4722
		} else {
4723
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4724
				$int = get_real_interface($ifname);
4725
				return $int;
4726
			}
4727
		}
4728
	}
4729

    
4730
	return false;
4731
}
4732

    
4733
/*
4734
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4735
 *   (or if $bits is specified, where an IP within the subnet is found)
4736
 */
4737
function find_virtual_ip_alias($ip, $bits = null) {
4738
	global $config;
4739

    
4740
	if (!is_array($config['virtualip']['vip'])) {
4741
		return false;
4742
	}
4743
	if (!is_ipaddr($ip)) {
4744
		return false;
4745
	}
4746

    
4747
	$isv6ip = is_ipaddrv6($ip);
4748

    
4749
	foreach ($config['virtualip']['vip'] as $vip) {
4750
		if ($vip['mode'] === "ipalias") {
4751
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
4752
				continue;
4753
			}
4754
			if (is_null($bits)) {
4755
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4756
					return $vip;
4757
				}
4758
			} else {
4759
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
4760
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4761
					return $vip;
4762
				}
4763
			}
4764
		}
4765
	}
4766
	return false;
4767
}
4768

    
4769
/*
4770
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4771
 */
4772
function find_number_of_created_carp_interfaces() {
4773
	return `/sbin/ifconfig | /usr/bin/grep "carp:" | /usr/bin/wc -l`;
4774
}
4775

    
4776
/*
4777
 * find_carp_interface($ip): return the carp interface where an ip is defined
4778
 */
4779
function find_carp_interface($ip) {
4780
	global $config;
4781
	if (is_array($config['virtualip']['vip'])) {
4782
		foreach ($config['virtualip']['vip'] as $vip) {
4783
			if ($vip['mode'] == "carp") {
4784
				if (is_ipaddrv4($ip)) {
4785
					$carp_ip = get_interface_ip($vip['interface']);
4786
				}
4787
				if (is_ipaddrv6($ip)) {
4788
					$carp_ip = get_interface_ipv6($vip['interface']);
4789
				}
4790
				exec("/sbin/ifconfig", $output, $return);
4791
				foreach ($output as $line) {
4792
					$elements = preg_split("/[ ]+/i", $line);
4793
					if (strstr($elements[0], "vip")) {
4794
						$curif = str_replace(":", "", $elements[0]);
4795
					}
4796
					if (stristr($line, $ip)) {
4797
						$if = $curif;
4798
						continue;
4799
					}
4800
				}
4801

    
4802
				if ($if) {
4803
					return $if;
4804
				}
4805
			}
4806
		}
4807
	}
4808
}
4809

    
4810
function link_carp_interface_to_parent($interface) {
4811
	global $config;
4812

    
4813
	if (empty($interface)) {
4814
		return;
4815
	}
4816

    
4817
	$carp_ip = get_interface_ip($interface);
4818
	$carp_ipv6 = get_interface_ipv6($interface);
4819

    
4820
	if ((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6))) {
4821
		return;
4822
	}
4823

    
4824
	/* if list */
4825
	$ifdescrs = get_configured_interface_list();
4826
	foreach ($ifdescrs as $ifdescr => $ifname) {
4827
		/* check IPv4 */
4828
		if (is_ipaddrv4($carp_ip)) {
4829
			$interfaceip = get_interface_ip($ifname);
4830
			$subnet_bits = get_interface_subnet($ifname);
4831
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4832
			if (ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}")) {
4833
				return $ifname;
4834
			}
4835
		}
4836
		/* Check IPv6 */
4837
		if (is_ipaddrv6($carp_ipv6)) {
4838
			$interfaceipv6 = get_interface_ipv6($ifname);
4839
			$prefixlen = get_interface_subnetv6($ifname);
4840
			if (ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}")) {
4841
				return $ifname;
4842
			}
4843
		}
4844
	}
4845
	return "";
4846
}
4847

    
4848

    
4849
/****f* interfaces/link_ip_to_carp_interface
4850
 * NAME
4851
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4852
 * INPUTS
4853
 *   $ip
4854
 * RESULT
4855
 *   $carp_ints
4856
 ******/
4857
function link_ip_to_carp_interface($ip) {
4858
	global $config;
4859

    
4860
	if (!is_ipaddr($ip)) {
4861
		return;
4862
	}
4863

    
4864
	$carp_ints = "";
4865
	if (is_array($config['virtualip']['vip'])) {
4866
		$first = 0;
4867
		$carp_int = array();
4868
		foreach ($config['virtualip']['vip'] as $vip) {
4869
			if ($vip['mode'] == "carp") {
4870
				$carp_ip = $vip['subnet'];
4871
				$carp_sn = $vip['subnet_bits'];
4872
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4873
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4874
					$carp_int[] = get_real_interface($vip['interface']);
4875
				}
4876
			}
4877
		}
4878
		if (!empty($carp_int)) {
4879
			$carp_ints = implode(" ", array_unique($carp_int));
4880
		}
4881
	}
4882

    
4883
	return $carp_ints;
4884
}
4885

    
4886
function link_interface_to_track6($int, $action = "") {
4887
	global $config;
4888

    
4889
	if (empty($int)) {
4890
		return;
4891
	}
4892

    
4893
	if (is_array($config['interfaces'])) {
4894
		$list = array();
4895
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4896
			if (!isset($ifcfg['enable'])) {
4897
				continue;
4898
			}
4899
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4900
				if ($action == "update") {
4901
					interface_track6_configure($ifname, $ifcfg);
4902
				} else if ($action == "") {
4903
					$list[$ifname] = $ifcfg;
4904
				}
4905
			}
4906
		}
4907
		return $list;
4908
	}
4909
}
4910

    
4911
function interface_find_child_cfgmtu($realiface) {
4912
	global $config;
4913

    
4914
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
4915
	$vlans = link_interface_to_vlans($realiface);
4916
	$bridge = link_interface_to_bridge($realiface);
4917
	if (!empty($interface)) {
4918
		$gifs = link_interface_to_gif($interface);
4919
		$gres = link_interface_to_gre($interface);
4920
	} else {
4921
		$gifs = array();
4922
		$gres = array();
4923
	}
4924

    
4925
	$mtu = 0;
4926
	if (is_array($vlans)) {
4927
		foreach ($vlans as $vlan) {
4928
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4929
			if (empty($ifass)) {
4930
				continue;
4931
			}
4932
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4933
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4934
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4935
				}
4936
			}
4937
		}
4938
	}
4939
	if (is_array($gifs)) {
4940
		foreach ($gifs as $vlan) {
4941
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['gifif']);
4942
			if (empty($ifass)) {
4943
				continue;
4944
			}
4945
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4946
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4947
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4948
				}
4949
			}
4950
		}
4951
	}
4952
	if (is_array($gres)) {
4953
		foreach ($gres as $vlan) {
4954
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['greif']);
4955
			if (empty($ifass)) {
4956
				continue;
4957
			}
4958
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4959
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4960
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4961
				}
4962
			}
4963
		}
4964
	}
4965
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
4966
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
4967
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4968
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
4969
		}
4970
	}
4971
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
4972

    
4973
	return $mtu;
4974
}
4975

    
4976
function link_interface_to_vlans($int, $action = "") {
4977
	global $config;
4978

    
4979
	if (empty($int)) {
4980
		return;
4981
	}
4982

    
4983
	if (is_array($config['vlans']['vlan'])) {
4984
		$ifaces = array();
4985
		foreach ($config['vlans']['vlan'] as $vlan) {
4986
			if ($int == $vlan['if']) {
4987
				if ($action == "update") {
4988
					interfaces_bring_up($int);
4989
				} else {
4990
					$ifaces[$vlan['tag']] = $vlan;
4991
				}
4992
			}
4993
		}
4994
		if (!empty($ifaces)) {
4995
			return $ifaces;
4996
		}
4997
	}
4998
}
4999

    
5000
function link_interface_to_vips($int, $action = "", $vhid = '') {
5001
	global $config;
5002

    
5003
	if (is_array($config['virtualip']['vip'])) {
5004
		$result = array();
5005
		foreach ($config['virtualip']['vip'] as $vip) {
5006
			if ($int == $vip['interface']) {
5007
				if ($action == "update") {
5008
					interfaces_vips_configure($int);
5009
				} else {
5010
					if (empty($vhid) || ($vhid == $vip['vhid'])) {
5011
						$result[] = $vip;
5012
					}
5013
				}
5014
			}
5015
		}
5016
		return $result;
5017
	}
5018
}
5019

    
5020
/****f* interfaces/link_interface_to_bridge
5021
 * NAME
5022
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5023
 * INPUTS
5024
 *   $ip
5025
 * RESULT
5026
 *   bridge[0-99]
5027
 ******/
5028
function link_interface_to_bridge($int) {
5029
	global $config;
5030

    
5031
	if (is_array($config['bridges']['bridged'])) {
5032
		foreach ($config['bridges']['bridged'] as $bridge) {
5033
			if (in_array($int, explode(',', $bridge['members']))) {
5034
				return "{$bridge['bridgeif']}";
5035
			}
5036
		}
5037
	}
5038
}
5039

    
5040
function link_interface_to_group($int) {
5041
	global $config;
5042

    
5043
	$result = array();
5044

    
5045
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5046
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5047
			if (in_array($int, explode(" ", $group['members']))) {
5048
				$result[$group['ifname']] = $int;
5049
			}
5050
		}
5051
	}
5052

    
5053
	return $result;
5054
}
5055

    
5056
function link_interface_to_gre($interface) {
5057
	global $config;
5058

    
5059
	$result = array();
5060

    
5061
	if (is_array($config['gres']['gre'])) {
5062
		foreach ($config['gres']['gre'] as $gre) {
5063
			if ($gre['if'] == $interface) {
5064
				$result[] = $gre;
5065
			}
5066
		}
5067
	}
5068

    
5069
	return $result;
5070
}
5071

    
5072
function link_interface_to_gif($interface) {
5073
	global $config;
5074

    
5075
	$result = array();
5076

    
5077
	if (is_array($config['gifs']['gif'])) {
5078
		foreach ($config['gifs']['gif'] as $gif) {
5079
			if ($gif['if'] == $interface) {
5080
				$result[] = $gif;
5081
			}
5082
		}
5083
	}
5084

    
5085
	return $result;
5086
}
5087

    
5088
/*
5089
 * find_interface_ip($interface): return the interface ip (first found)
5090
 */
5091
function find_interface_ip($interface, $flush = false) {
5092
	global $interface_ip_arr_cache;
5093
	global $interface_sn_arr_cache;
5094

    
5095
	$interface = str_replace("\n", "", $interface);
5096

    
5097
	if (!does_interface_exist($interface)) {
5098
		return;
5099
	}
5100

    
5101
	/* Setup IP cache */
5102
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5103
		$ifinfo = pfSense_get_interface_addresses($interface);
5104
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5105
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5106
	}
5107

    
5108
	return $interface_ip_arr_cache[$interface];
5109
}
5110

    
5111
/*
5112
 * find_interface_ipv6($interface): return the interface ip (first found)
5113
 */
5114
function find_interface_ipv6($interface, $flush = false) {
5115
	global $interface_ipv6_arr_cache;
5116
	global $interface_snv6_arr_cache;
5117
	global $config;
5118

    
5119
	$interface = trim($interface);
5120
	$interface = get_real_interface($interface);
5121

    
5122
	if (!does_interface_exist($interface)) {
5123
		return;
5124
	}
5125

    
5126
	/* Setup IP cache */
5127
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5128
		$ifinfo = pfSense_get_interface_addresses($interface);
5129
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5130
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5131
	}
5132

    
5133
	return $interface_ipv6_arr_cache[$interface];
5134
}
5135

    
5136
/*
5137
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5138
 */
5139
function find_interface_ipv6_ll($interface, $flush = false) {
5140
	global $interface_llv6_arr_cache;
5141
	global $config;
5142

    
5143
	$interface = str_replace("\n", "", $interface);
5144

    
5145
	if (!does_interface_exist($interface)) {
5146
		return;
5147
	}
5148

    
5149
	/* Setup IP cache */
5150
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5151
		$ifinfo = pfSense_getall_interface_addresses($interface);
5152
		foreach ($ifinfo as $line) {
5153
			if (strstr($line, ":")) {
5154
				$parts = explode("/", $line);
5155
				if (is_linklocal($parts[0])) {
5156
					$ifinfo['linklocal'] = $parts[0];
5157
				}
5158
			}
5159
		}
5160
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5161
	}
5162
	return $interface_llv6_arr_cache[$interface];
5163
}
5164

    
5165
function find_interface_subnet($interface, $flush = false) {
5166
	global $interface_sn_arr_cache;
5167
	global $interface_ip_arr_cache;
5168

    
5169
	$interface = str_replace("\n", "", $interface);
5170
	if (does_interface_exist($interface) == false) {
5171
		return;
5172
	}
5173

    
5174
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5175
		$ifinfo = pfSense_get_interface_addresses($interface);
5176
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5177
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5178
	}
5179

    
5180
	return $interface_sn_arr_cache[$interface];
5181
}
5182

    
5183
function find_interface_subnetv6($interface, $flush = false) {
5184
	global $interface_snv6_arr_cache;
5185
	global $interface_ipv6_arr_cache;
5186

    
5187
	$interface = str_replace("\n", "", $interface);
5188
	if (does_interface_exist($interface) == false) {
5189
		return;
5190
	}
5191

    
5192
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5193
		$ifinfo = pfSense_get_interface_addresses($interface);
5194
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5195
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5196
	}
5197

    
5198
	return $interface_snv6_arr_cache[$interface];
5199
}
5200

    
5201
function ip_in_interface_alias_subnet($interface, $ipalias) {
5202
	global $config;
5203

    
5204
	if (empty($interface) || !is_ipaddr($ipalias)) {
5205
		return false;
5206
	}
5207
	if (is_array($config['virtualip']['vip'])) {
5208
		foreach ($config['virtualip']['vip'] as $vip) {
5209
			switch ($vip['mode']) {
5210
				case "ipalias":
5211
					if ($vip['interface'] <> $interface) {
5212
						break;
5213
					}
5214
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5215
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5216
						return true;
5217
					}
5218
					break;
5219
			}
5220
		}
5221
	}
5222

    
5223
	return false;
5224
}
5225

    
5226
function get_possible_listen_ips($include_ipv6_link_local=false) {
5227

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

    
5259
	$interfaces['lo0'] = 'Localhost';
5260

    
5261
	return $interfaces;
5262
}
5263

    
5264
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5265
	global $config;
5266

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

    
5281
function get_interface_ip($interface = "wan") {
5282

    
5283
	$realif = get_failover_interface($interface, 'inet');
5284
	if (!$realif) {
5285
		return null;
5286
	}
5287

    
5288
	if (substr($interface, 0, 4) == '_vip') {
5289
		return get_configured_carp_interface_list($interface, 'inet', 'ip');
5290
	} else if (substr($interface, 0, 5) == '_lloc') {
5291
		/* No link-local address for v4. */
5292
		return null;
5293
	}
5294

    
5295
	$curip = find_interface_ip($realif);
5296
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5297
		return $curip;
5298
	} else {
5299
		return null;
5300
	}
5301
}
5302

    
5303
function get_interface_ipv6($interface = "wan", $flush = false) {
5304
	global $config;
5305

    
5306
	$realif = get_failover_interface($interface, 'inet6');
5307
	if (!$realif) {
5308
		return null;
5309
	}
5310

    
5311
	if (substr($interface, 0, 4) == '_vip') {
5312
		return get_configured_carp_interface_list($interface, 'inet6', 'ip');
5313
	} else if (substr($interface, 0, 5) == '_lloc') {
5314
		return get_interface_linklocal($interface);
5315
	}
5316

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

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

    
5348
function get_interface_linklocal($interface = "wan") {
5349

    
5350
	$realif = get_failover_interface($interface, 'inet6');
5351
	if (!$realif) {
5352
		return null;
5353
	}
5354

    
5355
	if (substr($interface, 0, 4) == '_vip') {
5356
		$realif = get_real_interface($interface);
5357
	} else if (substr($interface, 0, 5) == '_lloc') {
5358
		$realif = get_real_interface(substr($interface, 5));
5359
	}
5360

    
5361
	$curip = find_interface_ipv6_ll($realif);
5362
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5363
		return $curip;
5364
	} else {
5365
		return null;
5366
	}
5367
}
5368

    
5369
function get_interface_subnet($interface = "wan") {
5370

    
5371
	if (substr($interface, 0, 4) == '_vip') {
5372
		return get_configured_carp_interface_list($interface, 'inet', 'subnet');
5373
	}
5374

    
5375
	$realif = get_real_interface($interface);
5376
	if (!$realif) {
5377
		return null;
5378
	}
5379

    
5380
	$cursn = find_interface_subnet($realif);
5381
	if (!empty($cursn)) {
5382
		return $cursn;
5383
	}
5384

    
5385
	return null;
5386
}
5387

    
5388
function get_interface_subnetv6($interface = "wan") {
5389

    
5390
	if (substr($interface, 0, 4) == '_vip') {
5391
		return get_configured_carp_interface_list($interface, 'inet6', 'subnet');
5392
	} else if (substr($interface, 0, 5) == '_lloc') {
5393
		$interface = substr($interface, 5);
5394
	}
5395

    
5396
	$realif = get_real_interface($interface, 'inet6');
5397
	if (!$realif) {
5398
		return null;
5399
	}
5400

    
5401
	$cursn = find_interface_subnetv6($realif);
5402
	if (!empty($cursn)) {
5403
		return $cursn;
5404
	}
5405

    
5406
	return null;
5407
}
5408

    
5409
/* return outside interfaces with a gateway */
5410
function get_interfaces_with_gateway() {
5411
	global $config;
5412

    
5413
	$ints = array();
5414

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

    
5436
/* return true if interface has a gateway */
5437
function interface_has_gateway($friendly) {
5438
	global $config;
5439

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

    
5465
	return false;
5466
}
5467

    
5468
/* return true if interface has a gateway */
5469
function interface_has_gatewayv6($friendly) {
5470
	global $config;
5471

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

    
5496
	return false;
5497
}
5498

    
5499
/****f* interfaces/is_altq_capable
5500
 * NAME
5501
 *   is_altq_capable - Test if interface is capable of using ALTQ
5502
 * INPUTS
5503
 *   $int            - string containing interface name
5504
 * RESULT
5505
 *   boolean         - true or false
5506
 ******/
5507

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

    
5522
	$int_family = remove_ifindex($int);
5523

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

    
5537
/****f* interfaces/is_interface_wireless
5538
 * NAME
5539
 *   is_interface_wireless - Returns if an interface is wireless
5540
 * RESULT
5541
 *   $tmp       - Returns if an interface is wireless
5542
 ******/
5543
function is_interface_wireless($interface) {
5544
	global $config, $g;
5545

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

    
5560
function get_wireless_modes($interface) {
5561
	/* return wireless modes and channels */
5562
	$wireless_modes = array();
5563

    
5564
	$cloned_interface = get_real_interface($interface);
5565

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

    
5571
		$interface_channels = "";
5572
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5573
		$interface_channel_count = count($interface_channels);
5574

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

    
5608
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5609
function get_wireless_channel_info($interface) {
5610
	$wireless_channels = array();
5611

    
5612
	$cloned_interface = get_real_interface($interface);
5613

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

    
5619
		$interface_channels = "";
5620
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5621

    
5622
		foreach ($interface_channels as $channel_line) {
5623
			$channel_line = explode(",", $channel_line);
5624
			if (!isset($wireless_channels[$channel_line[0]])) {
5625
				$wireless_channels[$channel_line[0]] = $channel_line;
5626
			}
5627
		}
5628
	}
5629
	return($wireless_channels);
5630
}
5631

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

    
5643
function get_interface_mac($interface) {
5644

    
5645
	$macinfo = pfSense_get_interface_addresses($interface);
5646
	return $macinfo["macaddr"];
5647
}
5648

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

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

    
5677
	if (isset($capable['caps']['vlanmtu'])) {
5678
		return true;
5679
	}
5680

    
5681
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5682
	if (substr($iface, 0, 4) == "lagg") {
5683
		return true;
5684
	}
5685

    
5686
	return false;
5687
}
5688

    
5689
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5690
	global $g;
5691

    
5692
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5693

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

    
5700
EOD;
5701

    
5702
		@file_put_contents($cron_file, $cron_cmd);
5703
		chmod($cron_file, 0755);
5704
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5705
	} else {
5706
		unlink_if_exists($cron_file);
5707
	}
5708
}
5709

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

    
5727
	/* Never reached */
5728
	return 1500;
5729
}
5730

    
5731
function get_vip_descr($ipaddress) {
5732
	global $config;
5733

    
5734
	foreach ($config['virtualip']['vip'] as $vip) {
5735
		if ($vip['subnet'] == $ipaddress) {
5736
			return ($vip['descr']);
5737
		}
5738
	}
5739
	return "";
5740
}
5741

    
5742
function interfaces_staticarp_configure($if) {
5743
	global $config, $g;
5744
	if (isset($config['system']['developerspew'])) {
5745
		$mt = microtime();
5746
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5747
	}
5748

    
5749
	$ifcfg = $config['interfaces'][$if];
5750

    
5751
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5752
		return 0;
5753
	}
5754

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

    
5776
	return 0;
5777
}
5778

    
5779
function get_failover_interface($interface, $family = "all") {
5780
	global $config;
5781

    
5782
	/* shortcut to get_real_interface if we find it in the config */
5783
	if (is_array($config['interfaces'][$interface])) {
5784
		return get_real_interface($interface, $family);
5785
	}
5786

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

    
5802
function remove_ifindex($ifname) {
5803
	return preg_replace("/[0-9]+$/", "", $ifname);
5804
}
5805

    
5806
?>
(25-25/65)