Project

General

Profile

Download (160 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
	return $interface_arr_cache;
69
}
70

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

    
78
	if(!$interface)
79
		return false;
80

    
81
	$ints = get_interface_arr($flush);
82
	if (in_array($interface, $ints))
83
		return true;
84
	else
85
		return false;
86
}
87

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

    
95
	if(!$vip)
96
		return false;
97

    
98

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

    
114
	$ifacedata = pfSense_getall_interface_addresses($realif);
115
	foreach ($ifacedata as $vipips) {
116
		if ($vipips == "{$vip['subnet']}/{$vip['subnet_bits']}")
117
			return true;
118
	}
119

    
120
	return false;
121
}
122

    
123
function interface_netgraph_needed($interface = "wan") {
124
	global $config;
125

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

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

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

    
181
function interfaces_loopback_configure() {
182
	global $g;
183

    
184
	if ($g['platform'] == 'jail')
185
		return;
186
	if (platform_booting())
187
		echo gettext("Configuring loopback interface...");
188
	pfSense_interface_setaddress("lo0", "127.0.0.1");
189
	interfaces_bring_up("lo0");
190
	if (platform_booting())
191
		echo gettext("done.") . "\n";
192
	return 0;
193
}
194

    
195
function interfaces_vlan_configure($realif = "") {
196
	global $config, $g;
197
	if (platform_booting())
198
		echo gettext("Configuring VLAN interfaces...");
199
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
200
		foreach ($config['vlans']['vlan'] as $vlan) {
201
			if (empty($vlan['vlanif']))
202
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
203
			if (!empty($realif) && $realif != $vlan['vlanif'])
204
				continue;
205

    
206
			/* XXX: Maybe we should report any errors?! */
207
			interface_vlan_configure($vlan);
208
		}
209
	}
210
	if (platform_booting())
211
		echo gettext("done.") . "\n";
212
}
213

    
214
function interface_vlan_configure(&$vlan) {
215
	global $config, $g;
216

    
217
	if (!is_array($vlan)) {
218
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
219
		return;
220
	}
221
	$if = $vlan['if'];
222
	$vlanif  = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
223
	$tag = $vlan['tag'];
224

    
225
	if (empty($if)) {
226
		log_error(gettext("interface_vlan_configure called with if undefined."));
227
		return;
228
	}
229

    
230
	/* make sure the parent interface is up */
231
	interfaces_bring_up($if);
232
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
233
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
234

    
235
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
236
		interface_bring_down($vlanif, true);
237
	} else {
238
		$tmpvlanif = pfSense_interface_create("vlan");
239
		pfSense_interface_rename($tmpvlanif, $vlanif);
240
		pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
241
	}
242

    
243
	pfSense_vlan_create($vlanif, $if, $tag);
244

    
245
	interfaces_bring_up($vlanif);
246

    
247
	/* invalidate interface cache */
248
	get_interface_arr(true);
249

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

    
253
	return $vlanif;
254
}
255

    
256
function interface_qinq_configure(&$vlan, $fd = NULL) {
257
	global $config, $g;
258

    
259
	if (!is_array($vlan)) {
260
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
261
		return;
262
	}
263

    
264
	$qinqif = $vlan['if'];
265
	$tag = $vlan['tag'];
266
	if(empty($qinqif)) {
267
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
268
		return;
269
	}
270

    
271
	if(!does_interface_exist($qinqif)) {
272
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
273
		return;
274
	}
275

    
276
	$vlanif = interface_vlan_configure($vlan);
277

    
278
	if ($fd == NULL) {
279
		$exec = true;
280
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
281
	} else
282
		$exec = false;
283
	/* make sure the parent is converted to ng_vlan(4) and is up */
284
	interfaces_bring_up($qinqif);
285

    
286
	pfSense_ngctl_attach(".", $qinqif);
287
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
288
		fwrite($fd, "shutdown {$qinqif}qinq:\n");
289
		exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
290
		if (empty($result)) {
291
			fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
292
			fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
293
			fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
294
		}
295
	} else {
296
		fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
297
		fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
298
		fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
299
	}
300

    
301
	/* invalidate interface cache */
302
	get_interface_arr(true);
303

    
304
	if (!stristr($qinqif, "_vlan"))
305
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
306

    
307
	$macaddr = get_interface_mac($qinqif);
308
	if (!empty($vlan['members'])) {
309
		$members = explode(" ", $vlan['members']);
310
		foreach ($members as $qtag) {
311
			$qinq = array();
312
			$qinq['tag'] = $qtag;
313
			$qinq['if'] = $vlanif;
314
			interface_qinq2_configure($qinq, $fd, $macaddr);
315
		}
316
	}
317
	if ($exec == true) {
318
		fclose($fd);
319
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
320
	}
321

    
322
	interfaces_bring_up($qinqif);
323
	if (!empty($vlan['members'])) {
324
		$members = explode(" ", $vlan['members']);
325
		foreach ($members as $qif)
326
			interfaces_bring_up("{$vlanif}_{$qif}");
327
	}
328

    
329
	return $vlanif;
330
}
331

    
332
function interfaces_qinq_configure() {
333
	global $config, $g;
334
	if (platform_booting())
335
		echo gettext("Configuring QinQ interfaces...");
336
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
337
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
338
			/* XXX: Maybe we should report any errors?! */
339
			interface_qinq_configure($qinq);
340
		}
341
	}
342
	if (platform_booting())
343
		echo gettext( "done.") . "\n";
344
}
345

    
346
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
347
	global $config, $g;
348

    
349
	if (!is_array($qinq)) {
350
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
351
		return;
352
	}
353

    
354
	$if = $qinq['if'];
355
	$tag = $qinq['tag'];
356
	$vlanif = "{$if}_{$tag}";
357
	if(empty($if)) {
358
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
359
		return;
360
	}
361

    
362
	fwrite($fd, "shutdown {$if}h{$tag}:\n");
363
	fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
364
	fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
365
	fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
366
	fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
367
	fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
368

    
369
	/* invalidate interface cache */
370
	get_interface_arr(true);
371

    
372
	return $vlanif;
373
}
374

    
375
function interfaces_create_wireless_clones() {
376
	global $config, $g;
377

    
378
	if (platform_booting())
379
		echo gettext("Creating wireless clone interfaces...");
380

    
381
	$iflist = get_configured_interface_list();
382

    
383
	foreach ($iflist as $if) {
384
		$realif = $config['interfaces'][$if]['if'];
385
		if (is_interface_wireless($realif))
386
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
387
	}
388

    
389
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
390
		foreach ($config['wireless']['clone'] as $clone) {
391
			if(empty($clone['cloneif']))
392
				continue;
393
			if(does_interface_exist($clone['cloneif']))
394
				continue;
395
			/* XXX: Maybe we should report any errors?! */
396
			interface_wireless_clone($clone['cloneif'], $clone);
397
		}
398
	}
399
	if (platform_booting())
400
		echo gettext("done.") . "\n";
401

    
402
}
403

    
404
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
405
	global $config;
406

    
407
	$i = 0;
408
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
409
		foreach ($config['bridges']['bridged'] as $bridge) {
410
			if (empty($bridge['bridgeif']))
411
				$bridge['bridgeif'] = "bridge{$i}";
412
			if (!empty($realif) && $realif != $bridge['bridgeif'])
413
				continue;
414

    
415
			if ($checkmember == 1) {
416
				if (strstr($bridge['if'], "_vip"))
417
					continue;
418
				$members = explode(',', $bridge['members']);
419
				foreach ($members as $member) {
420
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6")
421
						continue 2;
422
				}
423
			}
424
			else if ($checkmember == 2) {
425
				$members = explode(',', $bridge['members']);
426
				foreach ($members as $member) {
427
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6")
428
						continue 2;
429
				}
430
			}
431
			/* XXX: Maybe we should report any errors?! */
432
			interface_bridge_configure($bridge, $checkmember);
433
			$i++;
434
		}
435
	}
436
}
437

    
438
function interface_bridge_configure(&$bridge, $checkmember = 0) {
439
	global $config, $g;
440

    
441
	if (!is_array($bridge))
442
		return;
443

    
444
	if (empty($bridge['members'])) {
445
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
446
		return;
447
	}
448

    
449
	$members = explode(',', $bridge['members']);
450
	if (!count($members))
451
		return;
452

    
453
	/* Calculate smaller mtu and enforce it */
454
	$smallermtu = 0;
455
	$commonrx = true;
456
	$commontx = true;
457
	$foundgif = false;
458
	foreach ($members as $member) {
459
		$realif = get_real_interface($member);
460
		$mtu = get_interface_mtu($realif);
461
		if (substr($realif, 0, 3) == "gif") {
462
			$foundgif = true;
463
			if ($checkmember == 1)
464
				return;
465
			if ($mtu <= 1500)
466
				continue;
467
		}
468
		if ($smallermtu == 0 && !empty($mtu))
469
			$smallermtu = $mtu;
470
		else if (!empty($mtu) && $mtu < $smallermtu)
471
			$smallermtu = $mtu;
472
	}
473
	if ($foundgif == false && $checkmember == 2)
474
		return;
475

    
476
	/* Just in case anything is not working well */
477
	if ($smallermtu == 0)
478
		$smallermtu = 1500;
479

    
480
	if (platform_booting() || !empty($bridge['bridgeif'])) {
481
		pfSense_interface_destroy($bridge['bridgeif']);
482
		pfSense_interface_create($bridge['bridgeif']);
483
		$bridgeif = escapeshellarg($bridge['bridgeif']);
484
	} else {
485
		$bridgeif = pfSense_interface_create("bridge");
486
		$bridge['bridgeif'] = $bridgeif;
487
	}
488

    
489
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
490
	if ($bridgemtu > $smallermtu)
491
		$smallermtu = $bridgemtu;
492

    
493
	$checklist = get_configured_interface_list();
494

    
495
	/* Add interfaces to bridge */
496
	foreach ($members as $member) {
497
		if (empty($checklist[$member]))
498
			continue;
499
		$realif = get_real_interface($member);
500
		if (!$realif) {
501
			log_error(gettext("realif not defined in interfaces bridge - up"));
502
			continue;
503
		}
504
		/* make sure the parent interface is up */
505
		pfSense_interface_mtu($realif, $smallermtu);
506
		interfaces_bring_up($realif);
507
		enable_hardware_offloading($member);
508
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
509
	}
510

    
511
	if (isset($bridge['enablestp'])) {
512
		/* Choose spanning tree proto */
513
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
514

    
515
		if (!empty($bridge['stp'])) {
516
			$stpifs = explode(',', $bridge['stp']);
517
			foreach ($stpifs as $stpif) {
518
				$realif = get_real_interface($stpif);
519
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
520
			}
521
		}
522
		if (!empty($bridge['maxage']))
523
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
524
		if (!empty($bridge['fwdelay']))
525
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
526
		if (!empty($bridge['hellotime']))
527
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
528
		if (!empty($bridge['priority']))
529
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
530
		if (!empty($bridge['holdcnt']))
531
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
532
		if (!empty($bridge['ifpriority'])) {
533
			$pconfig = explode(",", $bridge['ifpriority']);
534
			$ifpriority = array();
535
			foreach ($pconfig as $cfg) {
536
				$embcfg = explode_assoc(":", $cfg);
537
				foreach ($embcfg as $key => $value)
538
					$ifpriority[$key] = $value;
539
			}
540
			foreach ($ifpriority as $key => $value) {
541
				$realif = get_real_interface($key);
542
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
543
			}
544
		}
545
		if (!empty($bridge['ifpathcost'])) {
546
			$pconfig = explode(",", $bridge['ifpathcost']);
547
			$ifpathcost = array();
548
			foreach ($pconfig as $cfg) {
549
				$embcfg = explode_assoc(":", $cfg);
550
				foreach ($embcfg as $key => $value)
551
					$ifpathcost[$key] = $value;
552
			}
553
			foreach ($ifpathcost as $key => $value) {
554
				$realif = get_real_interface($key);
555
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
556
			}
557
		}
558
	}
559

    
560
	if ($bridge['maxaddr'] <> "")
561
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
562
	if ($bridge['timeout'] <> "")
563
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
564
	if ($bridge['span'] <> "") {
565
		$realif = get_real_interface($bridge['span']);
566
		mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
567
	}
568
	if (!empty($bridge['edge'])) {
569
		$edgeifs = explode(',', $bridge['edge']);
570
		foreach ($edgeifs as $edgeif) {
571
			$realif = get_real_interface($edgeif);
572
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
573
		}
574
	}
575
	if (!empty($bridge['autoedge'])) {
576
		$edgeifs = explode(',', $bridge['autoedge']);
577
		foreach ($edgeifs as $edgeif) {
578
			$realif = get_real_interface($edgeif);
579
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
580
		}
581
	}
582
	if (!empty($bridge['ptp'])) {
583
		$ptpifs = explode(',', $bridge['ptp']);
584
		foreach ($ptpifs as $ptpif) {
585
			$realif = get_real_interface($ptpif);
586
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
587
		}
588
	}
589
	if (!empty($bridge['autoptp'])) {
590
		$ptpifs = explode(',', $bridge['autoptp']);
591
		foreach ($ptpifs as $ptpif) {
592
			$realif = get_real_interface($ptpif);
593
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
594
		}
595
	}
596
	if (!empty($bridge['static'])) {
597
		$stickyifs = explode(',', $bridge['static']);
598
		foreach ($stickyifs as $stickyif) {
599
			$realif = get_real_interface($stickyif);
600
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
601
		}
602
	}
603
	if (!empty($bridge['private'])) {
604
		$privateifs = explode(',', $bridge['private']);
605
		foreach ($privateifs as $privateif) {
606
			$realif = get_real_interface($privateif);
607
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
608
		}
609
	}
610

    
611
	if ($bridge['bridgeif'])
612
		interfaces_bring_up($bridge['bridgeif']);
613
	else
614
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
615
}
616

    
617
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
618

    
619
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface))
620
		return;
621

    
622
	if ($flagsapplied == false) {
623
		$mtu = get_interface_mtu($bridgeif);
624
		$mtum = get_interface_mtu($interface);
625
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500))
626
			pfSense_interface_mtu($interface, $mtu);
627

    
628
		hardware_offloading_applyflags($interface);
629
		interfaces_bring_up($interface);
630
	}
631

    
632
	pfSense_bridge_add_member($bridgeif, $interface);
633
}
634

    
635
function interfaces_lagg_configure($realif = "") {
636
	global $config, $g;
637
	if (platform_booting())
638
		echo gettext("Configuring LAGG interfaces...");
639
	$i = 0;
640
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
641
		foreach ($config['laggs']['lagg'] as $lagg) {
642
			if(empty($lagg['laggif']))
643
				$lagg['laggif'] = "lagg{$i}";
644
			if (!empty($realif) && $realif != $lagg['laggif'])
645
				continue;
646
			/* XXX: Maybe we should report any errors?! */
647
			interface_lagg_configure($lagg);
648
			$i++;
649
		}
650
	}
651
	if (platform_booting())
652
		echo gettext("done.") . "\n";
