Project

General

Profile

Download (144 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
		$realif = "{$vip['interface']}_vip{$vip['vhid']}";
102
		if (!does_interface_exist($realif)) {
103
			return false;
104
		}
105
		break;
106
	case "ipalias":
107
		$realif = get_real_interface($vip['interface']);
108
		if (!does_interface_exist($realif)) {
109
			return false;
110
		}
111
		break;
112
	case "proxyarp":
113
		/* XXX: Implement this */
114
	default:
115
		return false;
116
	}
117

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

    
124
	return false;
125
}
126

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

    
130
	$found = false;
131
	if (!empty($config['pptpd']) &&
132
		$config['pptpd']['mode'] == "server")
133
		$found = true;
134
	if ($found == false && !empty($config['l2tp']) &&
135
		$config['l2tp']['mode'] == "server")
136
		$found = true;
137
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
138
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
139
			if ($pppoe['mode'] != "server")
140
				continue;
141
			if ($pppoe['interface'] == $interface)
142
				$found = true;
143
				break;
144
		}
145
	}
146
	if ($found == false) {
147
		if (!empty($config['interfaces'][$interface])) {
148
			switch ($config['interfaces'][$interface]['ipaddr']) {
149
			case "ppp":
150
			case "pppoe":
151
			case "l2tp":
152
			case "pptp":
153
				$found = true;
154
				break;
155
			default:
156
				$found = false;
157
				break;
158
			}
159
		}
160
	}
161
	if ($found == false) {
162
		$realif = get_real_interface($interface);
163
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
164
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
165

    
166
/* This if block doesn't do anything. It can be deleted.
167
PPP interfaces are found above in the previous if ($found == false) block.
168
This block of code is only entered for OPTx interfaces that are configured for PPPoE modem access, so $realif != $ppp['if']
169

    
170
				if ($realif == $ppp['if']) {
171
					$found = true;
172
					break;
173
				}
174
*/
175
				$ports = explode(',',$ppp['ports']);
176
				foreach($ports as $pid => $port){
177
					$port = get_real_interface($port);
178
					if ($realif == $port) {
179
						$found = true;
180
						break;
181
					}
182
					/* Find the parent interfaces of the vlans in the MLPPP configs
183
					* there should be only one element in the array here
184
					* -- this could be better . . . */
185
					$parent_if = get_parent_interface($port);
186
					if ($realif == $parent_if[0]) {
187
						$found = true;
188
						break;
189
					}
190
				}
191
			}
192
		}
193
	}
194

    
195
	if ($found == false) {
196
		$realif = get_real_interface($interface);
197
		pfSense_ngctl_detach("{$realif}:", $realif);
198
	}
199
	/* NOTE: We make sure for this on interface_ppps_configure()
200
	 *	no need to do it here agan.
201
	 *	else
202
	 *		pfSense_ngctl_attach(".", $realif);
203
	 */
204
}
205

    
206
function interfaces_loopback_configure() {
207
	global $g;
208

    
209
	if ($g['platform'] == 'jail')
210
		return;
211
	if($g['booting'])
212
		echo gettext("Configuring loopback interface...");
213
	pfSense_interface_setaddress("lo0", "127.0.0.1");
214
	interfaces_bring_up("lo0");
215
	if($g['booting'])
216
		echo gettext("done.") . "\n";
217
	return 0;
218
}
219

    
220
function interfaces_vlan_configure() {
221
	global $config, $g;
222
	if($g['booting'])
223
		echo gettext("Configuring VLAN interfaces...");
224
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
225
		foreach ($config['vlans']['vlan'] as $vlan) {
226
			if(empty($vlan['vlanif']))
227
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
228
			/* XXX: Maybe we should report any errors?! */
229
			interface_vlan_configure($vlan);
230
		}
231
	}
232
	if($g['booting'])
233
		echo gettext("done.") . "\n";
234
}
235

    
236
function interface_vlan_configure(&$vlan) {
237
	global $config, $g;
238

    
239
	if (!is_array($vlan)) {
240
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
241
		return;
242
	}
243
	$if = $vlan['if'];
244
	$vlanif  = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
245
	$tag = $vlan['tag'];
246

    
247
	if (empty($if)) {
248
		log_error(gettext("interface_vlan_configure called with if undefined."));
249
		return;
250
	}
251

    
252
	/* make sure the parent interface is up */
253
	interfaces_bring_up($if);
254
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
255
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
256

    
257
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
258
		interface_bring_down($vlanif, true);
259
	} else {
260
		$tmpvlanif = pfSense_interface_create("vlan");
261
		pfSense_interface_rename($tmpvlanif, $vlanif);
262
		pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
263
	}
264

    
265
	pfSense_vlan_create($vlanif, $if, $tag);
266

    
267
	interfaces_bring_up($vlanif);
268

    
269
	/* invalidate interface cache */
270
	get_interface_arr(true);
271

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

    
275
	return $vlanif;
276
}
277

    
278
function interface_qinq_configure(&$vlan, $fd = NULL) {
279
	global $config, $g;
280

    
281
	if (!is_array($vlan)) {
282
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
283
		return;
284
	}
285

    
286
	$qinqif = $vlan['if'];
287
	$tag = $vlan['tag'];
288
	if(empty($qinqif)) {
289
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
290
		return;
291
	}
292

    
293
	if(!does_interface_exist($qinqif)) {
294
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
295
		return;
296
	}
297

    
298
	$vlanif = interface_vlan_configure($vlan);
299

    
300
	if ($fd == NULL) {
301
		$exec = true;
302
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
303
	} else
304
		$exec = false;
305
	/* make sure the parent is converted to ng_vlan(4) and is up */
306
	interfaces_bring_up($qinqif);
307

    
308
	pfSense_ngctl_attach(".", $qinqif);
309
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
310
		fwrite($fd, "shutdown {$qinqif}qinq:\n");
311
		exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
312
		if (empty($result)) {
313
			fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
314
			fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
315
			fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
316
		}
317
	} else {
318
		fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
319
		fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
320
		fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
321
	}
322

    
323
	/* invalidate interface cache */
324
	get_interface_arr(true);
325

    
326
	if (!stristr($qinqif, "_vlan"))
327
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
328

    
329
	$macaddr = get_interface_mac($qinqif);
330
	if (!empty($vlan['members'])) {
331
		$members = explode(" ", $vlan['members']);
332
		foreach ($members as $qtag) {
333
			$qinq = array();
334
			$qinq['tag'] = $qtag;
335
			$qinq['if'] = $vlanif;
336
			interface_qinq2_configure($qinq, $fd, $macaddr);
337
		}
338
	}
339
	if ($exec == true) {
340
		fclose($fd);
341
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
342
	}
343

    
344
	interfaces_bring_up($qinqif);
345
	if (!empty($vlan['members'])) {
346
		$members = explode(" ", $vlan['members']);
347
		foreach ($members as $qif)
348
			interfaces_bring_up("{$vlanif}_{$qif}");
349
	}
350

    
351
	return $vlanif;
352
}
353

    
354
function interfaces_qinq_configure() {
355
	global $config, $g;
356
	if($g['booting'])
357
		echo gettext("Configuring QinQ interfaces...");
358
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
359
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
360
			/* XXX: Maybe we should report any errors?! */
361
			interface_qinq_configure($qinq);
362
		}
363
	}
364
	if($g['booting'])
365
		echo gettext( "done.") . "\n";
366
}
367

    
368
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
369
	global $config, $g;
370

    
371
	if (!is_array($qinq)) {
372
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
373
		return;
374
	}
375

    
376
	$if = $qinq['if'];
377
	$tag = $qinq['tag'];
378
	$vlanif = "{$if}_{$tag}";
379
	if(empty($if)) {
380
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
381
		return;
382
	}
383

    
384
	fwrite($fd, "shutdown {$if}h{$tag}:\n");
385
	fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
386
	fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
387
	fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
388
	fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
389
	fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
390

    
391
	/* invalidate interface cache */
392
	get_interface_arr(true);
393

    
394
	return $vlanif;
395
}
396

    
397
function interfaces_create_wireless_clones() {
398
	global $config, $g;
399

    
400
	if($g['booting'])
401
		echo gettext("Creating wireless clone interfaces...");
402

    
403
	$iflist = get_configured_interface_list();
404

    
405
	foreach ($iflist as $if) {
406
		$realif = $config['interfaces'][$if]['if'];
407
		if (is_interface_wireless($realif))
408
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
409
	}
410

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

    
424
}
425

    
426
function interfaces_bridge_configure($checkmember = 0) {
427
	global $config;
428

    
429
	$i = 0;
430
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
431
		foreach ($config['bridges']['bridged'] as $bridge) {
432
			if(empty($bridge['bridgeif']))
433
				$bridge['bridgeif'] = "bridge{$i}";
434
			if ($checkmember == 1) {
435
				$members = explode(',', $bridge['members']);
436
				foreach ($members as $member) {
437
					if (strstr($bridge['if'], "_vip"))
438
						continue 2;
439
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6")
440
						continue 2;
441
				}
442
			}
443
			else if ($checkmember == 2) {
444
				$members = explode(',', $bridge['members']);
445
				foreach ($members as $member) {
446
					if (!strstr($bridge['if'], "_vip"))
447
						continue 2;
448
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6")
449
						continue 2;
450
				}
451
			}
452
			/* XXX: Maybe we should report any errors?! */
453
			interface_bridge_configure($bridge, $checkmember);
454
			$i++;
455
		}
456
	}
457
}
458

    
459
function interface_bridge_configure(&$bridge, $checkmember = 0) {
460
	global $config, $g;
461

    
462
	if (!is_array($bridge))
463
		return;
464

    
465
	if (empty($bridge['members'])) {
466
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
467
		return;
468
	}
469

    
470
	$members = explode(',', $bridge['members']);
471
	if (!count($members))
472
		return;
473

    
474
	/* Calculate smaller mtu and enforce it */
475
	$smallermtu = 0;
476
	$commonrx = true;
477
	$commontx = true;
478
	$foundgif = false;
479
	foreach ($members as $member) {
480
		$realif = get_real_interface($member);
481
		$opts = pfSense_get_interface_addresses($realif);
482
		$mtu = $opts['mtu'];
483
		if (substr($realif, 0, 3) == "gif") {
484
			$foundgif = true;
485
			if ($checkmember == 1)
486
				return;
487
			if ($mtu <= 1500)
488
				continue;
489
		}
490
		if (!isset($opts['caps']['txcsum']))
491
			$commontx = false;
492
		if (!isset($opts['caps']['rxcsum']))
493
			$commonrx = false;
494
		if (!isset($opts['caps']['tso4']))
495
			$commontso4 = false;
496
		if (!isset($opts['caps']['tso6']))
497
			$commontso6 = false;
498
		if (!isset($opts['caps']['lro']))
499
			$commonlro = false;
500
		if ($smallermtu == 0 && !empty($mtu))
501
			$smallermtu = $mtu;
502
		else if (!empty($mtu) && $mtu < $smallermtu)
503
			$smallermtu = $mtu;
504
	}
505
	if ($foundgif == false && $checkmember == 2)
506
		return;
507

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

    
512
	$flags_on = 0;
513
	$flags_off = 0;
514
	if (isset($config['system']['disablechecksumoffloading']) || ($commonrx === false))
515
		$flags_off |= IFCAP_RXCSUM;
516
	else
517
		$flags_on |= IFCAP_RXCSUM;
518
	if (isset($config['system']['disablechecksumoffloading']) || ($commontx === false))
519
		$flags_off |= IFCAP_TXCSUM;
520
	else
521
		$flags_on |= IFCAP_TXCSUM;
522
	if (isset($config['system']['disablesegmentationoffloading']) || ($commontso4 === false))
523
		$flags_off |= IFCAP_TSO4;
524
	else
525
		$flags_on |= IFCAP_TSO4;
526
	if (isset($config['system']['disablesegmentationoffloading']) || ($commontso6 === false))
527
		$flags_off |= IFCAP_TSO6;
528
	else
529
		$flags_on |= IFCAP_TSO6;
530
	if (isset($config['system']['disablelargereceiveoffloading']) || ($commonlro === false))
531
		$flags_off |= IFCAP_LRO;
532
	else
533
		$flags_on |= IFCAP_LRO;
534

    
535
	if ($g['booting'] || !empty($bridge['bridgeif'])) {
536
		pfSense_interface_destroy($bridge['bridgeif']);
537
		pfSense_interface_create($bridge['bridgeif']);
538
		$bridgeif = escapeshellarg($bridge['bridgeif']);
539
	} else {
540
		$bridgeif = pfSense_interface_create("bridge");
541
		$bridge['bridgeif'] = $bridgeif;
542
	}
543

    
544
	$checklist = get_configured_interface_list();
545

    
546
	/* Add interfaces to bridge */
547
	foreach ($members as $member) {
548
		if (empty($checklist[$member]))
549
			continue;
550
		$realif = get_real_interface($member);
551
		if (!$realif) {
552
			log_error(gettext("realif not defined in interfaces bridge - up"));
553
			continue;
554
		}
555
		/* make sure the parent interface is up */
556
		pfSense_interface_mtu($realif, $smallermtu);
557
		pfSense_interface_capabilities($realif, -$flags_off);
558
		pfSense_interface_capabilities($realif, $flags_on);
559
		interfaces_bring_up($realif);
560
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
561
	}
562

    
563
	if (isset($bridge['enablestp'])) {
564
		/* Choose spanning tree proto */
565
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
566

    
567
		if (!empty($bridge['stp'])) {
568
			$stpifs = explode(',', $bridge['stp']);
569
			foreach ($stpifs as $stpif) {
570
				$realif = get_real_interface($stpif);
571
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
572
			}
573
		}
574
		if (!empty($bridge['maxage']))
575
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
576
		if (!empty($bridge['fwdelay']))
577
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
578
		if (!empty($bridge['hellotime']))
579
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
580
		if (!empty($bridge['priority']))
581
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
582
		if (!empty($bridge['holdcnt']))
583
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
584
		if (!empty($bridge['ifpriority'])) {
585
			$pconfig = explode(",", $bridge['ifpriority']);
586
			$ifpriority = array();
587
			foreach ($pconfig as $cfg) {
588
				$embcfg = explode_assoc(":", $cfg);
589
				foreach ($embcfg as $key => $value)
590
					$ifpriority[$key] = $value;
591
			}
592
			foreach ($ifpriority as $key => $value) {
593
				$realif = get_real_interface($key);
594
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
595
			}
596
		}
597
		if (!empty($bridge['ifpathcost'])) {
598
			$pconfig = explode(",", $bridge['ifpathcost']);
599
			$ifpathcost = array();
600
			foreach ($pconfig as $cfg) {
601
				$embcfg = explode_assoc(":", $cfg);
602
				foreach ($embcfg as $key => $value)
603
					$ifpathcost[$key] = $value;
604
			}
605
			foreach ($ifpathcost as $key => $value) {
606
				$realif = get_real_interface($key);
607
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
608
			}
609
		}
610
	}
611

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

    
663
	if ($bridge['bridgeif'])
664
		interfaces_bring_up($bridge['bridgeif']);
665
	else
666
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
667
}
668

    
669
function interface_bridge_add_member($bridgeif, $interface) {
670

    
671
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface))
672
		return;
673

    
674
	$mtu = get_interface_mtu($bridgeif);
675
	$mtum = get_interface_mtu($interface);
676

    
677
	if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500))
678
		pfSense_interface_mtu($interface, $mtu);
679

    
680
	$options = pfSense_get_interface_addresses($bridgeif);
681
	$flags_on = 0;
682
	$flags_off = 0;
683
	if (isset($options['encaps']['txcsum']))
684
		$flags_on |= IFCAP_TXCSUM;
685
	else
686
		$flags_off |= IFCAP_TXCSUM;
687
	if (isset($options['encaps']['rxcsum']))
688
		$flags_on |= IFCAP_RXCSUM;
689
	else
690
		$flags_off |= IFCAP_RXCSUM;
691
	if (isset($options['encaps']['tso4']))
692
		$flags_on |= IFCAP_TSO4;
693
	else
694
		$flags_off |= IFCAP_TSO4;
695
	if (isset($options['encaps']['tso6']))
696
		$flags_on |= IFCAP_TSO6;
697
	else
698
		$flags_off |= IFCAP_TSO6;
699
	if (isset($options['encaps']['lro']))
700
		$flags_on |= IFCAP_LRO;
701
	else
702
		$flags_off |= IFCAP_LRO;
703

    
704
	pfSense_interface_capabilities($interface, -$flags_off);
705
	pfSense_interface_capabilities($interface, $flags_on);
706

    
707
	interfaces_bring_up($interface);
708
	pfSense_bridge_add_member($bridgeif, $interface);
709
}
710

    
711
function interfaces_lagg_configure() {
712
	global $config, $g;
713
	if($g['booting'])
714
		echo gettext("Configuring LAGG interfaces...");
715
	$i = 0;
716
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
717
		foreach ($config['laggs']['lagg'] as $lagg) {
718
			if(empty($lagg['laggif']))
719
				$lagg['laggif'] = "lagg{$i}";
720
			/* XXX: Maybe we should report any errors?! */
721
			interface_lagg_configure($lagg);
722
			$i++;
723
		}
724
	}
725
	if($g['booting'])
726
		echo gettext("done.") . "\n";