653
}
654

    
655
function interface_lagg_configure($lagg) {
656
	global $config, $g;
657

    
658
	if (!is_array($lagg))
659
		return -1;
660

    
661
	$members = explode(',', $lagg['members']);
662
	if (!count($members))
663
		return -1;
664

    
665
	if (platform_booting() || !(empty($lagg['laggif']))) {
666
		pfSense_interface_destroy($lagg['laggif']);
667
		pfSense_interface_create($lagg['laggif']);
668
		$laggif = $lagg['laggif'];
669
	} else
670
		$laggif = pfSense_interface_create("lagg");
671

    
672
	/* Check if MTU was defined for this lagg interface */
673
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
674
	if ($lagg_mtu == 0) {
675
		/* Calculate smaller mtu and enforce it */
676
		$smallermtu = 0;
677
		foreach ($members as $member) {
678
			$mtu = get_interface_mtu($member);
679
			if ($smallermtu == 0 && !empty($mtu))
680
				$smallermtu = $mtu;
681
			else if (!empty($mtu) && $mtu < $smallermtu)
682
				$smallermtu = $mtu;
683
		}
684
		$lagg_mtu = $smallermtu;
685
	}
686

    
687
	/* Just in case anything is not working well */
688
	if ($lagg_mtu == 0)
689
		$lagg_mtu = 1500;
690

    
691
	foreach ($members as $member) {
692
		if (!does_interface_exist($member))
693
			continue;
694
		/* make sure the parent interface is up */
695
		pfSense_interface_mtu($member, $lagg_mtu);
696
		interfaces_bring_up($member);
697
		hardware_offloading_applyflags($member);
698
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
699
	}
700
	pfSense_interface_capabilities($laggif, -$flags_off);
701
	pfSense_interface_capabilities($laggif, $flags_on);
702

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

    
705
	interfaces_bring_up($laggif);
706

    
707
	return $laggif;
708
}
709

    
710
function interfaces_gre_configure($checkparent = 0, $realif = "") {
711
	global $config;
712

    
713
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
714
		foreach ($config['gres']['gre'] as $i => $gre) {
715
			if (empty($gre['greif']))
716
				$gre['greif'] = "gre{$i}";
717
			if (!empty($realif) && $realif != $gre['greif'])
718
				continue;
719

    
720
			if ($checkparent == 1) {
721
				if (strstr($gre['if'], "_vip"))
722
					continue;
723
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6")
724
					continue;
725
			}
726
			else if ($checkparent == 2) {
727
				if (!strstr($gre['if'], "_vip") && (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6"))
728
					continue;
729
			}
730
			/* XXX: Maybe we should report any errors?! */
731
			interface_gre_configure($gre);
732
		}
733
	}
734
}
735

    
736
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
737
function interface_gre_configure(&$gre, $grekey = "") {
738
	global $config, $g;
739

    
740
	if (!is_array($gre))
741
		return -1;
742

    
743
	$realif = get_real_interface($gre['if']);
744
	$realifip = get_interface_ip($gre['if']);
745

    
746
	/* make sure the parent interface is up */
747
	interfaces_bring_up($realif);
748

    
749
	if (platform_booting() || !(empty($gre['greif']))) {
750
		pfSense_interface_destroy($gre['greif']);
751
		pfSense_interface_create($gre['greif']);
752
		$greif = $gre['greif'];
753
	} else
754
		$greif = pfSense_interface_create("gre");
755

    
756
	/* Do not change the order here for more see gre(4) NOTES section. */
757
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
758
	if((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
759
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
760
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
761
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
762
	} else {
763
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
764
	}
765
	if (isset($gre['link0']))
766
		pfSense_interface_flags($greif, IFF_LINK0);
767
	if (isset($gre['link1']))
768
		pfSense_interface_flags($greif, IFF_LINK1);
769
	if (isset($gre['link2']))
770
		pfSense_interface_flags($greif, IFF_LINK2);
771

    
772
	if($greif)
773
		interfaces_bring_up($greif);
774
	else
775
		log_error(gettext("Could not bring greif up -- variable not defined."));
776

    
777
	if (isset($gre['link1']) && $gre['link1'])
778
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
779
	if(is_ipaddrv4($gre['tunnel-remote-addr']))
780
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
781
	if(is_ipaddrv6($gre['tunnel-remote-addr']))
782
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
783

    
784
	interfaces_bring_up($greif);
785

    
786
	return $greif;
787
}
788

    
789
function interfaces_gif_configure($checkparent = 0, $realif = "") {
790
	global $config;
791

    
792
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
793
		foreach ($config['gifs']['gif'] as $i => $gif) {
794
			if (empty($gif['gifif']))
795
				$gre['gifif'] = "gif{$i}";
796
			if (!empty($realif) && $realif != $gif['gifif'])
797
				continue;
798

    
799
			if ($checkparent == 1) {
800
				if (strstr($gif['if'], "_vip"))
801
					continue;
802
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6")
803
					continue;
804
			}
805
			else if ($checkparent == 2) {
806
				if (!strstr($gif['if'], "_vip") && (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6"))
807
					continue;
808
			}
809
			/* XXX: Maybe we should report any errors?! */
810
			interface_gif_configure($gif);
811
		}
812
	}
813
}
814

    
815
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
816
function interface_gif_configure(&$gif, $gifkey = "") {
817
	global $config, $g;
818

    
819
	if (!is_array($gif))
820
		return -1;
821

    
822
	$realif = get_real_interface($gif['if']);
823
	$ipaddr = $gif['ipaddr'];
824

    
825
	if (is_ipaddrv4($gif['remote-addr'])) {
826
		if (is_ipaddrv4($ipaddr))
827
			$realifip = $ipaddr;
828
		else
829
			$realifip = get_interface_ip($gif['if']);
830
		$realifgw = get_interface_gateway($gif['if']);
831
	} else if (is_ipaddrv6($gif['remote-addr'])) {
832
		if (is_ipaddrv6($ipaddr))
833
			$realifip = $ipaddr;
834
		else
835
			$realifip = get_interface_ipv6($gif['if']);
836
		$realifgw = get_interface_gateway_v6($gif['if']);
837
	}
838
	/* make sure the parent interface is up */
839
	if($realif)
840
		interfaces_bring_up($realif);
841
	else
842
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
843

    
844
	if (platform_booting() || !(empty($gif['gifif']))) {
845
		pfSense_interface_destroy($gif['gifif']);
846
		pfSense_interface_create($gif['gifif']);
847
		$gifif = $gif['gifif'];
848
	} else
849
		$gifif = pfSense_interface_create("gif");
850

    
851
	/* Do not change the order here for more see gif(4) NOTES section. */
852
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
853
	if((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
854
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
855
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
856
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
857
	} else {
858
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
859
	}
860
	if (isset($gif['link0']))
861
		pfSense_interface_flags($gifif, IFF_LINK0);
862
	if (isset($gif['link1']))
863
		pfSense_interface_flags($gifif, IFF_LINK1);
864
	if($gifif)
865
		interfaces_bring_up($gifif);
866
	else
867
		log_error(gettext("could not bring gifif up -- variable not defined"));
868

    
869
	if (!platform_booting()) {
870
		$iflist = get_configured_interface_list();
871
		foreach($iflist as $ifname) {
872
			if($config['interfaces'][$ifname]['if'] == $gifif) {
873
				if(get_interface_gateway($ifname)) {
874
					system_routing_configure($ifname);
875
					break;
876
				}
877
				if(get_interface_gateway_v6($ifname)) {
878
					system_routing_configure($ifname);
879
					break;
880
				}
881
			}
882
		}
883
	}
884

    
885

    
886
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
887
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
888
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
889
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
890

    
891
	if (is_ipaddrv4($realifgw)) {
892
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
893
	}
894
	if (is_ipaddrv6($realifgw)) {
895
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
896
	}
897

    
898
	interfaces_bring_up($gifif);
899

    
900
	return $gifif;
901
}
902

    
903
function interfaces_configure() {
904
	global $config, $g;
905

    
906
	if ($g['platform'] == 'jail')
907
		return;
908

    
909
	/* Set up our loopback interface */
910
	interfaces_loopback_configure();
911

    
912
	/* create the unconfigured wireless clones */
913
	interfaces_create_wireless_clones();
914

    
915
	/* set up LAGG virtual interfaces */
916
	interfaces_lagg_configure();
917

    
918
	/* set up VLAN virtual interfaces */
919
	interfaces_vlan_configure();
920

    
921
	interfaces_qinq_configure();
922

    
923
	$iflist = get_configured_interface_with_descr();
924
	$delayed_list = array();
925
	$bridge_list = array();
926
	$track6_list = array();
927

    
928
	/* This is needed to speedup interfaces on bootup. */
929
	$reload = false;
930
	if (!platform_booting())
931
		$reload = true;
932

    
933
	foreach($iflist as $if => $ifname) {
934
		$realif = $config['interfaces'][$if]['if'];
935
		if (strstr($realif, "bridge"))
936
			$bridge_list[$if] = $ifname;
937
		else if (strstr($realif, "gre"))
938
			$delayed_list[$if] = $ifname;
939
		else if (strstr($realif, "gif"))
940
			$delayed_list[$if] = $ifname;
941
		else if (strstr($realif, "ovpn")) {
942
			//echo "Delaying OpenVPN interface configuration...done.\n";
943
			continue;
944
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
945
			$track6_list[$if] = $ifname;
946
		} else {
947
			if (platform_booting())
948
				printf(gettext("Configuring %s interface..."), $ifname);
949

    
950
			if($g['debug'])
951
				log_error(sprintf(gettext("Configuring %s"), $ifname));
952
			interface_configure($if, $reload);
953
			if (platform_booting())
954
				echo gettext( "done.") . "\n";
955
		}
956
	}
957

    
958
	/*
959
	 * NOTE: The following function parameter consists of
960
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
961
	 *	2 - Do load gre/gif/bridge with parent/member as vip
962
	 */
963

    
964
	/* set up GRE virtual interfaces */
965
	interfaces_gre_configure(1);
966

    
967
	/* set up GIF virtual interfaces */
968
	interfaces_gif_configure(1);
969

    
970
	/* set up BRIDGe virtual interfaces */
971
	interfaces_bridge_configure(1);
972

    
973
	foreach ($track6_list as $if => $ifname) {
974
		if (platform_booting())
975
			printf(gettext("Configuring %s interface..."), $ifname);
976
		if ($g['debug'])
977
			log_error(sprintf(gettext("Configuring %s"), $ifname));
978

    
979
		interface_configure($if, $reload);
980

    
981
		if (platform_booting())
982
			echo gettext("done.") . "\n";
983
	}
984

    
985
	/* bring up vip interfaces */
986
	interfaces_vips_configure();
987

    
988
	/* set up GRE virtual interfaces */
989
	interfaces_gre_configure(2);
990

    
991
	/* set up GIF virtual interfaces */
992
	interfaces_gif_configure(2);
993

    
994
	foreach ($delayed_list as $if => $ifname) {
995
		if (platform_booting())
996
			printf(gettext("Configuring %s interface..."), $ifname);
997
		if ($g['debug'])
998
			log_error(sprintf(gettext("Configuring %s"), $ifname));
999

    
1000
		interface_configure($if, $reload);
1001

    
1002
		if (platform_booting())
1003
			echo gettext("done.") . "\n";
1004
	}
1005

    
1006
	/* set up BRIDGe virtual interfaces */
1007
	interfaces_bridge_configure(2);
1008

    
1009
	foreach ($bridge_list as $if => $ifname) {
1010
		if (platform_booting())
1011
			printf(gettext("Configuring %s interface..."), $ifname);
1012
		if($g['debug'])
1013
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1014

    
1015
		interface_configure($if, $reload);
1016

    
1017
		if (platform_booting())
1018
			echo gettext("done.") . "\n";
1019
	}
1020

    
1021
	/* configure interface groups */
1022
	interfaces_group_setup();
1023

    
1024
	if (!platform_booting()) {
1025
		/* reconfigure static routes (kernel may have deleted them) */
1026
		system_routing_configure();
1027

    
1028
		/* reload IPsec tunnels */
1029
		vpn_ipsec_configure();
1030

    
1031
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1032
		services_dhcpd_configure();
1033

    
1034
		/* restart dnsmasq or unbound */
1035
		if (isset($config['dnsmasq']['enable']))
1036
			services_dnsmasq_configure();
1037
		elseif (isset($config['unbound']['enable']))
1038
			services_unbound_configure();
1039
	}
1040

    
1041
	return 0;
1042
}
1043

    
1044
function interface_reconfigure($interface = "wan", $reloadall = false) {
1045
	interface_bring_down($interface);
1046
	interface_configure($interface, $reloadall);
1047
}
1048

    
1049
function interface_vip_bring_down($vip) {
1050
	global $g;
1051

    
1052
	if (strpos($vip['interface'], '_vip')) {
1053
		if (is_ipaddrv6($vip['subnet']))
1054
			$family = 'inet6';
1055
		else
1056
			$family = 'inet';
1057

    
1058
		$carpvip = get_configured_carp_interface_list($vip['interface'], $family, 'vip');
1059
		$iface = $carpvip['interface'];
1060
	} else
1061
		$iface = $vip['interface'];
1062

    
1063
	$vipif = get_real_interface($iface);
1064
	switch ($vip['mode']) {
1065
	case "proxyarp":
1066
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1067
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1068
		break;
1069
	case "ipalias":
1070
		if (does_interface_exist($vipif)) {
1071
			if (is_ipaddrv6($vip['subnet']))
1072
				mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1073
			else
1074
				pfSense_interface_deladdress($vipif, $vip['subnet']);
1075
		}
1076
		break;
1077
	case "carp":
1078
		/* XXX: Is enough to delete ip address? */
1079
		if (does_interface_exist($vipif)) {
1080
			if (is_ipaddrv6($vip['subnet']))
1081
				mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1082
			else
1083
				pfSense_interface_deladdress($vipif, $vip['subnet']);
1084
		}
1085
		break;
1086
	}
1087
}
1088

    
1089
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1090
	global $config, $g;
1091

    
1092
	if (!isset($config['interfaces'][$interface]))
1093
		return;
1094

    
1095
	if ($g['debug'])
1096
		log_error("Calling interface down for interface {$interface}, destroy is " . (($destroy) ? 'true' : 'false'));
1097

    
1098
	/*
1099
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1100
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1101
	 * Keep this in mind while doing changes here!
1102
	 */
1103
	if ($ifacecfg === false) {
1104
		$ifcfg = $config['interfaces'][$interface];
1105
		$ppps = $config['ppps']['ppp'];
1106
		$realif = get_real_interface($interface);
1107
		$realifv6 = get_real_interface($interface, "inet6", true);
1108
	} elseif (!is_array($ifacecfg)) {
1109
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1110
		$ifcfg = $config['interfaces'][$interface];
1111
		$ppps = $config['ppps']['ppp'];
1112
		$realif = get_real_interface($interface);
1113
		$realifv6 = get_real_interface($interface, "inet6", true);
1114
	} else {
1115
		$ifcfg = $ifacecfg['ifcfg'];
1116
		$ppps = $ifacecfg['ppps'];
1117
		if (isset($ifacecfg['ifcfg']['realif'])) {
1118
			$realif = $ifacecfg['ifcfg']['realif'];
1119
			/* XXX: Any better way? */
1120
			$realifv6 = $realif;
1121
		} else {
1122
			$realif = get_real_interface($interface);
1123
			$realifv6 = get_real_interface($interface, "inet6", true);
1124
		}
1125
	}
1126

    
1127
	switch ($ifcfg['ipaddr']) {
1128
	case "ppp":
1129
	case "pppoe":
1130
	case "pptp":
1131
	case "l2tp":
1132
		if (is_array($ppps) && count($ppps)) {
1133
			foreach ($ppps as $pppid => $ppp) {
1134
				if ($realif == $ppp['if']) {
1135
					if (isset($ppp['ondemand']) && !$destroy){
1136
						send_event("interface reconfigure {$interface}");
1137
						break;
1138
					}
1139
					if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1140
						killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1141
						sleep(2);
1142
					}
1143
					unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1144
					break;
1145
				}
1146
			}
1147
		}
1148
		break;
1149
	case "dhcp":
1150
		kill_dhclient_process($realif);
1151
		unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1152
		if(does_interface_exist("$realif")) {
1153
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1154
			interface_ipalias_cleanup($interface);
1155
			if ($destroy == true)
1156
				pfSense_interface_flags($realif, -IFF_UP);
1157
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1158
		}
1159
		break;
1160
	default:
1161
		if(does_interface_exist("$realif")) {
1162
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1163
			interface_ipalias_cleanup($interface);
1164
			if ($destroy == true)
1165
				pfSense_interface_flags($realif, -IFF_UP);
1166
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1167
		}
1168
		break;
1169
	}
1170

    
1171
	$track6 = array();
1172
	switch ($ifcfg['ipaddrv6']) {
1173
		case "slaac":
1174
		case "dhcp6":
1175
			$pidv6 = find_dhcp6c_process($realif);
1176
			if ($pidv6) {
1177
				posix_kill($pidv6, SIGTERM);
1178
			}
1179
			sleep(3);
1180
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1181
			if (does_interface_exist($realifv6)) {
1182
				$ip6 = find_interface_ipv6($realifv6);
1183
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1184
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1185
				}
1186
				interface_ipalias_cleanup($interface, "inet6");
1187
				if ($destroy == true) {
1188
					pfSense_interface_flags($realif, -IFF_UP);
1189
				}
1190
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1191
			}
1192
			$track6 = link_interface_to_track6($interface);
1193
			break;
1194
		case "6rd":
1195
		case "6to4":
1196
			$realif = "{$interface}_stf";
1197
			if (does_interface_exist("$realif")) {
1198
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1199
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1200
					($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1201
					$destroy = true;
1202
				} else {
1203
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1204
					$ip6 = get_interface_ipv6($interface);
1205
					if (is_ipaddrv6($ip6))
1206
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1207
				}
1208
				interface_ipalias_cleanup($interface, "inet6");
1209
				if ($destroy == true) {
1210
					pfSense_interface_flags($realif, -IFF_UP);
1211
				}
1212
			}
1213
			$track6 = link_interface_to_track6($interface);
1214
			break;
1215
		default:
1216
			if (does_interface_exist("$realif")) {
1217
				$ip6 = get_interface_ipv6($interface);
1218
				if (is_ipaddrv6($ip6)) {
1219
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1220
				}
1221
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1222
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1223
				}
1224
				interface_ipalias_cleanup($interface, "inet6");
1225
				if ($destroy == true) {
1226
					pfSense_interface_flags($realif, -IFF_UP);
1227
				}
1228
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1229
			}
1230
			$track6 = link_interface_to_track6($interface);
1231
			break;
1232
	}
1233

    
1234
	if (!empty($track6) && is_array($track6)) {
1235
		if (!function_exists('services_dhcpd_configure'))
1236
			require_once('services.inc');
1237
		/* Bring down radvd and dhcp6 on these interfaces */
1238
		services_dhcpd_configure('inet6', $track6);
1239
	}
1240

    
1241
	$old_router = '';
1242
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1243
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1244

    
1245
	/* remove interface up file if it exists */
1246
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1247
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1248
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1249
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1250
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1251
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1252
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1253

    
1254
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1255
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1256
	if (is_array($ifcfg['wireless'])) {
1257
		kill_hostapd($realif);
1258
		mwexec(kill_wpasupplicant($realif));
1259
	}
1260

    
1261
	if ($destroy == true) {
1262
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif))
1263
			pfSense_interface_destroy($realif);
1264
	}
1265

    
1266
	return;
1267
}
1268

    
1269
function interfaces_carp_set_maintenancemode($carp_maintenancemode){
1270
	global $config;
1271
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1272
		unset($config["virtualip_carp_maintenancemode"]);
1273
		write_config("Leave CARP maintenance mode");
1274
	} else
1275
	if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1276
		$config["virtualip_carp_maintenancemode"] = true;
1277
		write_config("Enter CARP maintenance mode");
1278
	}
1279

    
1280
	$viparr = &$config['virtualip']['vip'];
1281
	foreach ($viparr as $vip) {
1282
		if ($vip['mode'] == "carp") {
1283
			interface_carp_configure($vip);
1284
		}
1285
	}
1286
}
1287

    
1288
function interface_isppp_type($interface) {
1289
	global $config;
1290

    
1291
	if (!is_array($config['interfaces'][$interface]))
1292
		return false;
1293

    
1294
	switch ($config['interfaces'][$interface]['ipaddr']) {
1295
	case 'pptp':
1296
	case 'l2tp':
1297
	case 'pppoe':
1298
	case 'ppp':
1299
		return true;
1300
		break;
1301
	default:
1302
		return false;
1303
		break;
1304
	}
1305
}
1306

    
1307
function interfaces_ptpid_used($ptpid) {
1308
	global $config;
1309

    
1310
	if (is_array($config['ppps']['ppp']))
1311
		foreach ($config['ppps']['ppp'] as & $settings)
1312
			if ($ptpid == $settings['ptpid'])
1313
				return true;
1314

    
1315
	return false;
1316
}
1317

    
1318
function interfaces_ptpid_next() {
1319

    
1320
	$ptpid = 0;
1321
	while(interfaces_ptpid_used($ptpid))
1322
		$ptpid++;
1323

    
1324
	return $ptpid;
1325
}
1326

    
1327
function getMPDCRONSettings($pppif) {
1328
	global $config;
1329

    
1330
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1331
	if (is_array($config['cron']['item'])) {
1332
		foreach ($config['cron']['item'] as $i => $item) {
1333
			if (stripos($item['command'], $cron_cmd_file) !== false)
1334
				return array("ID" => $i, "ITEM" => $item);
1335
		}
1336
	}
1337

    
1338
	return NULL;
1339
}
1340

    
1341
function handle_pppoe_reset($post_array) {
1342
	global $config, $g;
1343

    
1344
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1345
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1346

    
1347
	if (!is_array($config['cron']['item']))
1348
		$config['cron']['item'] = array();
1349

    
1350
	$itemhash = getMPDCRONSettings($pppif);
1351

    
1352
	// reset cron items if necessary and return
1353
	if (empty($post_array['pppoe-reset-type'])) {
1354
		if (isset($itemhash))
1355
			unset($config['cron']['item'][$itemhash['ID']]);
1356
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1357
		return;
1358
	}
1359

    
1360
	if (empty($itemhash))
1361
		$itemhash = array();
1362
	$item = array();
1363
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1364
		$item['minute'] = $post_array['pppoe_resetminute'];
1365
		$item['hour'] = $post_array['pppoe_resethour'];
1366
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1367
			$date = explode("/", $post_array['pppoe_resetdate']);
1368
			$item['mday'] = $date[1];
1369
			$item['month'] = $date[0];
1370
		} else {
1371
			$item['mday'] = "*";
1372
			$item['month'] = "*";
1373
		}
1374
		$item['wday'] = "*";
1375
		$item['who'] = "root";
1376
		$item['command'] = $cron_cmd_file;
1377
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1378
		switch ($post_array['pppoe_pr_preset_val']) {
1379
		case "monthly":
1380
			$item['minute'] = "0";
1381
			$item['hour'] = "0";
1382
			$item['mday'] = "1";
1383
			$item['month'] = "*";
1384
			$item['wday'] = "*";
1385
			break;
1386
		case "weekly":
1387
			$item['minute'] = "0";
1388
			$item['hour'] = "0";
1389
			$item['mday'] = "*";
1390
			$item['month'] = "*";
1391
			$item['wday'] = "0";
1392
			break;
1393
		case "daily":
1394
			$item['minute'] = "0";
1395
			$item['hour'] = "0";
1396
			$item['mday'] = "*";
1397
			$item['month'] = "*";
1398
			$item['wday'] = "*";
1399
			break;
1400
		case "hourly":
1401
			$item['minute'] = "0";
1402
			$item['hour'] = "*";
1403
			$item['mday'] = "*";
1404
			$item['month'] = "*";
1405
			$item['wday'] = "*";
1406
			break;
1407
		} // end switch