727
}
728

    
729
function interface_lagg_configure(&$lagg) {
730
	global $config, $g;
731

    
732
	if (!is_array($lagg))
733
		return -1;
734

    
735
	$members = explode(',', $lagg['members']);
736
	if (!count($members))
737
		return -1;
738

    
739
	if ($g['booting'] || !(empty($lagg['laggif']))) {
740
		pfSense_interface_destroy($lagg['laggif']);
741
		pfSense_interface_create($lagg['laggif']);
742
		$laggif = $lagg['laggif'];
743
	} else
744
		$laggif = pfSense_interface_create("lagg");
745

    
746
	/* Calculate smaller mtu and enforce it */
747
	$smallermtu = 0;
748
	foreach ($members as $member) {
749
		$opts = pfSense_get_interface_addresses($member);
750
		$mtu = $opts['mtu'];
751
		if (!isset($opts['caps']['txcsum']))
752
			$commontx = false;
753
		if (!isset($opts['caps']['rxcsum']))
754
			$commonrx = false;
755
		if (!isset($opts['caps']['tso4']))
756
			$commontso4 = false;
757
		if (!isset($opts['caps']['tso6']))
758
			$commontso6 = false;
759
		if (!isset($opts['caps']['lro']))
760
			$commonlro = false;
761
		if ($smallermtu == 0 && !empty($mtu))
762
			$smallermtu = $mtu;
763
		else if (!empty($mtu) && $mtu < $smallermtu)
764
			$smallermtu = $mtu;
765
	}
766

    
767
	/* Just in case anything is not working well */
768
	if ($smallermtu == 0)
769
		$smallermtu = 1500;
770

    
771
	$flags_on = 0;
772
	$flags_off = 0;
773
	if (isset($config['system']['disablechecksumoffloading']) || ($commonrx === false))
774
		$flags_off |= IFCAP_RXCSUM;
775
	else
776
		$flags_on |= IFCAP_RXCSUM;
777
	if (isset($config['system']['disablechecksumoffloading']) || ($commontx === false))
778
		$flags_off |= IFCAP_TXCSUM;
779
	else
780
		$flags_on |= IFCAP_TXCSUM;
781
	if (isset($config['system']['disablesegmentationoffloading']) || ($commontso4 === false))
782
		$flags_off |= IFCAP_TSO4;
783
	else
784
		$flags_on |= IFCAP_TSO4;
785
	if (isset($config['system']['disablesegmentationoffloading']) || ($commontso6 === false))
786
		$flags_off |= IFCAP_TSO6;
787
	else
788
		$flags_on |= IFCAP_TSO6;
789
	if (isset($config['system']['disablelargereceiveoffloading']) || ($commonlro === false))
790
		$flags_off |= IFCAP_LRO;
791
	else
792
		$flags_on |= IFCAP_LRO;
793

    
794
	$checklist = get_interface_list();
795

    
796
	foreach ($members as $member) {
797
		if (!array_key_exists($member, $checklist))
798
			continue;
799
		/* make sure the parent interface is up */
800
		pfSense_interface_mtu($member, $smallermtu);
801
		pfSense_interface_capabilities($member, -$flags_off);
802
		pfSense_interface_capabilities($member, $flags_on);
803
		interfaces_bring_up($member);
804
		mwexec("/sbin/ifconfig {$laggif} laggport {$member}");
805
	}
806

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

    
809
	interfaces_bring_up($laggif);
810

    
811
	return $laggif;
812
}
813

    
814
function interfaces_gre_configure($checkparent = 0) {
815
	global $config;
816

    
817
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
818
		foreach ($config['gres']['gre'] as $i => $gre) {
819
			if(empty($gre['greif']))
820
				$gre['greif'] = "gre{$i}";
821
			if ($checkparent == 1) {
822
				if (strstr($gre['if'], "_vip"))
823
					continue;
824
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6")
825
					continue;
826
			}
827
			else if ($checkparent == 2) {
828
				if (!strstr($gre['if'], "_vip"))
829
					continue;
830
				if (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")
831
					continue;
832
			}
833
			/* XXX: Maybe we should report any errors?! */
834
			interface_gre_configure($gre);
835
		}
836
	}
837
}
838

    
839
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
840
function interface_gre_configure(&$gre, $grekey = "") {
841
	global $config, $g;
842

    
843
	if (!is_array($gre))
844
		return -1;
845

    
846
	$realif = get_real_interface($gre['if']);
847
	$realifip = get_interface_ip($gre['if']);
848

    
849
	/* make sure the parent interface is up */
850
	interfaces_bring_up($realif);
851

    
852
	if ($g['booting'] || !(empty($gre['greif']))) {
853
		pfSense_interface_destroy($gre['greif']);
854
		pfSense_interface_create($gre['greif']);
855
		$greif = $gre['greif'];
856
	} else
857
		$greif = pfSense_interface_create("gre");
858

    
859
	/* Do not change the order here for more see gre(4) NOTES section. */
860
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
861
	if((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
862
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
863
	} else {
864
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
865
	}
866
	if (isset($gre['link0']))
867
		pfSense_interface_flags($greif, IFF_LINK0);
868
	if (isset($gre['link1']))
869
		pfSense_interface_flags($greif, IFF_LINK1);
870
	if (isset($gre['link2']))
871
		pfSense_interface_flags($greif, IFF_LINK2);
872

    
873
	if($greif)
874
		interfaces_bring_up($greif);
875
	else
876
		log_error(gettext("Could not bring greif up -- variable not defined."));
877

    
878
	if (isset($gre['link1']) && $gre['link1'])
879
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
880
	if(is_ipaddrv4($gre['tunnel-remote-addr']))
881
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
882
	if(is_ipaddrv6($gre['tunnel-remote-addr']))
883
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
884

    
885
	interfaces_bring_up($laggif);
886

    
887
	return $greif;
888
}
889

    
890
function interfaces_gif_configure($checkparent = 0) {
891
	global $config;
892

    
893
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
894
		foreach ($config['gifs']['gif'] as $i => $gif) {
895
			if(empty($gif['gifif']))
896
				$gre['gifif'] = "gif{$i}";
897
			if ($checkparent == 1) {
898
				if (strstr($gif['if'], "_vip"))
899
					continue;
900
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6")
901
					continue;
902
			}
903
			else if ($checkparent == 2) {
904
				if (!strstr($gre['if'], "_vip"))
905
					continue;
906
				if (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")
907
					continue;
908
			}
909
			/* XXX: Maybe we should report any errors?! */
910
			interface_gif_configure($gif);
911
		}
912
	}
913
}
914

    
915
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
916
function interface_gif_configure(&$gif, $gifkey = "") {
917
	global $config, $g;
918

    
919
	if (!is_array($gif))
920
		return -1;
921

    
922
	$realif = get_real_interface($gif['if']);
923
	$ipaddr = $gif['ipaddr'];
924

    
925
	if (is_ipaddrv4($gif['remote-addr'])) {
926
		if (is_ipaddrv4($ipaddr))
927
			$realifip = $ipaddr;
928
		else
929
			$realifip = get_interface_ip($gif['if']);
930
		$realifgw = get_interface_gateway($gif['if']);
931
	} else if (is_ipaddrv6($gif['remote-addr'])) {
932
		if (is_ipaddrv6($ipaddr))
933
			$realifip = $ipaddr;
934
		else
935
			$realifip = get_interface_ipv6($gif['if']);
936
		$realifgw = get_interface_gatewayv6($gif['if']);
937
	}
938
	/* make sure the parent interface is up */
939
	if($realif)
940
		interfaces_bring_up($realif);
941
	else
942
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
943

    
944
	if ($g['booting'] || !(empty($gif['gifif']))) {
945
		pfSense_interface_destroy($gif['gifif']);
946
		pfSense_interface_create($gif['gifif']);
947
		$gifif = $gif['gifif'];
948
	} else
949
		$gifif = pfSense_interface_create("gif");
950

    
951
	/* Do not change the order here for more see gif(4) NOTES section. */
952
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
953
	if((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
954
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
955
	} else {
956
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
957
	}
958
	if (isset($gif['link0']))
959
		pfSense_interface_flags($gifif, IFF_LINK0);
960
	if (isset($gif['link1']))
961
		pfSense_interface_flags($gifif, IFF_LINK1);
962
	if($gifif)
963
		interfaces_bring_up($gifif);
964
	else
965
		log_error(gettext("could not bring gifif up -- variable not defined"));
966

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

    
981

    
982
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
983
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
984
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
985
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
986

    
987
	if (is_ipaddrv4($realifgw)) {
988
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
989
	}
990
	if (is_ipaddrv6($realifgw)) {
991
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
992
	}
993

    
994
	interfaces_bring_up($laggif);
995

    
996
	return $gifif;
997
}
998

    
999
function interfaces_configure() {
1000
	global $config, $g;
1001

    
1002
	if ($g['platform'] == 'jail')
1003
		return;
1004

    
1005
	/* Set up our loopback interface */
1006
	interfaces_loopback_configure();
1007

    
1008
	/* create the unconfigured wireless clones */
1009
	interfaces_create_wireless_clones();
1010

    
1011
	/* set up LAGG virtual interfaces */
1012
	interfaces_lagg_configure();
1013

    
1014
	/* set up VLAN virtual interfaces */
1015
	interfaces_vlan_configure();
1016

    
1017
	interfaces_qinq_configure();
1018

    
1019
	$iflist = get_configured_interface_with_descr();
1020
	$delayed_list = array();
1021
	$bridge_list = array();
1022
	$track6_list = array();
1023

    
1024
	/* This is needed to speedup interfaces on bootup. */
1025
	$reload = false;
1026
	if (!$g['booting'])
1027
		$reload = true;
1028

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

    
1046
			if($g['debug'])
1047
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1048
			interface_configure($if, $reload);
1049
			if ($g['booting'])
1050
				echo gettext( "done.") . "\n";
1051
		}
1052
	}
1053

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

    
1060
	/* set up GRE virtual interfaces */
1061
	interfaces_gre_configure(1);
1062

    
1063
	/* set up GIF virtual interfaces */
1064
	interfaces_gif_configure(1);
1065

    
1066
	/* set up BRIDGe virtual interfaces */
1067
	interfaces_bridge_configure(1);
1068

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

    
1075
		interface_configure($if, $reload);
1076

    
1077
		if ($g['booting'])
1078
			echo gettext("done.") . "\n";
1079
	}
1080

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

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

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

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

    
1096
		interface_configure($if, $reload);
1097

    
1098
		if ($g['booting'])
1099
			echo gettext("done.") . "\n";
1100
	}
1101

    
1102
	/* set up BRIDGe virtual interfaces */
1103
	interfaces_bridge_configure(2);
1104

    
1105
	foreach ($bridge_list as $if => $ifname) {
1106
		if ($g['booting'])
1107
			printf(gettext("Configuring %s interface..."), $ifname);
1108
		if($g['debug'])
1109
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1110

    
1111
		interface_configure($if, $reload);
1112

    
1113
		if ($g['booting'])
1114
			echo gettext("done.") . "\n";
1115
	}
1116

    
1117
	/* configure interface groups */
1118
	interfaces_group_setup();
1119

    
1120
	if (!$g['booting']) {
1121
		/* reconfigure static routes (kernel may have deleted them) */
1122
		system_routing_configure();
1123

    
1124
		/* reload IPsec tunnels */
1125
		vpn_ipsec_configure();
1126

    
1127
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1128
		services_dhcpd_configure();
1129

    
1130
		/* restart dnsmasq */
1131
		services_dnsmasq_configure();
1132

    
1133
		/* reload captive portal */
1134
		if (function_exists('captiveportal_init_rules'))
1135
			captiveportal_init_rules();
1136
	}
1137

    
1138
	return 0;
1139
}
1140

    
1141
function interface_reconfigure($interface = "wan", $reloadall = false) {
1142
	interface_bring_down($interface);
1143
	interface_configure($interface, $reloadall);
1144
}
1145

    
1146
function interface_vip_bring_down($vip) {
1147
	global $g;
1148

    
1149
	switch ($vip['mode']) {
1150
	case "proxyarp":
1151
		$vipif = get_real_interface($vip['interface']);
1152
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1153
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1154
		break;
1155
	case "ipalias":
1156
		$vipif = get_real_interface($vip['interface']);
1157
		if (does_interface_exist($vipif)) {
1158
			if (is_ipaddrv6($vip['subnet']))
1159
				mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1160
			else
1161
				pfSense_interface_deladdress($vipif, $vip['subnet']);
1162
		}
1163
		break;
1164
	case "carp":
1165
		$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
1166
		if (does_interface_exist($vipif))
1167
			pfSense_interface_destroy($vipif);
1168
		break;
1169
	}
1170
}
1171

    
1172
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1173
	global $config, $g;
1174

    
1175
	if (!isset($config['interfaces'][$interface]))
1176
		return;
1177

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

    
1181
	/*
1182
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1183
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1184
	 * Keep this in mind while doing changes here!
1185
	 */
1186
	if ($ifacecfg === false) {
1187
		$ifcfg = $config['interfaces'][$interface];
1188
		$ppps = $config['ppps']['ppp'];
1189
		$realif = get_real_interface($interface);
1190
		$realifv6 = get_real_interface($interface, "inet6", true);
1191
	} elseif (!is_array($ifacecfg)) {
1192
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1193
		$ifcfg = $config['interfaces'][$interface];
1194
		$ppps = $config['ppps']['ppp'];
1195
		$realif = get_real_interface($interface);
1196
		$realifv6 = get_real_interface($interface, "inet6", true);
1197
	} else {
1198
		$ifcfg = $ifacecfg['ifcfg'];
1199
		$ppps = $ifacecfg['ppps'];
1200
		if (isset($ifacecfg['ifcfg']['realif'])) {
1201
			$realif = $ifacecfg['ifcfg']['realif'];
1202
			/* XXX: Any better way? */
1203
			$realifv6 = $realif;
1204
		} else {
1205
			$realif = get_real_interface($interface);
1206
			$realifv6 = get_real_interface($interface, "inet6", true);
1207
		}
1208
	}
1209

    
1210
	switch ($ifcfg['ipaddr']) {
1211
	case "ppp":
1212
	case "pppoe":
1213
	case "pptp":
1214
	case "l2tp":
1215
		if (is_array($ppps) && count($ppps)) {
1216
			foreach ($ppps as $pppid => $ppp) {
1217
				if ($realif == $ppp['if']) {
1218
					if (isset($ppp['ondemand']) && !$destroy){
1219
						send_event("interface reconfigure {$interface}");
1220
						break;
1221
					}
1222
					if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1223
						killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1224
						sleep(2);
1225
					}
1226
					unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1227
					break;
1228
				}
1229
			}
1230
		}
1231
		break;
1232
	case "dhcp":
1233
		$pid = find_dhclient_process($realif);
1234
		if($pid)
1235
			posix_kill($pid, SIGTERM);
1236
		sleep(1);
1237
		unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1238
		if(does_interface_exist("$realif")) {
1239
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1240
			if ($destroy == true)
1241
				pfSense_interface_flags($realif, -IFF_UP);
1242
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1243
		}
1244
		break;
1245
	default:
1246
		if(does_interface_exist("$realif")) {
1247
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1248
			if ($destroy == true)
1249
				pfSense_interface_flags($realif, -IFF_UP);
1250
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1251
		}
1252
		break;
1253
	}
1254

    
1255
	$track6 = array();
1256
	switch ($ifcfg['ipaddrv6']) {
1257
	case "slaac":
1258
	case "dhcp6":
1259
		$pidv6 = find_dhcp6c_process($realif);
1260
		if($pidv6)
1261
			posix_kill($pidv6, SIGTERM);
1262
		sleep(3);
1263
		unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1264
		if (does_interface_exist($realifv6)) {
1265
			$ip6 = find_interface_ipv6($realifv6);
1266
			if (is_ipaddrv6($ip6) && $ip6 != "::")
1267
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1268
			if ($destroy == true)
1269
				pfSense_interface_flags($realif, -IFF_UP);
1270
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1271
		}
1272
		$track6 = link_interface_to_track6($interface);
1273
		break;
1274
	case "6rd":
1275
	case "6to4":
1276
		$realif = "{$interface}_stf";
1277
		if(does_interface_exist("$realif")) {
1278
			$ip6 = get_interface_ipv6($interface);
1279
			if (is_ipaddrv6($ip6))
1280
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1281
			if ($destroy == true)
1282
				pfSense_interface_flags($realif, -IFF_UP);
1283
		}
1284
		$track6 = link_interface_to_track6($interface);
1285
		break;
1286
	default:
1287
		if(does_interface_exist("$realif")) {
1288
			$ip6 = get_interface_ipv6($interface);
1289
			if (is_ipaddrv6($ip6))
1290
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1291
			if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
1292
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1293
			if ($destroy == true)
1294
				pfSense_interface_flags($realif, -IFF_UP);
1295
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1296
		}
1297
		$track6 = link_interface_to_track6($interface);
1298
		break;
1299
	}
1300

    
1301
	if (!empty($track6) && is_array($track6)) {
1302
		if (!function_exists('services_dhcp_configure'))
1303
			require_once('services.inc');
1304
		/* Bring down radvd and dhcp6 on these interfaces */
1305
		services_dhcpd_configure('inet6', $track6);
1306
	}
1307

    
1308
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1309
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1310
//	log_error("Checking for old router states: {$g['tmp_path']}/{$realif}_router = {$old_router}");
1311
	if (!empty($old_router)) {
1312
		log_error("Clearing states to old gateway {$old_router}.");
1313
		mwexec("/sbin/pfctl -i " . escapeshellarg($realif) . " -Fs -G {$old_router}");
1314
	}
1315

    
1316
	/* remove interface up file if it exists */
1317
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1318
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1319
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1320
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1321
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1322
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1323
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1324

    
1325
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1326
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1327
	if (is_array($ifcfg['wireless'])) {
1328
		kill_hostapd($realif);
1329
		mwexec(kill_wpasupplicant($realif));
1330
	}