1408
		$item['who'] = "root";
1409
		$item['command'] = $cron_cmd_file;
1410
	}
1411
	if (empty($item))
1412
		return;
1413
	if (isset($itemhash['ID']))
1414
		$config['cron']['item'][$itemhash['ID']] = $item;
1415
	else
1416
		$config['cron']['item'][] = $item;
1417
}
1418

    
1419
/*
1420
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1421
 * It writes the mpd config file to /var/etc every time the link is opened.
1422
 */
1423
function interface_ppps_configure($interface) {
1424
	global $config, $g;
1425

    
1426
	/* Return for unassigned interfaces. This is a minimum requirement. */
1427
	if (empty($config['interfaces'][$interface]))
1428
		return 0;
1429
	$ifcfg = $config['interfaces'][$interface];
1430
	if (!isset($ifcfg['enable']))
1431
		return 0;
1432

    
1433
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1434
	if(!is_dir("/var/spool/lock")) {
1435
		mkdir("/var/spool/lock", 0777, true);
1436
	}
1437
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1438
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1439
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1440

    
1441
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1442
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1443
			if ($ifcfg['if'] == $ppp['if'])
1444
				break;
1445
		}
1446
	}
1447
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1448
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1449
		return 0;
1450
	}
1451
	$pppif = $ifcfg['if'];
1452
	if ($ppp['type'] == "ppp")
1453
		$type = "modem";
1454
	else
1455
		$type = $ppp['type'];
1456
	$upper_type = strtoupper($ppp['type']);
1457

    
1458
	/* XXX: This does not make sense and may create trouble
1459
	 * comment it for now to be removed later on.
1460
	if (platform_booting()) {
1461
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1462
		echo "starting {$pppif} link...";
1463
		if(isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1464
			return 0;
1465
	}
1466
	*/
1467

    
1468
	$ports = explode(',',$ppp['ports']);
1469
	if ($type != "modem") {
1470
		foreach ($ports as $pid => $port) {
1471
			$ports[$pid] = get_real_interface($port);
1472
			if (empty($ports[$pid]))
1473
				return 0;
1474
		}
1475
	}
1476
	$localips = explode(',',$ppp['localip']);
1477
	$gateways = explode(',',$ppp['gateway']);
1478
	$subnets = explode(',',$ppp['subnet']);
1479

    
1480
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1481
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1482
	 */
1483
	foreach($ports as $pid => $port){
1484
		switch ($ppp['type']) {
1485
			case "pppoe":
1486
				/* Bring the parent interface up */
1487
				interfaces_bring_up($port);
1488
				pfSense_ngctl_attach(".", $port);
1489
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1490
				mwexec("ngctl msg {$port}: setautosrc 1");
1491
				break;
1492
			case "pptp":
1493
			case "l2tp":
1494
				/* configure interface */
1495
				if(is_ipaddr($localips[$pid])){
1496
					// Manually configure interface IP/subnet
1497
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1498
					interfaces_bring_up($port);
1499
				} else if (empty($localips[$pid]))
1500
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1501

    
1502
				if(!is_ipaddr($localips[$pid])){
1503
					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!");
1504
					$localips[$pid] = "0.0.0.0";
1505
				}
1506
				if(!is_ipaddr($gateways[$pid])){
1507
					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));
1508
					return 0;
1509
				}
1510
				pfSense_ngctl_attach(".", $port);
1511
				break;
1512
			case "ppp":
1513
				if (!file_exists("{$port}")) {
1514
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1515
					return 0;
1516
				}
1517
				break;
1518
			default:
1519
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1520
				break;
1521
		}
1522
	}
1523

    
1524
	if (is_array($ports) && count($ports) > 1)
1525
		$multilink = "enable";
1526
	else
1527
		$multilink = "disable";
1528

    
1529
	if ($type == "modem"){
1530
		if (is_ipaddr($ppp['localip']))
1531
			$localip = $ppp['localip'];
1532
		else
1533
			$localip = '0.0.0.0';
1534

    
1535
		if (is_ipaddr($ppp['gateway']))
1536
			$gateway = $ppp['gateway'];
1537
		else
1538
			$gateway = "10.64.64.{$pppid}";
1539
		$ranges = "{$localip}/0 {$gateway}/0";
1540

    
1541
		if (empty($ppp['apnum']))
1542
			$ppp['apnum'] = 1;
1543
	} else
1544
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1545

    
1546
	if (isset($ppp['ondemand']))
1547
		$ondemand = "enable";
1548
	else
1549
		$ondemand = "disable";
1550
	if (!isset($ppp['idletimeout']))
1551
		$ppp['idletimeout'] = 0;
1552

    
1553
	if (empty($ppp['username']) && $type == "modem"){
1554
		$ppp['username'] = "user";
1555
		$ppp['password'] = "none";
1556
	}
1557
	if (empty($ppp['password']) && $type == "modem")
1558
		$passwd = "none";
1559
	else
1560
		$passwd = base64_decode($ppp['password']);
1561

    
1562
	$bandwidths = explode(',',$ppp['bandwidth']);
1563
	$defaultmtu = "1492";
1564
	if (!empty($ifcfg['mtu']))
1565
		$defaultmtu = intval($ifcfg['mtu']);
1566
	$mtus = explode(',',$ppp['mtu']);
1567
	$mrus = explode(',',$ppp['mru']);
1568

    
1569
	if (isset($ppp['mrru']))
1570
		$mrrus = explode(',',$ppp['mrru']);
1571

    
1572
	// Construct the mpd.conf file
1573
	$mpdconf = <<<EOD
1574
startup:
1575
	# configure the console
1576
	set console close
1577
	# configure the web server
1578
	set web close
1579

    
1580
default:
1581
{$ppp['type']}client:
1582
	create bundle static {$interface}
1583
	set bundle enable ipv6cp
1584
	set iface name {$pppif}
1585

    
1586
EOD;
1587
	$setdefaultgw = false;
1588
	$founddefaultgw = false;
1589
	if (is_array($config['gateways']['gateway_item'])) {
1590
		foreach($config['gateways']['gateway_item'] as $gateway) {
1591
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1592
				$setdefaultgw = true;
1593
				break;
1594
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1595
				$founddefaultgw = true;
1596
				break;
1597
			}
1598
		}
1599
	}
1600

    
1601
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1602
		$setdefaultgw = true;
1603
		$mpdconf .= <<<EOD
1604
	set iface route default
1605

    
1606
EOD;
1607
	}
1608
	$mpdconf .= <<<EOD
1609
	set iface {$ondemand} on-demand
1610
	set iface idle {$ppp['idletimeout']}
1611

    
1612
EOD;
1613

    
1614
	if (isset($ppp['ondemand']))
1615
		$mpdconf .= <<<EOD
1616
	set iface addrs 10.10.1.1 10.10.1.2
1617

    
1618
EOD;
1619

    
1620
	if (isset($ppp['tcpmssfix']))
1621
		$tcpmss = "disable";
1622
	else
1623
		$tcpmss = "enable";
1624
		$mpdconf .= <<<EOD
1625
	set iface {$tcpmss} tcpmssfix
1626

    
1627
EOD;
1628

    
1629
	$mpdconf .= <<<EOD
1630
	set iface up-script /usr/local/sbin/ppp-linkup
1631
	set iface down-script /usr/local/sbin/ppp-linkdown
1632
	set ipcp ranges {$ranges}
1633

    
1634
EOD;
1635
	if (isset($ppp['vjcomp']))
1636
		$mpdconf .= <<<EOD
1637
	set ipcp no vjcomp
1638

    
1639
EOD;
1640

    
1641
	if (isset($config['system']['dnsallowoverride']))
1642
		$mpdconf .= <<<EOD
1643
	set ipcp enable req-pri-dns
1644
	set ipcp enable req-sec-dns
1645

    
1646
EOD;
1647
	if (!isset($ppp['verbose_log']))
1648
		$mpdconf .= <<<EOD
1649
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1650

    
1651
EOD;
1652
	foreach($ports as $pid => $port){
1653
		$port = get_real_interface($port);
1654
		$mpdconf .= <<<EOD
1655

    
1656
	create link static {$interface}_link{$pid} {$type}
1657
	set link action bundle {$interface}
1658
	set link {$multilink} multilink
1659
	set link keep-alive 10 60
1660
	set link max-redial 0
1661

    
1662
EOD;
1663
		if (isset($ppp['shortseq']))
1664
			$mpdconf .= <<<EOD
1665
	set link no shortseq
1666

    
1667
EOD;
1668

    
1669
		if (isset($ppp['acfcomp']))
1670
			$mpdconf .= <<<EOD
1671
	set link no acfcomp
1672

    
1673
EOD;
1674

    
1675
		if (isset($ppp['protocomp']))
1676
			$mpdconf .= <<<EOD
1677
	set link no protocomp
1678

    
1679
EOD;
1680

    
1681
		$mpdconf .= <<<EOD
1682
	set link disable chap pap
1683
	set link accept chap pap eap
1684
	set link disable incoming
1685

    
1686
EOD;
1687

    
1688

    
1689
		if (!empty($bandwidths[$pid]))
1690
			$mpdconf .= <<<EOD
1691
	set link bandwidth {$bandwidths[$pid]}
1692

    
1693
EOD;
1694

    
1695
		if (empty($mtus[$pid]))
1696
			$mtus[$pid] = $defaultmtu;
1697
			$mpdconf .= <<<EOD
1698
	set link mtu {$mtus[$pid]}
1699

    
1700
EOD;
1701

    
1702
		if (!empty($mrus[$pid]))
1703
			$mpdconf .= <<<EOD
1704
	set link mru {$mrus[$pid]}
1705

    
1706
EOD;
1707

    
1708
		if (!empty($mrrus[$pid]))
1709
			$mpdconf .= <<<EOD
1710
	set link mrru {$mrrus[$pid]}
1711

    
1712
EOD;
1713

    
1714
		$mpdconf .= <<<EOD
1715
	set auth authname "{$ppp['username']}"
1716
	set auth password {$passwd}
1717

    
1718
EOD;
1719
		if ($type == "modem") {
1720
			$mpdconf .= <<<EOD
1721
	set modem device {$ppp['ports']}
1722
	set modem script DialPeer
1723
	set modem idle-script Ringback
1724
	set modem watch -cd
1725
	set modem var \$DialPrefix "DT"
1726
	set modem var \$Telephone "{$ppp['phone']}"
1727

    
1728
EOD;
1729
		}
1730
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1731
			$mpdconf .= <<<EOD
1732
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1733

    
1734
EOD;
1735
		}
1736
		if (isset($ppp['initstr']) && $type == "modem") {
1737
			$initstr = base64_decode($ppp['initstr']);
1738
			$mpdconf .= <<<EOD
1739
	set modem var \$InitString "{$initstr}"
1740

    
1741
EOD;
1742
		}
1743
		if (isset($ppp['simpin']) && $type == "modem") {
1744
			if($ppp['pin-wait'] == "")
1745
				$ppp['pin-wait'] = 0;
1746
			$mpdconf .= <<<EOD
1747
	set modem var \$SimPin "{$ppp['simpin']}"
1748
	set modem var \$PinWait "{$ppp['pin-wait']}"
1749

    
1750
EOD;
1751
		}
1752
		if (isset($ppp['apn']) && $type == "modem") {
1753
			$mpdconf .= <<<EOD
1754
	set modem var \$APN "{$ppp['apn']}"
1755
	set modem var \$APNum "{$ppp['apnum']}"
1756

    
1757
EOD;
1758
		}
1759
		if ($type == "pppoe") {
1760
			// Send a null service name if none is set.
1761
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1762
			$mpdconf .= <<<EOD
1763
	set pppoe service "{$provider}"
1764

    
1765
EOD;
1766
		}
1767
		if ($type == "pppoe")
1768
			$mpdconf .= <<<EOD
1769
	set pppoe iface {$port}
1770

    
1771
EOD;
1772

    
1773
		if ($type == "pptp" || $type == "l2tp") {
1774
			$mpdconf .= <<<EOD
1775
	set {$type} self {$localips[$pid]}
1776
	set {$type} peer {$gateways[$pid]}
1777

    
1778
EOD;
1779
		}
1780

    
1781
		$mpdconf .= "\topen\n";
1782
	} //end foreach($port)
1783

    
1784

    
1785
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1786
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1787
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1788
	else {
1789
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1790
		if (!$fd) {
1791
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1792
			return 0;
1793
		}
1794
		// Write out mpd_ppp.conf
1795
		fwrite($fd, $mpdconf);
1796
		fclose($fd);
1797
		unset($mpdconf);
1798
	}
1799

    
1800
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1801
	if (isset($ppp['uptime'])) {
1802
		if (!file_exists("/conf/{$pppif}.log")) {
1803
			conf_mount_rw();
1804
			file_put_contents("/conf/{$pppif}.log", '');
1805
			conf_mount_ro();
1806
		}
1807
	} else {
1808
		if (file_exists("/conf/{$pppif}.log")) {
1809
			conf_mount_rw();
1810
			@unlink("/conf/{$pppif}.log");
1811
			conf_mount_ro();
1812
		}
1813
	}
1814

    
1815
	/* clean up old lock files */
1816
	foreach($ports as $port) {
1817
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1818
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1819
	}
1820

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

    
1825
	// Check for PPPoE periodic reset request
1826
	if ($type == "pppoe") {
1827
		if (!empty($ppp['pppoe-reset-type']))
1828
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1829
		else
1830
			interface_setup_pppoe_reset_file($ppp['if']);
1831
	}
1832
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1833
	$i = 0;
1834
	while($i < 3) {
1835
		sleep(10);
1836
		if (does_interface_exist($ppp['if'], true))
1837
			break;
1838
		$i++;
1839
	}
1840

    
1841
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
1842
	/* We should be able to launch the right version for each modem */
1843
	/* We can also guess the mondev from the manufacturer */
1844
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
1845
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
1846
	foreach($ports as $port) {
1847
		if(preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1848
			$mondev  = substr(basename($port), 0, -1);
1849
			$devlist = glob("/dev/{$mondev}?");
1850
			$mondev = basename(end($devlist));
1851
		}
1852
		if(preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1853
			$mondev  = substr(basename($port), 0, -1) . "1";
1854
		}
1855
		if($mondev != '') {
1856
			log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
1857
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
1858
		}
1859
	}
1860

    
1861
	return 1;
1862
}
1863

    
1864
function interfaces_sync_setup() {
1865
	global $g, $config;
1866

    
1867
	if (isset($config['system']['developerspew'])) {
1868
		$mt = microtime();
1869
		echo "interfaces_sync_setup() being called $mt\n";
1870
	}
1871

    
1872
	if (platform_booting()) {
1873
		echo gettext("Configuring CARP settings...");
1874
		mute_kernel_msgs();
1875
	}
1876

    
1877
	/* suck in configuration items */
1878
	if ($config['hasync']) {
1879
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1880
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1881
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1882
	} else {
1883
		unset($pfsyncinterface);
1884
		unset($pfsyncenabled);
1885
	}
1886

    
1887
	set_sysctl(array(
1888
		"net.inet.carp.preempt" => "1",
1889
		"net.inet.carp.log" => "1")
1890
	);
1891

    
1892
	if (!empty($pfsyncinterface))
1893
		$carp_sync_int = get_real_interface($pfsyncinterface);
1894
	else
1895
		unset($carp_sync_int);
1896

    
1897
	/* setup pfsync interface */
1898
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
1899
		if (is_ipaddr($pfsyncpeerip))
1900
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1901
		else
1902
			$syncpeer = "-syncpeer";
1903

    
1904
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
1905
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
1906

    
1907
		sleep(1);
1908

    
1909
		/* 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
1910
		 * for existing sessions.
1911
		 */
1912
		log_error("waiting for pfsync...");
1913
		$i = 0;
1914
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1915
			$i++;
1916
			sleep(1);
1917
		}
1918
		log_error("pfsync done in $i seconds.");
1919
		log_error("Configuring CARP settings finalize...");
1920
	} else {
1921
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
1922
	}
1923

    
1924
	if($config['virtualip']['vip'])
1925
		set_single_sysctl("net.inet.carp.allow", "1");
1926
	else
1927
		set_single_sysctl("net.inet.carp.allow", "0");
1928

    
1929
	if (platform_booting()) {
1930
		unmute_kernel_msgs();
1931
		echo gettext("done.") . "\n";
1932
	}
1933
}
1934

    
1935
function interface_proxyarp_configure($interface = "") {
1936
	global $config, $g;
1937
	if(isset($config['system']['developerspew'])) {
1938
		$mt = microtime();
1939
		echo "interface_proxyarp_configure() being called $mt\n";
1940
	}
1941

    
1942
	/* kill any running choparp */
1943
	if (empty($interface))
1944
		killbyname("choparp");
1945
	else {
1946
		$vipif = get_real_interface($interface);
1947
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1948
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1949
	}
1950

    
1951
	$paa = array();
1952
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1953

    
1954
		/* group by interface */
1955
		foreach ($config['virtualip']['vip'] as $vipent) {
1956
			if ($vipent['mode'] === "proxyarp") {
1957
				if ($vipent['interface'])
1958
					$proxyif = $vipent['interface'];
1959
				else
1960
					$proxyif = "wan";
1961

    
1962
				if (!empty($interface) && $interface != $proxyif)
1963
					continue;
1964

    
1965
				if (!is_array($paa[$proxyif]))
1966
					$paa[$proxyif] = array();
1967

    
1968
				$paa[$proxyif][] = $vipent;
1969
			}
1970
		}
1971
	}
1972

    
1973
	if (!empty($interface)) {
1974
		if (is_array($paa[$interface])) {
1975
			$paaifip = get_interface_ip($interface);
1976
			if (!is_ipaddr($paaifip))
1977
				return;
1978
			$args = get_real_interface($interface) . " auto";
1979
			foreach ($paa[$interface] as $paent) {
1980
				if (isset($paent['subnet']))
1981
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1982
				else if (isset($paent['range']))
1983
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1984
			}
1985
			mwexec_bg("/usr/local/sbin/choparp " . $args);
1986
		}
1987
	} else if (count($paa) > 0) {
1988
		foreach ($paa as $paif => $paents)  {
1989
			$paaifip = get_interface_ip($paif);
1990
			if (!is_ipaddr($paaifip))
1991
				continue;
1992
			$args = get_real_interface($paif) . " auto";
1993
			foreach ($paents as $paent) {
1994
				if (isset($paent['subnet']))
1995
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1996
				else if (isset($paent['range']))
1997
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1998
			}
1999
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2000
		}
2001
	}
2002
}
2003

    
2004
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2005
	global $g, $config;
2006

    
2007
	if (is_array($config['virtualip']['vip'])) {
2008
		foreach ($config['virtualip']['vip'] as $vip) {
2009
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2010
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2011
					interface_vip_bring_down($vip);
2012
				else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2013
					interface_vip_bring_down($vip);
2014
			}
2015
		}
2016
	}