1331

    
1332
	if ($destroy == true) {
1333
		if (preg_match("/^[a-z0-9]+_vip|^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif))
1334
			pfSense_interface_destroy($realif);
1335
	}
1336

    
1337
	return;
1338
}
1339

    
1340
function interfaces_ptpid_used($ptpid) {
1341
	global $config;
1342

    
1343
	if (is_array($config['ppps']['ppp']))
1344
		foreach ($config['ppps']['ppp'] as & $settings)
1345
			if ($ptpid == $settings['ptpid'])
1346
				return true;
1347

    
1348
	return false;
1349
}
1350

    
1351
function interfaces_ptpid_next() {
1352

    
1353
	$ptpid = 0;
1354
	while(interfaces_ptpid_used($ptpid))
1355
		$ptpid++;
1356

    
1357
	return $ptpid;
1358
}
1359

    
1360
function getMPDCRONSettings($pppif) {
1361
	global $config;
1362

    
1363
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1364
	if (is_array($config['cron']['item'])) {
1365
		foreach ($config['cron']['item'] as $i => $item) {
1366
			if (stripos($item['command'], $cron_cmd_file) !== false)
1367
				return array("ID" => $i, "ITEM" => $item);
1368
		}
1369
	}
1370

    
1371
	return NULL;
1372
}
1373

    
1374
function handle_pppoe_reset($post_array) {
1375
	global $config, $g;
1376

    
1377
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1378
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1379

    
1380
	if (!is_array($config['cron']['item']))
1381
		$config['cron']['item'] = array();
1382

    
1383
	$itemhash = getMPDCRONSettings($pppif);
1384

    
1385
	// reset cron items if necessary and return
1386
	if (empty($post_array['pppoe-reset-type'])) {
1387
		if (isset($itemhash))
1388
			unset($config['cron']['item'][$itemhash['ID']]);
1389
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1390
		return;
1391
	}
1392

    
1393
	if (empty($itemhash))
1394
		$itemhash = array();
1395
	$item = array();
1396
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1397
		$item['minute'] = $post_array['pppoe_resetminute'];
1398
		$item['hour'] = $post_array['pppoe_resethour'];
1399
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1400
			$date = explode("/", $post_array['pppoe_resetdate']);
1401
			$item['mday'] = $date[1];
1402
			$item['month'] = $date[0];
1403
		} else {
1404
			$item['mday'] = "*";
1405
			$item['month'] = "*";
1406
		}
1407
		$item['wday'] = "*";
1408
		$item['who'] = "root";
1409
		$item['command'] = $cron_cmd_file;
1410
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1411
		switch ($post_array['pppoe_pr_preset_val']) {
1412
		case "monthly":
1413
			$item['minute'] = "0";
1414
			$item['hour'] = "0";
1415
			$item['mday'] = "1";
1416
			$item['month'] = "*";
1417
			$item['wday'] = "*";
1418
			break;
1419
		case "weekly":
1420
			$item['minute'] = "0";
1421
			$item['hour'] = "0";
1422
			$item['mday'] = "*";
1423
			$item['month'] = "*";
1424
			$item['wday'] = "0";
1425
			break;
1426
		case "daily":
1427
			$item['minute'] = "0";
1428
			$item['hour'] = "0";
1429
			$item['mday'] = "*";
1430
			$item['month'] = "*";
1431
			$item['wday'] = "*";
1432
			break;
1433
		case "hourly":
1434
			$item['minute'] = "0";
1435
			$item['hour'] = "*";
1436
			$item['mday'] = "*";
1437
			$item['month'] = "*";
1438
			$item['wday'] = "*";
1439
			break;
1440
		} // end switch
1441
		$item['who'] = "root";
1442
		$item['command'] = $cron_cmd_file;
1443
	}
1444
	if (empty($item))
1445
		return;
1446
	if (isset($itemhash['ID']))
1447
		$config['cron']['item'][$itemhash['ID']] = $item;
1448
	else
1449
		$config['cron']['item'][] = $item;
1450
}
1451

    
1452
/*
1453
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1454
 * It writes the mpd config file to /var/etc every time the link is opened.
1455
 */
1456
function interface_ppps_configure($interface) {
1457
	global $config, $g;
1458

    
1459
	/* Return for unassigned interfaces. This is a minimum requirement. */
1460
	if (empty($config['interfaces'][$interface]))
1461
		return 0;
1462
	$ifcfg = $config['interfaces'][$interface];
1463
	if (!isset($ifcfg['enable']))
1464
		return 0;
1465

    
1466
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1467
	if(!is_dir("/var/spool/lock")) {
1468
		mkdir("/var/spool/lock", 0777, true);
1469
	}
1470
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1471
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1472
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1473

    
1474
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1475
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1476
			if ($ifcfg['if'] == $ppp['if'])
1477
				break;
1478
		}
1479
	}
1480
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1481
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1482
		return 0;
1483
	}
1484
	$pppif = $ifcfg['if'];
1485
	if ($ppp['type'] == "ppp")
1486
		$type = "modem";
1487
	else
1488
		$type = $ppp['type'];
1489
	$upper_type = strtoupper($ppp['type']);
1490

    
1491
	if($g['booting']) {
1492
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1493
		echo "starting {$pppif} link...";
1494
		// Do not re-configure the interface if we are booting and it's already been started
1495
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1496
			return 0;
1497
	}
1498

    
1499
	$ports = explode(',',$ppp['ports']);
1500
	if ($type != "modem") {
1501
		foreach ($ports as $pid => $port) {
1502
			$ports[$pid] = get_real_interface($port);
1503
			if (empty($ports[$pid]))
1504
				return 0;
1505
		}
1506
	}
1507
	$localips = explode(',',$ppp['localip']);
1508
	$gateways = explode(',',$ppp['gateway']);
1509
	$subnets = explode(',',$ppp['subnet']);
1510

    
1511
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1512
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1513
	 */
1514
	foreach($ports as $pid => $port){
1515
		switch ($ppp['type']) {
1516
			case "pppoe":
1517
				/* Bring the parent interface up */
1518
				interfaces_bring_up($port);
1519
				pfSense_ngctl_attach(".", $port);
1520
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1521
				mwexec("ngctl msg {$port}: setautosrc 1");
1522
				break;
1523
			case "pptp":
1524
			case "l2tp":
1525
				/* configure interface */
1526
				if(is_ipaddr($localips[$pid])){
1527
					// Manually configure interface IP/subnet
1528
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1529
					interfaces_bring_up($port);
1530
				} else if (empty($localips[$pid]))
1531
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1532

    
1533
				if(!is_ipaddr($localips[$pid])){
1534
					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!");
1535
					$localips[$pid] = "0.0.0.0";
1536
				}
1537
				if(!is_ipaddr($gateways[$pid])){
1538
					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));
1539
					return 0;
1540
				}
1541
				pfSense_ngctl_attach(".", $port);
1542
				break;
1543
			case "ppp":
1544
				if (!file_exists("{$port}")) {
1545
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1546
					return 0;
1547
				}
1548
				break;
1549
			default:
1550
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1551
				break;
1552
		}
1553
	}
1554

    
1555
	if (is_array($ports) && count($ports) > 1)
1556
		$multilink = "enable";
1557
	else
1558
		$multilink = "disable";
1559

    
1560
	if ($type == "modem"){
1561
		if (is_ipaddr($ppp['localip']))
1562
			$localip = $ppp['localip'];
1563
		else
1564
			$localip = '0.0.0.0';
1565

    
1566
		if (is_ipaddr($ppp['gateway']))
1567
			$gateway = $ppp['gateway'];
1568
		else
1569
			$gateway = "10.64.64.{$pppid}";
1570
		$ranges = "{$localip}/0 {$gateway}/0";
1571

    
1572
		if (empty($ppp['apnum']))
1573
			$ppp['apnum'] = 1;
1574
	} else
1575
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1576

    
1577
	if (isset($ppp['ondemand']))
1578
		$ondemand = "enable";
1579
	else
1580
		$ondemand = "disable";
1581
	if (!isset($ppp['idletimeout']))
1582
		$ppp['idletimeout'] = 0;
1583

    
1584
	if (empty($ppp['username']) && $type == "modem"){
1585
		$ppp['username'] = "user";
1586
		$ppp['password'] = "none";
1587
	}
1588
	if (empty($ppp['password']) && $type == "modem")
1589
		$passwd = "none";
1590
	else
1591
		$passwd = base64_decode($ppp['password']);
1592

    
1593
	$bandwidths = explode(',',$ppp['bandwidth']);
1594
	$defaultmtu = "1492";
1595
	if (!empty($ifcfg['mtu']))
1596
		$defaultmtu = intval($ifcfg['mtu']);
1597
	$mtus = explode(',',$ppp['mtu']);
1598
	$mrus = explode(',',$ppp['mru']);
1599

    
1600
	if (isset($ppp['mrru']))
1601
		$mrrus = explode(',',$ppp['mrru']);
1602

    
1603
	// Construct the mpd.conf file
1604
	$mpdconf = <<<EOD
1605
startup:
1606
	# configure the console
1607
	set console close
1608
	# configure the web server
1609
	set web close
1610

    
1611
default:
1612
{$ppp['type']}client:
1613
	create bundle static {$interface}
1614
	set bundle enable ipv6cp
1615
	set iface name {$pppif}
1616

    
1617
EOD;
1618
	$setdefaultgw = false;
1619
	$founddefaultgw = false;
1620
	if (is_array($config['gateways']['gateway_item'])) {
1621
		foreach($config['gateways']['gateway_item'] as $gateway) {
1622
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1623
				$setdefaultgw = true;
1624
				break;
1625
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1626
				$founddefaultgw = true;
1627
				break;
1628
			}
1629
		}
1630
	}
1631

    
1632
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1633
		$setdefaultgw = true;
1634
		$mpdconf .= <<<EOD
1635
	set iface route default
1636

    
1637
EOD;
1638
	}
1639
	$mpdconf .= <<<EOD
1640
	set iface {$ondemand} on-demand
1641
	set iface idle {$ppp['idletimeout']}
1642

    
1643
EOD;
1644

    
1645
	if (isset($ppp['ondemand']))
1646
		$mpdconf .= <<<EOD
1647
	set iface addrs 10.10.1.1 10.10.1.2
1648

    
1649
EOD;
1650

    
1651
	if (isset($ppp['tcpmssfix']))
1652
		$tcpmss = "disable";
1653
	else
1654
		$tcpmss = "enable";
1655
		$mpdconf .= <<<EOD
1656
	set iface {$tcpmss} tcpmssfix
1657

    
1658
EOD;
1659

    
1660
	$mpdconf .= <<<EOD
1661
	set iface up-script /usr/local/sbin/ppp-linkup
1662
	set iface down-script /usr/local/sbin/ppp-linkdown
1663
	set ipcp ranges {$ranges}
1664

    
1665
EOD;
1666
	if (isset($ppp['vjcomp']))
1667
		$mpdconf .= <<<EOD
1668
	set ipcp no vjcomp
1669

    
1670
EOD;
1671

    
1672
	if (isset($config['system']['dnsallowoverride']))
1673
		$mpdconf .= <<<EOD
1674
	set ipcp enable req-pri-dns
1675
	set ipcp enable req-sec-dns
1676

    
1677
EOD;
1678
	if (!isset($ppp['verbose_log']))
1679
		$mpdconf .= <<<EOD
1680
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1681

    
1682
EOD;
1683
	foreach($ports as $pid => $port){
1684
		$port = get_real_interface($port);
1685
		$mpdconf .= <<<EOD
1686

    
1687
	create link static {$interface}_link{$pid} {$type}
1688
	set link action bundle {$interface}
1689
	set link {$multilink} multilink
1690
	set link keep-alive 10 60
1691
	set link max-redial 0
1692

    
1693
EOD;
1694
		if (isset($ppp['shortseq']))
1695
			$mpdconf .= <<<EOD
1696
	set link no shortseq
1697

    
1698
EOD;
1699

    
1700
		if (isset($ppp['acfcomp']))
1701
			$mpdconf .= <<<EOD
1702
	set link no acfcomp
1703

    
1704
EOD;
1705

    
1706
		if (isset($ppp['protocomp']))
1707
			$mpdconf .= <<<EOD
1708
	set link no protocomp
1709

    
1710
EOD;
1711

    
1712
		$mpdconf .= <<<EOD
1713
	set link disable chap pap
1714
	set link accept chap pap eap
1715
	set link disable incoming
1716

    
1717
EOD;
1718

    
1719

    
1720
		if (!empty($bandwidths[$pid]))
1721
			$mpdconf .= <<<EOD
1722
	set link bandwidth {$bandwidths[$pid]}
1723

    
1724
EOD;
1725

    
1726
		if (empty($mtus[$pid]))
1727
			$mtus[$pid] = $defaultmtu;
1728
			$mpdconf .= <<<EOD
1729
	set link mtu {$mtus[$pid]}
1730

    
1731
EOD;
1732

    
1733
		if (!empty($mrus[$pid]))
1734
			$mpdconf .= <<<EOD
1735
	set link mru {$mrus[$pid]}
1736

    
1737
EOD;
1738

    
1739
		if (!empty($mrrus[$pid]))
1740
			$mpdconf .= <<<EOD
1741
	set link mrru {$mrrus[$pid]}
1742

    
1743
EOD;
1744

    
1745
		$mpdconf .= <<<EOD
1746
	set auth authname "{$ppp['username']}"
1747
	set auth password {$passwd}
1748

    
1749
EOD;
1750
		if ($type == "modem") {
1751
			$mpdconf .= <<<EOD
1752
	set modem device {$ppp['ports']}
1753
	set modem script DialPeer
1754
	set modem idle-script Ringback
1755
	set modem watch -cd
1756
	set modem var \$DialPrefix "DT"
1757
	set modem var \$Telephone "{$ppp['phone']}"
1758

    
1759
EOD;
1760
		}
1761
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1762
			$mpdconf .= <<<EOD
1763
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1764

    
1765
EOD;
1766
		}
1767
		if (isset($ppp['initstr']) && $type == "modem") {
1768
			$initstr = base64_decode($ppp['initstr']);
1769
			$mpdconf .= <<<EOD
1770
	set modem var \$InitString "{$initstr}"
1771

    
1772
EOD;
1773
		}
1774
		if (isset($ppp['simpin']) && $type == "modem") {
1775
			if($ppp['pin-wait'] == "")
1776
				$ppp['pin-wait'] = 0;
1777
			$mpdconf .= <<<EOD
1778
	set modem var \$SimPin "{$ppp['simpin']}"
1779
	set modem var \$PinWait "{$ppp['pin-wait']}"
1780

    
1781
EOD;
1782
		}
1783
		if (isset($ppp['apn']) && $type == "modem") {
1784
			$mpdconf .= <<<EOD
1785
	set modem var \$APN "{$ppp['apn']}"
1786
	set modem var \$APNum "{$ppp['apnum']}"
1787

    
1788
EOD;
1789
		}
1790
		if ($type == "pppoe") {
1791
			// Send a null service name if none is set.
1792
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1793
			$mpdconf .= <<<EOD
1794
	set pppoe service "{$provider}"
1795

    
1796
EOD;
1797
		}
1798
		if ($type == "pppoe")
1799
			$mpdconf .= <<<EOD
1800
	set pppoe iface {$port}
1801

    
1802
EOD;
1803

    
1804
		if ($type == "pptp" || $type == "l2tp") {
1805
			$mpdconf .= <<<EOD
1806
	set {$type} self {$localips[$pid]}
1807
	set {$type} peer {$gateways[$pid]}
1808

    
1809
EOD;
1810
		}
1811

    
1812
		$mpdconf .= "\topen\n";
1813
	} //end foreach($port)
1814

    
1815

    
1816
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1817
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1818
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1819
	else {
1820
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1821
		if (!$fd) {
1822
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1823
			return 0;
1824
		}
1825
		// Write out mpd_ppp.conf
1826
		fwrite($fd, $mpdconf);
1827
		fclose($fd);
1828
		unset($mpdconf);
1829
	}
1830

    
1831
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1832
	if (isset($ppp['uptime'])) {
1833
		if (!file_exists("/conf/{$pppif}.log")) {
1834
			conf_mount_rw();
1835
			file_put_contents("/conf/{$pppif}.log", '');
1836
			conf_mount_ro();
1837
		}
1838
	} else {
1839
		if (file_exists("/conf/{$pppif}.log")) {
1840
			conf_mount_rw();
1841
			@unlink("/conf/{$pppif}.log");
1842
			conf_mount_ro();
1843
		}
1844
	}
1845

    
1846
	/* clean up old lock files */
1847
	foreach($ports as $port) {
1848
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1849
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1850
	}
1851

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

    
1856
	// Check for PPPoE periodic reset request
1857
	if ($type == "pppoe") {
1858
		if (!empty($ppp['pppoe-reset-type']))
1859
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1860
		else
1861
			interface_setup_pppoe_reset_file($ppp['if']);
1862
	}
1863
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1864
	$i = 0;
1865
	while($i < 10) {
1866
		exec("/sbin/ifconfig " . escapeshellarg($ppp['if']) . " 2>&1", $out, $ret);
1867
		if($ret == 0)
1868
			break;
1869
		sleep(1);
1870
		$i++;
1871
	}
1872

    
1873
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
1874
	/* We should be able to launch the right version for each modem */
1875
	/* We can also guess the mondev from the manufacturer */
1876
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
1877
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
1878
	foreach($ports as $port) {
1879
		if(preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1880
			$mondev  = substr(basename($port), 0, -1);
1881
			$devlist = glob("/dev/{$mondev}?");
1882
			$mondev = basename(end($devlist));
1883
		}
1884
		if(preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1885
			$mondev  = substr(basename($port), 0, -1) . "1";
1886
		}
1887
		log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
1888
		mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
1889
	}
1890

    
1891
	return 1;
1892
}
1893

    
1894
function interfaces_carp_setup() {
1895
	global $g, $config;
1896

    
1897
	if (isset($config['system']['developerspew'])) {
1898
		$mt = microtime();
1899
		echo "interfaces_carp_setup() being called $mt\n";
1900
	}
1901

    
1902
	if ($g['booting']) {
1903
		echo gettext("Configuring CARP settings...");
1904
		mute_kernel_msgs();
1905
	}
1906

    
1907
	/* suck in configuration items */
1908
	if ($config['hasync']) {
1909
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1910
		$balancing = $config['hasync']['balancing'];
1911
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1912
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1913
	} else {
1914
		unset($pfsyncinterface);
1915
		unset($balancing);
1916
		unset($pfsyncenabled);
1917
	}
1918

    
1919
	if ($balancing) {
1920
		mwexec("/sbin/sysctl net.inet.carp.arpbalance=1", true);
1921
		mwexec("/sbin/sysctl net.inet.carp.preempt=0", true);
1922
	} else
1923
		mwexec("/sbin/sysctl net.inet.carp.preempt=1", true);
1924

    
1925
	mwexec("sbin/sysctl net.inet.carp.log=1", true);
1926
	if (!empty($pfsyncinterface))
1927
		$carp_sync_int = get_real_interface($pfsyncinterface);
1928
	else
1929
		unset($carp_sync_int);
1930

    
1931
	/* setup pfsync interface */
1932
	if ($carp_sync_int and $pfsyncenabled) {
1933
		if (is_ipaddr($pfsyncpeerip))
1934
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1935
		else
1936
			$syncpeer = "-syncpeer";
1937

    
1938
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
1939

    
1940
		sleep(1);
1941

    
1942
		/* 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
1943
		 * for existing sessions.
1944
		 */
1945
		log_error("waiting for pfsync...");
1946
		$i = 0;
1947
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1948
			$i++;
1949
			sleep(1);
1950
		}
1951
		log_error("pfsync done in $i seconds.");
1952
		log_error("Configuring CARP settings finalize...");
1953
	} else {
1954
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
1955
	}
1956

    
1957
	if($config['virtualip']['vip'])
1958
		mwexec("/sbin/sysctl net.inet.carp.allow=1", true);
1959
	else
1960
		mwexec("/sbin/sysctl net.inet.carp.allow=0", true);
1961

    
1962
	if ($g['booting']) {
1963
		unmute_kernel_msgs();
1964
		echo gettext("done.") . "\n";
1965
	}
1966
}
1967

    
1968
function interface_proxyarp_configure($interface = "") {
1969
	global $config, $g;
1970
	if(isset($config['system']['developerspew'])) {
1971
		$mt = microtime();
1972
		echo "interface_proxyarp_configure() being called $mt\n";
1973
	}
1974

    
1975
	/* kill any running choparp */
1976
	if (empty($interface))
1977
		killbyname("choparp");
1978
	else {
1979
		$vipif = get_real_interface($interface);
1980
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1981
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1982
	}
1983

    
1984
	$paa = array();
1985
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1986

    
1987
		/* group by interface */
1988
		foreach ($config['virtualip']['vip'] as $vipent) {
1989
			if ($vipent['mode'] === "proxyarp") {
1990
				if ($vipent['interface'])
1991
					$proxyif = $vipent['interface'];
1992
				else
1993
					$proxyif = "wan";
1994

    
1995
				if (!empty($interface) && $interface != $proxyif)
1996
					continue;
1997

    
1998
				if (!is_array($paa[$proxyif]))
1999
					$paa[$proxyif] = array();
2000

    
2001
				$paa[$proxyif][] = $vipent;
2002
			}
2003
		}
2004
	}
2005

    
2006
	if (!empty($interface)) {
2007
		if (is_array($paa[$interface])) {
2008
			$paaifip = get_interface_ip($interface);
2009
			if (!is_ipaddr($paaifip))
2010
				return;
2011
			$args = get_real_interface($interface) . " auto";
2012
			foreach ($paa[$interface] as $paent) {
2013
				if (isset($paent['subnet']))
2014
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2015
				else if (isset($paent['range']))
2016
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2017
			}
2018
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2019
		}
2020
	} else if (count($paa) > 0) {
2021
		foreach ($paa as $paif => $paents)  {
2022
			$paaifip = get_interface_ip($paif);
2023
			if (!is_ipaddr($paaifip))
2024
				continue;
2025
			$args = get_real_interface($paif) . " auto";
2026
			foreach ($paents as $paent) {
2027
				if (isset($paent['subnet']))
2028
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2029
				else if (isset($paent['range']))
2030
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2031
			}
2032
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2033
		}
2034
	}
2035
}
2036

    
2037
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2038
	global $g, $config;
2039

    
2040
	if (is_array($config['virtualip']['vip'])) {
2041
		foreach ($config['virtualip']['vip'] as $vip) {
2042
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2043
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2044
					interface_vip_bring_down($vip);
2045
				else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2046
					interface_vip_bring_down($vip);
2047
			}
2048
		}
2049
	}
2050
}
2051

    
2052
function interfaces_vips_configure($interface = "") {
2053
	global $g, $config;
2054
	if(isset($config['system']['developerspew'])) {
2055
		$mt = microtime();
2056
		echo "interfaces_vips_configure() being called $mt\n";
2057
	}
2058
	$paa = array();
2059
	if(is_array($config['virtualip']['vip'])) {
2060
		$carp_setuped = false;
2061
		$anyproxyarp = false;
2062
		foreach ($config['virtualip']['vip'] as $vip) {
2063
			switch ($vip['mode']) {
2064
			case "proxyarp":
2065
				/* nothing it is handled on interface_proxyarp_configure() */
2066
				if ($interface <> "" && $vip['interface'] <> $interface)
2067
					continue;
2068
				$anyproxyarp = true;
2069
				break;
2070
			case "ipalias":
2071
				if ($interface <> "" && $vip['interface'] <> $interface)
2072
					continue;
2073
				interface_ipalias_configure($vip);
2074
				break;
2075
			case "carp":
2076
				if ($interface <> "" && $vip['interface'] <> $interface)
2077
					continue;
2078
				if ($carp_setuped == false)
2079
					$carp_setuped = true;
2080
				interface_carp_configure($vip);
2081
				break;
2082
			}
2083
		}
2084
		if ($carp_setuped == true)
2085
			interfaces_carp_setup();
2086
		if ($anyproxyarp == true)
2087
			interface_proxyarp_configure();
2088
	}
2089
}
2090

    
2091
function interface_ipalias_configure(&$vip) {
2092
	if ($vip['mode'] == "ipalias") {
2093
		$if = get_real_interface($vip['interface']);
2094
		$af = "inet";
2095
		if(is_ipaddrv6($vip['subnet']))
2096
			$af = "inet6";
2097
		mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
2098
	}
2099
}
2100

    
2101
function interface_reload_carps($cif) {
2102
	global $config;
2103

    
2104
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2105
	if (empty($carpifs))
2106
		return;
2107

    
2108
	$carps = explode(" ", $carpifs);
2109
	if(is_array($config['virtualip']['vip'])) {
2110
		$viparr = &$config['virtualip']['vip'];
2111
		foreach ($viparr as $vip) {
2112
			if (in_array($vip['carpif'], $carps)) {
2113
				switch ($vip['mode']) {
2114
				case "carp":
2115
					interface_vip_bring_down($vip);
2116
					sleep(1);
2117
					interface_carp_configure($vip);
2118
					break;
2119
				case "ipalias":
2120
					interface_vip_bring_down($vip);
2121
					sleep(1);
2122
					interface_ipalias_configure($vip);
2123
					break;
2124
				}
2125
			}
2126
		}
2127
	}
2128
}
2129

    
2130
function interface_carp_configure(&$vip) {
2131
	global $config, $g;
2132
	if(isset($config['system']['developerspew'])) {
2133
		$mt = microtime();
2134
		echo "interface_carp_configure() being called $mt\n";
2135
	}
2136

    
2137
	if ($vip['mode'] != "carp")
2138
		return;
2139

    
2140
	/*
2141
	 * ensure the interface containing the VIP really exists
2142
	 * prevents a panic if the interface is missing or invalid
2143
	 */
2144
	$realif = get_real_interface($vip['interface']);
2145
	if (!does_interface_exist($realif)) {
2146
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2147
		return;
2148
	}
2149

    
2150
	if(is_ipaddrv4($vip['subnet'])) {
2151
		/* Ensure CARP IP really exists prior to loading up. */
2152
		$ww_subnet_ip = find_interface_ip($realif);
2153
		$ww_subnet_bits = find_interface_subnet($realif);
2154
		if (!ip_in_subnet($vip['subnet'], gen_subnet($ww_subnet_ip, $ww_subnet_bits) . "/" . $ww_subnet_bits) && !ip_in_interface_alias_subnet($vip['interface'], $vip['subnet'])) {
2155
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a matching real interface subnet for the virtual IP address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2156
			return;
2157
		}
2158
	}
2159
	if(is_ipaddrv6($vip['subnet'])) {
2160
		/* Ensure CARP IP really exists prior to loading up. */
2161
		$ww_subnet_ip = find_interface_ipv6($realif);
2162
		$ww_subnet_bits = find_interface_subnetv6($realif);
2163
		if (!ip_in_subnet($vip['subnet'], gen_subnetv6($ww_subnet_ip, $ww_subnet_bits) . "/" . $ww_subnet_bits) && !ip_in_interface_alias_subnet($vip['interface'], $vip['subnet'])) {
2164
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a matching real interface subnet for the virtual IPv6 address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2165
			return;
2166
		}
2167
	}
2168

    
2169
	// set the vip interface to the vhid
2170
	$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
2171

    
2172
	/* create the carp interface and setup */
2173
	if (does_interface_exist($vipif)) {
2174
		pfSense_interface_flags($vipif, -IFF_UP);
2175
	} else {
2176
		$carpif = pfSense_interface_create("carp");
2177
		pfSense_interface_rename($carpif, $vipif);
2178
		pfSense_ngctl_name("{$carpif}:", $vipif);
2179
	}
2180

    
2181
	/* invalidate interface cache */
2182
	get_interface_arr(true);
2183

    
2184
	$vip_password = $vip['password'];
2185
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2186
	if ($vip['password'] != "")
2187
		$password = " pass {$vip_password}";
2188

    
2189
	$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2190
	$advbase = "";
2191
	if (!empty($vip['advbase']))
2192
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2193

    
2194
	if(is_ipaddrv4($vip['subnet'])) {
2195
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2196
		mwexec("/sbin/ifconfig {$vipif} {$vip['subnet']}/{$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2197
	}
2198
	if(is_ipaddrv6($vip['subnet'])) {
2199
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2200
		mwexec("/sbin/ifconfig {$vipif} inet6 {$vip['subnet']} prefixlen {$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2201
	}
2202

    
2203
	interfaces_bring_up($vipif);
2204

    
2205
	return $vipif;
2206
}
2207

    
2208
function interface_wireless_clone($realif, $wlcfg) {
2209
	global $config, $g;
2210
	/*   Check to see if interface has been cloned as of yet.
2211
	 *   If it has not been cloned then go ahead and clone it.
2212
	 */
2213
	$needs_clone = false;
2214
	if(is_array($wlcfg['wireless']))
2215
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2216
	else
2217
		$wlcfg_mode = $wlcfg['mode'];
2218
	switch($wlcfg_mode) {
2219
	case "hostap":
2220
		$mode = "wlanmode hostap";
2221
		break;
2222
	case "adhoc":
2223
		$mode = "wlanmode adhoc";
2224
		break;
2225
	default:
2226
		$mode = "";
2227
		break;
2228
	}
2229
	$baseif = interface_get_wireless_base($wlcfg['if']);
2230
	if(does_interface_exist($realif)) {
2231
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2232
		$ifconfig_str = implode($output);
2233
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
2234
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2235
			$needs_clone = true;
2236
		}
2237
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
2238
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2239
			$needs_clone = true;
2240
		}
2241
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2242
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2243
			$needs_clone = true;
2244
		}
2245
	} else {
2246
		$needs_clone = true;
2247
	}
2248

    
2249
	if($needs_clone == true) {
2250
		/* remove previous instance if it exists */
2251
		if(does_interface_exist($realif))
2252
			pfSense_interface_destroy($realif);
2253

    
2254
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2255
		// Create the new wlan interface. FreeBSD returns the new interface name.
2256
		// example:  wlan2
2257
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2258
		if($ret <> 0) {
2259
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2260
			return false;
2261
		}
2262
		$newif = trim($out[0]);
2263
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2264
		pfSense_interface_rename($newif, $realif);
2265
		// FIXME: not sure what ngctl is for. Doesn't work.
2266
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
2267
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2268
	}
2269
	return true;
2270
}
2271

    
2272
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2273
	global $config, $g;
2274

    
2275
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2276
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2277
				 'regdomain', 'regcountry', 'reglocation');
2278

    
2279
	if(!is_interface_wireless($ifcfg['if']))
2280
		return;
2281

    
2282
	$baseif = interface_get_wireless_base($ifcfg['if']);
2283

    
2284
	// Sync shared settings for assigned clones
2285
	$iflist = get_configured_interface_list(false, true);
2286
	foreach ($iflist as $if) {
2287
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2288
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2289
				foreach ($shared_settings as $setting) {
2290
					if ($sync_changes) {
2291
						if (isset($ifcfg['wireless'][$setting]))
2292
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2293
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2294
							unset($config['interfaces'][$if]['wireless'][$setting]);
2295
					} else {
2296
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2297
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2298
						else if (isset($ifcfg['wireless'][$setting]))
2299
							unset($ifcfg['wireless'][$setting]);
2300
					}
2301
				}
2302
				if (!$sync_changes)
2303
					break;
2304
			}
2305
		}
2306
	}
2307

    
2308
	// Read or write settings at shared area
2309
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2310
		foreach ($shared_settings as $setting) {
2311
			if ($sync_changes) {
2312
				if (isset($ifcfg['wireless'][$setting]))
2313
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2314
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2315
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2316
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2317
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2318
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2319
				else if (isset($ifcfg['wireless'][$setting]))
2320
					unset($ifcfg['wireless'][$setting]);
2321
			}
2322
		}
2323
	}
2324

    
2325
	// Sync the mode on the clone creation page with the configured mode on the interface
2326
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2327
		foreach ($config['wireless']['clone'] as &$clone) {
2328
			if ($clone['cloneif'] == $ifcfg['if']) {
2329
				if ($sync_changes) {
2330
					$clone['mode'] = $ifcfg['wireless']['mode'];
2331
				} else {
2332
					$ifcfg['wireless']['mode'] = $clone['mode'];
2333
				}
2334
				break;
2335
			}
2336
		}
2337
		unset($clone);
2338
	}
2339
}
2340

    
2341
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2342
	global $config, $g;
2343

    
2344
	/*    open up a shell script that will be used to output the commands.
2345
	 *    since wireless is changing a lot, these series of commands are fragile
2346
	 *    and will sometimes need to be verified by a operator by executing the command
2347
	 *    and returning the output of the command to the developers for inspection.  please
2348
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2349
	 */
2350

    
2351
	// Remove script file
2352
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2353

    
2354
	// Clone wireless nic if needed.
2355
	interface_wireless_clone($if, $wl);
2356

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

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

    
2364
	/* set values for /path/program */
2365
	$hostapd = "/usr/sbin/hostapd";
2366
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2367
	$ifconfig = "/sbin/ifconfig";
2368
	$sysctl = "/sbin/sysctl";
2369
	$killall = "/usr/bin/killall";
2370

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

    
2373
	$wlcmd = array();
2374
	$wl_sysctl = array();
2375
	/* Make sure it's up */
2376
	$wlcmd[] = "up";
2377
	/* Set a/b/g standard */
2378
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2379
	$wlcmd[] = "mode " . escapeshellarg($standard);
2380

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

    
2386
	/* Set ssid */
2387
	if($wlcfg['ssid'])
2388
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2389

    
2390
	/* Set 802.11g protection mode */
2391
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2392

    
2393
	/* set wireless channel value */
2394
	if(isset($wlcfg['channel'])) {
2395
		if($wlcfg['channel'] == "0") {
2396
			$wlcmd[] = "channel any";
2397
		} else {
2398
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2399
		}
2400
	}
2401

    
2402
	/* Set antenna diversity value */
2403
	if(isset($wlcfg['diversity']))
2404
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2405

    
2406
	/* Set txantenna value */
2407
	if(isset($wlcfg['txantenna']))
2408
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2409

    
2410
	/* Set rxantenna value */
2411
	if(isset($wlcfg['rxantenna']))
2412
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2413

    
2414
	/* set Distance value */
2415
	if($wlcfg['distance'])
2416
		$distance = escapeshellarg($wlcfg['distance']);
2417

    
2418
	/* Set wireless hostap mode */
2419
	if ($wlcfg['mode'] == "hostap") {
2420
		$wlcmd[] = "mediaopt hostap";
2421
	} else {
2422
		$wlcmd[] = "-mediaopt hostap";
2423
	}
2424

    
2425
	/* Set wireless adhoc mode */
2426
	if ($wlcfg['mode'] == "adhoc") {
2427
		$wlcmd[] = "mediaopt adhoc";
2428
	} else {
2429
		$wlcmd[] = "-mediaopt adhoc";
2430
	}
2431

    
2432
	/* Not neccesary to set BSS mode as this is default if adhoc and/or hostap is NOT set */
2433

    
2434
	/* handle hide ssid option */
2435
	if(isset($wlcfg['hidessid']['enable'])) {
2436
		$wlcmd[] = "hidessid";
2437
	} else {
2438
		$wlcmd[] = "-hidessid";
2439
	}
2440

    
2441
	/* handle pureg (802.11g) only option */
2442
	if(isset($wlcfg['pureg']['enable'])) {
2443
		$wlcmd[] = "mode 11g pureg";
2444
	} else {
2445
		$wlcmd[] = "-pureg";
2446
	}
2447

    
2448
	/* handle puren (802.11n) only option */
2449
	if(isset($wlcfg['puren']['enable'])) {
2450
		$wlcmd[] = "puren";
2451
	} else {
2452
		$wlcmd[] = "-puren";
2453
	}
2454

    
2455
	/* enable apbridge option */
2456
	if(isset($wlcfg['apbridge']['enable'])) {
2457
		$wlcmd[] = "apbridge";
2458
	} else {
2459
		$wlcmd[] = "-apbridge";
2460
	}