2017
}
2018

    
2019
function interfaces_vips_configure($interface = "") {
2020
	global $g, $config;
2021
	if(isset($config['system']['developerspew'])) {
2022
		$mt = microtime();
2023
		echo "interfaces_vips_configure() being called $mt\n";
2024
	}
2025
	$paa = array();
2026
	if(is_array($config['virtualip']['vip'])) {
2027
		$carp_setuped = false;
2028
		$anyproxyarp = false;
2029
		foreach ($config['virtualip']['vip'] as $vip) {
2030
			switch ($vip['mode']) {
2031
			case "proxyarp":
2032
				/* nothing it is handled on interface_proxyarp_configure() */
2033
				if ($interface <> "" && $vip['interface'] <> $interface)
2034
					continue;
2035
				$anyproxyarp = true;
2036
				break;
2037
			case "ipalias":
2038
				if ($interface <> "" && $vip['interface'] <> $interface)
2039
					continue;
2040
				interface_ipalias_configure($vip);
2041
				break;
2042
			case "carp":
2043
				if ($interface <> "" && $vip['interface'] <> $interface)
2044
					continue;
2045
				if ($carp_setuped == false)
2046
					$carp_setuped = true;
2047
				interface_carp_configure($vip);
2048
				break;
2049
			}
2050
		}
2051
		if ($carp_setuped == true)
2052
			interfaces_sync_setup();
2053
		if ($anyproxyarp == true)
2054
			interface_proxyarp_configure();
2055
	}
2056
}
2057

    
2058
function interface_ipalias_configure(&$vip) {
2059
	global $config;
2060

    
2061
	if ($vip['mode'] != 'ipalias')
2062
		return;
2063

    
2064
	if ($vip['interface'] != 'lo0' && stripos($vip['interface'], '_vip') === false) {
2065
		if (!isset($config['interfaces'][$vip['interface']]))
2066
			return;
2067

    
2068
		if (!isset($config['interfaces'][$vip['interface']]['enable']))
2069
			return;
2070
	}
2071

    
2072
	$af = 'inet';
2073
	if(is_ipaddrv6($vip['subnet']))
2074
		$af = 'inet6';
2075
	$iface = $vip['interface'];
2076
	$vipadd = '';
2077
	if (strpos($vip['interface'], '_vip')) {
2078
		$carpvip = get_configured_carp_interface_list($vip['interface'], $af, 'vip');
2079
		$iface = $carpvip['interface'];
2080
		$vipadd = "vhid {$carpvip['vhid']}";
2081
	}
2082
	$if = get_real_interface($iface);
2083
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vipadd}");
2084
	unset($iface, $af, $if, $carpvip, $vipadd);
2085
}
2086

    
2087
function interface_reload_carps($cif) {
2088
	global $config;
2089

    
2090
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2091
	if (empty($carpifs))
2092
		return;
2093

    
2094
	$carps = explode(" ", $carpifs);
2095
	if(is_array($config['virtualip']['vip'])) {
2096
		$viparr = &$config['virtualip']['vip'];
2097
		foreach ($viparr as $vip) {
2098
			if (in_array($vip['carpif'], $carps)) {
2099
				switch ($vip['mode']) {
2100
				case "carp":
2101
					interface_vip_bring_down($vip);
2102
					sleep(1);
2103
					interface_carp_configure($vip);
2104
					break;
2105
				case "ipalias":
2106
					interface_vip_bring_down($vip);
2107
					sleep(1);
2108
					interface_ipalias_configure($vip);
2109
					break;
2110
				}
2111
			}
2112
		}
2113
	}
2114
}
2115

    
2116
function interface_carp_configure(&$vip) {
2117
	global $config, $g;
2118
	if(isset($config['system']['developerspew'])) {
2119
		$mt = microtime();
2120
		echo "interface_carp_configure() being called $mt\n";
2121
	}
2122

    
2123
	if ($vip['mode'] != "carp")
2124
		return;
2125

    
2126
	/* NOTE: Maybe its useless nowadays */
2127
	$realif = get_real_interface($vip['interface']);
2128
	if (!does_interface_exist($realif)) {
2129
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2130
		return;
2131
	}
2132

    
2133
	$vip_password = $vip['password'];
2134
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2135
	if ($vip['password'] != "")
2136
		$password = " pass {$vip_password}";
2137

    
2138
	$advbase = "";
2139
	if (!empty($vip['advbase']))
2140
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2141

    
2142
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2143
	if ($carp_maintenancemode)
2144
		$advskew = "advskew 254";
2145
	else
2146
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2147
	
2148
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) . " {$advskew} {$advbase} {$password}");
2149

    
2150
	if (is_ipaddrv4($vip['subnet']))
2151
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2152
	else if (is_ipaddrv6($vip['subnet']))
2153
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2154

    
2155
	return $realif;
2156
}
2157

    
2158
function interface_wireless_clone($realif, $wlcfg) {
2159
	global $config, $g;
2160
	/*   Check to see if interface has been cloned as of yet.
2161
	 *   If it has not been cloned then go ahead and clone it.
2162
	 */
2163
	$needs_clone = false;
2164
	if(is_array($wlcfg['wireless']))
2165
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2166
	else
2167
		$wlcfg_mode = $wlcfg['mode'];
2168
	switch($wlcfg_mode) {
2169
	case "hostap":
2170
		$mode = "wlanmode hostap";
2171
		break;
2172
	case "adhoc":
2173
		$mode = "wlanmode adhoc";
2174
		break;
2175
	default:
2176
		$mode = "";
2177
		break;
2178
	}
2179
	$baseif = interface_get_wireless_base($wlcfg['if']);
2180
	if(does_interface_exist($realif)) {
2181
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2182
		$ifconfig_str = implode($output);
2183
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
2184
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2185
			$needs_clone = true;
2186
		}
2187
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
2188
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2189
			$needs_clone = true;
2190
		}
2191
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2192
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2193
			$needs_clone = true;
2194
		}
2195
	} else {
2196
		$needs_clone = true;
2197
	}
2198

    
2199
	if($needs_clone == true) {
2200
		/* remove previous instance if it exists */
2201
		if(does_interface_exist($realif))
2202
			pfSense_interface_destroy($realif);
2203

    
2204
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2205
		// Create the new wlan interface. FreeBSD returns the new interface name.
2206
		// example:  wlan2
2207
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2208
		if($ret <> 0) {
2209
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2210
			return false;
2211
		}
2212
		$newif = trim($out[0]);
2213
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2214
		pfSense_interface_rename($newif, $realif);
2215
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2216
	}
2217
	return true;
2218
}
2219

    
2220
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2221
	global $config, $g;
2222

    
2223
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2224
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2225
				 'regdomain', 'regcountry', 'reglocation');
2226

    
2227
	if(!is_interface_wireless($ifcfg['if']))
2228
		return;
2229

    
2230
	$baseif = interface_get_wireless_base($ifcfg['if']);
2231

    
2232
	// Sync shared settings for assigned clones
2233
	$iflist = get_configured_interface_list(false, true);
2234
	foreach ($iflist as $if) {
2235
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2236
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2237
				foreach ($shared_settings as $setting) {
2238
					if ($sync_changes) {
2239
						if (isset($ifcfg['wireless'][$setting]))
2240
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2241
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2242
							unset($config['interfaces'][$if]['wireless'][$setting]);
2243
					} else {
2244
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2245
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2246
						else if (isset($ifcfg['wireless'][$setting]))
2247
							unset($ifcfg['wireless'][$setting]);
2248
					}
2249
				}
2250
				if (!$sync_changes)
2251
					break;
2252
			}
2253
		}
2254
	}
2255

    
2256
	// Read or write settings at shared area
2257
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2258
		foreach ($shared_settings as $setting) {
2259
			if ($sync_changes) {
2260
				if (isset($ifcfg['wireless'][$setting]))
2261
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2262
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2263
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2264
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2265
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2266
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2267
				else if (isset($ifcfg['wireless'][$setting]))
2268
					unset($ifcfg['wireless'][$setting]);
2269
			}
2270
		}
2271
	}
2272

    
2273
	// Sync the mode on the clone creation page with the configured mode on the interface
2274
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2275
		foreach ($config['wireless']['clone'] as &$clone) {
2276
			if ($clone['cloneif'] == $ifcfg['if']) {
2277
				if ($sync_changes) {
2278
					$clone['mode'] = $ifcfg['wireless']['mode'];
2279
				} else {
2280
					$ifcfg['wireless']['mode'] = $clone['mode'];
2281
				}
2282
				break;
2283
			}
2284
		}
2285
		unset($clone);
2286
	}
2287
}
2288

    
2289
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2290
	global $config, $g;
2291

    
2292
	/*    open up a shell script that will be used to output the commands.
2293
	 *    since wireless is changing a lot, these series of commands are fragile
2294
	 *    and will sometimes need to be verified by a operator by executing the command
2295
	 *    and returning the output of the command to the developers for inspection.  please
2296
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2297
	 */
2298

    
2299
	// Remove script file
2300
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2301

    
2302
	// Clone wireless nic if needed.
2303
	interface_wireless_clone($if, $wl);
2304

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

    
2308
	$fd_set = fopen("{$g['tmp_path']}/{$if}_setup.sh","w");
2309
	fwrite($fd_set, "#!/bin/sh\n");
2310
	fwrite($fd_set, "# {$g['product_name']} wireless configuration script.\n\n");
2311
	
2312
	$wlan_setup_log = fopen("{$g['tmp_path']}/{$if}_setup.log","w");
2313

    
2314
	/* set values for /path/program */
2315
	$hostapd = "/usr/sbin/hostapd";
2316
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2317
	$ifconfig = "/sbin/ifconfig";
2318
	$sysctl = "/sbin/sysctl";
2319
	$killall = "/usr/bin/killall";
2320

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

    
2323
	$wlcmd = array();
2324
	$wl_sysctl = array();
2325
	/* Make sure it's up */
2326
	$wlcmd[] = "up";
2327
	/* Set a/b/g standard */
2328
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2329
	/* skip mode entirely for "auto" */
2330
	if ($wlcfg['standard'] != "auto") {
2331
		$wlcmd[] = "mode " . escapeshellarg($standard);
2332
	}
2333

    
2334
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2335
	 * to prevent massive packet loss under certain conditions. */
2336
	if(preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na"))
2337
		$wlcmd[] = "-ampdu";
2338

    
2339
	/* Set ssid */
2340
	if($wlcfg['ssid'])
2341
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2342

    
2343
	/* Set 802.11g protection mode */
2344
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2345

    
2346
	/* set wireless channel value */
2347
	if(isset($wlcfg['channel'])) {
2348
		if($wlcfg['channel'] == "0") {
2349
			$wlcmd[] = "channel any";
2350
		} else {
2351
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2352
		}
2353
	}
2354

    
2355
	/* Set antenna diversity value */
2356
	if(isset($wlcfg['diversity']))
2357
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2358

    
2359
	/* Set txantenna value */
2360
	if(isset($wlcfg['txantenna']))
2361
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2362

    
2363
	/* Set rxantenna value */
2364
	if(isset($wlcfg['rxantenna']))
2365
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2366

    
2367
	/* set Distance value */
2368
	if($wlcfg['distance'])
2369
		$distance = escapeshellarg($wlcfg['distance']);
2370

    
2371
	/* Set wireless hostap mode */
2372
	if ($wlcfg['mode'] == "hostap") {
2373
		$wlcmd[] = "mediaopt hostap";
2374
	} else {
2375
		$wlcmd[] = "-mediaopt hostap";
2376
	}
2377

    
2378
	/* Set wireless adhoc mode */
2379
	if ($wlcfg['mode'] == "adhoc") {
2380
		$wlcmd[] = "mediaopt adhoc";
2381
	} else {
2382
		$wlcmd[] = "-mediaopt adhoc";
2383
	}
2384

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

    
2387
	/* handle hide ssid option */
2388
	if(isset($wlcfg['hidessid']['enable'])) {
2389
		$wlcmd[] = "hidessid";
2390
	} else {
2391
		$wlcmd[] = "-hidessid";
2392
	}
2393

    
2394
	/* handle pureg (802.11g) only option */
2395
	if(isset($wlcfg['pureg']['enable'])) {
2396
		$wlcmd[] = "mode 11g pureg";
2397
	} else {
2398
		$wlcmd[] = "-pureg";
2399
	}
2400

    
2401
	/* handle puren (802.11n) only option */
2402
	if(isset($wlcfg['puren']['enable'])) {
2403
		$wlcmd[] = "puren";
2404
	} else {
2405
		$wlcmd[] = "-puren";
2406
	}
2407

    
2408
	/* enable apbridge option */
2409
	if(isset($wlcfg['apbridge']['enable'])) {
2410
		$wlcmd[] = "apbridge";
2411
	} else {
2412
		$wlcmd[] = "-apbridge";
2413
	}
2414

    
2415
	/* handle turbo option */
2416
	if(isset($wlcfg['turbo']['enable'])) {
2417
		$wlcmd[] = "mediaopt turbo";
2418
	} else {
2419
		$wlcmd[] = "-mediaopt turbo";
2420
	}
2421

    
2422
	/* handle txpower setting */
2423
	// or don't. this has issues at the moment.
2424
	/*
2425
	if($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2426
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2427
	}*/
2428
	
2429
	/* handle wme option */
2430
	if(isset($wlcfg['wme']['enable'])) {
2431
		$wlcmd[] = "wme";
2432
	} else {
2433
		$wlcmd[] = "-wme";
2434
	}
2435

    
2436
	/* set up wep if enabled */
2437
	$wepset = "";
2438
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2439
		switch($wlcfg['wpa']['auth_algs']) {
2440
			case "1":
2441
				$wepset .= "authmode open wepmode on ";
2442
				break;
2443
			case "2":
2444
				$wepset .= "authmode shared wepmode on ";
2445
				break;
2446
			case "3":
2447
				$wepset .= "authmode mixed wepmode on ";
2448
		}
2449
		$i = 1;
2450
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2451
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2452
			if (isset($wepkey['txkey'])) {
2453
				$wlcmd[] = "weptxkey {$i} ";
2454
			}
2455
			$i++;
2456
		}
2457
		$wlcmd[] = $wepset;
2458
	} else if (isset($wlcfg['wpa']['enable'])) {
2459
		$wlcmd[] = "authmode wpa wepmode off ";
2460
	} else {
2461
		$wlcmd[] = "authmode open wepmode off ";
2462
	}
2463

    
2464
	kill_hostapd($if);
2465
	mwexec(kill_wpasupplicant("{$if}"));
2466

    
2467
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2468
	conf_mount_rw();
2469

    
2470
	switch ($wlcfg['mode']) {
2471
	case 'bss':
2472
		if (isset($wlcfg['wpa']['enable'])) {
2473
			$wpa .= <<<EOD
2474
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2475
ctrl_interface_group=0
2476
ap_scan=1
2477
#fast_reauth=1
2478
network={
2479
ssid="{$wlcfg['ssid']}"
2480
scan_ssid=1
2481
priority=5
2482
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2483
psk="{$wlcfg['wpa']['passphrase']}"
2484
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2485
group={$wlcfg['wpa']['wpa_pairwise']}
2486
}
2487
EOD;
2488

    
2489
			@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2490
			unset($wpa);
2491
		}
2492
		break;
2493
	case 'hostap':
2494
		if (!empty($wlcfg['wpa']['passphrase']))
2495
			$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2496
		else
2497
			$wpa_passphrase = "";
2498
		if (isset($wlcfg['wpa']['enable'])) {
2499
			$wpa .= <<<EOD
2500
interface={$if}
2501
driver=bsd
2502
logger_syslog=-1
2503
logger_syslog_level=0
2504
logger_stdout=-1
2505
logger_stdout_level=0
2506
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2507
ctrl_interface={$g['varrun_path']}/hostapd
2508
ctrl_interface_group=wheel
2509
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2510
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2511
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2512
ssid={$wlcfg['ssid']}
2513
debug={$wlcfg['wpa']['debug_mode']}
2514
auth_algs={$wlcfg['wpa']['auth_algs']}
2515
wpa={$wlcfg['wpa']['wpa_mode']}
2516
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2517
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2518
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2519
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2520
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2521
{$wpa_passphrase}
2522

    
2523
EOD;
2524

    
2525
			if (isset($wlcfg['wpa']['rsn_preauth'])) {
2526
				$wpa .= <<<EOD
2527
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2528
rsn_preauth=1
2529
rsn_preauth_interfaces={$if}
2530

    
2531
EOD;
2532
			}
2533
			if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2534
				$wpa .= "ieee8021x=1\n";
2535

    
2536
			if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2537
				$auth_server_port = "1812";
2538
				if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port']))
2539
					$auth_server_port = intval($wlcfg['auth_server_port']);
2540
				$wpa .= <<<EOD
2541

    
2542
auth_server_addr={$wlcfg['auth_server_addr']}
2543
auth_server_port={$auth_server_port}
2544
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2545

    
2546
EOD;
2547
				if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2548
					$auth_server_port2 = "1812";
2549
					if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2']))
2550
						$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2551

    
2552
					$wpa .= <<<EOD
2553
auth_server_addr={$wlcfg['auth_server_addr2']}
2554
auth_server_port={$auth_server_port2}
2555
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2556

    
2557
EOD;
2558
					}
2559
				}
2560
			}
2561

    
2562
			@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2563
			unset($wpa);
2564
		}
2565
		break;
2566
	}
2567

    
2568
	/*
2569
	 *    all variables are set, lets start up everything
2570
	 */
2571

    
2572
	$baseif = interface_get_wireless_base($if);
2573
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2574
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2575

    
2576
	/* set sysctls for the wireless interface */
2577
	if (!empty($wl_sysctl)) {
2578
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2579
		foreach ($wl_sysctl as $wl_sysctl_line) {
2580
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2581
		}
2582
	}
2583

    
2584
	/* set ack timers according to users preference (if he/she has any) */
2585
	if($distance) {
2586
		fwrite($fd_set, "# Enable ATH distance settings\n");
2587
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2588
	}
2589

    
2590
	if (isset($wlcfg['wpa']['enable'])) {
2591
		if ($wlcfg['mode'] == "bss") {
2592
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2593
		}
2594
		if ($wlcfg['mode'] == "hostap") {
2595
			/* add line to script to restore old mac to make hostapd happy */
2596
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2597
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2598
				if (is_macaddr($if_oldmac))
2599
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2600
						" link " . escapeshellarg($if_oldmac) . "\n");
2601
			}
2602

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

    
2605
			/* add line to script to restore spoofed mac after running hostapd */
2606
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2607
				if ($wl['spoofmac'])
2608
					$if_curmac = $wl['spoofmac'];
2609
				else
2610
					$if_curmac = get_interface_mac($if);
2611
				if (is_macaddr($if_curmac))
2612
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2613
						" link " . escapeshellarg($if_curmac) . "\n");
2614
			}
2615
		}
2616
	}
2617

    
2618
	fclose($fd_set);
2619
	conf_mount_ro();
2620

    
2621
	/* Making sure regulatory settings have actually changed
2622
	 * before applying, because changing them requires bringing
2623
	 * down all wireless networks on the interface. */
2624
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2625
	$ifconfig_str = implode($output);
2626
	unset($output);
2627
	$reg_changing = false;
2628

    
2629
	/* special case for the debug country code */
2630
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2631
		$reg_changing = true;
2632
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2633
		$reg_changing = true;
2634
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2635
		$reg_changing = true;
2636
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2637
		$reg_changing = true;
2638
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2639
		$reg_changing = true;
2640

    
2641
	if ($reg_changing) {
2642
		/* set regulatory domain */
2643
		if($wlcfg['regdomain'])
2644
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2645

    
2646
		/* set country */
2647
		if($wlcfg['regcountry'])
2648
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2649

    
2650
		/* set location */
2651
		if($wlcfg['reglocation'])
2652
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2653

    
2654
		$wlregcmd_args = implode(" ", $wlregcmd);
2655

    
2656
		/* build a complete list of the wireless clones for this interface */
2657
		$clone_list = array();
2658
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2659
			$clone_list[] = interface_get_wireless_clone($baseif);
2660
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2661
			foreach ($config['wireless']['clone'] as $clone) {
2662
				if ($clone['if'] == $baseif)
2663
					$clone_list[] = $clone['cloneif'];
2664
			}
2665
		}
2666

    
2667
		/* find which clones are up and bring them down */
2668
		$clones_up = array();
2669
		foreach ($clone_list as $clone_if) {
2670
			$clone_status = pfSense_get_interface_addresses($clone_if);
2671
			if ($clone_status['status'] == 'up') {
2672
				$clones_up[] = $clone_if;
2673
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2674
			}
2675
		}
2676

    
2677
		/* apply the regulatory settings */
2678
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2679
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2680

    
2681
		/* bring the clones back up that were previously up */
2682
		foreach ($clones_up as $clone_if) {
2683
			interfaces_bring_up($clone_if);
2684

    
2685
			/*
2686
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2687
			 * is in infrastructure mode, and WPA is enabled.
2688
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2689
			 */
2690
			if ($clone_if != $if) {
2691
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2692
				if ( !empty($friendly_if)
2693
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2694
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2695
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2696
				}
2697
			}
2698
		}
2699
	}
2700

    
2701
	/* 20150318 cmb - Note: the below no longer appears to be true on FreeBSD 10.x, so don't set 
2702
	 * mode twice (for now at least). This can be removed entirely in the future if no problems are found
2703
	
2704
	 * The mode must be specified in a separate command before ifconfig
2705
	 * will allow the mode and channel at the same time in the next. */
2706
	//mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2707
	//fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
2708

    
2709
	/* configure wireless */
2710
	$wlcmd_args = implode(" ", $wlcmd);
2711
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2712
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
2713
	fclose($wlan_setup_log);
2714
	
2715
	unset($wlcmd_args, $wlcmd);
2716

    
2717

    
2718
	sleep(1);
2719
	/* execute hostapd and wpa_supplicant if required in shell */
2720
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2721

    
2722
	return 0;
2723

    
2724
}
2725

    
2726
function kill_hostapd($interface) {
2727
	global $g;
2728

    
2729
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2730
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2731
}
2732

    
2733
function kill_wpasupplicant($interface) {
2734
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2735
}
2736

    
2737
function find_dhclient_process($interface) {
2738
	if ($interface)
2739
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2740
	else
2741
		$pid = 0;
2742

    
2743
	return intval($pid);
2744
}
2745

    
2746
function kill_dhclient_process($interface) {
2747
	if (empty($interface) || !does_interface_exist($interface))
2748
		return;
2749

    
2750
	$i = 0;
2751
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2752
		/* 3rd time make it die for sure */
2753
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2754
		posix_kill($pid, $sig);
2755
		sleep(1);
2756
		$i++;
2757
	}
2758
	unset($i);
2759
}
2760

    
2761
function find_dhcp6c_process($interface) {
2762
	global $g;
2763

    
2764
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid"))
2765
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2766
	else
2767
		return(false);
2768

    
2769
	return intval($pid);
2770
}
2771

    
2772
function interface_virtual_create($interface) {
2773
	global $config;
2774

    
2775
	if (strstr($interface, "_vlan")) {
2776
		interfaces_vlan_configure($vlan);
2777
	} else if (substr($interface, 0, 3) == "gre") {
2778
		interfaces_gre_configure(0, $interface);
2779
	} else if (substr($interface, 0, 3) == "gif") {
2780
		interfaces_gif_configure(0, $interface);
2781
	} else if (substr($interface, 0, 5) == "ovpns") {
2782
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
2783
			foreach ($config['openvpn']['openvpn-server'] as $server) {
2784
				if ($interface == "ovpns{$server['vpnid']}") {
2785
					if (!function_exists('openvpn_resync'))
2786
						require_once('openvpn.inc');
2787
					log_error("OpenVPN: Resync server {$server['description']}");
2788
					openvpn_resync('server', $server);
2789
				}
2790
			}
2791
			unset($server);
2792
		}
2793
	} else if (substr($interface, 0, 5) == "ovpnc") {
2794
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
2795
			foreach ($config['openvpn']['openvpn-client'] as $client) {
2796
				if ($interface == "ovpnc{$client['vpnid']}") {
2797
					if (!function_exists('openvpn_resync'))
2798
						require_once('openvpn.inc');
2799
					log_error("OpenVPN: Resync server {$client['description']}");
2800
					openvpn_resync('client', $client);
2801
				}
2802
			}
2803
			unset($client);
2804
		}
2805
	} else if (substr($interface, 0, 4) == "lagg") {
2806
		interfaces_lagg_configure($interface);
2807
	} else if (substr($interface, 0, 6) == "bridge") {
2808
		interfaces_bridge_configure(0, $interface);
2809
	}
2810
}
2811

    
2812
function interface_vlan_mtu_configured($realhwif, $mtu) {
2813
	global $config;
2814

    
2815
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
2816
		foreach ($config['vlans']['vlan'] as $vlan) {
2817
			if ($vlan['if'] != $realhwif)
2818
				continue;
2819
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2820
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
2821
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2822
					$mtu = $config['interfaces'][$assignedport]['mtu'];
2823
			}
2824
		}
2825
	}
2826

    
2827
	return $mtu;
2828
}
2829

    
2830
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2831
	global $config;
2832

    
2833
	if (!is_array($vlanifs))
2834
		return;
2835

    
2836
	/* All vlans need to use the same mtu value as their parent. */
2837
	foreach ($vlanifs as $vlan) {
2838
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2839
		if (!empty($assignedport)) {
2840
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
2841
				pfSense_interface_mtu($vlan['vlanif'], $config['interfaces'][$assignedport]['mtu']);
2842
			} else {
2843
				if (get_interface_mtu($vlan['vlanif']) != $mtu)
2844
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2845
			}
2846
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2847
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
2848
	}
2849
}
2850

    
2851
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2852
	global $config, $g;
2853
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2854
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2855

    
2856
	$wancfg = $config['interfaces'][$interface];
2857

    
2858
	if (!isset($wancfg['enable']))
2859
		return;
2860

    
2861
	$realif = get_real_interface($interface);
2862
	$realhwif_array = get_parent_interface($interface);
2863
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2864
	$realhwif = $realhwif_array[0];
2865

    
2866
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
2867
		/* remove all IPv4 and IPv6 addresses */
2868
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2869
		if (is_array($tmpifaces)) {
2870
			foreach ($tmpifaces as $tmpiface) {
2871
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
2872
					if (!is_linklocal($tmpiface))
2873
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2874
				} else {
2875
					if (is_subnetv4($tmpiface)) {
2876
						$tmpip = explode('/', $tmpiface);
2877
						$tmpip = $tmpip[0];
2878
					} else
2879
						$tmpip = $tmpiface;
2880
					pfSense_interface_deladdress($realif, $tmpip);
2881
				}
2882
			}
2883
		}
2884

    
2885
		/* only bring down the interface when both v4 and v6 are set to NONE */
2886
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6']))
2887
			interface_bring_down($interface);
2888
	}
2889

    
2890
	$interface_to_check = $realif;
2891
	if (interface_isppp_type($interface))
2892
		$interface_to_check = $realhwif;
2893

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

    
2898
	/* Disable Accepting router advertisements unless specifically requested */
2899
	if ($g['debug'])
2900
		log_error("Deny router advertisements for interface {$interface}");
2901
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
2902

    
2903
	/* wireless configuration? */
2904
	if (is_array($wancfg['wireless']))
2905
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2906

    
2907
	$mac = get_interface_mac($realhwif);
2908
	/*
2909
	 * Don't try to reapply the spoofed MAC if it's already applied.
2910
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2911
	 * the interface config again, which attempts to spoof the MAC again,
2912
	 * which cycles the link again...
2913
	 */
2914
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
2915
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2916
			" link " . escapeshellarg($wancfg['spoofmac']));
2917
	}  else {
2918

    
2919
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2920
			/*   this is not a valid mac address.  generate a
2921
			 *   temporary mac address so the machine can get online.
2922
			 */
2923
			echo gettext("Generating new MAC address.");
2924
			$random_mac = generate_random_mac_address();
2925
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2926
				" link " . escapeshellarg($random_mac));
2927
			$wancfg['spoofmac'] = $random_mac;
2928
			write_config();
2929
			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");
2930
		}
2931
	}
2932

    
2933
	/* media */
2934
	if ($wancfg['media'] || $wancfg['mediaopt']) {
2935
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2936
		if ($wancfg['media'])
2937
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2938
		if ($wancfg['mediaopt'])
2939
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2940
		mwexec($cmd);
2941
	}
2942

    
2943
	/* Apply hw offloading policies as configured */
2944
	enable_hardware_offloading($interface);
2945

    
2946
	/* invalidate interface/ip/sn cache */
2947
	get_interface_arr(true);
2948
	unset($interface_ip_arr_cache[$realif]);
2949
	unset($interface_sn_arr_cache[$realif]);
2950
	unset($interface_ipv6_arr_cache[$realif]);
2951
	unset($interface_snv6_arr_cache[$realif]);
2952

    
2953
	$tunnelif = substr($realif, 0, 3);
2954

    
2955
	if (does_interface_exist($wancfg['if']))
2956
		interfaces_bring_up($wancfg['if']);
2957

    
2958
	if (!empty($wancfg['mtu'])) {
2959
		if (stristr($realif, "_vlan")) {
2960
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
2961
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
2962
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
2963
				if ($wancfg['mtu'] > $parentmtu)
2964
					log_error("There is a conflict on MTU between parent {$realhwif} and VLAN({$realif})");
2965
			} else
2966
				$parentmtu = 0;
2967

    
2968
			$parentmtu = interface_vlan_mtu_configured($realhwif, $parentmtu);
2969

    
2970
			if (get_interface_mtu($realhwif) != $parentmtu)
2971
				pfSense_interface_mtu($realhwif, $parentmtu);
2972

    
2973
			/* All vlans need to use the same mtu value as their parent. */
2974
			interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $parentmtu);
2975
		} else if (substr($realif, 0, 4) == 'lagg') {
2976
			/* LAGG interface must be destroyed and re-created to change MTU */
2977
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
2978
				if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
2979
					foreach ($config['laggs']['lagg'] as $lagg) {
2980
						if ($lagg['laggif'] == $realif) {
2981
							interface_lagg_configure($lagg);
2982
							break;
2983
						}
2984
					}
2985
				}
2986
			}
2987
		} else {
2988
			if ($wancfg['mtu'] != get_interface_mtu($realif))
2989
				pfSense_interface_mtu($realif, $wancfg['mtu']);
2990

    
2991
			/* This case is needed when the parent of vlans is being configured */
2992
			$vlans = link_interface_to_vlans($realif);
2993
			if (is_array($vlans))
2994
				interface_vlan_adapt_mtu($vlans, $wancfg['mtu']);
2995
			unset($vlans);
2996
		}
2997
		/* XXX: What about gre/gif/.. ? */
2998
	}
2999

    
3000
	switch ($wancfg['ipaddr']) {
3001
	case 'dhcp':
3002
		interface_dhcp_configure($interface);
3003
		break;
3004
	case 'pppoe':
3005
	case 'l2tp':
3006
	case 'pptp':
3007
	case 'ppp':
3008
		interface_ppps_configure($interface);
3009
		break;
3010
	default:
3011
		/* XXX: Kludge for now related to #3280 */
3012
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3013
			if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "")
3014
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3015
		}
3016
		break;
3017
	}
3018

    
3019
	switch ($wancfg['ipaddrv6']) {
3020
	case 'slaac':
3021
	case 'dhcp6':
3022
		interface_dhcpv6_configure($interface, $wancfg);
3023
		break;
3024
	case '6rd':
3025
		interface_6rd_configure($interface, $wancfg);
3026
		break;
3027
	case '6to4':
3028
		interface_6to4_configure($interface, $wancfg);
3029
		break;
3030
	case 'track6':
3031
		interface_track6_configure($interface, $wancfg, $linkupevent);
3032
		break;
3033
	default:
3034
		/* XXX: Kludge for now related to #3280 */
3035
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3036
			if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3037
				//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3038
				// FIXME: Add IPv6 Support to the pfSense module
3039
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3040
			}
3041
		}
3042
		break;
3043
	}
3044

    
3045
	interface_netgraph_needed($interface);
3046

    
3047
	if (!platform_booting()) {
3048
		link_interface_to_vips($interface, "update");
3049

    
3050
		if ($tunnelif != 'gre') {
3051
			unset($gre);
3052
			$gre = link_interface_to_gre($interface);
3053
			if (!empty($gre))
3054
				array_walk($gre, 'interface_gre_configure');
3055
		}
3056

    
3057
		if ($tunnelif != 'gif') {
3058
			unset($gif);
3059
			$gif = link_interface_to_gif($interface);
3060
			if (!empty($gif))
3061
				array_walk($gif, 'interface_gif_configure');
3062
		}
3063

    
3064
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3065
			unset($bridgetmp);
3066
			$bridgetmp = link_interface_to_bridge($interface);
3067
			if (!empty($bridgetmp))
3068
				interface_bridge_add_member($bridgetmp, $realif);
3069
		}
3070

    
3071
		$grouptmp = link_interface_to_group($interface);
3072
		if (!empty($grouptmp))
3073
			array_walk($grouptmp, 'interface_group_add_member');
3074

    
3075
		if ($interface == "lan")
3076
			/* make new hosts file */
3077
			system_hosts_generate();
3078

    
3079
		if ($reloadall == true) {
3080

    
3081
			/* reconfigure static routes (kernel may have deleted them) */
3082
			system_routing_configure($interface);
3083

    
3084
			/* reload ipsec tunnels */
3085
			send_event("service reload ipsecdns");
3086

    
3087
			/* restart dnsmasq or unbound */
3088
			if (isset($config['dnsmasq']['enable']))
3089
				services_dnsmasq_configure();
3090
			elseif (isset($config['unbound']['enable']))
3091
				services_unbound_configure();
3092

    
3093
			/* update dyndns */
3094
			send_event("service reload dyndns {$interface}");
3095

    
3096
			/* reload captive portal */
3097
			if (!function_exists('captiveportal_init_rules_byinterface'))
3098
				require_once('captiveportal.inc');
3099
			captiveportal_init_rules_byinterface($interface);
3100
		}
3101
	}
3102

    
3103
	interfaces_staticarp_configure($interface);
3104
	return 0;
3105
}
3106

    
3107
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3108
	global $config, $g;
3109

    
3110
	if (!is_array($wancfg))
3111
		return;
3112

    
3113
	if (!isset($wancfg['enable']))
3114
		return;
3115

    
3116
	/* If the interface is not configured via another, exit */
3117
	if (empty($wancfg['track6-interface']))
3118
		return;
3119

    
3120
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3121
	$realif = get_real_interface($interface);
3122
	$linklocal = find_interface_ipv6_ll($realif);
3123
	if (!empty($linklocal))
3124
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3125
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3126
	/* XXX: Probably should remove? */
3127
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3128

    
3129
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3130
	if (!isset($trackcfg['enable'])) {
3131
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3132
		return;
3133
	}
3134

    
3135
	switch($trackcfg['ipaddrv6']) {
3136
	case "6to4":
3137
		if ($g['debug'])
3138
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3139
		interface_track6_6to4_configure($interface, $wancfg);
3140
		break;
3141
	case "6rd":
3142
		if ($g['debug'])
3143
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3144
		interface_track6_6rd_configure($interface, $wancfg);
3145
		break;
3146
	case "dhcp6":
3147
		if ($linkupevent == true) {
3148
			/* 
3149
			 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
3150
			 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3151
			 *
3152
			 * XXX: Probably DHCPv6 client should handle this automagically itself?
3153
			 */
3154
			$parentrealif = get_real_interface($wancfg['track6-interface']);
3155
			$pidv6 = find_dhcp6c_process($parentrealif);
3156
			if($pidv6)
3157
				posix_kill($pidv6, SIGHUP);
3158
		}
3159
		break;
3160
	}
3161

    
3162
	if ($linkupevent == false) {
3163
		if (!function_exists('services_dhcpd_configure'))
3164
			require_once("services.inc");
3165

    
3166
		if (isset($config['unbound']['enable']))
3167
			services_unbound_configure();
3168

    
3169
		services_dhcpd_configure("inet6");
3170
	}
3171

    
3172
	return 0;
3173
}
3174

    
3175
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3176
	global $config, $g;
3177
	global $interface_ipv6_arr_cache;
3178
	global $interface_snv6_arr_cache;
3179

    
3180
	if (!is_array($lancfg))
3181
		return;
3182

    
3183
	/* If the interface is not configured via another, exit */
3184
	if (empty($lancfg['track6-interface']))
3185
		return;
3186

    
3187
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3188
	if (empty($wancfg)) {
3189
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3190
		return;
3191
	}
3192

    
3193
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3194
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3195
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not valid, not configuring 6RD tunnel");
3196
		return;
3197
	}
3198
	$hexwanv4 = return_hex_ipv4($ip4address);
3199

    
3200
	/* create the long prefix notation for math, save the prefix length */
3201
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3202
	$rd6prefixlen = $rd6prefix[1];
3203
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3204

    
3205
	/* binary presentation of the prefix for all 128 bits. */
3206
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3207

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

    
3213
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3214
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3215
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3216
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3217
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3218
	/* fill the rest out with zeros */
3219
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3220

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

    
3224
	$lanif = get_real_interface($interface);
3225
	$oip = find_interface_ipv6($lanif);
3226
	if (is_ipaddrv6($oip))
3227
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3228
	unset($interface_ipv6_arr_cache[$lanif]);
3229
	unset($interface_snv6_arr_cache[$lanif]);
3230
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3231
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3232

    
3233
	return 0;
3234
}
3235

    
3236
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3237
	global $config, $g;
3238
	global $interface_ipv6_arr_cache;
3239
	global $interface_snv6_arr_cache;
3240

    
3241
	if (!is_array($lancfg))
3242
		return;
3243

    
3244
	/* If the interface is not configured via another, exit */
3245
	if (empty($lancfg['track6-interface']))
3246
		return;
3247

    
3248
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3249
	if (empty($wancfg)) {
3250
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3251
		return;
3252
	}
3253

    
3254
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3255
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3256
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3257
		return;
3258
	}
3259
	$hexwanv4 = return_hex_ipv4($ip4address);
3260

    
3261
	/* create the long prefix notation for math, save the prefix length */
3262
	$sixto4prefix = "2002::";
3263
	$sixto4prefixlen = 16;
3264
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3265

    
3266
	/* binary presentation of the prefix for all 128 bits. */
3267
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3268

    
3269
	/* just save the left prefix length bits */
3270
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3271
	/* add the v4 address */
3272
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3273
	/* add the custom prefix id */
3274
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3275
	/* fill the rest out with zeros */
3276
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3277

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

    
3281
	$lanif = get_real_interface($interface);
3282
	$oip = find_interface_ipv6($lanif);
3283
	if (is_ipaddrv6($oip))
3284
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3285
	unset($interface_ipv6_arr_cache[$lanif]);
3286
	unset($interface_snv6_arr_cache[$lanif]);
3287
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3288
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3289

    
3290
	return 0;