2461

    
2462
	/* handle turbo option */
2463
	if(isset($wlcfg['turbo']['enable'])) {
2464
		$wlcmd[] = "mediaopt turbo";
2465
	} else {
2466
		$wlcmd[] = "-mediaopt turbo";
2467
	}
2468

    
2469
	/* handle txpower setting */
2470
	/* if($wlcfg['txpower'] <> "")
2471
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2472
	*/
2473
	/* handle wme option */
2474
	if(isset($wlcfg['wme']['enable'])) {
2475
		$wlcmd[] = "wme";
2476
	} else {
2477
		$wlcmd[] = "-wme";
2478
	}
2479

    
2480
	/* set up wep if enabled */
2481
	$wepset = "";
2482
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2483
		switch($wlcfg['wpa']['auth_algs']) {
2484
			case "1":
2485
				$wepset .= "authmode open wepmode on ";
2486
				break;
2487
			case "2":
2488
				$wepset .= "authmode shared wepmode on ";
2489
				break;
2490
			case "3":
2491
				$wepset .= "authmode mixed wepmode on ";
2492
		}
2493
		$i = 1;
2494
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2495
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2496
			if (isset($wepkey['txkey'])) {
2497
				$wlcmd[] = "weptxkey {$i} ";
2498
			}
2499
			$i++;
2500
		}
2501
		$wlcmd[] = $wepset;
2502
	} else {
2503
		$wlcmd[] = "authmode open wepmode off ";
2504
	}
2505

    
2506
	kill_hostapd($if);
2507
	mwexec(kill_wpasupplicant("{$if}"));
2508

    
2509
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2510
	conf_mount_rw();
2511

    
2512
	switch ($wlcfg['mode']) {
2513
	case 'bss':
2514
		if (isset($wlcfg['wpa']['enable'])) {
2515
			$wpa .= <<<EOD
2516
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2517
ctrl_interface_group=0
2518
ap_scan=1
2519
#fast_reauth=1
2520
network={
2521
ssid="{$wlcfg['ssid']}"
2522
scan_ssid=1
2523
priority=5
2524
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2525
psk="{$wlcfg['wpa']['passphrase']}"
2526
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2527
group={$wlcfg['wpa']['wpa_pairwise']}
2528
}
2529
EOD;
2530

    
2531
			@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2532
			unset($wpa);
2533
		}
2534
		break;
2535
	case 'hostap':
2536
		if (!empty($wlcfg['wpa']['passphrase']))
2537
			$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2538
		else
2539
			$wpa_passphrase = "";
2540
		if (isset($wlcfg['wpa']['enable'])) {
2541
			$wpa .= <<<EOD
2542
interface={$if}
2543
driver=bsd
2544
logger_syslog=-1
2545
logger_syslog_level=0
2546
logger_stdout=-1
2547
logger_stdout_level=0
2548
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2549
ctrl_interface={$g['varrun_path']}/hostapd
2550
ctrl_interface_group=wheel
2551
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2552
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2553
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2554
ssid={$wlcfg['ssid']}
2555
debug={$wlcfg['wpa']['debug_mode']}
2556
auth_algs={$wlcfg['wpa']['auth_algs']}
2557
wpa={$wlcfg['wpa']['wpa_mode']}
2558
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2559
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2560
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2561
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2562
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2563
{$wpa_passphrase}
2564

    
2565
EOD;
2566

    
2567
			if (isset($wlcfg['wpa']['rsn_preauth'])) {
2568
				$wpa .= <<<EOD
2569
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2570
rsn_preauth=1
2571
rsn_preauth_interfaces={$if}
2572

    
2573
EOD;
2574
			}
2575
			if (isset($wlcfg['wpa']['ieee8021x'])) {
2576
				$wpa .= "ieee8021x=1\n";
2577

    
2578
			if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2579
				$auth_server_port = "1812";
2580
				if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port']))
2581
					$auth_server_port = intval($wlcfg['auth_server_port']);
2582
				$wpa .= <<<EOD
2583

    
2584
auth_server_addr={$wlcfg['auth_server_addr']}
2585
auth_server_port={$auth_server_port}
2586
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2587

    
2588
EOD;
2589
				if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2590
					$auth_server_port2 = "1812";
2591
					if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2']))
2592
						$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2593

    
2594
					$wpa .= <<<EOD
2595
auth_server_addr={$wlcfg['auth_server_addr2']}
2596
auth_server_port={$auth_server_port2}
2597
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2598

    
2599
EOD;
2600
					}
2601
				}
2602
			}
2603

    
2604
			@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2605
			unset($wpa);
2606
		}
2607
		break;
2608
	}
2609

    
2610
	/*
2611
	 *    all variables are set, lets start up everything
2612
	 */
2613

    
2614
	$baseif = interface_get_wireless_base($if);
2615
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2616
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2617

    
2618
	/* set sysctls for the wireless interface */
2619
	if (!empty($wl_sysctl)) {
2620
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2621
		foreach ($wl_sysctl as $wl_sysctl_line) {
2622
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2623
		}
2624
	}
2625

    
2626
	/* set ack timers according to users preference (if he/she has any) */
2627
	if($distance) {
2628
		fwrite($fd_set, "# Enable ATH distance settings\n");
2629
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2630
	}
2631

    
2632
	if (isset($wlcfg['wpa']['enable'])) {
2633
		if ($wlcfg['mode'] == "bss") {
2634
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2635
		}
2636
		if ($wlcfg['mode'] == "hostap") {
2637
			/* add line to script to restore old mac to make hostapd happy */
2638
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2639
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2640
				if (is_macaddr($if_oldmac))
2641
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2642
						" link " . escapeshellarg($if_oldmac) . "\n");
2643
			}
2644

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

    
2647
			/* add line to script to restore spoofed mac after running hostapd */
2648
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2649
				if ($wl['spoofmac'])
2650
					$if_curmac = $wl['spoofmac'];
2651
				else
2652
					$if_curmac = get_interface_mac($if);
2653
				if (is_macaddr($if_curmac))
2654
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2655
						" link " . escapeshellarg($if_curmac) . "\n");
2656
			}
2657
		}
2658
	}
2659

    
2660
	fclose($fd_set);
2661
	conf_mount_ro();
2662

    
2663
	/* Making sure regulatory settings have actually changed
2664
	 * before applying, because changing them requires bringing
2665
	 * down all wireless networks on the interface. */
2666
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2667
	$ifconfig_str = implode($output);
2668
	unset($output);
2669
	$reg_changing = false;
2670

    
2671
	/* special case for the debug country code */
2672
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2673
		$reg_changing = true;
2674
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2675
		$reg_changing = true;
2676
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2677
		$reg_changing = true;
2678
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2679
		$reg_changing = true;
2680
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2681
		$reg_changing = true;
2682

    
2683
	if ($reg_changing) {
2684
		/* set regulatory domain */
2685
		if($wlcfg['regdomain'])
2686
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2687

    
2688
		/* set country */
2689
		if($wlcfg['regcountry'])
2690
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2691

    
2692
		/* set location */
2693
		if($wlcfg['reglocation'])
2694
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2695

    
2696
		$wlregcmd_args = implode(" ", $wlregcmd);
2697

    
2698
		/* build a complete list of the wireless clones for this interface */
2699
		$clone_list = array();
2700
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2701
			$clone_list[] = interface_get_wireless_clone($baseif);
2702
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2703
			foreach ($config['wireless']['clone'] as $clone) {
2704
				if ($clone['if'] == $baseif)
2705
					$clone_list[] = $clone['cloneif'];
2706
			}
2707
		}
2708

    
2709
		/* find which clones are up and bring them down */
2710
		$clones_up = array();
2711
		foreach ($clone_list as $clone_if) {
2712
			$clone_status = pfSense_get_interface_addresses($clone_if);
2713
			if ($clone_status['status'] == 'up') {
2714
				$clones_up[] = $clone_if;
2715
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2716
			}
2717
		}
2718

    
2719
		/* apply the regulatory settings */
2720
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2721

    
2722
		/* bring the clones back up that were previously up */
2723
		foreach ($clones_up as $clone_if) {
2724
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2725

    
2726
			/*
2727
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2728
			 * is in infrastructure mode, and WPA is enabled.
2729
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2730
			 */
2731
			if ($clone_if != $if) {
2732
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2733
				if ( !empty($friendly_if)
2734
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2735
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2736
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2737
				}
2738
			}
2739
		}
2740
	}
2741

    
2742
	/* The mode must be specified in a separate command before ifconfig
2743
	 * will allow the mode and channel at the same time in the next. */
2744
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2745

    
2746
	/* configure wireless */
2747
	$wlcmd_args = implode(" ", $wlcmd);
2748
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2749
	unset($wlcmd_args, $wlcmd);
2750

    
2751

    
2752
	sleep(1);
2753
	/* execute hostapd and wpa_supplicant if required in shell */
2754
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2755

    
2756
	return 0;
2757

    
2758
}
2759

    
2760
function kill_hostapd($interface) {
2761
	global $g;
2762

    
2763
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2764
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2765
}
2766

    
2767
function kill_wpasupplicant($interface) {
2768
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2769
}
2770

    
2771
function find_dhclient_process($interface) {
2772
	if ($interface)
2773
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2774
	else
2775
		$pid = 0;
2776

    
2777
	return intval($pid);
2778
}
2779

    
2780
function find_dhcp6c_process($interface) {
2781
	global $g;
2782

    
2783
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid"))
2784
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2785
	else
2786
		return(false);
2787

    
2788
	return intval($pid);
2789
}
2790

    
2791
function interface_vlan_mtu_configured($realhwif, $mtu) {
2792
	global $config;
2793

    
2794
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
2795
		foreach ($config['vlans']['vlan'] as $vlan) {
2796
			if ($vlan['if'] != $realhwif)
2797
				continue;
2798
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2799
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
2800
				if (intval($config['interfaces'][$assignedport]['mtu'])> $mtu)
2801
					$mtu = $portmtu;
2802
			}
2803
		}
2804
	}
2805

    
2806
	return $mtu;
2807
}
2808

    
2809
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2810
	global $config;
2811

    
2812
	if (!is_array($vlanifs))
2813
		return;
2814

    
2815
	/* All vlans need to use the same mtu value as their parent. */
2816
	foreach ($vlanifs as $vlan) {
2817
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2818
		if (!empty($assignedport)) {
2819
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
2820
				/*
2821
				* XXX: This is really never going to happen just keep the code for safety and readbility.
2822
				* It never happens since interface_vlan_mtu_configured finds the biggest mtu on vlans.
2823
				* Also if it has a lower mtu configured just respect user choice.
2824
				*/
2825
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2826
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2827
			} else {
2828
				if (get_interface_mtu($vlan['vlanif']) != $mtu)
2829
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2830
			}
2831
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2832
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
2833
	}
2834
}
2835

    
2836
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2837
	global $config, $g;
2838
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2839
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2840

    
2841
	$wancfg = $config['interfaces'][$interface];
2842

    
2843
	if (!isset($wancfg['enable']))
2844
		return;
2845

    
2846
	$realif = get_real_interface($interface);
2847
	$realhwif_array = get_parent_interface($interface);
2848
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2849
	$realhwif = $realhwif_array[0];
2850

    
2851
	if (!does_interface_exist($realif)) {
2852
		$matches = array();
2853
		if (preg_match('/^(.*)_vlan([0-9]+)$/', $realif, $matches))
2854
			if (is_array($config['vlans']['vlan']))
2855
				foreach ($config['vlans']['vlan'] as $vlan)
2856
					if ($vlan['if'] == $matches[1] && $vlan['tag'] == $matches[2]) {
2857
						interface_vlan_configure($vlan);
2858
						break;
2859
					}
2860
		unset($matches);
2861
	}
2862

    
2863
	/* Disable Accepting router advertisements unless specifically requested */
2864
	if ($g['debug'])
2865
		log_error("Deny router advertisements for interface {$interface}");
2866
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2867

    
2868
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2869
		/* remove all IPv4 and IPv6 addresses */
2870
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2871
		if (is_array($tmpifaces)) {
2872
			foreach ($tmpifaces as $tmpiface) {
2873
				if (strstr($iface, ":"))
2874
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2875
				else
2876
					pfSense_interface_deladdress($realif, $tmpiface);
2877
			}
2878
		}
2879

    
2880
		/* only bring down the interface when both v4 and v6 are set to NONE */
2881
		if(empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
2882
			interface_bring_down($interface);
2883
		}
2884
	}
2885

    
2886
	/* wireless configuration? */
2887
	if (is_array($wancfg['wireless']))
2888
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2889

    
2890
	$mac = get_interface_mac($realhwif);
2891
	/*
2892
	 * Don't try to reapply the spoofed MAC if it's already applied.
2893
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2894
	 * the interface config again, which attempts to spoof the MAC again,
2895
	 * which cycles the link again...
2896
	 */
2897
	if (!empty($wancfg['spoofmac']) && ($wancfg['spoofmac'] != $mac)) {
2898
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2899
			" link " . escapeshellarg($wancfg['spoofmac']));
2900

    
2901
		/*
2902
		 * All vlans need to spoof their parent mac address, too.  see
2903
		 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2904
		 */
2905
		if (is_array($config['vlans']['vlan'])) {
2906
			foreach ($config['vlans']['vlan'] as $vlan) {
2907
				if ($vlan['if'] == $realhwif)
2908
					mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2909
					" link " . escapeshellarg($wancfg['spoofmac']));
2910
			}
2911
		}
2912
	}  else {
2913

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

    
2928
	/* media */
2929
	if (!empty($wancfg['media']) || !empty($wancfg['mediaopt'])) {
2930
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2931
		if ($wancfg['media'])
2932
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2933
		if ($wancfg['mediaopt'])
2934
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2935
		mwexec($cmd);
2936
	}
2937
	$options = pfSense_get_interface_addresses($realhwif);
2938

    
2939
	/* skip vlans for checksumming and polling */
2940
	if (!stristr($realif, "_vlan") && is_array($options)) {
2941
		$flags_on = 0;
2942
		$flags_off = 0;
2943
		if(isset($config['system']['disablechecksumoffloading'])) {
2944
			if (isset($options['encaps']['txcsum']))
2945
				$flags_off |= IFCAP_TXCSUM;
2946
			if (isset($options['encaps']['rxcsum']))
2947
				$flags_off |= IFCAP_RXCSUM;
2948
		} else {
2949
			if (isset($options['caps']['txcsum']))
2950
				$flags_on |= IFCAP_TXCSUM;
2951
			if (isset($options['caps']['rxcsum']))
2952
				$flags_on |= IFCAP_RXCSUM;
2953
		}
2954

    
2955
		if(isset($config['system']['disablesegmentationoffloading']))
2956
			$flags_off |= IFCAP_TSO;
2957
		else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6']))
2958
			$flags_on |= IFCAP_TSO;
2959

    
2960
		if(isset($config['system']['disablelargereceiveoffloading']))
2961
			$flags_off |= IFCAP_LRO;
2962
		else if (isset($options['caps']['lro']))
2963
			$flags_on |= IFCAP_LRO;
2964

    
2965
		/* if the NIC supports polling *AND* it is enabled in the GUI */
2966
		if (!isset($config['system']['polling']))
2967
			$flags_off |= IFCAP_POLLING;
2968
		else if (isset($options['caps']['polling']))
2969
			$flags_on |= IFCAP_POLLING;
2970

    
2971
		pfSense_interface_capabilities($realhwif, -$flags_off);
2972
		pfSense_interface_capabilities($realhwif, $flags_on);
2973
	}
2974

    
2975
	/* invalidate interface/ip/sn cache */
2976
	get_interface_arr(true);
2977
	unset($interface_ip_arr_cache[$realif]);
2978
	unset($interface_sn_arr_cache[$realif]);
2979
	unset($interface_ipv6_arr_cache[$realif]);
2980
	unset($interface_snv6_arr_cache[$realif]);
2981

    
2982
	$tunnelif = substr($realif, 0, 3);
2983
	switch ($wancfg['ipaddr']) {
2984
		case 'dhcp':
2985
			interface_dhcp_configure($interface);
2986
			break;
2987
		case 'pppoe':
2988
		case 'l2tp':
2989
		case 'pptp':
2990
		case 'ppp':
2991
			interface_ppps_configure($interface);
2992
			break;
2993
		default:
2994
			if ($tunnelif == "gre") {
2995
				if (is_array($config['gres']['gre'])) {
2996
					foreach ($config['gres']['gre'] as $gre)
2997
						if ($gre['greif'] == $realif)
2998
							interface_gre_configure($gre);
2999
				}
3000
			} else if ($tunnelif == "gif") {
3001
				if (is_array($config['gifs']['gif'])) {
3002
					foreach ($config['gifs']['gif'] as $gif)
3003
						if($gif['gifif'] == $realif)
3004
							interface_gif_configure($gif);
3005
				}
3006
			} else if (substr($realif, 0, 4) == "ovpn") {
3007
				/* XXX: Should be done anything?! */
3008
			} else if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3009
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3010
			}
3011
			break;
3012
	}
3013

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

    
3039
	if (!empty($wancfg['mtu'])) {
3040
		if (stristr($realif, "_vlan")) {
3041
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3042
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
3043
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3044
			else 
3045
				$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
3046

    
3047
			if ($wancfg['mtu'] > $parentmtu) {
3048
				if (get_interface_mtu($realhwif) != $wancfg['mtu'])
3049
					pfSense_interface_mtu($realhwif, $wancfg['mtu']);
3050

    
3051
				/* All vlans need to use the same mtu value as their parent. */
3052
				interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $wancfg['mtu']);
3053
			} else
3054
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3055
		} else {
3056
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3057
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3058

    
3059
			/* This case is needed when the parent of vlans is being configured */
3060
			interface_vlan_adapt_mtu(link_interface_to_vlans($realif), $wancfg['mtu']);
3061
		}
3062
		/* XXX: What about gre/gif/lagg/.. ? */