3291
}
3292

    
3293
function interface_6rd_configure($interface = "wan", $wancfg) {
3294
	global $config, $g;
3295

    
3296
	/* because this is a tunnel interface we can only function
3297
	 *	with a public IPv4 address on the interface */
3298

    
3299
	if (!is_array($wancfg))
3300
		return;
3301

    
3302
	if (!is_module_loaded('if_stf.ko'))
3303
		mwexec('/sbin/kldload if_stf.ko');
3304

    
3305
	$wanif = get_real_interface($interface);
3306
	$ip4address = find_interface_ip($wanif);
3307
	if (!is_ipaddrv4($ip4address)) {
3308
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3309
		return false;
3310
	}
3311
	$hexwanv4 = return_hex_ipv4($ip4address);
3312

    
3313
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3314
		$wancfg['prefix-6rd-v4plen'] = 0;
3315

    
3316
	/* create the long prefix notation for math, save the prefix length */
3317
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3318
	$rd6prefixlen = $rd6prefix[1];
3319
	$brgw = explode('.', $wancfg['gateway-6rd']);
3320
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3321
	$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);
3322
	if (strlen($rd6brgw) < 128)
3323
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3324
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3325
	unset($brgw);
3326
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3327

    
3328
	/* binary presentation of the prefix for all 128 bits. */
3329
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3330

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

    
3338
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3339
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3340

    
3341

    
3342
	/* XXX: need to extend to support variable prefix size for v4 */
3343
	if (!is_module_loaded("if_stf"))
3344
		mwexec("/sbin/kldload if_stf.ko");
3345
	$stfiface = "{$interface}_stf";
3346
	if (does_interface_exist($stfiface))
3347
		pfSense_interface_destroy($stfiface);
3348
	$tmpstfiface = pfSense_interface_create("stf");
3349
	pfSense_interface_rename($tmpstfiface, $stfiface);
3350
	pfSense_interface_flags($stfiface, IFF_LINK2);
3351
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3352
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3353
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32)
3354
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3355
	if ($g['debug'])
3356
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3357

    
3358
	/* write out a default router file */
3359
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3360
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3361

    
3362
	$ip4gateway = get_interface_gateway($interface);
3363
	if (is_ipaddrv4($ip4gateway))
3364
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3365

    
3366
	/* configure dependent interfaces */
3367
	if (!platform_booting())
3368
		link_interface_to_track6($interface, "update");
3369

    
3370
	return 0;
3371
}
3372

    
3373
function interface_6to4_configure($interface = "wan", $wancfg){
3374
	global $config, $g;
3375

    
3376
	/* because this is a tunnel interface we can only function
3377
	 *	with a public IPv4 address on the interface */
3378

    
3379
	if (!is_array($wancfg))
3380
		return;
3381

    
3382
	$wanif = get_real_interface($interface);
3383
	$ip4address = find_interface_ip($wanif);
3384
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3385
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3386
		return false;
3387
	}
3388

    
3389
	/* create the long prefix notation for math, save the prefix length */
3390
	$stfprefixlen = 16;
3391
	$stfprefix = Net_IPv6::uncompress("2002::");
3392
	$stfarr = explode(":", $stfprefix);
3393
	$v4prefixlen = "0";
3394

    
3395
	/* we need the hex form of the interface IPv4 address */
3396
	$ip4arr = explode(".", $ip4address);
3397
	$hexwanv4 = "";
3398
	foreach($ip4arr as $octet)
3399
		$hexwanv4 .= sprintf("%02x", $octet);
3400

    
3401
	/* we need the hex form of the broker IPv4 address */
3402
	$ip4arr = explode(".", "192.88.99.1");
3403
	$hexbrv4 = "";
3404
	foreach($ip4arr as $octet)
3405
		$hexbrv4 .= sprintf("%02x", $octet);
3406

    
3407
	/* binary presentation of the prefix for all 128 bits. */
3408
	$stfprefixbin = "";
3409
	foreach($stfarr as $element) {
3410
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3411
	}
3412
	/* just save the left prefix length bits */
3413
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3414

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

    
3419
	/* for the local subnet too. */
3420
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3421
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3422

    
3423
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3424
	$stfbrarr = array();
3425
	$stfbrbinarr = array();
3426
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3427
	foreach($stfbrbinarr as $bin)
3428
		$stfbrarr[] = dechex(bindec($bin));
3429
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3430

    
3431
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3432
	$stflanarr = array();
3433
	$stflanbinarr = array();
3434
	$stflanbinarr = str_split($stflanbin, 16);
3435
	foreach($stflanbinarr as $bin)
3436
		$stflanarr[] = dechex(bindec($bin));
3437
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3438
	$stflanarr[7] = 1;
3439
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3440

    
3441
	/* setup the stf interface */
3442
	if (!is_module_loaded("if_stf"))
3443
		mwexec("/sbin/kldload if_stf.ko");
3444
	$stfiface = "{$interface}_stf";
3445
	if (does_interface_exist($stfiface))
3446
		pfSense_interface_destroy($stfiface);
3447
	$tmpstfiface = pfSense_interface_create("stf");
3448
	pfSense_interface_rename($tmpstfiface, $stfiface);
3449
	pfSense_interface_flags($stfiface, IFF_LINK2);
3450
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3451

    
3452
	if ($g['debug'])
3453
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3454

    
3455
	/* write out a default router file */
3456
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3457
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3458

    
3459
	$ip4gateway = get_interface_gateway($interface);
3460
	if (is_ipaddrv4($ip4gateway))
3461
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3462

    
3463
	if (!platform_booting())
3464
		link_interface_to_track6($interface, "update");
3465

    
3466
	return 0;
3467
}
3468

    
3469
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3470
	global $config, $g;
3471

    
3472
	if (!is_array($wancfg))
3473
		return;
3474

    
3475
	$wanif = get_real_interface($interface, "inet6");
3476
	$dhcp6cconf = "";
3477
	$dhcp6cconf .= "interface {$wanif} {\n";
3478

    
3479
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3480
	if($wancfg['ipaddrv6'] == "slaac") {
3481
		$dhcp6cconf .= "	information-only;\n";
3482
		$dhcp6cconf .= "	request domain-name-servers;\n";
3483
		$dhcp6cconf .= "	request domain-name;\n";
3484
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3485
		$dhcp6cconf .= "};\n";
3486
	} else {
3487
		$trackiflist = array();
3488
		$iflist = link_interface_to_track6($interface);
3489
		foreach ($iflist as $ifname => $ifcfg) {
3490
			if (is_numeric($ifcfg['track6-prefix-id']))
3491
				$trackiflist[$ifname] = $ifcfg;
3492
		}
3493

    
3494
		/* skip address request if this is set */
3495
		if(!isset($wancfg['dhcp6prefixonly']))
3496
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3497
		if(is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist))
3498
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3499

    
3500
		$dhcp6cconf .= "\trequest domain-name-servers;\n";
3501
		$dhcp6cconf .= "\trequest domain-name;\n";
3502
		$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3503

    
3504
		$dhcp6cconf .= "};\n";
3505

    
3506
		if(!isset($wancfg['dhcp6prefixonly']))
3507
			$dhcp6cconf .= "id-assoc na 0 { };\n";
3508

    
3509
		if(is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3510
			/* Setup the prefix delegation */
3511
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3512
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3513
			if (isset($wancfg['dhcp6-ia-pd-send-hint']))
3514
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3515
			foreach ($trackiflist as $friendly => $ifcfg) {
3516
				if ($g['debug'])
3517
					log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3518
				$realif = get_real_interface($friendly);
3519
				$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3520
				$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3521
				$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3522
				$dhcp6cconf .= "	};\n";
3523
			}
3524
			unset($preflen, $iflist, $ifcfg, $ifname);
3525
			$dhcp6cconf .= "};\n";
3526
		}
3527
		unset($trackiflist);
3528
	}
3529

    
3530
	// DHCP6 Config File Advanced
3531
	if ($wancfg['adv_dhcp6_config_advanced']) { $dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif); }
3532

    
3533
	// DHCP6 Config File Override
3534
	if ($wancfg['adv_dhcp6_config_file_override']) { $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif); }
3535

    
3536
	/* wide-dhcp6c works for now. */
3537
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3538
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3539
		unset($dhcp6cconf);
3540
		return 1;
3541
	}
3542
	unset($dhcp6cconf);
3543

    
3544
	$dhcp6cscript = "#!/bin/sh\n";
3545
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3546
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3547
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3548
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3549
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3550
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3551
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3552
		unset($dhcp6cscript);
3553
		return 1;
3554
	}
3555
	unset($dhcp6cscript);
3556
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3557

    
3558
	$rtsoldscript = "#!/bin/sh\n";
3559
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3560
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3561
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3562
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Recieved RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
3563
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3564
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3565
	$rtsoldscript .= "\t/bin/sleep 1\n";
3566
	$rtsoldscript .= "fi\n";
3567
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3568
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3569
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3570
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3571
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3572
		unset($rtsoldscript);
3573
		return 1;
3574
	}
3575
	unset($rtsoldscript);
3576
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3577

    
3578
	/* accept router advertisements for this interface */
3579
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3580
	log_error("Accept router advertisements on interface {$wanif} ");
3581
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3582

    
3583
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3584
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3585
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3586
		sleep(2);
3587
	}
3588
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3589

    
3590
	/* NOTE: will be called from rtsold invoked script
3591
	 * link_interface_to_track6($interface, "update");
3592
	 */
3593

    
3594
	return 0;
3595
}
3596

    
3597
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3598
	global $g;
3599

    
3600
	$send_options = "";
3601
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3602
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_send_options']);
3603
		foreach ($options as $option) {
3604
			$send_options .= "\tsend " . trim($option) . ";\n";
3605
		}
3606
	}
3607

    
3608
	$request_options = "";
3609
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3610
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_request_options']);
3611
		foreach ($options as $option) {
3612
			$request_options .= "\trequest " . trim($option) . ";\n";
3613
		}
3614
	}
3615

    
3616
	$information_only = "";
3617
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') 
3618
		$information_only = "\tinformation-only;\n";
3619

    
3620
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3621
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '')
3622
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3623

    
3624
	$interface_statement  = "interface";
3625
	$interface_statement .= " {$wanif}";
3626
	$interface_statement .= " {\n";
3627
	$interface_statement .= "$send_options";
3628
	$interface_statement .= "$request_options";
3629
	$interface_statement .= "$information_only";
3630
	$interface_statement .= "$script";
3631
	$interface_statement .= "};\n";
3632

    
3633
	$id_assoc_statement_address = "";
3634
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3635
		$id_assoc_statement_address .= "id-assoc";
3636
		$id_assoc_statement_address .= " na";
3637
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) 
3638
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3639
		$id_assoc_statement_address .= " { ";
3640

    
3641
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') && 
3642
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) || 
3643
			 ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity')) ) {
3644
			$id_assoc_statement_address .= "\n\taddress";
3645
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3646
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3647
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) || 
3648
							($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity') ) 
3649
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3650
			$id_assoc_statement_address .= ";\n";
3651
		}
3652

    
3653
		$id_assoc_statement_address  .= "};\n";
3654
	}
3655

    
3656
	$id_assoc_statement_prefix = "";
3657
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3658
		$id_assoc_statement_prefix .= "id-assoc";
3659
		$id_assoc_statement_prefix .= " pd";
3660
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) 
3661
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3662
		$id_assoc_statement_prefix .= " { ";
3663

    
3664
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') && 
3665
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) || 
3666
			 ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity')) ) {
3667
			$id_assoc_statement_prefix .= "\n\tprefix";
3668
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3669
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3670
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) || 
3671
						  ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity') ) 
3672
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3673
			$id_assoc_statement_prefix .= ";";
3674
		}
3675

    
3676
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3677
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3678
			$id_assoc_statement_prefix .= " {$wanif}";
3679
			$id_assoc_statement_prefix .= " {\n";
3680
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3681
			if ( ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) && 
3682
				 ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128) ) 
3683
				 $id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3684
			$id_assoc_statement_prefix .= "\t};";
3685
		}
3686

    
3687
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') || 
3688
			 (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) ) { 
3689
			$id_assoc_statement_prefix .= "\n";
3690
		}
3691

    
3692
		$id_assoc_statement_prefix  .= "};\n";
3693
	}
3694

    
3695
	$authentication_statement = "";
3696
	if ( ($wancfg['adv_dhcp6_authentication_statement_authname'] != '') && 
3697
		 ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed') ) {
3698
		$authentication_statement .= "authentication";
3699
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
3700
		$authentication_statement .= " {\n";
3701
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
3702
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) 
3703
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
3704
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') 
3705
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
3706
		$authentication_statement .= "};\n";
3707
	}
3708

    
3709
	$key_info_statement = "";
3710
	if ( ($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') && 
3711
		 ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') && 
3712
		 (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) && 
3713
		 ($wancfg['adv_dhcp6_key_info_statement_secret'] != '') ) {
3714
		$key_info_statement .= "keyinfo";
3715
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
3716
		$key_info_statement .= " {\n";
3717
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
3718
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
3719
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
3720
		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'])) 
3721
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
3722
		$key_info_statement .= "};\n";
3723
	}
3724

    
3725
	$dhcp6cconf  = $interface_statement;
3726
	$dhcp6cconf .= $id_assoc_statement_address;
3727
	$dhcp6cconf .= $id_assoc_statement_prefix;
3728
	$dhcp6cconf .= $authentication_statement;
3729
	$dhcp6cconf .= $key_info_statement;
3730

    
3731
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3732

    
3733
	return $dhcp6cconf;
3734
}
3735

    
3736

    
3737
function DHCP6_Config_File_Override($wancfg, $wanif) {
3738

    
3739
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
3740
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3741

    
3742
	return $dhcp6cconf;
3743
}
3744

    
3745

    
3746
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
3747

    
3748
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3749

    
3750
	return $dhcp6cconf;
3751
}
3752

    
3753

    
3754
function interface_dhcp_configure($interface = "wan") {
3755
	global $config, $g;
3756

    
3757
	$wancfg = $config['interfaces'][$interface];
3758
	$wanif = $wancfg['if'];
3759
	if (empty($wancfg))
3760
		$wancfg = array();
3761

    
3762
	/* generate dhclient_wan.conf */
3763
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3764
	if (!$fd) {
3765
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3766
		return 1;
3767
	}
3768

    
3769
	if ($wancfg['dhcphostname']) {
3770
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3771
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3772
	} else {
3773
		$dhclientconf_hostname = "";
3774
	}
3775

    
3776
	$wanif = get_real_interface($interface);
3777
	if (empty($wanif)) {
3778
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3779
		return 0;
3780
	}
3781
	$dhclientconf = "";
3782

    
3783
	$dhclientconf .= <<<EOD
3784
interface "{$wanif}" {
3785
timeout 60;
3786
retry 15;
3787
select-timeout 0;
3788
initial-interval 1;
3789
	{$dhclientconf_hostname}
3790
	script "/sbin/dhclient-script";
3791
EOD;
3792

    
3793
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3794
	$dhclientconf .= <<<EOD
3795

    
3796
	reject {$wancfg['dhcprejectfrom']};
3797
EOD;
3798
}
3799
	$dhclientconf .= <<<EOD
3800

    
3801
}
3802

    
3803
EOD;
3804

    
3805
	// DHCP Config File Advanced
3806
	if ($wancfg['adv_dhcp_config_advanced']) { $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif); }
3807

    
3808
if(is_ipaddr($wancfg['alias-address'])) {
3809
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3810
	$dhclientconf .= <<<EOD
3811
alias {
3812
	interface  "{$wanif}";
3813
	fixed-address {$wancfg['alias-address']};
3814
	option subnet-mask {$subnetmask};
3815
}
3816

    
3817
EOD;
3818
}
3819

    
3820
	// DHCP Config File Override
3821
	if ($wancfg['adv_dhcp_config_file_override']) { $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif); }
3822

    
3823
	fwrite($fd, $dhclientconf);
3824
	fclose($fd);
3825

    
3826
	/* bring wan interface up before starting dhclient */
3827
	if($wanif)
3828
		interfaces_bring_up($wanif);
3829
	else
3830
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3831

    
3832
	/* Make sure dhclient is not running */
3833
	kill_dhclient_process($wanif);
3834

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

    
3838
	return 0;
3839
}
3840

    
3841
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3842

    
3843
	$hostname = "";
3844
	if ($wancfg['dhcphostname'] != '') {
3845
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3846
	}
3847

    
3848
	/* DHCP Protocol Timings */
3849
	$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");
3850
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
3851
		$pt_variable = "{$Protocol_Timing}";
3852
		${$pt_variable} = "";
3853
		if ($wancfg[$Protocol_Timing] != "") {
3854
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
3855
		}
3856
	}
3857

    
3858
	$send_options = "";
3859
	if ($wancfg['adv_dhcp_send_options'] != '') {
3860
		$options = explode(',', $wancfg['adv_dhcp_send_options']);
3861
		foreach ($options as $option) {
3862
			$send_options .= "\tsend " . trim($option) . ";\n";
3863
		}
3864
	}
3865

    
3866
	$request_options = "";
3867
	if ($wancfg['adv_dhcp_request_options'] != '') {
3868
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
3869
	}
3870

    
3871
	$required_options = "";
3872
	if ($wancfg['adv_dhcp_required_options'] != '') {
3873
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
3874
	}
3875

    
3876
	$option_modifiers = "";
3877
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
3878
		$modifiers = explode(',', $wancfg['adv_dhcp_option_modifiers']);
3879
		foreach ($modifiers as $modifier) {
3880
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
3881
		}
3882
	}
3883

    
3884
 	$dhclientconf  = "interface \"{$wanif}\" {\n";
3885
 	$dhclientconf .= "\n";
3886
 	$dhclientconf .= "# DHCP Protocol Timing Values\n";
3887
 	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
3888
 	$dhclientconf .= "{$adv_dhcp_pt_retry}";
3889
 	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
3890
 	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
3891
 	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
3892
 	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
3893
 	$dhclientconf .= "\n";
3894
 	$dhclientconf .= "# DHCP Protocol Options\n";
3895
 	$dhclientconf .= "{$hostname}";
3896
 	$dhclientconf .= "{$send_options}";
3897
 	$dhclientconf .= "{$request_options}";
3898
 	$dhclientconf .= "{$required_options}";
3899
 	$dhclientconf .= "{$option_modifiers}";
3900
 	$dhclientconf .= "\n";
3901
 	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
3902
 	$dhclientconf .= "}\n";
3903

    
3904
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3905

    
3906
	return $dhclientconf;
3907
}
3908

    
3909

    
3910
function DHCP_Config_File_Override($wancfg, $wanif) {
3911

    
3912
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
3913
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3914

    
3915
	return $dhclientconf;
3916
}
3917

    
3918

    
3919
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
3920

    
3921
	/* Apply Interface Substitutions */
3922
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
3923

    
3924
	/* Apply Hostname Substitutions */
3925
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
3926

    
3927
	/* Arrays of MAC Address Types, Cases, Delimiters */
3928
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
3929
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
3930
	$various_mac_cases      = array("U", "L");
3931
	$various_mac_delimiters = array("", " ", ":", "-", ".");
3932

    
3933
	/* Apply MAC Address Substitutions */
3934
	foreach ($various_mac_types as $various_mac_type) {
3935
		foreach ($various_mac_cases as $various_mac_case) {
3936
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
3937

    
3938
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
3939
				if ($res !== false) {
3940

    
3941
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
3942
					if ("$various_mac_case" == "U") $dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
3943
					if ("$various_mac_case" == "L") $dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
3944

    
3945
					if ("$various_mac_type" == "mac_addr_hex") {
3946
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
3947
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
3948
						$dhcpclientconf_mac_hex = "";
3949
						$delimiter = "";
3950
						for($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
3951
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
3952
							$delimiter = ":";
3953
						}
3954
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
3955
					}
3956

    
3957
					/* MAC Address Delimiter Substitutions */
3958
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
3959

    
3960
					/* Apply MAC Address Substitutions */
3961
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
3962
				}
3963
			}
3964
		}
3965
	}
3966

    
3967
	return $dhclientconf;
3968
}
3969

    
3970
function interfaces_group_setup() {
3971
	global $config;
3972

    
3973
	if (!is_array($config['ifgroups']['ifgroupentry']))
3974
		return;
3975

    
3976
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3977
		interface_group_setup($groupar);
3978

    
3979
	return;
3980
}
3981

    
3982
function interface_group_setup(&$groupname /* The parameter is an array */) {
3983
	global $config;
3984

    
3985
	if (!is_array($groupname))
3986
		return;
3987
	$members = explode(" ", $groupname['members']);
3988
	foreach($members as $ifs) {
3989
		$realif = get_real_interface($ifs);
3990
		if ($realif && does_interface_exist($realif))
3991
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3992
	}
3993

    
3994
	return;
3995
}
3996

    
3997
function is_interface_group($if) {
3998
	global $config;
3999

    
4000
	if (is_array($config['ifgroups']['ifgroupentry']))
4001
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4002
			if ($groupentry['ifname'] === $if)
4003
				return true;
4004
		}
4005

    
4006
	return false;
4007
}
4008

    
4009
function interface_group_add_member($interface, $groupname) {
4010
	$interface = get_real_interface($interface);
4011
	if (does_interface_exist($interface))
4012
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4013
}
4014

    
4015
/* COMPAT Function */
4016
function convert_friendly_interface_to_real_interface_name($interface) {
4017
	return get_real_interface($interface);
4018
}
4019

    
4020
/* COMPAT Function */
4021
function get_real_wan_interface($interface = "wan") {
4022
	return get_real_interface($interface);
4023
}
4024

    
4025
/* COMPAT Function */
4026
function get_current_wan_address($interface = "wan") {
4027
	return get_interface_ip($interface);
4028
}
4029

    
4030
/*
4031
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4032
 */
4033
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4034
	global $config;
4035

    
4036
	if (stripos($interface, "_vip")) {
4037
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
4038
			if ($vip['mode'] == "carp")  {
4039
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4040
				return $vip['interface'];
4041
			}
4042
		}
4043
	}
4044

    
4045
	/* XXX: For speed reasons reference directly the interface array */
4046
	$ifdescrs = &$config['interfaces'];
4047
	//$ifdescrs = get_configured_interface_list(false, true);
4048

    
4049
	foreach ($ifdescrs as $if => $ifname) {
4050
		if ($if == $interface || $ifname['if'] == $interface)
4051
			return $if;
4052

    
4053
		if (get_real_interface($if) == $interface)
4054
			return $if;
4055

    
4056
		if ($checkparent == false)
4057
			continue;
4058

    
4059
		$int = get_parent_interface($if, true);
4060
		if (is_array($int)) {
4061
			foreach ($int as $iface) {
4062
				if ($iface == $interface)
4063
					return $if;
4064
			}
4065
		}
4066
	}
4067

    
4068
	if ($interface == "enc0")
4069
		return 'IPsec';
4070
}
4071

    
4072
/* attempt to resolve interface to friendly descr */
4073
function convert_friendly_interface_to_friendly_descr($interface) {
4074
	global $config;
4075

    
4076
	switch ($interface) {
4077
	case "l2tp":
4078
		$ifdesc = "L2TP";
4079
		break;
4080
	case "pptp":
4081
		$ifdesc = "PPTP";
4082
		break;
4083
	case "pppoe":
4084
		$ifdesc = "PPPoE";
4085
		break;
4086
	case "openvpn":
4087
		$ifdesc = "OpenVPN";
4088
		break;
4089
	case "enc0":
4090
	case "ipsec":
4091
	case "IPsec":
4092
		$ifdesc = "IPsec";
4093
		break;
4094
	default:
4095
		if (isset($config['interfaces'][$interface])) {
4096
			if (empty($config['interfaces'][$interface]['descr']))
4097
				$ifdesc = strtoupper($interface);
4098
			else
4099
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4100
			break;
4101
		} else if (stristr($interface, "_vip")) {
4102
			if (is_array($config['virtualip']['vip'])) {
4103
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
4104
					if ($vip['mode'] == "carp")  {
4105
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4106
							return "{$vip['subnet']} - {$vip['descr']}";
4107
					}
4108
				}
4109
			}
4110
		} else {
4111
			/* if list */
4112
			$ifdescrs = get_configured_interface_with_descr(false, true);
4113
			foreach ($ifdescrs as $if => $ifname) {
4114
				if ($if == $interface || $ifname == $interface)
4115
					return $ifname;
4116
			}
4117
		}
4118
		break;
4119
	}
4120

    
4121
	return $ifdesc;
4122
}
4123

    
4124
function convert_real_interface_to_friendly_descr($interface) {
4125

    
4126
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4127

    
4128
	if (!empty($ifdesc))
4129
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4130

    
4131
	return $interface;
4132
}
4133

    
4134
/*
4135
 *  get_parent_interface($interface):
4136
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4137
 *				or virtual interface (i.e. vlan)
4138
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4139
 *			-- returns $interface passed in if $interface parent is not found
4140
 *			-- returns empty array if an invalid interface is passed
4141
 *	(Only handles ppps and vlans now.)
4142
 */
4143
function get_parent_interface($interface, $avoidrecurse = false) {
4144
	global $config;
4145

    
4146
	$parents = array();
4147
	//Check that we got a valid interface passed
4148
	$realif = get_real_interface($interface);
4149
	if ($realif == NULL)
4150
		return $parents;
4151

    
4152
	// If we got a real interface, find it's friendly assigned name
4153
	if ($interface == $realif && $avoidrecurse == false)
4154
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4155

    
4156
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4157
		$ifcfg = $config['interfaces'][$interface];
4158
		switch ($ifcfg['ipaddr']) {
4159
			case "ppp":
4160
			case "pppoe":
4161
			case "pptp":
4162
			case "l2tp":
4163
				if (empty($parents))
4164
					if (is_array($config['ppps']['ppp']))
4165
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4166
							if ($ifcfg['if'] == $ppp['if']) {
4167
								$ports = explode(',', $ppp['ports']);
4168
								foreach ($ports as $pid => $parent_if)
4169
									$parents[$pid] = get_real_interface($parent_if);
4170
								break;
4171
							}
4172
						}
4173
				break;
4174
			case "dhcp":
4175
			case "static":
4176
			default:
4177
				// Handle _vlans
4178
				if (strpos($realif, '_vlan') !== FALSE) {
4179
					if (is_array($config['vlans']['vlan'])) {
4180
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4181
							if ($ifcfg['if'] == $vlan['vlanif']) {
4182
								$parents[0] = $vlan['if'];
4183
								break;
4184
							}
4185
						}
4186
					}
4187
				}
4188
				break;
4189
		}
4190
	}
4191

    
4192
	if (empty($parents))
4193
		$parents[0] = $realif;
4194

    
4195
	return $parents;
4196
}
4197

    
4198
function interface_is_wireless_clone($wlif) {
4199
	if(!stristr($wlif, "_wlan")) {
4200
		return false;
4201
	} else {
4202
		return true;
4203
	}
4204
}
4205

    
4206
function interface_get_wireless_base($wlif) {
4207
	if(!stristr($wlif, "_wlan")) {
4208
		return $wlif;
4209
	} else {
4210
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4211
	}
4212
}
4213

    
4214
function interface_get_wireless_clone($wlif) {
4215
	if(!stristr($wlif, "_wlan")) {
4216
		return $wlif . "_wlan0";
4217
	} else {
4218
		return $wlif;
4219
	}
4220
}
4221

    
4222
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4223
	global $config, $g;
4224

    
4225
	$wanif = NULL;
4226

    
4227
	switch ($interface) {
4228
	case "l2tp":
4229
		$wanif = "l2tp";
4230
		break;
4231
	case "pptp":
4232
		$wanif = "pptp";
4233
		break;
4234
	case "pppoe":
4235
		$wanif = "pppoe";
4236
		break;
4237
	case "openvpn":
4238
		$wanif = "openvpn";
4239
		break;
4240
	case "ipsec":
4241
	case "enc0":
4242
		$wanif = "enc0";
4243
		break;
4244
	case "ppp":
4245
		$wanif = "ppp";
4246
		break;
4247
	default:
4248
		// If a real interface was already passed simply
4249
		// pass the real interface back.  This encourages
4250
		// the usage of this function in more cases so that
4251
		// we can combine logic for more flexibility.
4252
		if(does_interface_exist($interface, $flush)) {
4253
			$wanif = $interface;
4254
			break;
4255
		}
4256

    
4257
		if (empty($config['interfaces'][$interface]))
4258
			break;
4259

    
4260
		$cfg = &$config['interfaces'][$interface];
4261

    
4262
		if ($family == "inet6") {
4263
			switch ($cfg['ipaddrv6']) {
4264
			case "6rd":
4265
			case "6to4":
4266
				$wanif = "{$interface}_stf";
4267
				break;
4268
			case 'pppoe':
4269
			case 'ppp':
4270
			case 'l2tp':
4271
			case 'pptp':
4272
				if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4273
					$wanif = interface_get_wireless_clone($cfg['if']);
4274
				else
4275
					$wanif = $cfg['if'];
4276
				break;
4277
			default:
4278
				switch ($cfg['ipaddr']) {
4279
				case 'pppoe':
4280
				case 'ppp':
4281
				case 'l2tp':
4282
				case 'pptp':
4283
					if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false)
4284
						$wanif = $cfg['if'];
4285
					else {
4286
						$parents = get_parent_interface($interface);
4287
						if (!empty($parents[0]))
4288
							$wanif = $parents[0];
4289
						else
4290
							$wanif = $cfg['if'];
4291
					}
4292
					break;
4293
				default:
4294
					if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4295
						$wanif = interface_get_wireless_clone($cfg['if']);
4296
					else
4297
						$wanif = $cfg['if'];
4298
					break;
4299
				}
4300
				break;
4301
			}
4302
		} else {
4303
			// Wireless cloned NIC support (FreeBSD 8+)
4304
			// interface name format: $parentnic_wlanparentnic#
4305
			// example: ath0_wlan0
4306
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4307
				$wanif = interface_get_wireless_clone($cfg['if']);
4308
			else
4309
				$wanif = $cfg['if'];
4310
		}
4311
		break;
4312
	}
4313

    
4314
	return $wanif;
4315
}
4316

    
4317
/* Guess the physical interface by providing a IP address */
4318
function guess_interface_from_ip($ipaddress) {
4319

    
4320
	$family = '';
4321
	if(is_ipaddrv4($ipaddress))
4322
		$family = 'inet';
4323
	if (empty($family) && is_ipaddrv6($ipaddress))
4324
		$family = 'inet6';
4325

    
4326
	if (empty($family))
4327
		return false;
4328

    
4329
	/* create a route table we can search */
4330
	$output = '';
4331
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4332
	$output[0] = trim($output[0], " \n");
4333
	if (!empty($output[0]))
4334
		return $output[0];
4335

    
4336
	return false;
4337
}
4338

    
4339
/*
4340
 * find_ip_interface($ip): return the interface where an ip is defined
4341
 *   (or if $bits is specified, where an IP within the subnet is defined)
4342
 */
4343
function find_ip_interface($ip, $bits = null) {
4344
	if (!is_ipaddr($ip))
4345
		return false;
4346

    
4347
	$isv6ip = is_ipaddrv6($ip);
4348

    
4349
	/* if list */
4350
	$ifdescrs = get_configured_interface_list();
4351

    
4352
	foreach ($ifdescrs as $ifdescr => $ifname) {
4353
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4354
		if (is_null($ifip))
4355
			continue;
4356
		if (is_null($bits)) {
4357
			if ($ip == $ifip) {
4358
				$int = get_real_interface($ifname);
4359
				return $int;
4360
			}
4361
		}
4362
		else {
4363
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4364
				$int = get_real_interface($ifname);
4365
				return $int;
4366
			}
4367
		}
4368
	}
4369

    
4370
	return false;
4371
}
4372

    
4373
/*
4374
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4375
 *   (or if $bits is specified, where an IP within the subnet is found)
4376
 */
4377
function find_virtual_ip_alias($ip, $bits = null) {
4378
	global $config;
4379

    
4380
	if (!is_array($config['virtualip']['vip'])) {
4381
		return false;
4382
	}
4383
	if (!is_ipaddr($ip))
4384
		return false;
4385

    
4386
	$isv6ip = is_ipaddrv6($ip);
4387

    
4388
	foreach ($config['virtualip']['vip'] as $vip) {
4389
		if ($vip['mode'] === "ipalias") {
4390
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4391
				continue;
4392
			if (is_null($bits)) {
4393
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4394
					return $vip;
4395
				}
4396
			}
4397
			else {
4398
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4399
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4400
					return $vip;
4401
				}
4402
			}
4403
		}
4404
	}
4405
	return false;
4406
}
4407

    
4408
/*
4409
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4410
 */
4411
function find_number_of_created_carp_interfaces() {
4412
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4413
}
4414

    
4415
/*
4416
 * find_carp_interface($ip): return the carp interface where an ip is defined
4417
 */
4418
function find_carp_interface($ip) {
4419
	global $config;
4420
	if (is_array($config['virtualip']['vip'])) {
4421
		foreach ($config['virtualip']['vip'] as $vip) {
4422
			if ($vip['mode'] == "carp") {
4423
				if(is_ipaddrv4($ip)) {
4424
					$carp_ip = get_interface_ip($vip['interface']);
4425
				}
4426
				if(is_ipaddrv6($ip)) {
4427
					$carp_ip = get_interface_ipv6($vip['interface']);
4428
				}
4429
				exec("/sbin/ifconfig", $output, $return);
4430
				foreach($output as $line) {
4431
					$elements = preg_split("/[ ]+/i", $line);
4432
					if(strstr($elements[0], "vip"))
4433
						$curif = str_replace(":", "", $elements[0]);
4434
					if(stristr($line, $ip)) {
4435
						$if = $curif;
4436
						continue;
4437
					}
4438
				}
4439

    
4440
				if ($if)
4441
					return $if;
4442
			}
4443
		}
4444
	}
4445
}
4446

    
4447
function link_carp_interface_to_parent($interface) {
4448
	global $config;
4449

    
4450
	if (empty($interface))
4451
		return;
4452

    
4453
	$carp_ip = get_interface_ip($interface);
4454
	$carp_ipv6 = get_interface_ipv6($interface);
4455

    
4456
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4457
		return;
4458

    
4459
	/* if list */
4460
	$ifdescrs = get_configured_interface_list();
4461
	foreach ($ifdescrs as $ifdescr => $ifname) {
4462
		/* check IPv4 */
4463
		if(is_ipaddrv4($carp_ip)) {
4464
			$interfaceip = get_interface_ip($ifname);
4465
			$subnet_bits = get_interface_subnet($ifname);
4466
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4467
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4468
				return $ifname;
4469
		}
4470
		/* Check IPv6 */
4471
		if(is_ipaddrv6($carp_ipv6)) {
4472
			$interfaceipv6 = get_interface_ipv6($ifname);
4473
			$prefixlen = get_interface_subnetv6($ifname);
4474
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4475
				return $ifname;
4476
		}
4477
	}
4478
	return "";
4479
}
4480

    
4481

    
4482
/****f* interfaces/link_ip_to_carp_interface
4483
 * NAME
4484
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4485
 * INPUTS
4486
 *   $ip
4487
 * RESULT
4488
 *   $carp_ints
4489
 ******/
4490
function link_ip_to_carp_interface($ip) {
4491
	global $config;
4492

    
4493
	if (!is_ipaddr($ip))
4494
		return;
4495

    
4496
	$carp_ints = "";
4497
	if (is_array($config['virtualip']['vip'])) {
4498
		$first = 0;
4499
		$carp_int = array();
4500
		foreach ($config['virtualip']['vip'] as $vip) {
4501
			if ($vip['mode'] == "carp") {
4502
				$carp_ip = $vip['subnet'];
4503
				$carp_sn = $vip['subnet_bits'];
4504
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4505
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4506
					$carp_int[] = get_real_interface($vip['interface']);
4507
				}
4508
			}
4509
		}
4510
		if (!empty($carp_int))
4511
			$carp_ints = implode(" ", array_unique($carp_int));
4512
	}
4513

    
4514
	return $carp_ints;
4515
}
4516

    
4517
function link_interface_to_track6($int, $action = "") {
4518
	global $config;
4519

    
4520
	if (empty($int))
4521
		return;
4522

    
4523
	if (is_array($config['interfaces'])) {
4524
		$list = array();
4525
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4526
			if (!isset($ifcfg['enable']))
4527
				continue;
4528
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4529
				if ($action == "update")
4530
					interface_track6_configure($ifname, $ifcfg);
4531
				else if ($action == "")
4532
					$list[$ifname] = $ifcfg;
4533
			}
4534
		}
4535
		return $list;
4536
	}
4537
}
4538

    
4539
function interface_find_child_cfgmtu($realiface) {
4540
	global $config;
4541

    
4542
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
4543
	$vlans = link_interface_to_vlans($realiface);
4544
	$bridge = link_interface_to_bridge($realiface);
4545
	if (!empty($interface)) {
4546
		$gifs = link_interface_to_gif($interface);
4547
		$gres = link_interface_to_gre($interface);
4548
	} else {
4549
		$gifs = array();
4550
		$gres = array();
4551
	}
4552

    
4553
	$mtu = 0;
4554
	if (is_array($vlans)) {
4555
		foreach ($vlans as $vlan) {
4556
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4557
			if (empty($ifass))
4558
				continue;
4559
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4560
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu)
4561
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4562
			}
4563
		}
4564
	}
4565
	if (is_array($gifs)) {
4566
		foreach ($gifs as $vlan) {
4567
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['gifif']);
4568
			if (empty($ifass))
4569
				continue;
4570
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4571
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu)
4572
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4573
			}
4574
		}
4575
	}
4576
	if (is_array($gres)) {
4577
		foreach ($gres as $vlan) {
4578
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['greif']);
4579
			if (empty($ifass))
4580
				continue;
4581
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4582
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu)
4583
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4584
			}
4585
		}
4586
	}
4587
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
4588
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
4589
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu)
4590
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
4591
	}
4592
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
4593

    
4594
	return $mtu;
4595
}
4596

    
4597
function link_interface_to_vlans($int, $action = "") {
4598
	global $config;
4599

    
4600
	if (empty($int))
4601
		return;
4602

    
4603
	if (is_array($config['vlans']['vlan'])) {
4604
		$ifaces = array();
4605
		foreach ($config['vlans']['vlan'] as $vlan) {
4606
			if ($int == $vlan['if']) {
4607
				if ($action == "update") {
4608
					interfaces_bring_up($int);
4609
				} else
4610
					$ifaces[$vlan['tag']] = $vlan;
4611
			}
4612
		}
4613
		if (!empty($ifaces))
4614
			return $ifaces;
4615
	}
4616
}
4617

    
4618
function link_interface_to_vips($int, $action = "") {
4619
	global $config;
4620

    
4621
	if (is_array($config['virtualip']['vip'])) {
4622
		$result = array();
4623
		foreach ($config['virtualip']['vip'] as $vip) {
4624
			if ($int == $vip['interface']) {
4625
				if ($action == "update")
4626
					interfaces_vips_configure($int);
4627
				else
4628
					$result[] = $vip;
4629
			}
4630
		}
4631
		return $result;
4632
	}
4633
}
4634

    
4635
/****f* interfaces/link_interface_to_bridge
4636
 * NAME
4637
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4638
 * INPUTS
4639
 *   $ip
4640
 * RESULT
4641
 *   bridge[0-99]
4642
 ******/