3063
	}
3064

    
3065
	if (does_interface_exist($wancfg['if']))
3066
		interfaces_bring_up($wancfg['if']);
3067

    
3068
	interface_netgraph_needed($interface);
3069

    
3070
	if (!$g['booting']) {
3071
		link_interface_to_vips($interface, "update");
3072

    
3073
		unset($gre);
3074
		$gre = link_interface_to_gre($interface);
3075
		if (!empty($gre))
3076
			array_walk($gre, 'interface_gre_configure');
3077

    
3078
		unset($gif);
3079
		$gif = link_interface_to_gif($interface);
3080
		if (!empty($gif))
3081
			array_walk($gif, 'interface_gif_configure');
3082

    
3083
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3084
			unset($bridgetmp);
3085
			$bridgetmp = link_interface_to_bridge($interface);
3086
			if (!empty($bridgetmp))
3087
				interface_bridge_add_member($bridgetmp, $realif);
3088
		}
3089

    
3090
		$grouptmp = link_interface_to_group($interface);
3091
		if (!empty($grouptmp))
3092
			array_walk($grouptmp, 'interface_group_add_member');
3093

    
3094
		if ($interface == "lan")
3095
			/* make new hosts file */
3096
			system_hosts_generate();
3097

    
3098
		if ($reloadall == true) {
3099

    
3100
			/* reconfigure static routes (kernel may have deleted them) */
3101
			system_routing_configure($interface);
3102

    
3103
			/* reload ipsec tunnels */
3104
			vpn_ipsec_configure();
3105

    
3106
			/* restart dnsmasq */
3107
			services_dnsmasq_configure();
3108

    
3109
			/* update dyndns */
3110
			send_event("service reload dyndns {$interface}");
3111

    
3112
			/* reload captive portal */
3113
			captiveportal_init_rules();
3114
		}
3115
	}
3116

    
3117
	interfaces_staticarp_configure($interface);
3118
	return 0;
3119
}
3120

    
3121
function interface_track6_configure($interface = "lan", $wancfg) {
3122
	global $config, $g;
3123

    
3124
	if (!is_array($wancfg))
3125
		return;
3126

    
3127
	if (!isset($wancfg['enable']))
3128
		return;
3129

    
3130
	/* If the interface is not configured via another, exit */
3131
	if (empty($wancfg['track6-interface']))
3132
		return;
3133

    
3134
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3135
	$realif = get_real_interface($interface);
3136
	$linklocal = find_interface_ipv6_ll($realif);
3137
	if (!empty($linklocal))
3138
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3139
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3140
	/* XXX: Probably should remove? */
3141
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3142

    
3143
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3144
	if (!isset($trackcfg['enable'])) {
3145
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3146
		return;
3147
	}
3148

    
3149
	switch($trackcfg['ipaddrv6']) {
3150
	case "6to4":
3151
		if ($g['debug'])
3152
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3153
		interface_track6_6to4_configure($interface, $wancfg);
3154
		break;
3155
	case "6rd":
3156
		if ($g['debug'])
3157
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3158
		interface_track6_6rd_configure($interface, $wancfg);
3159
		break;
3160
	}
3161

    
3162
	if (!$g['booting']) {
3163
		if (!function_exists('services_dhcpd_configure'))
3164
			require_once("services.inc");
3165

    
3166
		services_dhcpd_configure("inet6");
3167
	}
3168

    
3169
	return 0;
3170
}
3171

    
3172
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3173
	global $config, $g;
3174
	global $interface_ipv6_arr_cache;
3175
	global $interface_snv6_arr_cache;
3176

    
3177
	if (!is_array($lancfg))
3178
		return;
3179

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

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

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

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

    
3202
	/* binary presentation of the prefix for all 128 bits. */
3203
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3204

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

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

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

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

    
3230
	return 0;
3231
}
3232

    
3233
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3234
	global $config, $g;
3235
	global $interface_ipv6_arr_cache;
3236
	global $interface_snv6_arr_cache;
3237

    
3238
	if (!is_array($lancfg))
3239
		return;
3240

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

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

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

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

    
3263
	/* binary presentation of the prefix for all 128 bits. */
3264
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3265

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

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

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

    
3287
	return 0;
3288
}
3289

    
3290
function interface_6rd_configure($interface = "wan", $wancfg) {
3291
	global $config, $g;
3292

    
3293
	/* because this is a tunnel interface we can only function
3294
	 *	with a public IPv4 address on the interface */
3295

    
3296
	if (!is_array($wancfg))
3297
		return;
3298

    
3299
	$wanif = get_real_interface($interface);
3300
	$ip4address = find_interface_ip($wanif);
3301
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3302
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3303
		return false;
3304
	}
3305
	$hexwanv4 = return_hex_ipv4($ip4address);
3306

    
3307
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3308
		$wancfg['prefix-6rd-v4plen'] = 0;
3309

    
3310
	/* create the long prefix notation for math, save the prefix length */
3311
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3312
	$rd6prefixlen = $rd6prefix[1];
3313
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3314

    
3315
	/* binary presentation of the prefix for all 128 bits. */
3316
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3317

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

    
3325
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3326
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3327

    
3328
	$rd6brgw = "{$rd6prefix}{$wancfg['gateway-6rd']}";
3329

    
3330
	/* XXX: need to extend to support variable prefix size for v4 */
3331
	if (!is_module_loaded("if_stf"))
3332
		mwexec("/sbin/kldload if_stf.ko");
3333
	$stfiface = "{$interface}_stf";
3334
	if (does_interface_exist($stfiface))
3335
		pfSense_interface_destroy($stfiface);
3336
	$tmpstfiface = pfSense_interface_create("stf");
3337
	pfSense_interface_rename($tmpstfiface, $stfiface);
3338
	pfSense_interface_flags($stfiface, IFF_LINK2);
3339
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3340
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3341
	if ($wancfg['prefix-6rd-v4plen'] > 0 && $wancfg['prefix-6rd-v4plen'] < 32)
3342
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/{$wancfg['prefix-6rd-v4plen']}");
3343
	if ($g['debug'])
3344
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3345

    
3346
	/* write out a default router file */
3347
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3348
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3349

    
3350
	$ip4gateway = get_interface_gateway($interface);
3351
	if (is_ipaddrv4($ip4gateway))
3352
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3353

    
3354
	/* configure dependent interfaces */
3355
	if (!$g['booting'])
3356
		link_interface_to_track6($interface, "update");
3357

    
3358
	return 0;
3359
}
3360

    
3361
function interface_6to4_configure($interface = "wan", $wancfg){
3362
	global $config, $g;
3363

    
3364
	/* because this is a tunnel interface we can only function
3365
	 *	with a public IPv4 address on the interface */
3366

    
3367
	if (!is_array($wancfg))
3368
		return;
3369

    
3370
	$wanif = get_real_interface($interface);
3371
	$ip4address = find_interface_ip($wanif);
3372
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3373
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3374
		return false;
3375
	}
3376

    
3377
	/* create the long prefix notation for math, save the prefix length */
3378
	$stfprefixlen = 16;
3379
	$stfprefix = Net_IPv6::uncompress("2002::");
3380
	$stfarr = explode(":", $stfprefix);
3381
	$v4prefixlen = "0";
3382

    
3383
	/* we need the hex form of the interface IPv4 address */
3384
	$ip4arr = explode(".", $ip4address);
3385
	$hexwanv4 = "";
3386
	foreach($ip4arr as $octet)
3387
		$hexwanv4 .= sprintf("%02x", $octet);
3388

    
3389
	/* we need the hex form of the broker IPv4 address */
3390
	$ip4arr = explode(".", "192.88.99.1");
3391
	$hexbrv4 = "";
3392
	foreach($ip4arr as $octet)
3393
		$hexbrv4 .= sprintf("%02x", $octet);
3394

    
3395
	/* binary presentation of the prefix for all 128 bits. */
3396
	$stfprefixbin = "";
3397
	foreach($stfarr as $element) {
3398
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3399
	}
3400
	/* just save the left prefix length bits */
3401
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3402

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

    
3407
	/* for the local subnet too. */
3408
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3409
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);;
3410

    
3411
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3412
	$stfbrarr = array();
3413
	$stfbrbinarr = array();
3414
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3415
	foreach($stfbrbinarr as $bin)
3416
		$stfbrarr[] = dechex(bindec($bin));
3417
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3418

    
3419
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3420
	$stflanarr = array();
3421
	$stflanbinarr = array();
3422
	$stflanbinarr = str_split($stflanbin, 16);
3423
	foreach($stflanbinarr as $bin)
3424
		$stflanarr[] = dechex(bindec($bin));
3425
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3426
	$stflanarr[7] = 1;
3427
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3428

    
3429
	/* setup the stf interface */
3430
	if (!is_module_loaded("if_stf"))
3431
		mwexec("/sbin/kldload if_stf.ko");
3432
	$stfiface = "{$interface}_stf";
3433
	if (does_interface_exist($stfiface))
3434
		pfSense_interface_destroy($stfiface);
3435
	$tmpstfiface = pfSense_interface_create("stf");
3436
	pfSense_interface_rename($tmpstfiface, $stfiface);
3437
	pfSense_interface_flags($stfiface, IFF_LINK2);
3438
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3439

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

    
3443
	/* write out a default router file */
3444
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3445
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3446

    
3447
	$ip4gateway = get_interface_gateway($interface);
3448
	if (is_ipaddrv4($ip4gateway))
3449
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3450

    
3451
	if (!$g['booting'])
3452
		link_interface_to_track6($interface, "update");
3453

    
3454
	return 0;
3455
}
3456

    
3457
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3458
	global $config, $g;
3459

    
3460
	if (!is_array($wancfg))
3461
		return;
3462

    
3463
	$wanif = get_real_interface($interface, "inet6");
3464
	$dhcp6cconf = "";
3465
	$dhcp6cconf .= "interface {$wanif} {\n";
3466

    
3467
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3468
	if($wancfg['ipaddrv6'] == "slaac") {
3469
		$dhcp6cconf .= "	information-only;\n";
3470
		$dhcp6cconf .= "	request domain-name-servers;\n";
3471
		$dhcp6cconf .= "	request domain-name;\n";
3472
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3473
		$dhcp6cconf .= "};\n";
3474
	} else {
3475
		/* skip address request if this is set */
3476
		if(!isset($wancfg['dhcp6prefixonly']))
3477
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3478
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3479
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3480

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

    
3485
		$dhcp6cconf .= "};\n";
3486

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

    
3490
		if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3491
			/* Setup the prefix delegation */
3492
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3493
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3494
			if (isset($wancfg['dhcp6-ia-pd-send-hint']))
3495
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3496
			$iflist = link_interface_to_track6($interface);
3497
			foreach ($iflist as $friendly => $ifcfg) {
3498
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3499
					if ($g['debug'])
3500
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3501
					$realif = get_real_interface($friendly);
3502
					$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3503
					$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3504
					$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3505
					$dhcp6cconf .= "	};\n";
3506
				}
3507
			}
3508
			unset($preflen, $iflist, $ifcfg);
3509
			$dhcp6cconf .= "};\n";
3510
		}
3511
	}
3512
	/* wide-dhcp6c works for now. */
3513
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3514
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3515
		unset($dhcp6cconf);
3516
		return 1;
3517
	}
3518
	unset($dhcp6cconf);
3519

    
3520
	$dhcp6cscript = "#!/bin/sh\n";
3521
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3522
	$dhcp6cscript .= "/etc/rc.newwanipv6 {$wanif} \n";
3523
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3524
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3525
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3526
		unset($dhcp6cscript);
3527
		return 1;
3528
	}
3529
	unset($dhcp6cscript);
3530
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3531

    
3532
	$rtsoldscript = "#!/bin/sh\n";
3533
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3534
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3535
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3536
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3537
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3538
	$rtsoldscript .= "\t/bin/sleep 1\n";
3539
	$rtsoldscript .= "fi\n";
3540
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3541
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3542
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3543
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3544
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3545
		unset($rtsoldscript);
3546
		return 1;
3547
	}
3548
	unset($rtsoldscript);
3549
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3550

    
3551
	/* accept router advertisements for this interface */
3552
	mwexec("/sbin/sysctl -w net.inet6.ip6.accept_rtadv=1");
3553
	log_error("Accept router advertisements on interface {$wanif} ");
3554
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3555

    
3556
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3557
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3558
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3559
		sleep(2);
3560
	}
3561
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3562

    
3563
	/* NOTE: will be called from rtsold invoked script
3564
	 * link_interface_to_track6($interface, "update");
3565
	 */
3566

    
3567
	return 0;
3568
}
3569

    
3570
function interface_dhcp_configure($interface = "wan") {
3571
	global $config, $g;
3572

    
3573
	$wancfg = $config['interfaces'][$interface];
3574
	$wanif = $wancfg['if'];
3575
	if (empty($wancfg))
3576
		$wancfg = array();
3577

    
3578
	/* generate dhclient_wan.conf */
3579
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3580
	if (!$fd) {
3581
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3582
		return 1;
3583
	}
3584

    
3585
	if ($wancfg['dhcphostname']) {
3586
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3587
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3588
	} else {
3589
		$dhclientconf_hostname = "";
3590
	}
3591

    
3592
	$wanif = get_real_interface($interface);
3593
	if (empty($wanif)) {
3594
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3595
		return 0;
3596
	}
3597
	$dhclientconf = "";
3598

    
3599
	$dhclientconf .= <<<EOD
3600
interface "{$wanif}" {
3601
timeout 60;
3602
retry 15;
3603
select-timeout 0;
3604
initial-interval 1;
3605
	{$dhclientconf_hostname}
3606
	script "/sbin/dhclient-script";
3607
EOD;
3608

    
3609
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3610
	$dhclientconf .= <<<EOD
3611

    
3612
	reject {$wancfg['dhcprejectfrom']};
3613
EOD;
3614
}
3615
	$dhclientconf .= <<<EOD
3616

    
3617
}
3618

    
3619
EOD;
3620

    
3621
if(is_ipaddr($wancfg['alias-address'])) {
3622
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3623
	$dhclientconf .= <<<EOD
3624
alias {
3625
	interface  "{$wanif}";
3626
	fixed-address {$wancfg['alias-address']};
3627
	option subnet-mask {$subnetmask};
3628
}
3629

    
3630
EOD;
3631
}
3632
	fwrite($fd, $dhclientconf);
3633
	fclose($fd);
3634

    
3635
	/* bring wan interface up before starting dhclient */
3636
	if($wanif)
3637
		interfaces_bring_up($wanif);
3638
	else
3639
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3640

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

    
3644
	return 0;
3645
}
3646

    
3647
function interfaces_group_setup() {
3648
	global $config;
3649

    
3650
	if (!is_array($config['ifgroups']['ifgroupentry']))
3651
		return;
3652

    
3653
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3654
		interface_group_setup($groupar);
3655

    
3656
	return;
3657
}
3658

    
3659
function interface_group_setup(&$groupname /* The parameter is an array */) {
3660
	global $config;
3661

    
3662
	if (!is_array($groupname))
3663
		return;
3664
	$members = explode(" ", $groupname['members']);
3665
	foreach($members as $ifs) {
3666
		$realif = get_real_interface($ifs);
3667
		if ($realif)
3668
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3669
	}
3670

    
3671
	return;
3672
}
3673

    
3674
function is_interface_group($if) {
3675
	global $config;
3676

    
3677
	if (is_array($config['ifgroups']['ifgroupentry']))
3678
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
3679
			if ($groupentry['ifname'] === $if)
3680
				return true;
3681
		}
3682

    
3683
	return false;
3684
}
3685

    
3686
function interface_group_add_member($interface, $groupname) {
3687
	$interface = get_real_interface($interface);
3688
	mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
3689
}
3690

    
3691
/* COMPAT Function */
3692
function convert_friendly_interface_to_real_interface_name($interface) {
3693
	return get_real_interface($interface);
3694
}
3695

    
3696
/* COMPAT Function */
3697
function get_real_wan_interface($interface = "wan") {
3698
	return get_real_interface($interface);
3699
}
3700

    
3701
/* COMPAT Function */
3702
function get_current_wan_address($interface = "wan") {
3703
	return get_interface_ip($interface);
3704
}
3705

    
3706
/*
3707
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
3708
 */
3709
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
3710
	global $config;
3711

    
3712
	if (stristr($interface, "_vip")) {
3713
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
3714
			if ($vip['mode'] == "carp")  {
3715
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3716
					return $vip['interface'];
3717
			}
3718
		}
3719
	}
3720

    
3721
	/* XXX: For speed reasons reference directly the interface array */
3722
	$ifdescrs = &$config['interfaces'];
3723
	//$ifdescrs = get_configured_interface_list(false, true);
3724

    
3725
	foreach ($ifdescrs as $if => $ifname) {
3726
		if ($if == $interface || $ifname['if'] == $interface)
3727
			return $if;
3728

    
3729
		if (get_real_interface($if) == $interface)
3730
			return $if;
3731

    
3732
		$int = get_parent_interface($if, true);
3733
		if (is_array($int)) {
3734
			foreach ($int as $iface) {
3735
				if ($iface == $interface)
3736
					return $if;
3737
			}
3738
		}
3739
	}
3740

    
3741
	return NULL;
3742
}
3743

    
3744
/* attempt to resolve interface to friendly descr */
3745
function convert_friendly_interface_to_friendly_descr($interface) {
3746
	global $config;
3747

    
3748
	switch ($interface) {
3749
	case "l2tp":
3750
		$ifdesc = "L2TP";
3751
		break;
3752
	case "pptp":
3753
		$ifdesc = "PPTP";
3754
		break;
3755
	case "pppoe":
3756
		$ifdesc = "PPPoE";
3757
		break;
3758
	case "openvpn":
3759
		$ifdesc = "OpenVPN";
3760
		break;
3761
	case "enc0":
3762
	case "ipsec":
3763
		$ifdesc = "IPsec";
3764
		break;
3765
	default:
3766
		if (isset($config['interfaces'][$interface])) {
3767
			if (empty($config['interfaces'][$interface]['descr']))
3768
				$ifdesc = strtoupper($interface);
3769
			else
3770
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
3771
			break;
3772
		} else if (stristr($interface, "_vip")) {
3773
			if (is_array($config['virtualip']['vip'])) {
3774
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
3775
					if ($vip['mode'] == "carp")  {
3776
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3777
							return "{$vip['subnet']} - {$vip['descr']}";
3778
					}
3779
				}
3780
			}
3781
		} else {
3782
			/* if list */
3783
			$ifdescrs = get_configured_interface_with_descr(false, true);
3784
			foreach ($ifdescrs as $if => $ifname) {
3785
				if ($if == $interface || $ifname == $interface)
3786
					return $ifname;
3787
			}
3788
		}
3789
		break;
3790
	}
3791

    
3792
	return $ifdesc;
3793
}
3794

    
3795
function convert_real_interface_to_friendly_descr($interface) {
3796
	global $config;
3797

    
3798
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
3799

    
3800
	if ($ifdesc) {
3801
		$iflist = get_configured_interface_with_descr(false, true);
3802
		return $iflist[$ifdesc];
3803
	}
3804

    
3805
	return $interface;
3806
}
3807

    
3808
/*
3809
 *  get_parent_interface($interface):
3810
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
3811
 *				or virtual interface (i.e. vlan)
3812
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
3813
 *			-- returns $interface passed in if $interface parent is not found
3814
 *			-- returns empty array if an invalid interface is passed
3815
 *	(Only handles ppps and vlans now.)
3816
 */
3817
function get_parent_interface($interface, $avoidrecurse = false) {
3818
	global $config;
3819

    
3820
	$parents = array();
3821
	//Check that we got a valid interface passed
3822
	$realif = get_real_interface($interface);
3823
	if ($realif == NULL)
3824
		return $parents;
3825

    
3826
	// If we got a real interface, find it's friendly assigned name
3827
	if ($interface == $realif && $avoidrecurse == false)
3828
		$interface = convert_real_interface_to_friendly_interface_name($interface);
3829

    
3830
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
3831
		$ifcfg = $config['interfaces'][$interface];
3832
		switch ($ifcfg['ipaddr']) {
3833
			case "ppp":
3834
			case "pppoe":
3835
			case "pptp":
3836
			case "l2tp":
3837
				if (empty($parents))
3838
					if (is_array($config['ppps']['ppp']))
3839
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
3840
							if ($ifcfg['if'] == $ppp['if']) {
3841
								$ports = explode(',', $ppp['ports']);
3842
								foreach ($ports as $pid => $parent_if)
3843
									$parents[$pid] = get_real_interface($parent_if);
3844
								break;
3845
							}
3846
						}
3847
				break;
3848
			case "dhcp":
3849
			case "static":
3850
			default:
3851
				// Handle _vlans
3852
				if (stristr($realif,"_vlan"))
3853
					if (is_array($config['vlans']['vlan']))
3854
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
3855
							if ($ifcfg['if'] == $vlan['vlanif']){
3856
								$parents[0] = $vlan['if'];
3857
								break;
3858
							}
3859
				break;
3860
		}
3861
	}
3862

    
3863
	if (empty($parents))
3864
		$parents[0] = $realif;
3865

    
3866
	return $parents;
3867
}
3868

    
3869
function interface_is_wireless_clone($wlif) {
3870
	if(!stristr($wlif, "_wlan")) {
3871
		return false;
3872
	} else {
3873
		return true;
3874
	}
3875
}
3876

    
3877
function interface_get_wireless_base($wlif) {
3878
	if(!stristr($wlif, "_wlan")) {
3879
		return $wlif;
3880
	} else {
3881
		return substr($wlif, 0, stripos($wlif, "_wlan"));
3882
	}
3883
}
3884

    
3885
function interface_get_wireless_clone($wlif) {
3886
	if(!stristr($wlif, "_wlan")) {
3887
		return $wlif . "_wlan0";
3888
	} else {
3889
		return $wlif;
3890
	}
3891
}
3892

    
3893
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
3894
	global $config, $g;
3895

    
3896
	$wanif = NULL;
3897

    
3898
	switch ($interface) {
3899
	case "l2tp":
3900
		$wanif = "l2tp";
3901
		break;
3902
	case "pptp":
3903
		$wanif = "pptp";
3904
		break;
3905
	case "pppoe":
3906
		$wanif = "pppoe";
3907
		break;
3908
	case "openvpn":
3909
		$wanif = "openvpn";
3910
		break;
3911
	case "ipsec":
3912
	case "enc0":
3913
		$wanif = "enc0";
3914
		break;
3915
	case "ppp":
3916
		$wanif = "ppp";
3917
		break;
3918
	default:
3919
		// If a real interface was alread passed simply
3920
		// pass the real interface back.  This encourages
3921
		// the usage of this function in more cases so that
3922
		// we can combine logic for more flexibility.
3923
		if(does_interface_exist($interface, $flush)) {
3924
			$wanif = $interface;
3925
			break;
3926
		}
3927

    
3928
		if (empty($config['interfaces'][$interface]))
3929
			break;
3930

    
3931
		$cfg = &$config['interfaces'][$interface];
3932

    
3933
		if ($family == "inet6") {
3934
			switch ($cfg['ipaddrv6']) {
3935
			case "6rd":
3936
			case "6to4":
3937
				$wanif = "{$interface}_stf";
3938
				break;
3939
			case 'pppoe':
3940
			case 'ppp':
3941
			case 'l2tp':
3942
			case 'pptp':
3943
				if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
3944
					$wanif = interface_get_wireless_clone($cfg['if']);
3945
				else
3946
					$wanif = $cfg['if'];
3947
				break;
3948
			default:
3949
				switch ($cfg['ipaddr']) {
3950
				case 'pppoe':
3951
				case 'ppp':
3952
				case 'l2tp':
3953
				case 'pptp':
3954
					if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false)
3955
						$wanif = $cfg['if'];
3956
					else {
3957
						$parents = get_parent_interface($interface);
3958
						if (!empty($parents[0]))
3959
							$wanif = $parents[0];
3960
						else
3961
							$wanif = $cfg['if'];
3962
					}
3963
					break;
3964
				default:
3965
					if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
3966
						$wanif = interface_get_wireless_clone($cfg['if']);
3967
					else
3968
						$wanif = $cfg['if'];
3969
					break;
3970
				}
3971
				break;
3972
			}
3973
		} else {
3974
			// Wireless cloned NIC support (FreeBSD 8+)
3975
			// interface name format: $parentnic_wlanparentnic#
3976
			// example: ath0_wlan0
3977
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
3978
				$wanif = interface_get_wireless_clone($cfg['if']);
3979
			else
3980
				$wanif = $cfg['if'];
3981
		}
3982
		break;
3983
	}
3984

    
3985
	return $wanif;
3986
}
3987

    
3988
/* Guess the physical interface by providing a IP address */
3989
function guess_interface_from_ip($ipaddress) {
3990
	if(! is_ipaddr($ipaddress)) {
3991
		return false;
3992
	}
3993
	if(is_ipaddrv4($ipaddress)) {
3994
		/* create a route table we can search */
3995
		exec("netstat -rnWf inet", $output, $ret);
3996
		foreach($output as $line) {
3997
			if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
3998
				$fields = preg_split("/[ ]+/", $line);
3999
				if(ip_in_subnet($ipaddress, $fields[0])) {
4000
					return $fields[6];
4001
				}
4002
			}
4003
		}
4004
	}
4005
	/* FIXME: This works from cursory testing, regexp might need fine tuning */
4006
	if(is_ipaddrv6($ipaddress)) {
4007
		/* create a route table we can search */
4008
		exec("netstat -rnWf inet6", $output, $ret);
4009
		foreach($output as $line) {
4010
			if(preg_match("/[0-9a-f]+[:]+[0-9a-f]+[:]+[\/][0-9]+/", $line)) {
4011
				$fields = preg_split("/[ ]+/", $line);
4012
				if(ip_in_subnet($ipaddress, $fields[0])) {
4013
					return $fields[6];
4014
				}
4015
			}
4016
		}
4017
	}
4018
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
4019
	if(empty($ret)) {
4020
		return false;
4021
	}
4022
	return $ret;
4023
}
4024

    
4025
/*
4026
 * find_ip_interface($ip): return the interface where an ip is defined
4027
 *   (or if $bits is specified, where an IP within the subnet is defined)
4028
 */
4029
function find_ip_interface($ip, $bits = null) {
4030
	if (!is_ipaddr($ip))
4031
		return false;
4032

    
4033
	$isv6ip = is_ipaddrv6($ip);
4034

    
4035
	/* if list */
4036
	$ifdescrs = get_configured_interface_list();
4037

    
4038
	foreach ($ifdescrs as $ifdescr => $ifname) {
4039
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4040
		if (is_null($ifip))
4041
			continue;
4042
		if (is_null($bits)) {
4043
			if ($ip == $ifip) {
4044
				$int = get_real_interface($ifname);
4045
				return $int;
4046
			}
4047
		}
4048
		else {
4049
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4050
				$int = get_real_interface($ifname);
4051
				return $int;
4052
			}
4053
		}
4054
	}
4055

    
4056
	return false;
4057
}
4058

    
4059
/*
4060
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4061
 *   (or if $bits is specified, where an IP within the subnet is found)
4062
 */
4063
function find_virtual_ip_alias($ip, $bits = null) {
4064
	global $config;
4065

    
4066
	if (!is_array($config['virtualip']['vip'])) {
4067
		return false;
4068
	}
4069
	if (!is_ipaddr($ip))
4070
		return false;
4071

    
4072
	$isv6ip = is_ipaddrv6($ip);
4073

    
4074
	foreach ($config['virtualip']['vip'] as $vip) {
4075
		if ($vip['mode'] === "ipalias") {
4076
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4077
				continue;
4078
			if (is_null($bits)) {
4079
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4080
					return $vip;
4081
				}
4082
			}
4083
			else {
4084
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4085
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4086
					return $vip;
4087
				}
4088
			}
4089
		}
4090
	}
4091
	return false;
4092
}
4093

    
4094
/*
4095
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4096
 */
4097
function find_number_of_created_carp_interfaces() {
4098
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4099
}
4100

    
4101
function get_all_carp_interfaces() {
4102
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
4103
	$ints = explode(" ", $ints);
4104
	return $ints;
4105
}
4106

    
4107
/*
4108
 * find_carp_interface($ip): return the carp interface where an ip is defined
4109
 */
4110
function find_carp_interface($ip) {
4111
	global $config;
4112
	if (is_array($config['virtualip']['vip'])) {
4113
		foreach ($config['virtualip']['vip'] as $vip) {
4114
			if ($vip['mode'] == "carp") {
4115
				if(is_ipaddrv4($ip)) {
4116
					$carp_ip = get_interface_ip($vip['interface']);
4117
				}
4118
				if(is_ipaddrv6($ip)) {
4119
					$carp_ip = get_interface_ipv6($vip['interface']);
4120
				}
4121
				exec("/sbin/ifconfig", $output, $return);
4122
				foreach($output as $line) {
4123
					$elements = preg_split("/[ ]+/i", $line);
4124
					if(strstr($elements[0], "vip"))
4125
						$curif = str_replace(":", "", $elements[0]);
4126
					if(stristr($line, $ip)) {
4127
						$if = $curif;
4128
						continue;
4129
					}
4130
				}
4131

    
4132
				if ($if)
4133
					return $if;
4134
			}
4135
		}
4136
	}
4137
}
4138

    
4139
function link_carp_interface_to_parent($interface) {
4140
	global $config;
4141

    
4142
	if (empty($interface))
4143
		return;
4144

    
4145
	$carp_ip = get_interface_ip($interface);
4146
	$carp_ipv6 = get_interface_ipv6($interface);
4147

    
4148
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4149
		return;
4150

    
4151
	/* if list */
4152
	$ifdescrs = get_configured_interface_list();
4153
	foreach ($ifdescrs as $ifdescr => $ifname) {
4154
		/* check IPv4 */
4155
		if(is_ipaddrv4($carp_ip)) {
4156
			$interfaceip = get_interface_ip($ifname);
4157
			$subnet_bits = get_interface_subnet($ifname);
4158
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4159
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4160
				return $ifname;
4161
		}
4162
		/* Check IPv6 */
4163
		if(is_ipaddrv6($carp_ipv6)) {
4164
			$interfaceipv6 = get_interface_ipv6($ifname);
4165
			$prefixlen = get_interface_subnetv6($ifname);
4166
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4167
				return $ifname;
4168
		}
4169
	}
4170
	return "";
4171
}
4172

    
4173

    
4174
/****f* interfaces/link_ip_to_carp_interface
4175
 * NAME
4176
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4177
 * INPUTS
4178
 *   $ip
4179
 * RESULT
4180
 *   $carp_ints
4181
 ******/
4182
function link_ip_to_carp_interface($ip) {
4183
	global $config;
4184

    
4185
	if (!is_ipaddr($ip))
4186
		return;
4187

    
4188
	$carp_ints = "";
4189
	if (is_array($config['virtualip']['vip'])) {
4190
		$first = 0;
4191
		$carp_int = array();
4192
		foreach ($config['virtualip']['vip'] as $vip) {
4193
			if ($vip['mode'] == "carp") {
4194
				$carp_ip = $vip['subnet'];
4195
				$carp_sn = $vip['subnet_bits'];
4196
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4197
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4198
					$carp_int[] = "{$vip['interface']}_vip{$vip['vhid']}";
4199
				}
4200
			}
4201
		}
4202
		if (!empty($carp_int))
4203
			$carp_ints = implode(" ", array_unique($carp_int));
4204
	}
4205

    
4206
	return $carp_ints;
4207
}
4208

    
4209
function link_interface_to_track6($int, $action = "") {
4210
	global $config;
4211

    
4212
	if (empty($int))
4213
		return;
4214

    
4215
	if (is_array($config['interfaces'])) {
4216
		$list = array();
4217
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4218
			if (!isset($ifcfg['enable']))
4219
				continue;
4220
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4221
				if ($action == "update")
4222
					interface_track6_configure($ifname, $ifcfg);
4223
				else if ($action == "")
4224
					$list[$ifname] = $ifcfg;
4225
			}
4226
		}
4227
		return $list;
4228
	}
4229
}
4230

    
4231
function link_interface_to_vlans($int, $action = "") {
4232
	global $config;
4233

    
4234
	if (empty($int))
4235
		return;
4236

    
4237
	if (is_array($config['vlans']['vlan'])) {
4238
		$ifaces = array();
4239
		foreach ($config['vlans']['vlan'] as $vlan) {
4240
			if ($int == $vlan['if']) {
4241
				if ($action == "update") {
4242
					interfaces_bring_up($int);
4243
				} else if ($action == "")
4244
					$ifaces[$vlan['tag']] = $vlan;
4245
			}
4246
		}
4247
		if (!empty($ifaces))
4248
			return $ifaces;
4249
	}
4250
}
4251

    
4252
function link_interface_to_vips($int, $action = "") {
4253
	global $config;
4254

    
4255
	if (is_array($config['virtualip']['vip'])) {
4256
		$result = array();
4257
		foreach ($config['virtualip']['vip'] as $vip) {
4258
			if ($int == $vip['interface']) {
4259
				if ($action == "update")
4260
					interfaces_vips_configure($int);
4261
				else
4262
					$result[] = $vip;
4263
			}
4264
		}
4265
		return $result;
4266
	}
4267
}
4268

    
4269
/****f* interfaces/link_interface_to_bridge
4270
 * NAME
4271
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4272
 * INPUTS
4273
 *   $ip
4274
 * RESULT
4275
 *   bridge[0-99]
4276
 ******/
4277
function link_interface_to_bridge($int) {
4278
	global $config;
4279

    
4280
	if (is_array($config['bridges']['bridged'])) {
4281
		foreach ($config['bridges']['bridged'] as $bridge) {
4282
			if (in_array($int, explode(',', $bridge['members'])))
4283
				return "{$bridge['bridgeif']}";
4284
		}
4285
	}
4286
}
4287

    
4288
function link_interface_to_group($int) {
4289
	global $config;
4290

    
4291
	$result = array();
4292

    
4293
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4294
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4295
			if (in_array($int, explode(" ", $group['members'])))
4296
				$result[$group['ifname']] = $int;
4297
		}
4298
	}
4299

    
4300
	return $result;
4301
}
4302

    
4303
function link_interface_to_gre($interface) {
4304
	global $config;
4305

    
4306
	$result = array();
4307

    
4308
	if (is_array($config['gres']['gre'])) {
4309
		foreach ($config['gres']['gre'] as $gre)
4310
			if($gre['if'] == $interface)
4311
				$result[] = $gre;
4312
	}
4313

    
4314
	return $result;
4315
}
4316

    
4317
function link_interface_to_gif($interface) {
4318
	global $config;
4319

    
4320
	$result = array();
4321

    
4322
	if (is_array($config['gifs']['gif'])) {
4323
		foreach ($config['gifs']['gif'] as $gif)
4324
			if($gif['if'] == $interface)
4325
				$result[] = $gif;
4326
	}
4327

    
4328
	return $result;
4329
}
4330

    
4331
/*
4332
 * find_interface_ip($interface): return the interface ip (first found)
4333
 */
4334
function find_interface_ip($interface, $flush = false) {
4335
	global $interface_ip_arr_cache;
4336
	global $interface_sn_arr_cache;
4337

    
4338
	$interface = str_replace("\n", "", $interface);
4339

    
4340
	if (!does_interface_exist($interface))
4341
		return;
4342

    
4343
	/* Setup IP cache */
4344
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4345
		$ifinfo = pfSense_get_interface_addresses($interface);
4346
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4347
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4348
	}