4643
function link_interface_to_bridge($int) {
4644
	global $config;
4645

    
4646
	if (is_array($config['bridges']['bridged'])) {
4647
		foreach ($config['bridges']['bridged'] as $bridge) {
4648
			if (in_array($int, explode(',', $bridge['members'])))
4649
				return "{$bridge['bridgeif']}";
4650
		}
4651
	}
4652
}
4653

    
4654
function link_interface_to_group($int) {
4655
	global $config;
4656

    
4657
	$result = array();
4658

    
4659
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4660
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4661
			if (in_array($int, explode(" ", $group['members'])))
4662
				$result[$group['ifname']] = $int;
4663
		}
4664
	}
4665

    
4666
	return $result;
4667
}
4668

    
4669
function link_interface_to_gre($interface) {
4670
	global $config;
4671

    
4672
	$result = array();
4673

    
4674
	if (is_array($config['gres']['gre'])) {
4675
		foreach ($config['gres']['gre'] as $gre)
4676
			if($gre['if'] == $interface)
4677
				$result[] = $gre;
4678
	}
4679

    
4680
	return $result;
4681
}
4682

    
4683
function link_interface_to_gif($interface) {
4684
	global $config;
4685

    
4686
	$result = array();
4687

    
4688
	if (is_array($config['gifs']['gif'])) {
4689
		foreach ($config['gifs']['gif'] as $gif)
4690
			if($gif['if'] == $interface)
4691
				$result[] = $gif;
4692
	}
4693

    
4694
	return $result;
4695
}
4696

    
4697
/*
4698
 * find_interface_ip($interface): return the interface ip (first found)
4699
 */
4700
function find_interface_ip($interface, $flush = false) {
4701
	global $interface_ip_arr_cache;
4702
	global $interface_sn_arr_cache;
4703

    
4704
	$interface = str_replace("\n", "", $interface);
4705

    
4706
	if (!does_interface_exist($interface))
4707
		return;
4708

    
4709
	/* Setup IP cache */
4710
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4711
		$ifinfo = pfSense_get_interface_addresses($interface);
4712
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4713
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4714
	}
4715

    
4716
	return $interface_ip_arr_cache[$interface];
4717
}
4718

    
4719
/*
4720
 * find_interface_ipv6($interface): return the interface ip (first found)
4721
 */
4722
function find_interface_ipv6($interface, $flush = false) {
4723
	global $interface_ipv6_arr_cache;
4724
	global $interface_snv6_arr_cache;
4725
	global $config;
4726

    
4727
	$interface = trim($interface);
4728
	$interface = get_real_interface($interface);
4729

    
4730
	if (!does_interface_exist($interface))
4731
		return;
4732

    
4733
	/* Setup IP cache */
4734
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4735
		$ifinfo = pfSense_get_interface_addresses($interface);
4736
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4737
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4738
	}
4739

    
4740
	return $interface_ipv6_arr_cache[$interface];
4741
}
4742

    
4743
/*
4744
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4745
 */
4746
function find_interface_ipv6_ll($interface, $flush = false) {
4747
	global $interface_llv6_arr_cache;
4748
	global $config;
4749

    
4750
	$interface = str_replace("\n", "", $interface);
4751

    
4752
	if (!does_interface_exist($interface))
4753
		return;
4754

    
4755
	/* Setup IP cache */
4756
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4757
		$ifinfo = pfSense_getall_interface_addresses($interface);
4758
		foreach($ifinfo as $line) {
4759
			if (strstr($line, ":")) {
4760
				$parts = explode("/", $line);
4761
				if(is_linklocal($parts[0])) {
4762
					$ifinfo['linklocal'] = $parts[0];
4763
				}
4764
			}
4765
		}
4766
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4767
	}
4768
	return $interface_llv6_arr_cache[$interface];
4769
}
4770

    
4771
function find_interface_subnet($interface, $flush = false) {
4772
	global $interface_sn_arr_cache;
4773
	global $interface_ip_arr_cache;
4774

    
4775
	$interface = str_replace("\n", "", $interface);
4776
	if (does_interface_exist($interface) == false)
4777
		return;
4778

    
4779
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4780
		$ifinfo = pfSense_get_interface_addresses($interface);
4781
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4782
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4783
	}
4784

    
4785
	return $interface_sn_arr_cache[$interface];
4786
}
4787

    
4788
function find_interface_subnetv6($interface, $flush = false) {
4789
	global $interface_snv6_arr_cache;
4790
	global $interface_ipv6_arr_cache;
4791

    
4792
	$interface = str_replace("\n", "", $interface);
4793
	if (does_interface_exist($interface) == false)
4794
		return;
4795

    
4796
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4797
		$ifinfo = pfSense_get_interface_addresses($interface);
4798
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4799
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4800
	}
4801

    
4802
	return $interface_snv6_arr_cache[$interface];
4803
}
4804

    
4805
function ip_in_interface_alias_subnet($interface, $ipalias) {
4806
	global $config;
4807

    
4808
	if (empty($interface) || !is_ipaddr($ipalias))
4809
		return false;
4810
	if (is_array($config['virtualip']['vip'])) {
4811
		foreach ($config['virtualip']['vip'] as $vip) {
4812
			switch ($vip['mode']) {
4813
			case "ipalias":
4814
				if ($vip['interface'] <> $interface)
4815
					break;
4816
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4817
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4818
					return true;
4819
				break;
4820
			}
4821
		}
4822
	}
4823

    
4824
	return false;
4825
}
4826

    
4827
function get_interface_ip($interface = "wan") {
4828
	
4829
	$realif = get_failover_interface($interface);
4830
	if (empty($realif)) {
4831
		if (strstr($interface, "_vip"))
4832
			return get_configured_carp_interface_list($interface);
4833
		else
4834
			return null;
4835
	}
4836
	
4837
	if (strstr($realif, "_vip")) {
4838
		return get_configured_carp_interface_list($realif);
4839
	}
4840

    
4841
	$curip = find_interface_ip($realif);
4842
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4843
		return $curip;
4844
	else
4845
		return null;
4846
}
4847

    
4848
function get_interface_ipv6($interface = "wan", $flush = false) {
4849
	global $config;
4850

    
4851
	$realif = get_failover_interface($interface, "inet6");
4852
	if (empty($realif)) {
4853
		if (strstr($interface, "_vip"))
4854
			return get_configured_carp_interface_list($interface, "inet6");
4855
		else
4856
			return null;
4857
	}
4858

    
4859
	if (is_array($config['interfaces'][$interface])) {
4860
		switch ($config['interfaces'][$interface]['ipaddr']) {
4861
		case 'pppoe':
4862
		case 'l2tp':
4863
		case 'pptp':
4864
		case 'ppp':
4865
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4866
				$realif = get_real_interface($interface, "inet6", false);
4867
			break;
4868
		}
4869
	}
4870

    
4871
	$curip = find_interface_ipv6($realif, $flush);
4872
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4873
		return $curip;
4874
	else {
4875
		/*
4876
		 * NOTE: On the case when only the prefix is requested,
4877
		 * the communication on WAN will be done over link-local.
4878
		 */
4879
		if (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4880
			$curip = find_interface_ipv6_ll($realif, $flush);
4881
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
4882
				return $curip;
4883
			}
4884
		}
4885
	}
4886
	return null;
4887
}
4888

    
4889
function get_interface_linklocal($interface = "wan") {
4890

    
4891
	$realif = get_failover_interface($interface, "inet6");
4892
	if (!$realif) {
4893
		if (strstr($interface, "_vip")) {
4894
			list($interface, $vhid) = explode("_vip", $interface);
4895
			$realif = get_real_interface($interface);
4896
		} else
4897
			return null;
4898
	}
4899

    
4900
	$curip = find_interface_ipv6_ll($realif);
4901
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4902
		return $curip;
4903
	else
4904
		return null;
4905
}
4906

    
4907
function get_interface_subnet($interface = "wan") {
4908
	$realif = get_real_interface($interface);
4909
	if (empty($realif)) {
4910
		if (strstr($interface, "_vip")) {
4911
			return get_configured_carp_interface_list($interface, 'inet', 'subnet');
4912
		} else
4913
			return null;
4914
	}
4915

    
4916
	$cursn = find_interface_subnet($realif);
4917
	if (!empty($cursn))
4918
		return $cursn;
4919

    
4920
	return null;
4921
}
4922

    
4923
function get_interface_subnetv6($interface = "wan") {
4924
	global $config;
4925

    
4926
	$realif = get_real_interface($interface, "inet6");
4927
	if (empty($realif)) {
4928
		if (strstr($interface, "_vip")) {
4929
			return get_configured_carp_interface_list($interface, 'inet6', 'subnet');
4930
		} else
4931
			return null;
4932
	}
4933

    
4934
	$cursn = find_interface_subnetv6($realif);
4935
	if (!empty($cursn))
4936
		return $cursn;
4937

    
4938
	return null;
4939
}
4940

    
4941
/* return outside interfaces with a gateway */
4942
function get_interfaces_with_gateway() {
4943
	global $config;
4944

    
4945
	$ints = array();
4946

    
4947
	/* loop interfaces, check config for outbound */
4948
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4949
		switch ($ifname['ipaddr']) {
4950
			case "dhcp":
4951
			case "pppoe":
4952
			case "pptp":
4953
			case "l2tp":
4954
			case "ppp":
4955
				$ints[$ifdescr] = $ifdescr;
4956
			break;
4957
			default:
4958
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
4959
				    !empty($ifname['gateway']))
4960
					$ints[$ifdescr] = $ifdescr;
4961
			break;
4962
		}
4963
	}
4964
	return $ints;
4965
}
4966

    
4967
/* return true if interface has a gateway */
4968
function interface_has_gateway($friendly) {
4969
	global $config;
4970

    
4971
	if (!empty($config['interfaces'][$friendly])) {
4972
		$ifname = &$config['interfaces'][$friendly];
4973
		switch ($ifname['ipaddr']) {
4974
			case "dhcp":
4975
			case "pppoe":
4976
			case "pptp":
4977
			case "l2tp":
4978
			case "ppp":
4979
				return true;
4980
			break;
4981
			default:
4982
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4983
					return true;
4984
				$tunnelif = substr($ifname['if'], 0, 3);
4985
				if ($tunnelif == "gif" || $tunnelif == "gre")
4986
					return true;
4987
				if (!empty($ifname['gateway']))
4988
					return true;
4989
			break;
4990
		}
4991
	}
4992

    
4993
	return false;
4994
}
4995

    
4996
/* return true if interface has a gateway */
4997
function interface_has_gatewayv6($friendly) {
4998
	global $config;
4999

    
5000
	if (!empty($config['interfaces'][$friendly])) {
5001
		$ifname = &$config['interfaces'][$friendly];
5002
		switch ($ifname['ipaddrv6']) {
5003
			case "slaac":
5004
			case "dhcp6":
5005
			case "6to4":
5006
			case "6rd":
5007
				return true;
5008
				break;
5009
			default:
5010
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
5011
					return true;
5012
				$tunnelif = substr($ifname['if'], 0, 3);
5013
				if ($tunnelif == "gif" || $tunnelif == "gre")
5014
					return true;
5015
				if (!empty($ifname['gatewayv6']))
5016
					return true;
5017
				break;
5018
		}
5019
	}
5020

    
5021
	return false;
5022
}
5023

    
5024
/****f* interfaces/is_altq_capable
5025
 * NAME
5026
 *   is_altq_capable - Test if interface is capable of using ALTQ
5027
 * INPUTS
5028
 *   $int            - string containing interface name
5029
 * RESULT
5030
 *   boolean         - true or false
5031
 ******/
5032

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

    
5047
	$int_family = remove_ifindex($int);
5048

    
5049
	if (in_array($int_family, $capable))
5050
		return true;
5051
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
5052
		return true;
5053
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
5054
		return true;
5055
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
5056
		return true;
5057
	else
5058
		return false;
5059
}
5060

    
5061
/****f* interfaces/is_interface_wireless
5062
 * NAME
5063
 *   is_interface_wireless - Returns if an interface is wireless
5064
 * RESULT
5065
 *   $tmp       - Returns if an interface is wireless
5066
 ******/
5067
function is_interface_wireless($interface) {
5068
	global $config, $g;
5069

    
5070
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5071
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
5072
		if (preg_match($g['wireless_regex'], $interface)) {
5073
			if (isset($config['interfaces'][$friendly]))
5074
				$config['interfaces'][$friendly]['wireless'] = array();
5075
			return true;
5076
		}
5077
		return false;
5078
	} else
5079
		return true;
5080
}
5081

    
5082
function get_wireless_modes($interface) {
5083
	/* return wireless modes and channels */
5084
	$wireless_modes = array();
5085

    
5086
	$cloned_interface = get_real_interface($interface);
5087

    
5088
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5089
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5090
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5091
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5092

    
5093
		$interface_channels = "";
5094
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5095
		$interface_channel_count = count($interface_channels);
5096

    
5097
		$c = 0;
5098
		while ($c < $interface_channel_count) {
5099
			$channel_line = explode(",", $interface_channels["$c"]);
5100
			$wireless_mode = trim($channel_line[0]);
5101
			$wireless_channel = trim($channel_line[1]);
5102
			if(trim($wireless_mode) != "") {
5103
				/* if we only have 11g also set 11b channels */
5104
				if($wireless_mode == "11g") {
5105
					if(!isset($wireless_modes["11b"]))
5106
						$wireless_modes["11b"] = array();
5107
				} else if($wireless_mode == "11g ht") {
5108
					if(!isset($wireless_modes["11b"]))
5109
						$wireless_modes["11b"] = array();
5110
					if(!isset($wireless_modes["11g"]))
5111
						$wireless_modes["11g"] = array();
5112
					$wireless_mode = "11ng";
5113
				} else if($wireless_mode == "11a ht") {
5114
					if(!isset($wireless_modes["11a"]))
5115
						$wireless_modes["11a"] = array();
5116
					$wireless_mode = "11na";
5117
				}
5118
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5119
			}
5120
			$c++;
5121
		}
5122
	}
5123
	return($wireless_modes);
5124
}
5125

    
5126
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5127
function get_wireless_channel_info($interface) {
5128
	$wireless_channels = array();
5129

    
5130
	$cloned_interface = get_real_interface($interface);
5131

    
5132
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5133
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5134
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5135
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5136

    
5137
		$interface_channels = "";
5138
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5139

    
5140
		foreach ($interface_channels as $channel_line) {
5141
			$channel_line = explode(",", $channel_line);
5142
			if(!isset($wireless_channels[$channel_line[0]]))
5143
				$wireless_channels[$channel_line[0]] = $channel_line;
5144
		}
5145
	}
5146
	return($wireless_channels);
5147
}
5148

    
5149
/****f* interfaces/get_interface_mtu
5150
 * NAME
5151
 *   get_interface_mtu - Return the mtu of an interface
5152
 * RESULT
5153
 *   $tmp       - Returns the mtu of an interface
5154
 ******/
5155
function get_interface_mtu($interface) {
5156
	$mtu = pfSense_interface_getmtu($interface);
5157
	return $mtu['mtu'];
5158
}
5159

    
5160
function get_interface_mac($interface) {
5161

    
5162
	$macinfo = pfSense_get_interface_addresses($interface);
5163
	return $macinfo["macaddr"];
5164
}
5165

    
5166
/****f* pfsense-utils/generate_random_mac_address
5167
 * NAME
5168
 *   generate_random_mac - generates a random mac address
5169
 * INPUTS
5170
 *   none
5171
 * RESULT
5172
 *   $mac - a random mac address
5173
 ******/
5174
function generate_random_mac_address() {
5175
	$mac = "02";
5176
	for($x=0; $x<5; $x++)
5177
		$mac .= ":" . dechex(rand(16, 255));
5178
	return $mac;
5179
}
5180

    
5181
/****f* interfaces/is_jumbo_capable
5182
 * NAME
5183
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5184
 * INPUTS
5185
 *   $int             - string containing interface name
5186
 * RESULT
5187
 *   boolean          - true or false
5188
 ******/
5189
function is_jumbo_capable($iface) {
5190
	$iface = trim($iface);
5191
	$capable = pfSense_get_interface_addresses($iface);
5192

    
5193
	if (isset($capable['caps']['vlanmtu']))
5194
		return true;
5195

    
5196
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5197
	if (substr($iface, 0, 4) == "lagg")
5198
		return true;
5199

    
5200
	return false;
5201
}
5202

    
5203
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5204
	global $g;
5205

    
5206
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5207

    
5208
	if(!empty($iface) && !empty($pppif)){
5209
		$cron_cmd = <<<EOD
5210
#!/bin/sh
5211
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5212
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5213

    
5214
EOD;
5215

    
5216
		@file_put_contents($cron_file, $cron_cmd);
5217
		chmod($cron_file, 0755);
5218
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5219
	} else
5220
		unlink_if_exists($cron_file);
5221
}
5222

    
5223
function get_interface_default_mtu($type = "ethernet") {
5224
	switch ($type) {
5225
	case "gre":
5226
		return 1476;
5227
		break;
5228
	case "gif":
5229
		return 1280;
5230
		break;
5231
	case "tun":
5232
	case "vlan":
5233
	case "tap":
5234
	case "ethernet":
5235
	default:
5236
		return 1500;
5237
		break;
5238
	}
5239

    
5240
	/* Never reached */
5241
	return 1500;
5242
}
5243

    
5244
function get_vip_descr($ipaddress) {
5245
	global $config;
5246

    
5247
	foreach ($config['virtualip']['vip'] as $vip) {
5248
		if ($vip['subnet'] == $ipaddress) {
5249
			return ($vip['descr']);
5250
		}
5251
	}
5252
	return "";
5253
}
5254

    
5255
function interfaces_staticarp_configure($if) {
5256
	global $config, $g;
5257
	if(isset($config['system']['developerspew'])) {
5258
		$mt = microtime();
5259
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5260
	}
5261

    
5262
	$ifcfg = $config['interfaces'][$if];
5263

    
5264
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5265
		return 0;
5266

    
5267
	/* Enable staticarp, if enabled */
5268
	if(isset($config['dhcpd'][$if]['staticarp'])) {
5269
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
5270
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5271
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5272

    
5273
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5274
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5275

    
5276
			}
5277

    
5278
		}
5279
	} else {
5280
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
5281
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5282
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5283
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5284
				if (isset($arpent['arp_table_static_entry'])) {
5285
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5286
				}
5287
			}
5288
		}
5289
	}
5290

    
5291
	return 0;
5292
}
5293

    
5294
function get_failover_interface($interface, $family = "all") {
5295
	global $config;
5296

    
5297
	/* shortcut to get_real_interface if we find it in the config */
5298
	if (is_array($config['interfaces'][$interface])) {
5299
		return get_real_interface($interface, $family);
5300
	}
5301

    
5302
	/* compare against gateway groups */
5303
	$a_groups = return_gateway_groups_array();
5304
	if (is_array($a_groups[$interface])) {
5305
		/* we found a gateway group, fetch the interface or vip */
5306
		if ($a_groups[$interface][0]['vip'] <> "")
5307
			return $a_groups[$interface][0]['vip'];
5308
		else
5309
			return $a_groups[$interface][0]['int'];
5310
	}
5311
	/* fall through to get_real_interface */
5312
	/* XXX: Really needed? */
5313
	return get_real_interface($interface, $family);
5314
}
5315

    
5316
function remove_ifindex($ifname) {
5317
	return preg_replace("/[0-9]+$/", "", $ifname);
5318
}
5319

    
5320
?>
(26-26/68)