4349

    
4350
	return $interface_ip_arr_cache[$interface];
4351
}
4352

    
4353
/*
4354
 * find_interface_ipv6($interface): return the interface ip (first found)
4355
 */
4356
function find_interface_ipv6($interface, $flush = false) {
4357
	global $interface_ipv6_arr_cache;
4358
	global $interface_snv6_arr_cache;
4359
	global $config;
4360

    
4361
	$interface = trim($interface);
4362
	$interface = get_real_interface($interface);
4363

    
4364
	if (!does_interface_exist($interface))
4365
		return;
4366

    
4367
	/* Setup IP cache */
4368
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4369
		$ifinfo = pfSense_get_interface_addresses($interface);
4370
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4371
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4372
	}
4373

    
4374
	return $interface_ipv6_arr_cache[$interface];
4375
}
4376

    
4377
/*
4378
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4379
 */
4380
function find_interface_ipv6_ll($interface, $flush = false) {
4381
	global $interface_llv6_arr_cache;
4382
	global $config;
4383

    
4384
	$interface = str_replace("\n", "", $interface);
4385

    
4386
	if (!does_interface_exist($interface))
4387
		return;
4388

    
4389
	/* Setup IP cache */
4390
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4391
		$ifinfo = pfSense_getall_interface_addresses($interface);
4392
		foreach($ifinfo as $line) {
4393
			if (strstr($line, ":")) {
4394
				$parts = explode("/", $line);
4395
				if(is_linklocal($parts[0])) {
4396
					$ifinfo['linklocal'] = $parts[0];
4397
				}
4398
			}
4399
		}
4400
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4401
	}
4402
	return $interface_llv6_arr_cache[$interface];
4403
}
4404

    
4405
function find_interface_subnet($interface, $flush = false) {
4406
	global $interface_sn_arr_cache;
4407
	global $interface_ip_arr_cache;
4408

    
4409
	$interface = str_replace("\n", "", $interface);
4410
	if (does_interface_exist($interface) == false)
4411
		return;
4412

    
4413
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4414
		$ifinfo = pfSense_get_interface_addresses($interface);
4415
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4416
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4417
	}
4418

    
4419
	return $interface_sn_arr_cache[$interface];
4420
}
4421

    
4422
function find_interface_subnetv6($interface, $flush = false) {
4423
	global $interface_snv6_arr_cache;
4424
	global $interface_ipv6_arr_cache;
4425

    
4426
	$interface = str_replace("\n", "", $interface);
4427
	if (does_interface_exist($interface) == false)
4428
		return;
4429

    
4430
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4431
		$ifinfo = pfSense_get_interface_addresses($interface);
4432
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4433
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4434
	}
4435

    
4436
	return $interface_snv6_arr_cache[$interface];
4437
}
4438

    
4439
function ip_in_interface_alias_subnet($interface, $ipalias) {
4440
	global $config;
4441

    
4442
	if (empty($interface) || !is_ipaddr($ipalias))
4443
		return false;
4444
	if (is_array($config['virtualip']['vip'])) {
4445
		foreach ($config['virtualip']['vip'] as $vip) {
4446
			switch ($vip['mode']) {
4447
			case "ipalias":
4448
				if ($vip['interface'] <> $interface)
4449
					break;
4450
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4451
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4452
					return true;
4453
				break;
4454
			}
4455
		}
4456
	}
4457

    
4458
	return false;
4459
}
4460

    
4461
function get_interface_ip($interface = "wan") {
4462
	$realif = get_failover_interface($interface);
4463
	if (!$realif) {
4464
		if (preg_match("/^carp/i", $interface))
4465
			$realif = $interface;
4466
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4467
			$realif = $interface;
4468
		else
4469
			return null;
4470
	}
4471

    
4472
	$curip = find_interface_ip($realif);
4473
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4474
		return $curip;
4475
	else
4476
		return null;
4477
}
4478

    
4479
function get_interface_ipv6($interface = "wan", $flush = false) {
4480
	global $config;
4481

    
4482
	$realif = get_failover_interface($interface, "inet6");
4483
	if (!$realif) {
4484
		if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4485
			$realif = $interface;
4486
		else
4487
			return null;
4488
	}
4489

    
4490
	/*
4491
	 * NOTE: On the case when only the prefix is requested,
4492
	 * the communication on WAN will be done over link-local.
4493
	 */
4494
	if (is_array($config['interfaces'][$interface])) {
4495
		switch ($config['interfaces'][$interface]['ipaddr']) {
4496
		case 'pppoe':
4497
		case 'l2tp':
4498
		case 'pptp':
4499
		case 'ppp':
4500
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4501
				$realif = get_real_interface($interface, "inet6", true);
4502
			break;
4503
		}
4504
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4505
			$curip = find_interface_ipv6_ll($realif, $flush);
4506
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4507
				return $curip;
4508
		}
4509
	}
4510

    
4511
	$curip = find_interface_ipv6($realif, $flush);
4512
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4513
		return $curip;
4514
	else
4515
		return null;
4516
}
4517

    
4518
function get_interface_linklocal($interface = "wan") {
4519

    
4520
	$realif = get_failover_interface($interface, "inet6");
4521
	if (!$realif) {
4522
		if (preg_match("/^carp/i", $interface))
4523
			$realif = $interface;
4524
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4525
			$realif = $interface;
4526
		else
4527
			return null;
4528
	}
4529

    
4530
	$curip = find_interface_ipv6_ll($realif);
4531
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4532
		return $curip;
4533
	else
4534
		return null;
4535
}
4536

    
4537
function get_interface_subnet($interface = "wan") {
4538
	$realif = get_real_interface($interface);
4539
	if (!$realif) {
4540
		if (preg_match("/^carp/i", $interface))
4541
			$realif = $interface;
4542
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4543
			$realif = $interface;
4544
		else
4545
			return null;
4546
	}
4547

    
4548
	$cursn = find_interface_subnet($realif);
4549
	if (!empty($cursn))
4550
		return $cursn;
4551

    
4552
	return null;
4553
}
4554

    
4555
function get_interface_subnetv6($interface = "wan") {
4556
	global $config;
4557

    
4558
	$realif = get_real_interface($interface, "inet6");
4559
	if (!$realif) {
4560
		if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4561
			$realif = $interface;
4562
		else
4563
			return null;
4564
	}
4565

    
4566
	$cursn = find_interface_subnetv6($realif);
4567
	if (!empty($cursn))
4568
		return $cursn;
4569

    
4570
	return null;
4571
}
4572

    
4573
/* return outside interfaces with a gateway */
4574
function get_interfaces_with_gateway() {
4575
	global $config;
4576

    
4577
	$ints = array();
4578

    
4579
	/* loop interfaces, check config for outbound */
4580
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4581
		switch ($ifname['ipaddr']) {
4582
			case "dhcp":
4583
			case "ppp";
4584
			case "pppoe":
4585
			case "pptp":
4586
			case "l2tp":
4587
			case "ppp";
4588
				$ints[$ifdescr] = $ifdescr;
4589
			break;
4590
			default:
4591
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
4592
				    !empty($ifname['gateway']))
4593
					$ints[$ifdescr] = $ifdescr;
4594
			break;
4595
		}
4596
	}
4597
	return $ints;
4598
}
4599

    
4600
/* return true if interface has a gateway */
4601
function interface_has_gateway($friendly) {
4602
	global $config;
4603

    
4604
	if (!empty($config['interfaces'][$friendly])) {
4605
		$ifname = &$config['interfaces'][$friendly];
4606
		switch ($ifname['ipaddr']) {
4607
			case "dhcp":
4608
			case "pppoe":
4609
			case "pptp":
4610
			case "l2tp":
4611
			case "ppp";
4612
				return true;
4613
			break;
4614
			default:
4615
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4616
					return true;
4617
				if (!empty($ifname['gateway']))
4618
					return true;
4619
			break;
4620
		}
4621
	}
4622

    
4623
	return false;
4624
}
4625

    
4626
/* return true if interface has a gateway */
4627
function interface_has_gatewayv6($friendly) {
4628
	global $config;
4629

    
4630
	if (!empty($config['interfaces'][$friendly])) {
4631
		$ifname = &$config['interfaces'][$friendly];
4632
		switch ($ifname['ipaddrv6']) {
4633
			case "slaac":
4634
			case "dhcp6":
4635
			case "6to4":
4636
			case "6rd":
4637
				return true;
4638
				break;
4639
			default:
4640
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4641
					return true;
4642
				if (!empty($ifname['gatewayv6']))
4643
					return true;
4644
				break;
4645
		}
4646
	}
4647

    
4648
	return false;
4649
}
4650

    
4651
/****f* interfaces/is_altq_capable
4652
 * NAME
4653
 *   is_altq_capable - Test if interface is capable of using ALTQ
4654
 * INPUTS
4655
 *   $int            - string containing interface name
4656
 * RESULT
4657
 *   boolean         - true or false
4658
 ******/
4659

    
4660
function is_altq_capable($int) {
4661
	/* Per:
4662
	 * http://www.freebsd.org/cgi/man.cgi?query=altq&manpath=FreeBSD+7.2-current&format=html
4663
	 * Only the following drivers have ALTQ support
4664
	 */
4665
	$capable = array("age", "alc", "ale", "an", "ath", "aue", "awi", "bce",
4666
			"bfe", "bge", "bridge", "cas", "dc", "de", "ed", "em", "ep", "fxp", "gem",
4667
			"hme", "igb", "ipw", "iwi", "jme", "le", "lem", "msk", "mxge", "my", "nfe",
4668
			"npe", "nve", "ral", "re", "rl", "rum", "run", "bwn", "sf", "sis", "sk",
4669
			"ste", "stge", "txp", "udav", "ural", "vge", "vr", "wi", "xl",
4670
			"ndis", "tun", "ovpns", "ovpnc", "vlan", "pppoe", "pptp", "ng",
4671
			"l2tp", "ppp", "vtnet");
4672

    
4673
	$int_family = remove_ifindex($int);
4674

    
4675
	if (in_array($int_family, $capable))
4676
		return true;
4677
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
4678
		return true;
4679
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
4680
		return true;
4681
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
4682
		return true;
4683
	else
4684
		return false;
4685
}
4686

    
4687
/****f* interfaces/is_interface_wireless
4688
 * NAME
4689
 *   is_interface_wireless - Returns if an interface is wireless
4690
 * RESULT
4691
 *   $tmp       - Returns if an interface is wireless
4692
 ******/
4693
function is_interface_wireless($interface) {
4694
	global $config, $g;
4695

    
4696
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
4697
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
4698
		if (preg_match($g['wireless_regex'], $interface)) {
4699
			if (isset($config['interfaces'][$friendly]))
4700
				$config['interfaces'][$friendly]['wireless'] = array();
4701
			return true;
4702
		}
4703
		return false;
4704
	} else
4705
		return true;
4706
}
4707

    
4708
function get_wireless_modes($interface) {
4709
	/* return wireless modes and channels */
4710
	$wireless_modes = array();
4711

    
4712
	$cloned_interface = get_real_interface($interface);
4713

    
4714
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4715
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
4716
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4717
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
4718

    
4719
		$interface_channels = "";
4720
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4721
		$interface_channel_count = count($interface_channels);
4722

    
4723
		$c = 0;
4724
		while ($c < $interface_channel_count) {
4725
			$channel_line = explode(",", $interface_channels["$c"]);
4726
			$wireless_mode = trim($channel_line[0]);
4727
			$wireless_channel = trim($channel_line[1]);
4728
			if(trim($wireless_mode) != "") {
4729
				/* if we only have 11g also set 11b channels */
4730
				if($wireless_mode == "11g") {
4731
					if(!isset($wireless_modes["11b"]))
4732
						$wireless_modes["11b"] = array();
4733
				} else if($wireless_mode == "11g ht") {
4734
					if(!isset($wireless_modes["11b"]))
4735
						$wireless_modes["11b"] = array();
4736
					if(!isset($wireless_modes["11g"]))
4737
						$wireless_modes["11g"] = array();
4738
					$wireless_mode = "11ng";
4739
				} else if($wireless_mode == "11a ht") {
4740
					if(!isset($wireless_modes["11a"]))
4741
						$wireless_modes["11a"] = array();
4742
					$wireless_mode = "11na";
4743
				}
4744
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
4745
			}
4746
			$c++;
4747
		}
4748
	}
4749
	return($wireless_modes);
4750
}
4751

    
4752
/* return channel numbers, frequency, max txpower, and max regulation txpower */
4753
function get_wireless_channel_info($interface) {
4754
	$wireless_channels = array();
4755

    
4756
	$cloned_interface = get_real_interface($interface);
4757

    
4758
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4759
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
4760
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4761
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
4762

    
4763
		$interface_channels = "";
4764
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4765

    
4766
		foreach ($interface_channels as $channel_line) {
4767
			$channel_line = explode(",", $channel_line);
4768
			if(!isset($wireless_channels[$channel_line[0]]))
4769
				$wireless_channels[$channel_line[0]] = $channel_line;
4770
		}
4771
	}
4772
	return($wireless_channels);
4773
}
4774

    
4775
/****f* interfaces/get_interface_mtu
4776
 * NAME
4777
 *   get_interface_mtu - Return the mtu of an interface
4778
 * RESULT
4779
 *   $tmp       - Returns the mtu of an interface
4780
 ******/
4781
function get_interface_mtu($interface) {
4782
	$mtu = pfSense_get_interface_addresses($interface);
4783
	return $mtu['mtu'];
4784
}
4785

    
4786
function get_interface_mac($interface) {
4787

    
4788
	$macinfo = pfSense_get_interface_addresses($interface);
4789
	return $macinfo["macaddr"];
4790
}
4791

    
4792
/****f* pfsense-utils/generate_random_mac_address
4793
 * NAME
4794
 *   generate_random_mac - generates a random mac address
4795
 * INPUTS
4796
 *   none
4797
 * RESULT
4798
 *   $mac - a random mac address
4799
 ******/
4800
function generate_random_mac_address() {
4801
	$mac = "02";
4802
	for($x=0; $x<5; $x++)
4803
		$mac .= ":" . dechex(rand(16, 255));
4804
	return $mac;
4805
}
4806

    
4807
/****f* interfaces/is_jumbo_capable
4808
 * NAME
4809
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
4810
 * INPUTS
4811
 *   $int             - string containing interface name
4812
 * RESULT
4813
 *   boolean          - true or false
4814
 ******/
4815
function is_jumbo_capable($iface) {
4816
	$iface = trim($iface);
4817
	$capable = pfSense_get_interface_addresses($iface);
4818

    
4819
	if (isset($capable['caps']['vlanmtu']))
4820
		return true;
4821

    
4822
	return false;
4823
}
4824

    
4825
function interface_setup_pppoe_reset_file($pppif, $iface="") {
4826
	global $g;
4827

    
4828
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
4829

    
4830
	if(!empty($iface) && !empty($pppif)){
4831
		$cron_cmd = <<<EOD
4832
#!/bin/sh
4833
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
4834
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
4835

    
4836
EOD;
4837

    
4838
		@file_put_contents($cron_file, $cron_cmd);
4839
		chmod($cron_file, 0755);
4840
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
4841
	} else
4842
		unlink_if_exists($cron_file);
4843
}
4844

    
4845
function get_interface_default_mtu($type = "ethernet") {
4846
	switch ($type) {
4847
	case "gre":
4848
		return 1476;
4849
		break;
4850
	case "gif":
4851
		return 1280;
4852
		break;
4853
	case "tun":
4854
	case "vlan":
4855
	case "tap":
4856
	case "ethernet":
4857
	default:
4858
		return 1500;
4859
		break;
4860
	}
4861

    
4862
	/* Never reached */
4863
	return 1500;
4864
}
4865

    
4866
function get_vip_descr($ipaddress) {
4867
	global $config;
4868

    
4869
	foreach ($config['virtualip']['vip'] as $vip) {
4870
		if ($vip['subnet'] == $ipaddress) {
4871
			return ($vip['descr']);
4872
		}
4873
	}
4874
	return "";
4875
}
4876

    
4877
function interfaces_staticarp_configure($if) {
4878
	global $config, $g;
4879
	if(isset($config['system']['developerspew'])) {
4880
		$mt = microtime();
4881
		echo "interfaces_staticarp_configure($if) being called $mt\n";
4882
	}
4883

    
4884
	$ifcfg = $config['interfaces'][$if];
4885

    
4886
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
4887
		return 0;
4888

    
4889
	/* Enable staticarp, if enabled */
4890
	if(isset($config['dhcpd'][$if]['staticarp'])) {
4891
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
4892
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4893
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
4894

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

    
4898
			}
4899

    
4900
		}
4901
	} else {
4902
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
4903
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4904
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
4905
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
4906
				if (isset($arpent['arp_table_static_entry'])) {
4907
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
4908
				}
4909
			}
4910
		}
4911
	}
4912

    
4913
	return 0;
4914
}
4915

    
4916
function get_failover_interface($interface, $family = "all") {
4917
	global $config;
4918

    
4919
	/* shortcut to get_real_interface if we find it in the config */
4920
	if (is_array($config['interfaces'][$interface])) {
4921
		return get_real_interface($interface, $family);
4922
	}
4923

    
4924
	/* compare against gateway groups */
4925
	$a_groups = return_gateway_groups_array();
4926
	if (is_array($a_groups[$interface])) {
4927
		/* we found a gateway group, fetch the interface or vip */
4928
		if ($a_groups[$interface][0]['vip'] <> "")
4929
			return $a_groups[$interface][0]['vip'];
4930
		else
4931
			return $a_groups[$interface][0]['int'];
4932
	}
4933
	/* fall through to get_real_interface */
4934
	/* XXX: Really needed? */
4935
	return get_real_interface($interface, $family);
4936
}
4937

    
4938
function remove_ifindex($ifname) {
4939
	return preg_replace("/[0-9]+$/", "", $ifname);
4940
}
4941

    
4942
?>
(25-25/66)