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) {
76
	global $config;
77

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

    
81
	$ints = get_interface_arr(true);
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['encaps']['txcsum']))
491
			$commontx = false;
492
		if (!isset($opts['encaps']['rxcsum']))
493
			$commonrx = false;
494
		if (!isset($opts['encaps']['tso4']))
495
			$commontso4 = false;
496
		if (!isset($opts['encaps']['tso6']))
497
			$commontso6 = false;
498
		if (!isset($opts['encaps']['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 = 0;
513
	if ($commonrx === false)
514
		$flags |= IFCAP_RXCSUM;
515
	if ($commontx === false)
516
		$flags |= IFCAP_TXCSUM;
517
	if ($commontso4 === false)
518
		$flags |= IFCAP_TSO4;
519
	if ($commontso6 === false)
520
		$flags |= IFCAP_TSO6;
521
	if ($commonlro === false)
522
		$flags |= IFCAP_LRO;
523

    
524
	if ($g['booting'] || !empty($bridge['bridgeif'])) {
525
		pfSense_interface_destroy($bridge['bridgeif']);
526
		pfSense_interface_create($bridge['bridgeif']);
527
		$bridgeif = escapeshellarg($bridge['bridgeif']);
528
	} else {
529
		$bridgeif = pfSense_interface_create("bridge");
530
		$bridge['bridgeif'] = $bridgeif;
531
	}
532

    
533
	$checklist = get_configured_interface_list();
534

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

    
551
	if (isset($bridge['enablestp'])) {
552
		/* Choose spanning tree proto */
553
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
554

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

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

    
651
	if ($bridge['bridgeif'])
652
		interfaces_bring_up($bridge['bridgeif']);
653
	else
654
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
655
}
656

    
657
function interface_bridge_add_member($bridgeif, $interface) {
658

    
659
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface))
660
		return;
661

    
662
	$mtu = get_interface_mtu($bridgeif);
663
	$mtum = get_interface_mtu($interface);
664

    
665
	if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500))
666
		pfSense_interface_mtu($interface, $mtu);
667

    
668
	$options = pfSense_get_interface_addresses($bridgeif);
669
	$flags = 0;
670
	if (!isset($options['encaps']['txcsum']))
671
		$flags |= IFCAP_TXCSUM;
672

    
673
	if (!isset($options['encaps']['rxcsum']))
674
		$flags |= IFCAP_RXCSUM;
675

    
676
	pfSense_interface_capabilities($interface, -$flags);
677

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

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

    
700
function interface_lagg_configure(&$lagg) {
701
	global $config, $g;
702

    
703
	if (!is_array($lagg))
704
		return -1;
705

    
706
	$members = explode(',', $lagg['members']);
707
	if (!count($members))
708
		return -1;
709

    
710
	if ($g['booting'] || !(empty($lagg['laggif']))) {
711
		pfSense_interface_destroy($lagg['laggif']);
712
		pfSense_interface_create($lagg['laggif']);
713
		$laggif = $lagg['laggif'];
714
	} else
715
		$laggif = pfSense_interface_create("lagg");
716

    
717
	/* Calculate smaller mtu and enforce it */
718
	$smallermtu = 0;
719
	foreach ($members as $member) {
720
		$opts = pfSense_get_interface_addresses($member);
721
		$mtu = $opts['mtu'];
722
		if (!isset($opts['encaps']['txcsum']))
723
			$commontx = false;
724
		if (!isset($opts['encaps']['rxcsum']))
725
			$commonrx = false;
726
		if (!isset($opts['encaps']['tso4']))
727
			$commontso4 = false;
728
		if (!isset($opts['encaps']['tso6']))
729
			$commontso6 = false;
730
		if (!isset($opts['encaps']['lro']))
731
			$commonlro = false;
732
		if ($smallermtu == 0 && !empty($mtu))
733
			$smallermtu = $mtu;
734
		else if (!empty($mtu) && $mtu < $smallermtu)
735
			$smallermtu = $mtu;
736
	}
737

    
738
	/* Just in case anything is not working well */
739
	if ($smallermtu == 0)
740
		$smallermtu = 1500;
741

    
742
	$flags = 0;
743
	if ($commonrx === false)
744
		$flags |= IFCAP_RXCSUM;
745
	if ($commontx === false)
746
		$flags |= IFCAP_TXCSUM;
747
	if ($commontso4 === false)
748
		$flags |= IFCAP_TSO4;
749
	if ($commontso6 === false)
750
		$flags |= IFCAP_TSO6;
751
	if ($commonlro === false)
752
		$flags |= IFCAP_LRO;
753

    
754
	$checklist = get_interface_list();
755

    
756
	foreach ($members as $member) {
757
		if (!array_key_exists($member, $checklist))
758
			continue;
759
		/* make sure the parent interface is up */
760
		pfSense_interface_mtu($member, $smallermtu);
761
		pfSense_interface_capabilities($member, -$flags);
762
		interfaces_bring_up($member);
763
		mwexec("/sbin/ifconfig {$laggif} laggport {$member}");
764
	}
765

    
766
	mwexec("/sbin/ifconfig {$laggif} laggproto {$lagg['proto']}");
767

    
768
	interfaces_bring_up($laggif);
769

    
770
	return $laggif;
771
}
772

    
773
function interfaces_gre_configure($checkparent = 0) {
774
	global $config;
775

    
776
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
777
		foreach ($config['gres']['gre'] as $i => $gre) {
778
			if(empty($gre['greif']))
779
				$gre['greif'] = "gre{$i}";
780
			if ($checkparent == 1) {
781
				if (strstr($gre['if'], "_vip"))
782
					continue;
783
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6")  
784
					continue;
785
			}
786
			else if ($checkparent == 2) {
787
				if (!strstr($gre['if'], "_vip"))
788
					continue;
789
				if (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")  
790
					continue;
791
			}
792
			/* XXX: Maybe we should report any errors?! */
793
			interface_gre_configure($gre);
794
		}
795
	}
796
}
797

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

    
802
	if (!is_array($gre))
803
		return -1;
804

    
805
	$realif = get_real_interface($gre['if']);
806
	$realifip = get_interface_ip($gre['if']);
807

    
808
	/* make sure the parent interface is up */
809
	interfaces_bring_up($realif);
810

    
811
	if ($g['booting'] || !(empty($gre['greif']))) {
812
		pfSense_interface_destroy($gre['greif']);
813
		pfSense_interface_create($gre['greif']);
814
		$greif = $gre['greif'];
815
	} else
816
		$greif = pfSense_interface_create("gre");
817

    
818
	/* Do not change the order here for more see gre(4) NOTES section. */
819
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} {$gre['remote-addr']}");
820
	if((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
821
		mwexec("/sbin/ifconfig {$greif} inet6 {$gre['tunnel-local-addr']} {$gre['tunnel-remote-addr']} prefixlen /{$gre['tunnel-remote-net']} ");
822
	} else {
823
		mwexec("/sbin/ifconfig {$greif} {$gre['tunnel-local-addr']} {$gre['tunnel-remote-addr']} netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
824
	}
825
	if (isset($gre['link0']))
826
		pfSense_interface_flags($greif, IFF_LINK0);
827
	if (isset($gre['link1']))
828
		pfSense_interface_flags($greif, IFF_LINK1);
829
	if (isset($gre['link2']))
830
		pfSense_interface_flags($greif, IFF_LINK2);
831

    
832
	if($greif)
833
		interfaces_bring_up($greif);
834
	else
835
		log_error(gettext("Could not bring greif up -- variable not defined."));
836

    
837
	if (isset($gre['link1']) && $gre['link1'])
838
		mwexec("/sbin/route add {$gre['tunnel-remote-addr']}/{$gre['tunnel-remote-net']} {$gre['tunnel-local-addr']}");
839
	if(is_ipaddrv4($gre['tunnel-remote-addr']))
840
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
841
	if(is_ipaddrv6($gre['tunnel-remote-addr']))
842
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
843

    
844
	return $greif;
845
}
846

    
847
function interfaces_gif_configure($checkparent = 0) {
848
	global $config;
849

    
850
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
851
		foreach ($config['gifs']['gif'] as $i => $gif) {
852
			if(empty($gif['gifif']))
853
				$gre['gifif'] = "gif{$i}";
854
			if ($checkparent == 1) {
855
				if (strstr($gif['if'], "_vip"))
856
					continue;
857
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6")  
858
					continue;
859
			}
860
			else if ($checkparent == 2) {
861
				if (!strstr($gre['if'], "_vip"))
862
					continue;
863
				if (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")  
864
					continue;
865
			}
866
			/* XXX: Maybe we should report any errors?! */
867
			interface_gif_configure($gif);
868
		}
869
	}
870
}
871

    
872
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
873
function interface_gif_configure(&$gif, $gifkey = "") {
874
	global $config, $g;
875

    
876
	if (!is_array($gif))
877
		return -1;
878

    
879
	$realif = get_real_interface($gif['if']);
880
	$ipaddr = $gif['ipaddr'];
881

    
882
	if (is_ipaddrv4($gif['remote-addr'])) {
883
		if (is_ipaddrv4($ipaddr))
884
			$realifip = $ipaddr;
885
		else
886
			$realifip = get_interface_ip($gif['if']);
887
		$realifgw = get_interface_gateway($gif['if']);
888
	} else if (is_ipaddrv6($gif['remote-addr'])) {
889
		if (is_ipaddrv6($ipaddr))
890
			$realifip = $ipaddr;
891
		else
892
			$realifip = get_interface_ipv6($gif['if']);
893
		$realifgw = get_interface_gatewayv6($gif['if']);
894
	}
895
	/* make sure the parent interface is up */
896
	if($realif)
897
		interfaces_bring_up($realif);
898
	else
899
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
900

    
901
	if ($g['booting'] || !(empty($gif['gifif']))) {
902
		pfSense_interface_destroy($gif['gifif']);
903
		pfSense_interface_create($gif['gifif']);
904
		$gifif = $gif['gifif'];
905
	} else
906
		$gifif = pfSense_interface_create("gif");
907

    
908
	/* Do not change the order here for more see gif(4) NOTES section. */
909
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} {$gif['remote-addr']}");
910
	if((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
911
		mwexec("/sbin/ifconfig {$gifif} inet6 {$gif['tunnel-local-addr']} {$gif['tunnel-remote-addr']} prefixlen /{$gif['tunnel-remote-net']} ");
912
	} else {
913
		mwexec("/sbin/ifconfig {$gifif} {$gif['tunnel-local-addr']} {$gif['tunnel-remote-addr']} netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
914
	}
915
	if (isset($gif['link0']))
916
		pfSense_interface_flags($gifif, IFF_LINK0);
917
	if (isset($gif['link1']))
918
		pfSense_interface_flags($gifif, IFF_LINK1);
919
	if($gifif)
920
		interfaces_bring_up($gifif);
921
	else
922
		log_error(gettext("could not bring gifif up -- variable not defined"));
923

    
924
	$iflist = get_configured_interface_list();
925
	foreach($iflist as $ifname) {
926
		if($config['interfaces'][$ifname]['if'] == $gifif) {
927
			if(get_interface_gateway($ifname)) {
928
				system_routing_configure($ifname);
929
				break;
930
			}
931
			if(get_interface_gateway_v6($ifname)) {
932
				system_routing_configure($ifname);
933
				break;
934
			}
935
		}
936
	}
937

    
938

    
939
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
940
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
941
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
942
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
943

    
944
	if (is_ipaddrv4($realifgw)) {
945
		mwexec("route change -host {$gif['remote-addr']} {$realifgw}");
946
	}
947
	if (is_ipaddrv6($realifgw)) {
948
		mwexec("route change -host -inet6 {$gif['remote-addr']} {$realifgw}");
949
	}
950

    
951
	return $gifif;
952
}
953

    
954
function interfaces_configure() {
955
	global $config, $g;
956

    
957
	if ($g['platform'] == 'jail')
958
		return;
959

    
960
	/* Set up our loopback interface */
961
	interfaces_loopback_configure();
962

    
963
	/* create the unconfigured wireless clones */
964
	interfaces_create_wireless_clones();
965

    
966
	/* set up LAGG virtual interfaces */
967
	interfaces_lagg_configure();
968

    
969
	/* set up VLAN virtual interfaces */
970
	interfaces_vlan_configure();
971

    
972
	interfaces_qinq_configure();
973

    
974
	$iflist = get_configured_interface_with_descr();
975
	$delayed_list = array();
976
	$bridge_list = array();
977
	$track6_list = array();
978

    
979
	/* This is needed to speedup interfaces on bootup. */
980
	$reload = false;
981
	if (!$g['booting'])
982
		$reload = true;
983

    
984
	foreach($iflist as $if => $ifname) {
985
		$realif = $config['interfaces'][$if]['if'];
986
		if (strstr($realif, "bridge"))
987
			$bridge_list[$if] = $ifname;
988
		else if (strstr($realif, "gre"))
989
			$delayed_list[$if] = $ifname;
990
		else if (strstr($realif, "gif"))
991
			$delayed_list[$if] = $ifname;
992
		else if (strstr($realif, "ovpn")) {
993
			//echo "Delaying OpenVPN interface configuration...done.\n";
994
			continue;
995
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
996
			$track6_list[$if] = $ifname;
997
		} else {
998
			if ($g['booting'])
999
				printf(gettext("Configuring %s interface..."), $ifname);
1000

    
1001
			if($g['debug'])
1002
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1003
			interface_configure($if, $reload);
1004
			if ($g['booting'])
1005
				echo gettext( "done.") . "\n";
1006
		}
1007
	}
1008

    
1009
	/*
1010
	 * NOTE: The following function parameter consists of
1011
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1012
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1013
	 */
1014

    
1015
	/* set up GRE virtual interfaces */
1016
	interfaces_gre_configure(1);
1017

    
1018
	/* set up GIF virtual interfaces */
1019
	interfaces_gif_configure(1);
1020

    
1021
	/* set up BRIDGe virtual interfaces */
1022
	interfaces_bridge_configure(1);
1023

    
1024
	foreach ($track6_list as $if => $ifname) {
1025
		if ($g['booting'])
1026
			printf(gettext("Configuring %s interface..."), $ifname);
1027
		if ($g['debug'])
1028
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1029

    
1030
		interface_configure($if, $reload);
1031

    
1032
		if ($g['booting'])
1033
			echo gettext("done.") . "\n";
1034
	}
1035

    
1036
	/* bring up vip interfaces */
1037
	interfaces_vips_configure();
1038

    
1039
	/* set up GRE virtual interfaces */
1040
	interfaces_gre_configure(2);
1041

    
1042
	/* set up GIF virtual interfaces */
1043
	interfaces_gif_configure(2);
1044

    
1045
	foreach ($delayed_list as $if => $ifname) {
1046
		if ($g['booting'])
1047
			printf(gettext("Configuring %s interface..."), $ifname);
1048
		if ($g['debug'])
1049
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1050

    
1051
		interface_configure($if, $reload);
1052

    
1053
		if ($g['booting'])
1054
			echo gettext("done.") . "\n";
1055
	}
1056

    
1057
	/* set up BRIDGe virtual interfaces */
1058
	interfaces_bridge_configure(2);
1059

    
1060
	foreach ($bridge_list as $if => $ifname) {
1061
		if ($g['booting'])
1062
			printf(gettext("Configuring %s interface..."), $ifname);
1063
		if($g['debug'])
1064
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1065

    
1066
		interface_configure($if, $reload);
1067

    
1068
		if ($g['booting'])
1069
			echo gettext("done.") . "\n";
1070
	}
1071

    
1072
	/* configure interface groups */
1073
	interfaces_group_setup();
1074

    
1075
	if (!$g['booting']) {
1076
		/* reconfigure static routes (kernel may have deleted them) */
1077
		system_routing_configure();
1078

    
1079
		/* reload IPsec tunnels */
1080
		vpn_ipsec_configure();
1081

    
1082
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1083
		services_dhcpd_configure();
1084

    
1085
		/* restart dnsmasq */
1086
		services_dnsmasq_configure();
1087

    
1088
		/* reload captive portal */
1089
		if (function_exists('captiveportal_init_rules'))
1090
			captiveportal_init_rules();
1091
	}
1092

    
1093
	return 0;
1094
}
1095

    
1096
function interface_reconfigure($interface = "wan", $reloadall = false) {
1097
	interface_bring_down($interface);
1098
	interface_configure($interface, $reloadall);
1099
}
1100

    
1101
function interface_vip_bring_down($vip) {
1102
	global $g;
1103

    
1104
	switch ($vip['mode']) {
1105
	case "proxyarp":
1106
		$vipif = get_real_interface($vip['interface']);
1107
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1108
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1109
		break;
1110
	case "ipalias":
1111
		$vipif = get_real_interface($vip['interface']);
1112
		if (does_interface_exist($vipif)) {
1113
			if (is_ipaddrv6($vip['subnet']))
1114
				mwexec("/sbin/ifconfig {$vipif} inet6 {$vip['subnet']} -alias");
1115
			else
1116
				pfSense_interface_deladdress($vipif, $vip['subnet']);
1117
		}
1118
		break;
1119
	case "carp":
1120
		$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
1121
		if (does_interface_exist($vipif))
1122
			pfSense_interface_destroy($vipif);
1123
		break;
1124
	}
1125
}
1126

    
1127
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1128
	global $config, $g;
1129

    
1130
	if (!isset($config['interfaces'][$interface]))
1131
		return;
1132

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

    
1136
	if ($ifacecfg === false) {
1137
		$ifcfg = $config['interfaces'][$interface];
1138
		$ppps = $config['ppps']['ppp'];
1139
		$realif = get_real_interface($interface);
1140
	} elseif (!is_array($ifacecfg)) {
1141
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1142
	} else {
1143
		$ifcfg = $ifacecfg['ifcfg'];
1144
		$ppps = $ifacecfg['ppps'];
1145
		if (isset($ifacecfg['ifcfg']['realif']))
1146
			$realif = $ifacecfg['ifcfg']['realif'];
1147
		else
1148
			$realif = get_real_interface($interface);
1149
	}
1150

    
1151
	switch ($ifcfg['ipaddr']) {
1152
	case "ppp":
1153
	case "pppoe":
1154
	case "pptp":
1155
	case "l2tp":
1156
		if (is_array($ppps) && count($ppps)) {
1157
			foreach ($ppps as $pppid => $ppp) {
1158
				if ($realif == $ppp['if']) {
1159
					if (isset($ppp['ondemand']) && !$destroy){
1160
						send_event("interface reconfigure {$interface}");
1161
						break;
1162
					}
1163
					if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1164
						killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1165
						sleep(2);
1166
					}
1167
					unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1168
					break;
1169
				}
1170
			}
1171
		}
1172
		break;
1173
	case "dhcp":
1174
		$pid = find_dhclient_process($realif);
1175
		if($pid)
1176
			posix_kill($pid, SIGTERM);
1177
		sleep(1);
1178
		unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1179
		if(does_interface_exist("$realif")) {
1180
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1181
			if ($destroy == true)
1182
				pfSense_interface_flags($realif, -IFF_UP);
1183
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1184
		}
1185
		break;
1186
	default:
1187
		if(does_interface_exist("$realif")) {
1188
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1189
			if ($destroy == true)
1190
				pfSense_interface_flags($realif, -IFF_UP);
1191
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1192
		}
1193
		break;
1194
	}
1195

    
1196
	switch ($ifcfg['ipaddrv6']) {
1197
	case "slaac":
1198
	case "dhcp6":
1199
		$pidv6 = find_dhcp6c_process($realif);
1200
		if($pidv6)
1201
			posix_kill($pidv6, SIGTERM);
1202
		$pidv6 = find_rtsold_process($realif);
1203
		if($pidv6)
1204
			posix_kill($pidv6, SIGTERM);
1205
		sleep(3);
1206
		unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1207
		if (does_interface_exist("$realif")) {
1208
			$ip6 = get_interface_ipv6($interface);
1209
			if (is_ipaddrv6($ip6))
1210
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1211
			if ($destroy == true)
1212
				pfSense_interface_flags($realif, -IFF_UP);
1213
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1214
		}
1215
		break;
1216
	case "6rd":
1217
	case "6to4":
1218
		$realif = "{$interface}_stf";
1219
		if(does_interface_exist("$realif")) {
1220
			$ip6 = get_interface_ipv6($interface);
1221
			if (is_ipaddrv6($ip6))
1222
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1223
			if ($destroy == true)
1224
				pfSense_interface_flags($realif, -IFF_UP);
1225
		}
1226
		break;
1227
	default:
1228
		if(does_interface_exist("$realif")) {
1229
			$ip6 = get_interface_ipv6($interface);
1230
			if (is_ipaddrv6($ip6))
1231
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1232
			if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
1233
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1234
			if ($destroy == true)
1235
				pfSense_interface_flags($realif, -IFF_UP);
1236
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1237
		}
1238
		break;
1239
	}
1240

    
1241
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1242
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1243
//	log_error("Checking for old router states: {$g['tmp_path']}/{$realif}_router = {$old_router}");
1244
	if (!empty($old_router)) {
1245
		log_error("Clearing states to old gateway {$old_router}.");
1246
		mwexec("/sbin/pfctl -i {$realif} -Fs -G {$old_router}");
1247
	}
1248

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

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

    
1265
	if ($destroy == true) {
1266
		if (preg_match("/^[a-z0-9]+_vip|^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif))
1267
			pfSense_interface_destroy($realif);
1268
	}
1269

    
1270
	return;
1271
}
1272

    
1273
function interfaces_ptpid_used($ptpid) {
1274
	global $config;
1275

    
1276
	if (is_array($config['ppps']['ppp']))
1277
		foreach ($config['ppps']['ppp'] as & $settings)
1278
			if ($ptpid == $settings['ptpid'])
1279
				return true;
1280

    
1281
	return false;
1282
}
1283

    
1284
function interfaces_ptpid_next() {
1285

    
1286
	$ptpid = 0;
1287
	while(interfaces_ptpid_used($ptpid))
1288
		$ptpid++;
1289

    
1290
	return $ptpid;
1291
}
1292

    
1293
function getMPDCRONSettings($pppif) {
1294
	global $config;
1295

    
1296
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1297
	if (is_array($config['cron']['item'])) {
1298
		foreach ($config['cron']['item'] as $i => $item) {
1299
			if (stripos($item['command'], $cron_cmd_file) !== false)
1300
				return array("ID" => $i, "ITEM" => $item);
1301
		}
1302
	}
1303

    
1304
	return NULL;
1305
}
1306

    
1307
function handle_pppoe_reset($post_array) {
1308
	global $config, $g;
1309

    
1310
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1311
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1312

    
1313
	if (!is_array($config['cron']['item']))
1314
		$config['cron']['item'] = array();
1315

    
1316
	$itemhash = getMPDCRONSettings($pppif);
1317

    
1318
	// reset cron items if necessary and return
1319
	if (empty($post_array['pppoe-reset-type'])) {
1320
		if (isset($itemhash))
1321
			unset($config['cron']['item'][$itemhash['ID']]);
1322
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1323
		return;
1324
	}
1325

    
1326
	if (empty($itemhash))
1327
		$itemhash = array();
1328
	$item = array();
1329
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1330
		$item['minute'] = $post_array['pppoe_resetminute'];
1331
		$item['hour'] = $post_array['pppoe_resethour'];
1332
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1333
			$date = explode("/", $post_array['pppoe_resetdate']);
1334
			$item['mday'] = $date[1];
1335
			$item['month'] = $date[0];
1336
		} else {
1337
			$item['mday'] = "*";
1338
			$item['month'] = "*";
1339
		}
1340
		$item['wday'] = "*";
1341
		$item['who'] = "root";
1342
		$item['command'] = $cron_cmd_file;
1343
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1344
		switch ($post_array['pppoe_pr_preset_val']) {
1345
		case "monthly":
1346
			$item['minute'] = "0";
1347
			$item['hour'] = "0";
1348
			$item['mday'] = "1";
1349
			$item['month'] = "*";
1350
			$item['wday'] = "*";
1351
			break;
1352
	        case "weekly":
1353
			$item['minute'] = "0";
1354
			$item['hour'] = "0";
1355
			$item['mday'] = "*";
1356
			$item['month'] = "*";
1357
			$item['wday'] = "0";
1358
			break;
1359
		case "daily":
1360
			$item['minute'] = "0";
1361
			$item['hour'] = "0";
1362
			$item['mday'] = "*";
1363
			$item['month'] = "*";
1364
			$item['wday'] = "*";
1365
			break;
1366
		case "hourly":
1367
			$item['minute'] = "0";
1368
			$item['hour'] = "*";
1369
			$item['mday'] = "*";
1370
			$item['month'] = "*";
1371
			$item['wday'] = "*";
1372
			break;
1373
		} // end switch
1374
		$item['who'] = "root";
1375
		$item['command'] = $cron_cmd_file;
1376
	}
1377
	if (empty($item))
1378
		return;
1379
	if (isset($item['ID']))
1380
		$config['cron']['item'][$item['ID']] = $item;
1381
	else
1382
		$config['cron']['item'][] = $item;
1383
}
1384

    
1385
/*
1386
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1387
 * It writes the mpd config file to /var/etc every time the link is opened.
1388
 */
1389
function interface_ppps_configure($interface) {
1390
	global $config, $g;
1391

    
1392
	/* Return for unassigned interfaces. This is a minimum requirement. */
1393
	if (empty($config['interfaces'][$interface]))
1394
		return 0;
1395
	$ifcfg = $config['interfaces'][$interface];
1396
	if (!isset($ifcfg['enable']))
1397
		return 0;
1398

    
1399
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1400
	if(!is_dir("/var/spool/lock")) {
1401
		exec("/bin/mkdir -p /var/spool/lock");
1402
		exec("/bin/chmod a+rw /var/spool/lock/.");
1403
	}
1404
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1405
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1406
		mwexec("/bin/ln -s /usr/local/sbin/mpd.script {$g['varetc_path']}/.");
1407

    
1408
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1409
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1410
			if ($ifcfg['if'] == $ppp['if'])
1411
				break;
1412
		}
1413
	}
1414
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1415
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1416
		return 0;
1417
	}
1418
	$pppif = $ifcfg['if'];
1419
	if ($ppp['type'] == "ppp")
1420
		$type = "modem";
1421
	else
1422
		$type = $ppp['type'];
1423
	$upper_type = strtoupper($ppp['type']);
1424

    
1425
	if($g['booting']) {
1426
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1427
		echo "starting {$pppif} link...";
1428
		// Do not re-configure the interface if we are booting and it's already been started
1429
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1430
			return 0;
1431
	}
1432

    
1433
	$ports = explode(',',$ppp['ports']);
1434
	if ($type != "modem") {
1435
		foreach ($ports as $pid => $port) {
1436
			$ports[$pid] = get_real_interface($port);
1437
			if (empty($ports[$pid]))
1438
				return 0;
1439
		}
1440
	}
1441
	$localips = explode(',',$ppp['localip']);
1442
	$gateways = explode(',',$ppp['gateway']);
1443
	$subnets = explode(',',$ppp['subnet']);
1444

    
1445
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1446
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1447
	 */
1448
	foreach($ports as $pid => $port){
1449
		switch ($ppp['type']) {
1450
			case "pppoe":
1451
				/* Bring the parent interface up */
1452
				interfaces_bring_up($port);
1453
				pfSense_ngctl_attach(".", $port);
1454
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1455
				mwexec("ngctl msg {$port}: setautosrc 1");
1456
				break;
1457
			case "pptp":
1458
			case "l2tp":
1459
				/* configure interface */
1460
				if(is_ipaddr($localips[$pid])){
1461
					// Manually configure interface IP/subnet
1462
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1463
					interfaces_bring_up($port);
1464
				} else if (empty($localips[$pid]))
1465
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1466

    
1467
				if(!is_ipaddr($localips[$pid])){
1468
					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!");
1469
					$localips[$pid] = "0.0.0.0";
1470
				}
1471
				if(!is_ipaddr($gateways[$pid])){
1472
					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));
1473
					return 0;
1474
				}
1475
				pfSense_ngctl_attach(".", $port);
1476
				break;
1477
			case "ppp":
1478
				if (!file_exists("{$port}")) {
1479
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1480
					return 0;
1481
				}
1482
				break;
1483
			default:
1484
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1485
				break;
1486
		}
1487
	}
1488

    
1489
	if (is_array($ports) && count($ports) > 1)
1490
		$multilink = "enable";
1491
	else
1492
		$multilink = "disable";
1493

    
1494
	if ($type == "modem"){
1495
		if (is_ipaddr($ppp['localip']))
1496
			$localip = $ppp['localip'];
1497
		else
1498
			$localip = '0.0.0.0';
1499

    
1500
		if (is_ipaddr($ppp['gateway']))
1501
			$gateway = $ppp['gateway'];
1502
		else
1503
			$gateway = "10.64.64.{$pppid}";
1504
		$ranges = "{$localip}/0 {$gateway}/0";
1505

    
1506
		if (empty($ppp['apnum']))
1507
			$ppp['apnum'] = 1;
1508
	} else
1509
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1510

    
1511
	if (isset($ppp['ondemand']))
1512
		$ondemand = "enable";
1513
	else
1514
		$ondemand = "disable";
1515
	if (!isset($ppp['idletimeout']))
1516
		$ppp['idletimeout'] = 0;
1517

    
1518
	if (empty($ppp['username']) && $type == "modem"){
1519
		$ppp['username'] = "user";
1520
		$ppp['password'] = "none";
1521
	}
1522
	if (empty($ppp['password']) && $type == "modem")
1523
		$passwd = "none";
1524
	else
1525
		$passwd = base64_decode($ppp['password']);
1526

    
1527
	$bandwidths = explode(',',$ppp['bandwidth']);
1528
	$defaultmtu = "1492";
1529
	if (!empty($ifcfg['mtu']))
1530
		$defaultmtu = intval($ifcfg['mtu']);
1531
	$mtus = explode(',',$ppp['mtu']);
1532
	$mrus = explode(',',$ppp['mru']);
1533

    
1534
	if (isset($ppp['mrru']))
1535
		$mrrus = explode(',',$ppp['mrru']);
1536

    
1537
	// Construct the mpd.conf file
1538
	$mpdconf = <<<EOD
1539
startup:
1540
	# configure the console
1541
	set console close
1542
	# configure the web server
1543
	set web close
1544

    
1545
default:
1546
{$ppp['type']}client:
1547
	create bundle static {$interface}
1548
	set bundle enable ipv6cp
1549
	set iface name {$pppif}
1550

    
1551
EOD;
1552
	$setdefaultgw = false;
1553
	$founddefaultgw = false;
1554
	if (is_array($config['gateways']['gateway_item'])) {
1555
		foreach($config['gateways']['gateway_item'] as $gateway) {
1556
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1557
				$setdefaultgw = true;
1558
				break;
1559
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1560
				$founddefaultgw = true;
1561
				break;
1562
			}
1563
		}
1564
	}
1565

    
1566
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1567
		$setdefaultgw = true;
1568
		$mpdconf .= <<<EOD
1569
	set iface route default
1570

    
1571
EOD;
1572
	}
1573
	$mpdconf .= <<<EOD
1574
	set iface {$ondemand} on-demand
1575
	set iface idle {$ppp['idletimeout']}
1576

    
1577
EOD;
1578

    
1579
	if (isset($ppp['ondemand']))
1580
		$mpdconf .= <<<EOD
1581
	set iface addrs 10.10.1.1 10.10.1.2
1582

    
1583
EOD;
1584

    
1585
	if (isset($ppp['tcpmssfix']))
1586
		$tcpmss = "disable";
1587
	else
1588
		$tcpmss = "enable";
1589
		$mpdconf .= <<<EOD
1590
	set iface {$tcpmss} tcpmssfix
1591

    
1592
EOD;
1593

    
1594
	$mpdconf .= <<<EOD
1595
	set iface up-script /usr/local/sbin/ppp-linkup
1596
	set iface down-script /usr/local/sbin/ppp-linkdown
1597
	set ipcp ranges {$ranges}
1598

    
1599
EOD;
1600
	if (isset($ppp['vjcomp']))
1601
		$mpdconf .= <<<EOD
1602
	set ipcp no vjcomp
1603

    
1604
EOD;
1605

    
1606
	if (isset($config['system']['dnsallowoverride']))
1607
		$mpdconf .= <<<EOD
1608
	set ipcp enable req-pri-dns
1609
	set ipcp enable req-sec-dns
1610

    
1611
EOD;
1612
	if (!isset($ppp['verbose_log']))
1613
		$mpdconf .= <<<EOD
1614
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1615

    
1616
EOD;
1617
	foreach($ports as $pid => $port){
1618
		$port = get_real_interface($port);
1619
		$mpdconf .= <<<EOD
1620

    
1621
	create link static {$interface}_link{$pid} {$type}
1622
	set link action bundle {$interface}
1623
	set link {$multilink} multilink
1624
	set link keep-alive 10 60
1625
	set link max-redial 0
1626

    
1627
EOD;
1628
		if (isset($ppp['shortseq']))
1629
			$mpdconf .= <<<EOD
1630
	set link no shortseq
1631

    
1632
EOD;
1633

    
1634
		if (isset($ppp['acfcomp']))
1635
			$mpdconf .= <<<EOD
1636
	set link no acfcomp
1637

    
1638
EOD;
1639

    
1640
		if (isset($ppp['protocomp']))
1641
			$mpdconf .= <<<EOD
1642
	set link no protocomp
1643

    
1644
EOD;
1645

    
1646
		$mpdconf .= <<<EOD
1647
	set link disable chap pap
1648
	set link accept chap pap eap
1649
	set link disable incoming
1650

    
1651
EOD;
1652

    
1653

    
1654
		if (!empty($bandwidths[$pid]))
1655
			$mpdconf .= <<<EOD
1656
	set link bandwidth {$bandwidths[$pid]}
1657

    
1658
EOD;
1659

    
1660
		if (empty($mtus[$pid]))
1661
			$mtus[$pid] = $defaultmtu;
1662
			$mpdconf .= <<<EOD
1663
	set link mtu {$mtus[$pid]}
1664

    
1665
EOD;
1666

    
1667
		if (!empty($mrus[$pid]))
1668
			$mpdconf .= <<<EOD
1669
	set link mru {$mrus[$pid]}
1670

    
1671
EOD;
1672

    
1673
		if (!empty($mrrus[$pid]))
1674
			$mpdconf .= <<<EOD
1675
	set link mrru {$mrrus[$pid]}
1676

    
1677
EOD;
1678

    
1679
		$mpdconf .= <<<EOD
1680
	set auth authname "{$ppp['username']}"
1681
	set auth password {$passwd}
1682

    
1683
EOD;
1684
		if ($type == "modem") {
1685
			$mpdconf .= <<<EOD
1686
	set modem device {$ppp['ports']}
1687
	set modem script DialPeer
1688
	set modem idle-script Ringback
1689
	set modem watch -cd
1690
	set modem var \$DialPrefix "DT"
1691
	set modem var \$Telephone "{$ppp['phone']}"
1692

    
1693
EOD;
1694
		}
1695
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1696
			$mpdconf .= <<<EOD
1697
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1698

    
1699
EOD;
1700
		}
1701
		if (isset($ppp['initstr']) && $type == "modem") {
1702
			$initstr = base64_decode($ppp['initstr']);
1703
			$mpdconf .= <<<EOD
1704
	set modem var \$InitString "{$initstr}"
1705

    
1706
EOD;
1707
		}
1708
		if (isset($ppp['simpin']) && $type == "modem") {
1709
			if($ppp['pin-wait'] == "")
1710
				$ppp['pin-wait'] = 0;
1711
			$mpdconf .= <<<EOD
1712
	set modem var \$SimPin "{$ppp['simpin']}"
1713
	set modem var \$PinWait "{$ppp['pin-wait']}"
1714

    
1715
EOD;
1716
		}
1717
		if (isset($ppp['apn']) && $type == "modem") {
1718
			$mpdconf .= <<<EOD
1719
	set modem var \$APN "{$ppp['apn']}"
1720
	set modem var \$APNum "{$ppp['apnum']}"
1721

    
1722
EOD;
1723
		}
1724
		if ($type == "pppoe") {
1725
			// Send a null service name if none is set.
1726
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1727
			$mpdconf .= <<<EOD
1728
	set pppoe service "{$provider}"
1729

    
1730
EOD;
1731
		}
1732
		if ($type == "pppoe")
1733
			$mpdconf .= <<<EOD
1734
	set pppoe iface {$port}
1735

    
1736
EOD;
1737

    
1738
		if ($type == "pptp" || $type == "l2tp") {
1739
			$mpdconf .= <<<EOD
1740
	set {$type} self {$localips[$pid]}
1741
	set {$type} peer {$gateways[$pid]}
1742

    
1743
EOD;
1744
		}
1745

    
1746
		$mpdconf .= "\topen\n";
1747
	} //end foreach($port)
1748

    
1749

    
1750
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1751
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1752
		mwexec("/bin/ln -s {$g['conf_path']}/mpd_{$interface}.conf {$g['varetc_path']}/.");
1753
	else {
1754
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1755
		if (!$fd) {
1756
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1757
			return 0;
1758
		}
1759
		// Write out mpd_ppp.conf
1760
		fwrite($fd, $mpdconf);
1761
		fclose($fd);
1762
		unset($mpdconf);
1763
	}
1764

    
1765
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1766
	if (isset($ppp['uptime'])) {
1767
		if (!file_exists("/conf/{$pppif}.log")) {
1768
			conf_mount_rw();
1769
			mwexec("echo /dev/null > /conf/{$pppif}.log");
1770
			conf_mount_ro();
1771
		}
1772
	} else {
1773
		if (file_exists("/conf/{$pppif}.log")) {
1774
			conf_mount_rw();
1775
			mwexec("rm -f /conf/{$pppif}.log");
1776
			conf_mount_ro();
1777
		}
1778
	}
1779

    
1780
	/* clean up old lock files */
1781
	foreach($ports as $port) {
1782
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1783
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1784
	}
1785

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

    
1789
	// Check for PPPoE periodic reset request
1790
	if ($type == "pppoe") {
1791
		if (!empty($ppp['pppoe-reset-type']))
1792
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1793
		else
1794
			interface_setup_pppoe_reset_file($ppp['if']);
1795
	}
1796
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1797
	$i = 0;
1798
	while($i < 10) {
1799
		exec("/sbin/ifconfig {$ppp['if']} 2>&1", $out, $ret);
1800
		if($ret == 0)
1801
			break;
1802
		sleep(1);
1803
		$i++;
1804
	}
1805

    
1806
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
1807
	/* We should be able to launch the right version for each modem */
1808
	/* We can also guess the mondev from the manufacturer */
1809
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
1810
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
1811
	foreach($ports as $port) {
1812
		if(preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1813
			$mondev  = substr(basename($port), 0, -1);
1814
			$devlist = glob("/dev/{$mondev}?");
1815
			$mondev = basename(end($devlist));
1816
		}
1817
		if(preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1818
			$mondev  = substr(basename($port), 0, -1) . "1";
1819
		}
1820
		log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
1821
		mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
1822
	}
1823

    
1824
	return 1;
1825
}
1826

    
1827
function interfaces_carp_setup() {
1828
	global $g, $config;
1829

    
1830
	if (isset($config['system']['developerspew'])) {
1831
		$mt = microtime();
1832
		echo "interfaces_carp_setup() being called $mt\n";
1833
	}
1834

    
1835
	if ($g['booting']) {
1836
		echo gettext("Configuring CARP settings...");
1837
		mute_kernel_msgs();
1838
	}
1839

    
1840
	/* suck in configuration items */
1841
	if ($config['hasync']) {
1842
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1843
		$balanacing = $config['hasync']['balancing'];
1844
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1845
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1846
	} else {
1847
		unset($pfsyncinterface);
1848
		unset($balanacing);
1849
		unset($pfsyncenabled);
1850
	}
1851

    
1852
	if ($balanacing) {
1853
		mwexec("/sbin/sysctl net.inet.carp.arpbalance=1", true);
1854
		mwexec("/sbin/sysctl net.inet.carp.preempt=0", true);
1855
	} else
1856
		mwexec("/sbin/sysctl net.inet.carp.preempt=1", true);
1857

    
1858
	mwexec("sbin/sysctl net.inet.carp.log=1", true);
1859
	if (!empty($pfsyncinterface))
1860
		$carp_sync_int = get_real_interface($pfsyncinterface);
1861
	else
1862
		unset($carp_sync_int);
1863

    
1864
	/* setup pfsync interface */
1865
	if ($carp_sync_int and $pfsyncenabled) {
1866
		if (is_ipaddr($pfsyncpeerip))
1867
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1868
		else
1869
			$syncpeer = "-syncpeer";
1870

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

    
1873
		sleep(1);
1874

    
1875
		/* 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
1876
		 * for existing sessions.
1877
		 */
1878
		log_error("waiting for pfsync...");
1879
		$i = 0;
1880
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1881
			$i++;
1882
			sleep(1);
1883
		}
1884
		log_error("pfsync done in $i seconds.");
1885
		log_error("Configuring CARP settings finalize...");
1886
	} else {
1887
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
1888
	}
1889

    
1890
	if($config['virtualip']['vip'])
1891
		mwexec("/sbin/sysctl net.inet.carp.allow=1", true);
1892
	else
1893
		mwexec("/sbin/sysctl net.inet.carp.allow=0", true);
1894

    
1895
	if ($g['booting']) {
1896
		unmute_kernel_msgs();
1897
		echo gettext("done.") . "\n";
1898
	}
1899
}
1900

    
1901
function interface_proxyarp_configure($interface = "") {
1902
	global $config, $g;
1903
	if(isset($config['system']['developerspew'])) {
1904
		$mt = microtime();
1905
		echo "interface_proxyarp_configure() being called $mt\n";
1906
	}
1907

    
1908
	/* kill any running choparp */
1909
	if (empty($interface))
1910
		killbyname("choparp");
1911
	else {
1912
		$vipif = get_real_interface($interface);
1913
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1914
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1915
	}
1916

    
1917
	$paa = array();
1918
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1919

    
1920
		/* group by interface */
1921
		foreach ($config['virtualip']['vip'] as $vipent) {
1922
			if ($vipent['mode'] === "proxyarp") {
1923
				if ($vipent['interface'])
1924
					$proxyif = $vipent['interface'];
1925
				else
1926
					$proxyif = "wan";
1927

    
1928
				if (!empty($interface) && $interface != $proxyif)
1929
					continue;
1930

    
1931
				if (!is_array($paa[$proxyif]))
1932
					$paa[$proxyif] = array();
1933

    
1934
				$paa[$proxyif][] = $vipent;
1935
			}
1936
		}
1937
	}
1938

    
1939
	if (!empty($interface)) {
1940
		if (is_array($paa[$interface])) {
1941
			$paaifip = get_interface_ip($interface);
1942
			if (!is_ipaddr($paaifip))
1943
				return;
1944
			$args = get_real_interface($interface) . " auto";
1945
			foreach ($paa[$interface] as $paent) {
1946
				if (isset($paent['subnet']))
1947
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1948
				else if (isset($paent['range']))
1949
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1950
			}
1951
			mwexec_bg("/usr/local/sbin/choparp " . $args);
1952
		}
1953
	} else if (count($paa) > 0) {
1954
		foreach ($paa as $paif => $paents)  {
1955
			$paaifip = get_interface_ip($paif);
1956
			if (!is_ipaddr($paaifip))
1957
				continue;
1958
			$args = get_real_interface($paif) . " auto";
1959
			foreach ($paents as $paent) {
1960
				if (isset($paent['subnet']))
1961
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1962
				else if (isset($paent['range']))
1963
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1964
			}
1965
			mwexec_bg("/usr/local/sbin/choparp " . $args);
1966
		}
1967
	}
1968
}
1969

    
1970
function interfaces_vips_configure($interface = "") {
1971
	global $g, $config;
1972
	if(isset($config['system']['developerspew'])) {
1973
		$mt = microtime();
1974
		echo "interfaces_vips_configure() being called $mt\n";
1975
	}
1976
	$paa = array();
1977
	if(is_array($config['virtualip']['vip'])) {
1978
		$carp_setuped = false;
1979
		$anyproxyarp = false;
1980
		foreach ($config['virtualip']['vip'] as $vip) {
1981
			switch ($vip['mode']) {
1982
			case "proxyarp":
1983
				/* nothing it is handled on interface_proxyarp_configure() */
1984
				if ($interface <> "" && $vip['interface'] <> $interface)
1985
					continue;
1986
				$anyproxyarp = true;
1987
				break;
1988
			case "ipalias":
1989
				if ($interface <> "" && $vip['interface'] <> $interface)
1990
					continue;
1991
				interface_ipalias_configure($vip);
1992
				break;
1993
			case "carp":
1994
				if ($interface <> "" && $vip['interface'] <> $interface)
1995
					continue;
1996
				if ($carp_setuped == false)
1997
					$carp_setuped = true;
1998
				interface_carp_configure($vip);
1999
				break;
2000
			}
2001
		}
2002
		if ($carp_setuped == true)
2003
			interfaces_carp_setup();
2004
		if ($anyproxyarp == true)
2005
			interface_proxyarp_configure();
2006
	}
2007
}
2008

    
2009
function interface_ipalias_configure(&$vip) {
2010
	if ($vip['mode'] == "ipalias") {
2011
		$if = get_real_interface($vip['interface']);
2012
		$af = "inet";
2013
		if(is_ipaddrv6($vip['subnet']))
2014
			$af = "inet6";
2015
		mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
2016
	}
2017
}
2018

    
2019
function interface_reload_carps($cif) {
2020
	global $config;
2021

    
2022
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2023
	if (empty($carpifs))
2024
		return;
2025

    
2026
	$carps = explode(" ", $carpifs);
2027
	if(is_array($config['virtualip']['vip'])) {
2028
		$viparr = &$config['virtualip']['vip'];
2029
		foreach ($viparr as $vip) {
2030
			if (in_array($vip['carpif'], $carps)) {
2031
				switch ($vip['mode']) {
2032
				case "carp":
2033
					interface_vip_bring_down($vip);
2034
					sleep(1);
2035
					interface_carp_configure($vip);
2036
					break;
2037
				case "ipalias":
2038
					interface_vip_bring_down($vip);
2039
					sleep(1);
2040
					interface_ipalias_configure($vip);
2041
					break;
2042
				}
2043
			}
2044
		}
2045
	}
2046
}
2047

    
2048
function interface_carp_configure(&$vip) {
2049
	global $config, $g;
2050
	if(isset($config['system']['developerspew'])) {
2051
		$mt = microtime();
2052
		echo "interface_carp_configure() being called $mt\n";
2053
	}
2054

    
2055
	if ($vip['mode'] != "carp")
2056
		return;
2057

    
2058
	/*
2059
	 * ensure the interface containing the VIP really exists
2060
	 * prevents a panic if the interface is missing or invalid
2061
	 */
2062
	$realif = get_real_interface($vip['interface']);
2063
	if (!does_interface_exist($realif)) {
2064
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2065
		return;
2066
	}
2067

    
2068
	if(is_ipaddrv4($vip['subnet'])) {
2069
		/* Ensure CARP IP really exists prior to loading up. */
2070
		$ww_subnet_ip = find_interface_ip($realif);
2071
		$ww_subnet_bits = find_interface_subnet($realif);
2072
		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'])) {
2073
			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", "");
2074
			return;
2075
		}
2076
	}
2077
	if(is_ipaddrv6($vip['subnet'])) {
2078
		/* Ensure CARP IP really exists prior to loading up. */
2079
		$ww_subnet_ip = find_interface_ipv6($realif);
2080
		$ww_subnet_bits = find_interface_subnetv6($realif);
2081
		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'])) {
2082
			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", "");
2083
			return;
2084
		}
2085
	}
2086

    
2087
	// set the vip interface to the vhid
2088
	$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
2089

    
2090
	/* create the carp interface and setup */
2091
	if (does_interface_exist($vipif)) {
2092
		pfSense_interface_flags($vipif, -IFF_UP);
2093
	} else {
2094
		$carpif = pfSense_interface_create("carp");
2095
		pfSense_interface_rename($carpif, $vipif);
2096
		pfSense_ngctl_name("{$carpif}:", $vipif);
2097
	}
2098

    
2099
	/* invalidate interface cache */
2100
	get_interface_arr(true);
2101

    
2102
	$vip_password = $vip['password'];
2103
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2104
	if ($vip['password'] != "")
2105
		$password = " pass {$vip_password}";
2106

    
2107
	$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2108
	$advbase = "";
2109
	if (!empty($vip['advbase']))
2110
		$advbase = "advbase {$vip['advbase']}";
2111

    
2112
	if(is_ipaddrv4($vip['subnet'])) {
2113
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2114
		mwexec("/sbin/ifconfig {$vipif} {$vip['subnet']}/{$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2115
	}
2116
	if(is_ipaddrv6($vip['subnet'])) {
2117
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2118
		mwexec("/sbin/ifconfig {$vipif} inet6 {$vip['subnet']} prefixlen {$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2119
	}
2120

    
2121
	interfaces_bring_up($vipif);
2122

    
2123
	return $vipif;
2124
}
2125

    
2126
function interface_wireless_clone($realif, $wlcfg) {
2127
	global $config, $g;
2128
	/*   Check to see if interface has been cloned as of yet.
2129
	 *   If it has not been cloned then go ahead and clone it.
2130
	 */
2131
	$needs_clone = false;
2132
	if(is_array($wlcfg['wireless']))
2133
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2134
	else
2135
		$wlcfg_mode = $wlcfg['mode'];
2136
	switch($wlcfg_mode) {
2137
		 case "hostap":
2138
			$mode = "wlanmode hostap";
2139
			break;
2140
		 case "adhoc":
2141
			$mode = "wlanmode adhoc";
2142
			break;
2143
		 default:
2144
			$mode = "";
2145
			break;
2146
	}
2147
	$baseif = interface_get_wireless_base($wlcfg['if']);
2148
	if(does_interface_exist($realif)) {
2149
		exec("/sbin/ifconfig {$realif}", $output, $ret);
2150
		$ifconfig_str = implode($output);
2151
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
2152
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2153
			$needs_clone = true;
2154
		}
2155
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
2156
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2157
			$needs_clone = true;
2158
		}
2159
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2160
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2161
			$needs_clone = true;
2162
		}
2163
	} else {
2164
		$needs_clone = true;
2165
	}
2166

    
2167
	if($needs_clone == true) {
2168
		/* remove previous instance if it exists */
2169
		if(does_interface_exist($realif))
2170
			pfSense_interface_destroy($realif);
2171

    
2172
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2173
		// Create the new wlan interface. FreeBSD returns the new interface name.
2174
		// example:  wlan2
2175
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2176
		if($ret <> 0) {
2177
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2178
			return false;
2179
		}
2180
		$newif = trim($out[0]);
2181
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2182
		pfSense_interface_rename($newif, $realif);
2183
		// FIXME: not sure what ngctl is for. Doesn't work.
2184
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
2185
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2186
	}
2187
	return true;
2188
}
2189

    
2190
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2191
	global $config, $g;
2192

    
2193
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2194
	                         'diversity', 'txantenna', 'rxantenna', 'distance',
2195
	                         'regdomain', 'regcountry', 'reglocation');
2196

    
2197
	if(!is_interface_wireless($ifcfg['if']))
2198
		return;
2199

    
2200
	$baseif = interface_get_wireless_base($ifcfg['if']);
2201

    
2202
	// Sync shared settings for assigned clones
2203
	$iflist = get_configured_interface_list(false, true);
2204
	foreach ($iflist as $if) {
2205
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2206
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2207
				foreach ($shared_settings as $setting) {
2208
					if ($sync_changes) {
2209
						if (isset($ifcfg['wireless'][$setting]))
2210
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2211
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2212
							unset($config['interfaces'][$if]['wireless'][$setting]);
2213
					} else {
2214
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2215
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2216
						else if (isset($ifcfg['wireless'][$setting]))
2217
							unset($ifcfg['wireless'][$setting]);
2218
					}
2219
				}
2220
				if (!$sync_changes)
2221
					break;
2222
			}
2223
		}
2224
	}
2225

    
2226
	// Read or write settings at shared area
2227
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2228
		foreach ($shared_settings as $setting) {
2229
			if ($sync_changes) {
2230
				if (isset($ifcfg['wireless'][$setting]))
2231
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2232
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2233
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2234
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2235
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2236
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2237
				else if (isset($ifcfg['wireless'][$setting]))
2238
					unset($ifcfg['wireless'][$setting]);
2239
			}
2240
		}
2241
	}
2242

    
2243
	// Sync the mode on the clone creation page with the configured mode on the interface
2244
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2245
		foreach ($config['wireless']['clone'] as &$clone) {
2246
			if ($clone['cloneif'] == $ifcfg['if']) {
2247
				if ($sync_changes) {
2248
					$clone['mode'] = $ifcfg['wireless']['mode'];
2249
				} else {
2250
					$ifcfg['wireless']['mode'] = $clone['mode'];
2251
				}
2252
				break;
2253
			}
2254
		}
2255
		unset($clone);
2256
	}
2257
}
2258

    
2259
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2260
	global $config, $g;
2261

    
2262
	/*    open up a shell script that will be used to output the commands.
2263
	 *    since wireless is changing a lot, these series of commands are fragile
2264
	 *    and will sometimes need to be verified by a operator by executing the command
2265
	 *    and returning the output of the command to the developers for inspection.  please
2266
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2267
	 */
2268

    
2269
	// Remove script file
2270
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2271

    
2272
	// Clone wireless nic if needed.
2273
	interface_wireless_clone($if, $wl);
2274

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

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

    
2282
	/* set values for /path/program */
2283
	$hostapd = "/usr/sbin/hostapd";
2284
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2285
	$ifconfig = "/sbin/ifconfig";
2286
	$sysctl = "/sbin/sysctl";
2287
	$killall = "/usr/bin/killall";
2288

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

    
2291
	$wlcmd = array();
2292
	$wl_sysctl = array();
2293
	/* Make sure it's up */
2294
	$wlcmd[] = "up";
2295
	/* Set a/b/g standard */
2296
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2297
	$wlcmd[] = "mode " . escapeshellarg($standard);
2298

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

    
2304
	/* Set ssid */
2305
	if($wlcfg['ssid'])
2306
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2307

    
2308
	/* Set 802.11g protection mode */
2309
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2310

    
2311
	/* set wireless channel value */
2312
	if(isset($wlcfg['channel'])) {
2313
		if($wlcfg['channel'] == "0") {
2314
			$wlcmd[] = "channel any";
2315
		} else {
2316
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2317
		}
2318
	}
2319

    
2320
	/* Set antenna diversity value */
2321
	if(isset($wlcfg['diversity']))
2322
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2323

    
2324
	/* Set txantenna value */
2325
	if(isset($wlcfg['txantenna']))
2326
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2327

    
2328
	/* Set rxantenna value */
2329
	if(isset($wlcfg['rxantenna']))
2330
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2331

    
2332
	/* set Distance value */
2333
	if($wlcfg['distance'])
2334
		$distance = escapeshellarg($wlcfg['distance']);
2335

    
2336
	/* Set wireless hostap mode */
2337
	if ($wlcfg['mode'] == "hostap") {
2338
		$wlcmd[] = "mediaopt hostap";
2339
	} else {
2340
		$wlcmd[] = "-mediaopt hostap";
2341
	}
2342

    
2343
	/* Set wireless adhoc mode */
2344
	if ($wlcfg['mode'] == "adhoc") {
2345
		$wlcmd[] = "mediaopt adhoc";
2346
	} else {
2347
		$wlcmd[] = "-mediaopt adhoc";
2348
	}
2349

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

    
2352
	/* handle hide ssid option */
2353
	if(isset($wlcfg['hidessid']['enable'])) {
2354
		$wlcmd[] = "hidessid";
2355
	} else {
2356
		$wlcmd[] = "-hidessid";
2357
	}
2358

    
2359
	/* handle pureg (802.11g) only option */
2360
	if(isset($wlcfg['pureg']['enable'])) {
2361
		$wlcmd[] = "mode 11g pureg";
2362
	} else {
2363
		$wlcmd[] = "-pureg";
2364
	}
2365

    
2366
	/* handle puren (802.11n) only option */
2367
	if(isset($wlcfg['puren']['enable'])) {
2368
		$wlcmd[] = "puren";
2369
	} else {
2370
		$wlcmd[] = "-puren";
2371
	}
2372

    
2373
	/* enable apbridge option */
2374
	if(isset($wlcfg['apbridge']['enable'])) {
2375
		$wlcmd[] = "apbridge";
2376
	} else {
2377
		$wlcmd[] = "-apbridge";
2378
	}
2379

    
2380
	/* handle turbo option */
2381
	if(isset($wlcfg['turbo']['enable'])) {
2382
		$wlcmd[] = "mediaopt turbo";
2383
	} else {
2384
		$wlcmd[] = "-mediaopt turbo";
2385
	}
2386

    
2387
	/* handle txpower setting */
2388
	/* if($wlcfg['txpower'] <> "")
2389
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2390
	*/
2391
	/* handle wme option */
2392
	if(isset($wlcfg['wme']['enable'])) {
2393
		$wlcmd[] = "wme";
2394
	} else {
2395
		$wlcmd[] = "-wme";
2396
	}
2397

    
2398
	/* set up wep if enabled */
2399
	$wepset = "";
2400
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2401
		switch($wlcfg['wpa']['auth_algs']) {
2402
			case "1":
2403
				$wepset .= "authmode open wepmode on ";
2404
				break;
2405
			case "2":
2406
				$wepset .= "authmode shared wepmode on ";
2407
				break;
2408
			case "3":
2409
				$wepset .= "authmode mixed wepmode on ";
2410
		}
2411
		$i = 1;
2412
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2413
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2414
			if (isset($wepkey['txkey'])) {
2415
				$wlcmd[] = "weptxkey {$i} ";
2416
			}
2417
			$i++;
2418
		}
2419
		$wlcmd[] = $wepset;
2420
	} else {
2421
		$wlcmd[] = "authmode open wepmode off ";
2422
	}
2423

    
2424
	kill_hostapd($if);
2425
	mwexec(kill_wpasupplicant("{$if}"));
2426

    
2427
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2428
	conf_mount_rw();
2429

    
2430
	switch ($wlcfg['mode']) {
2431
		case 'bss':
2432
			if (isset($wlcfg['wpa']['enable'])) {
2433
				$wpa .= <<<EOD
2434
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2435
ctrl_interface_group=0
2436
ap_scan=1
2437
#fast_reauth=1
2438
network={
2439
ssid="{$wlcfg['ssid']}"
2440
scan_ssid=1
2441
priority=5
2442
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2443
psk="{$wlcfg['wpa']['passphrase']}"
2444
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2445
group={$wlcfg['wpa']['wpa_pairwise']}
2446
}
2447
EOD;
2448

    
2449
				$fd = fopen("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", "w");
2450
				fwrite($fd, "{$wpa}");
2451
				fclose($fd);
2452
			}
2453
			break;
2454
		case 'hostap':
2455
			if($wlcfg['wpa']['passphrase'])
2456
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2457
			else
2458
				$wpa_passphrase = "";
2459
			if (isset($wlcfg['wpa']['enable'])) {
2460
				$wpa .= <<<EOD
2461
interface={$if}
2462
driver=bsd
2463
logger_syslog=-1
2464
logger_syslog_level=0
2465
logger_stdout=-1
2466
logger_stdout_level=0
2467
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2468
ctrl_interface={$g['varrun_path']}/hostapd
2469
ctrl_interface_group=wheel
2470
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2471
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2472
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2473
ssid={$wlcfg['ssid']}
2474
debug={$wlcfg['wpa']['debug_mode']}
2475
auth_algs={$wlcfg['wpa']['auth_algs']}
2476
wpa={$wlcfg['wpa']['wpa_mode']}
2477
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2478
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2479
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2480
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2481
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2482
{$wpa_passphrase}
2483

    
2484
EOD;
2485

    
2486
if (isset($wlcfg['wpa']['rsn_preauth'])) {
2487
	$wpa .= <<<EOD
2488
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2489
rsn_preauth=1
2490
rsn_preauth_interfaces={$if}
2491

    
2492
EOD;
2493

    
2494
}
2495
				if($wlcfg['auth_server_addr'] && $wlcfg['auth_server_shared_secret']) {
2496
					$auth_server_port = "1812";
2497
					if($wlcfg['auth_server_port'])
2498
						$auth_server_port = $wlcfg['auth_server_port'];
2499
					$auth_server_port2 = "1812";
2500
					if($wlcfg['auth_server_port2'])
2501
						$auth_server_port2 = $wlcfg['auth_server_port2'];
2502
					$wpa .= <<<EOD
2503

    
2504
ieee8021x=1
2505
auth_server_addr={$wlcfg['auth_server_addr']}
2506
auth_server_port={$auth_server_port}
2507
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2508
auth_server_addr={$wlcfg['auth_server_addr2']}
2509
auth_server_port={$auth_server_port2}
2510
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2511

    
2512
EOD;
2513
				} else {
2514
					$wpa .= "ieee8021x={$wlcfg['wpa']['ieee8021x']}\n";
2515
				}
2516

    
2517
				$fd = fopen("{$g['varetc_path']}/hostapd_{$if}.conf", "w");
2518
				fwrite($fd, "{$wpa}");
2519
				fclose($fd);
2520

    
2521
			}
2522
			break;
2523
	}
2524

    
2525
	/*
2526
	 *    all variables are set, lets start up everything
2527
	 */
2528

    
2529
	$baseif = interface_get_wireless_base($if);
2530
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2531
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2532

    
2533
	/* set sysctls for the wireless interface */
2534
	if (!empty($wl_sysctl)) {
2535
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2536
		foreach ($wl_sysctl as $wl_sysctl_line) {
2537
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2538
		}
2539
	}
2540

    
2541
	/* set ack timers according to users preference (if he/she has any) */
2542
	if($distance) {
2543
		fwrite($fd_set, "# Enable ATH distance settings\n");
2544
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2545
	}
2546

    
2547
	if (isset($wlcfg['wpa']['enable'])) {
2548
		if ($wlcfg['mode'] == "bss") {
2549
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2550
		}
2551
		if ($wlcfg['mode'] == "hostap") {
2552
			/* add line to script to restore old mac to make hostapd happy */
2553
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2554
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2555
				if (is_macaddr($if_oldmac))
2556
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2557
						" link " . escapeshellarg($if_oldmac) . "\n");
2558
			}
2559

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

    
2562
			/* add line to script to restore spoofed mac after running hostapd */
2563
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2564
				if ($wl['spoofmac'])
2565
					$if_curmac = $wl['spoofmac'];
2566
				else
2567
					$if_curmac = get_interface_mac($if);
2568
				if (is_macaddr($if_curmac))
2569
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2570
						" link " . escapeshellarg($if_curmac) . "\n");
2571
			}
2572
		}
2573
	}
2574

    
2575
	fclose($fd_set);
2576
	conf_mount_ro();
2577

    
2578
	/* Making sure regulatory settings have actually changed
2579
	 * before applying, because changing them requires bringing
2580
	 * down all wireless networks on the interface. */
2581
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2582
	$ifconfig_str = implode($output);
2583
	unset($output);
2584
	$reg_changing = false;
2585

    
2586
	/* special case for the debug country code */
2587
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2588
		$reg_changing = true;
2589
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2590
		$reg_changing = true;
2591
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2592
		$reg_changing = true;
2593
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2594
		$reg_changing = true;
2595
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2596
		$reg_changing = true;
2597

    
2598
	if ($reg_changing) {
2599
		/* set regulatory domain */
2600
		if($wlcfg['regdomain'])
2601
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2602

    
2603
		/* set country */
2604
		if($wlcfg['regcountry'])
2605
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2606

    
2607
		/* set location */
2608
		if($wlcfg['reglocation'])
2609
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2610

    
2611
		$wlregcmd_args = implode(" ", $wlregcmd);
2612

    
2613
		/* build a complete list of the wireless clones for this interface */
2614
		$clone_list = array();
2615
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2616
			$clone_list[] = interface_get_wireless_clone($baseif);
2617
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2618
			foreach ($config['wireless']['clone'] as $clone) {
2619
				if ($clone['if'] == $baseif)
2620
					$clone_list[] = $clone['cloneif'];
2621
			}
2622
		}
2623

    
2624
		/* find which clones are up and bring them down */
2625
		$clones_up = array();
2626
		foreach ($clone_list as $clone_if) {
2627
			$clone_status = pfSense_get_interface_addresses($clone_if);
2628
			if ($clone_status['status'] == 'up') {
2629
				$clones_up[] = $clone_if;
2630
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2631
			}
2632
		}
2633

    
2634
		/* apply the regulatory settings */
2635
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2636

    
2637
		/* bring the clones back up that were previously up */
2638
		foreach ($clones_up as $clone_if) {
2639
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2640

    
2641
			/*
2642
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2643
			 * is in infrastructure mode, and WPA is enabled.
2644
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2645
			 */
2646
			if ($clone_if != $if) {
2647
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2648
				if ( !empty($friendly_if)
2649
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2650
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2651
					mwexec("/bin/sh {$g['tmp_path']}/{$clone_if}_setup.sh");
2652
				}
2653
			}
2654
		}
2655
	}
2656

    
2657
	/* The mode must be specified in a separate command before ifconfig
2658
	 * will allow the mode and channel at the same time in the next. */
2659
	mwexec("/sbin/ifconfig {$if} mode " . escapeshellarg($standard));
2660

    
2661
	/* configure wireless */
2662
	$wlcmd_args = implode(" ", $wlcmd);
2663
	mwexec("/sbin/ifconfig {$if} $wlcmd_args", false);
2664

    
2665

    
2666
	sleep(1);
2667
	/* execute hostapd and wpa_supplicant if required in shell */
2668
	mwexec("/bin/sh {$g['tmp_path']}/{$if}_setup.sh");
2669

    
2670
	return 0;
2671

    
2672
}
2673

    
2674
function kill_hostapd($interface) {
2675
	global $g;
2676

    
2677
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2678
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2679
}
2680

    
2681
function kill_wpasupplicant($interface) {
2682
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2683
}
2684

    
2685
function find_dhclient_process($interface) {
2686
	if ($interface)
2687
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2688
	else
2689
		$pid = 0;
2690

    
2691
	return intval($pid);
2692
}
2693

    
2694
function find_rtsold_process($interface) {
2695
	global $g;
2696

    
2697
	if ($interface)
2698
		if (isvalidpid("{$g['varrun_path']}/rtsold_{$interface}.pid"))
2699
			$pid = trim(file_get_contents("{$g['varrun_path']}/rtsold_{$interface}.pid"), " \n");
2700
	else
2701
		return(false);
2702

    
2703
	return intval($pid);
2704
}
2705

    
2706
function find_dhcp6c_process($interface) {
2707
	global $g;
2708

    
2709
	if ($interface)
2710
		if (isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid"))
2711
			$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2712
	else
2713
		return(false);
2714

    
2715
	return intval($pid);
2716
}
2717

    
2718
function interface_vlan_mtu_configured($realhwif, $mtu) {
2719
	global $config;
2720

    
2721
	if (is_array($config['vlans']['vlan'])) {
2722
		foreach ($config['vlans']['vlan'] as $vlan) {
2723
			if ($vlan['if'] != $realhwif)
2724
				continue;
2725
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2726
			if (!empty($assignedport)) {
2727
				$portmtu = $config['interfaces'][$assignedport]['mtu'];
2728
				if (!empty($portmtu) && $portmtu > $mtu)
2729
					$mtu = $portmtu;
2730
			}
2731
		}
2732
	}
2733

    
2734
	return $mtu;
2735
}
2736

    
2737
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2738
	global $config, $g;
2739
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2740
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2741

    
2742
	$wancfg = $config['interfaces'][$interface];
2743

    
2744
	if (!isset($wancfg['enable']))
2745
		return;
2746

    
2747
	$realif = get_real_interface($interface);
2748
	$realhwif_array = get_parent_interface($interface);
2749
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2750
	$realhwif = $realhwif_array[0];
2751

    
2752
	/* Disable Accepting router advertisements unless specifically requested */
2753
	if ($g['debug'])
2754
		log_error("Deny router advertisements for interface {$interface}");
2755
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2756

    
2757
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2758
		/* remove all IPv4 and IPv6 addresses */
2759
		while (mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " -alias", true) == 0);
2760
		while (mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -alias", true) == 0);
2761

    
2762
		/* only bring down the interface when both v4 and v6 are set to NONE */
2763
		if(empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
2764
			interface_bring_down($interface);
2765
		}
2766
	}
2767

    
2768
	/* wireless configuration? */
2769
	if (is_array($wancfg['wireless']))
2770
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2771

    
2772
	$mac = get_interface_mac($realhwif);
2773
	/*
2774
	 * Don't try to reapply the spoofed MAC if it's already applied.
2775
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2776
	 * the interface config again, which attempts to spoof the MAC again,
2777
	 * which cycles the link again...
2778
	 */
2779
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
2780
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2781
			" link " . escapeshellarg($wancfg['spoofmac']));
2782

    
2783
		/*
2784
		 * All vlans need to spoof their parent mac address, too.  see
2785
		 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2786
		 */
2787
		if (is_array($config['vlans']['vlan'])) {
2788
			foreach ($config['vlans']['vlan'] as $vlan) {
2789
				if ($vlan['if'] == $realhwif)
2790
					mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2791
					" link " . escapeshellarg($wancfg['spoofmac']));
2792
			}
2793
		}
2794
	}  else {
2795

    
2796
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2797
			/*   this is not a valid mac address.  generate a
2798
			 *   temporary mac address so the machine can get online.
2799
			 */
2800
			echo gettext("Generating new MAC address.");
2801
			$random_mac = generate_random_mac_address();
2802
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2803
				" link " . escapeshellarg($random_mac));
2804
			$wancfg['spoofmac'] = $random_mac;
2805
			write_config();
2806
			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");
2807
		}
2808
	}
2809

    
2810
	/* media */
2811
	if ($wancfg['media'] || $wancfg['mediaopt']) {
2812
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2813
		if ($wancfg['media'])
2814
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2815
		if ($wancfg['mediaopt'])
2816
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2817
		mwexec($cmd);
2818
	}
2819
	$options = pfSense_get_interface_addresses($realhwif);
2820
	if (is_array($options) && isset($options['caps']['polling'])) {
2821
		if (isset($config['system']['polling']))
2822
			pfSense_interface_capabilities($realif, IFCAP_POLLING);
2823
		else
2824
			pfSense_interface_capabilities($realif, -IFCAP_POLLING);
2825
	}
2826

    
2827
	/* skip vlans for checksumming and polling */
2828
	if (!stristr($realif, "_vlan") && is_array($options)) {
2829
		$flags = 0;
2830
		if(isset($config['system']['disablechecksumoffloading'])) {
2831
			if (isset($options['encaps']['txcsum']))
2832
				$flags |= IFCAP_TXCSUM;
2833
			if (isset($options['encaps']['rxcsum']))
2834
				$flags |= IFCAP_RXCSUM;
2835
		} else {
2836
			if (!isset($options['caps']['txcsum']))
2837
				$flags |= IFCAP_TXCSUM;
2838
			if (!isset($options['caps']['rxcsum']))
2839
				$flags |= IFCAP_RXCSUM;
2840
		}
2841

    
2842
		if(isset($config['system']['disablesegmentationoffloading'])) {
2843
			if (isset($options['encaps']['tso4']))
2844
				$flags |= IFCAP_TSO;
2845
			if (isset($options['encaps']['tso6']))
2846
				$flags |= IFCAP_TSO;
2847
		} else {
2848
			if (!isset($options['caps']['tso4']))
2849
				$flags |= IFCAP_TSO;
2850
			if (!isset($options['caps']['tso6']))
2851
				$flags |= IFCAP_TSO;
2852
		}
2853

    
2854
		if(isset($config['system']['disablelargereceiveoffloading'])) {
2855
			if (isset($options['encaps']['lro']))
2856
				$flags |= IFCAP_LRO;
2857
		} else {
2858
			if (!isset($options['caps']['lro']))
2859
				$flags |= IFCAP_LRO;
2860
		}
2861

    
2862
		/* if the NIC supports polling *AND* it is enabled in the GUI */
2863
		if (!isset($config['system']['polling']) || !isset($options['caps']['polling'])) {
2864
			$flags |= IFCAP_POLLING;
2865
		}
2866
		pfSense_interface_capabilities($realhwif, -$flags);
2867
	}
2868

    
2869
	/* invalidate interface/ip/sn cache */
2870
	get_interface_arr(true);
2871
	unset($interface_ip_arr_cache[$realif]);
2872
	unset($interface_sn_arr_cache[$realif]);
2873
	unset($interface_ipv6_arr_cache[$realif]);
2874
	unset($interface_snv6_arr_cache[$realif]);
2875

    
2876
	switch ($wancfg['ipaddr']) {
2877
		case 'dhcp':
2878
			interface_dhcp_configure($interface);
2879
			break;
2880
		case 'pppoe':
2881
		case 'l2tp':
2882
		case 'pptp':
2883
		case 'ppp':
2884
			interface_ppps_configure($interface);
2885
			break;
2886
		default:
2887
			if (is_ipaddr($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
2888
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
2889
			} else if (substr($realif, 0, 3) == "gre") {
2890
				if (is_array($config['gres']['gre'])) {
2891
					foreach ($config['gres']['gre'] as $gre)
2892
						if ($gre['greif'] == $realif)
2893
							interface_gre_configure($gre);
2894
				}
2895
			} else if (substr($realif, 0, 3) == "gif") {
2896
				if (is_array($config['gifs']['gif'])) {
2897
					foreach ($config['gifs']['gif'] as $gif)
2898
						if($gif['gifif'] == $realif)
2899
							interface_gif_configure($gif);
2900
				}
2901
			} else if (substr($realif, 0, 4) == "ovpn") {
2902
				/* XXX: Should be done anything?! */
2903
			}
2904
			break;
2905
	}
2906

    
2907
	switch ($wancfg['ipaddrv6']) {
2908
		case 'slaac':
2909
		case 'dhcp6':
2910
			interface_dhcpv6_configure($interface, $wancfg);
2911
			break;
2912
		case '6rd':
2913
			interface_6rd_configure($interface, $wancfg);
2914
			break;
2915
		case '6to4':
2916
			interface_6to4_configure($interface, $wancfg);
2917
			break;
2918
		case 'track6':
2919
			interface_track6_configure($interface, $wancfg);
2920
			break;
2921
		default:
2922
			if (is_ipaddr($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
2923
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
2924
				// FIXME: Add IPv6 Support to the pfSense module
2925
				mwexec("/sbin/ifconfig {$realif} inet6 {$wancfg['ipaddrv6']} prefixlen {$wancfg['subnetv6']} ");
2926
			}
2927
			break;
2928
	}
2929

    
2930
	$mtu = get_interface_default_mtu(remove_ifindex($realhwif));
2931
	$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
2932
	if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
2933
		$mtu = $config['interfaces'][$assignedparent]['mtu'];
2934

    
2935
	$vlanifs = link_interface_to_vlans($realhwif);
2936
	if (empty($vlanifs))
2937
		$vlanifs = array();
2938

    
2939
	if (!empty($wancfg['mtu'])) {
2940
		if (stristr($realif, "_vlan")) {
2941
			if (!empty($assignedparent)) {
2942
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
2943
				if (empty($parentmtu))
2944
					$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
2945
				if ($wancfg['mtu'] > $parentmtu) {
2946
					if (get_interface_mtu($realhwif) != $wancfg['mtu'])
2947
						pfSense_interface_mtu($realhwif, $wancfg['mtu']);
2948

    
2949
					/* All vlans need to use the same mtu value as their parent. */
2950
					foreach ($vlanifs as $vlan) {
2951
						if ($vlan['vlanif'] == $realif)
2952
							continue;
2953
						$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2954
						if (!empty($assignedport)) {
2955
							$portmtu = $config['interfaces'][$assignedport]['mtu'];
2956
							if (empty($portmtu) && (get_interface_mtu($vlan['vlanif']) != $wancfg['mtu']))
2957
								pfSense_interface_mtu($vlan['vlanif'], $wancfg['mtu']);
2958
						} else if (get_interface_mtu($vlan['vlanif']) != $wancfg['mtu'])
2959
							pfSense_interface_mtu($vlan['vlanif'], $wancfg['mtu']);
2960
					}
2961
				}
2962
			} else {
2963
				/* Parent is not assigned, back to default */
2964
				if (get_interface_mtu($realhwif) != $mtu)
2965
					pfSense_interface_mtu($realhwif, $mtu);
2966

    
2967
				/* All vlans need to use the same mtu value as their parent. */
2968
				foreach ($vlanifs as $vlan) {
2969
					if ($vlan['vlanif'] == $realif)
2970
						continue;
2971
					$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2972
					if (!empty($assignedport)) {
2973
						$portmtu = $config['interfaces'][$assignedport]['mtu'];
2974
						if (empty($portmtu) && (get_interface_mtu($vlan['vlanif']) != $mtu))
2975
							pfSense_interface_mtu($vlan['vlanif'], $mtu);
2976
					} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2977
						pfSense_interface_mtu($vlan['vlanif'], $mtu);
2978
				}
2979

    
2980
				if (get_interface_mtu($realif) != $wancfg['mtu'])
2981
					pfSense_interface_mtu($realif, $wancfg['mtu']);
2982
			}
2983
		} else {
2984
			foreach ($vlanifs as $vlan) {
2985
				$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2986
				if (empty($assignedport)) {
2987
					if (get_interface_mtu($vlan['vlanif']) != $wancfg['mtu'])
2988
						pfSense_interface_mtu($vlan['vlanif'], $wancfg['mtu']);
2989
				} else {
2990
					$vlanmtu = $config['interfaces'][$assignedport]['mtu'];
2991
					if ((empty($vlanmtu) || ($vlanmtu >= $wancfg['mtu'])) && (get_interface_mtu($vlan['vlanif']) != $wancfg['mtu']))
2992
						pfSense_interface_mtu($vlan['vlanif'], $wancfg['mtu']);
2993
				}
2994
			}
2995
		}
2996
		if ($wancfg['mtu'] != get_interface_mtu($realif))
2997
			pfSense_interface_mtu($realif, $wancfg['mtu']);
2998
	} else if (stristr($realif, "_vlan")) {
2999
		/* XXX: This is really dangerous for example with vlans changing their parent mtu! */
3000
		$bigmtu = interface_vlan_mtu_configured($realhwif, $mtu);
3001
		if ($mtu < $bigmtu)
3002
			$mtu = $bigmtu;
3003

    
3004
		if (get_interface_mtu($realhwif) != $mtu)
3005
			pfSense_interface_mtu($realhwif, $mtu);
3006

    
3007
		/* All vlans need to use the same mtu value as their parent. */
3008
		foreach ($vlanifs as $vlan) {
3009
			if ($vlan['vlanif'] == $realif)
3010
				continue;
3011
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3012
			if (!empty($assignedport)) {
3013
				$portmtu = $config['interfaces'][$assignedport]['mtu'];
3014
				if (empty($portmtu) && (get_interface_mtu($vlan['vlanif']) != $mtu))
3015
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
3016
			} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
3017
				pfSense_interface_mtu($vlan['vlanif'], $mtu);
3018
		}
3019
		if (get_interface_mtu($realif) != $mtu)
3020
			pfSense_interface_mtu($realif, $mtu);
3021
	} else {
3022
		/* All vlans need to use the same mtu value as their parent. */
3023
		foreach ($vlanifs as $vlan) {
3024
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3025
			if (!empty($assignedport)) {
3026
				$portmtu = $config['interfaces'][$assignedport]['mtu'];
3027
				if (empty($portmtu) && (get_interface_mtu($vlan['vlanif']) != $mtu))
3028
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
3029
			} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
3030
				pfSense_interface_mtu($vlan['vlanif'], $mtu);
3031
		}
3032
		if ($mtu != get_interface_mtu($realhwif))
3033
			pfSense_interface_mtu($realhwif, $mtu);
3034
	}
3035

    
3036
	unset($vlanifs);
3037

    
3038
	if(does_interface_exist($wancfg['if']))
3039
		interfaces_bring_up($wancfg['if']);
3040

    
3041
	interface_netgraph_needed($interface);
3042

    
3043
	if (!$g['booting']) {
3044
		link_interface_to_vips($interface, "update");
3045

    
3046
		unset($gre);
3047
		$gre = link_interface_to_gre($interface);
3048
		if (!empty($gre))
3049
			array_walk($gre, 'interface_gre_configure');
3050

    
3051
		unset($gif);
3052
		$gif = link_interface_to_gif($interface);
3053
		if (!empty($gif))
3054
			array_walk($gif, 'interface_gif_configure');
3055

    
3056
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3057
			unset($bridgetmp);
3058
			$bridgetmp = link_interface_to_bridge($interface);
3059
			if (!empty($bridgetmp))
3060
				interface_bridge_add_member($bridgetmp, $realif);
3061
		}
3062

    
3063
		$grouptmp = link_interface_to_group($interface);
3064
		if (!empty($grouptmp))
3065
			array_walk($grouptmp, 'interface_group_add_member');
3066

    
3067
		if ($interface == "lan")
3068
			/* make new hosts file */
3069
			system_hosts_generate();
3070

    
3071
		if ($reloadall == true) {
3072

    
3073
			/* reconfigure static routes (kernel may have deleted them) */
3074
			system_routing_configure($interface);
3075

    
3076
			/* reload ipsec tunnels */
3077
			vpn_ipsec_configure();
3078

    
3079
			/* restart dnsmasq */
3080
			services_dnsmasq_configure();
3081

    
3082
			/* update dyndns */
3083
			send_event("service reload dyndns {$interface}");
3084

    
3085
			/* reload captive portal */
3086
			captiveportal_init_rules();
3087
		}
3088
	}
3089

    
3090
	return 0;
3091
}
3092

    
3093
function interface_track6_configure($interface = "lan", $wancfg) {
3094
	global $config, $g;
3095

    
3096
	if (!is_array($wancfg))
3097
		return;
3098

    
3099
	if (!isset($wancfg['enable']))
3100
		return;
3101

    
3102
	/* If the interface is not configured via another, exit */
3103
	if (empty($wancfg['track6-interface']))
3104
		return;
3105

    
3106
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3107
	$realif = get_real_interface($interface);
3108
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3109

    
3110
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3111
	if (!isset($trackcfg['enable'])) {
3112
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3113
		return;
3114
	}
3115

    
3116
	switch($trackcfg['ipaddrv6']) {
3117
	case "6to4":
3118
		if ($g['debug'])
3119
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3120
		interface_track6_6to4_configure($interface, $wancfg);
3121
		break;
3122
	case "6rd":
3123
		if ($g['debug'])
3124
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3125
		interface_track6_6rd_configure($interface, $wancfg);
3126
		break;
3127
	case "dhcp6":
3128
		if ($g['debug'])
3129
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3130
		interface_track6_dhcp6_configure($interface, $wancfg);
3131
		break;
3132
	}
3133

    
3134
	if (!$g['booting']) {
3135
		if (!function_exists('services_dhcpd_configure'))
3136
			require_once("services.inc");
3137

    
3138
		services_dhcpd_configure("inet6");
3139
	}
3140

    
3141
	return 0;
3142
}
3143

    
3144
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3145
	global $config, $g;
3146
	global $interface_ipv6_arr_cache;
3147
        global $interface_snv6_arr_cache;
3148

    
3149
	if (!is_array($lancfg))
3150
		return;
3151

    
3152
	/* If the interface is not configured via another, exit */
3153
	if (empty($lancfg['track6-interface']))
3154
		return;
3155

    
3156
	if (!is_numeric($lancfg['track6-prefix-id']))
3157
		$lancfg['track6-prefix-id'] = 0;
3158

    
3159
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3160
	if (empty($wancfg)) {
3161
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3162
		return;
3163
	}
3164

    
3165
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3166
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3167
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3168
		return;
3169
	}
3170
	$hexwanv4 = return_hex_ipv4($ip4address);
3171

    
3172
	/* create the long prefix notation for math, save the prefix length */
3173
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3174
	$rd6prefixlen = $rd6prefix[1];
3175
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3176

    
3177
	/* binary presentation of the prefix for all 128 bits. */
3178
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3179

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

    
3185
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3186
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3187
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3188
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3189
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3190
	/* fill the rest out with zeros */
3191
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);;
3192

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

    
3196
	$lanif = get_real_interface($interface);
3197
	$oip = find_interface_ipv6($lanif);
3198
	if (is_ipaddrv6($oip))
3199
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3200
	unset($interface_ipv6_arr_cache[$lanif]);
3201
	unset($interface_snv6_arr_cache[$lanif]);
3202
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3203
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3204

    
3205
	return 0;
3206
}
3207

    
3208
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3209
	global $config, $g;
3210
	global $interface_ipv6_arr_cache;
3211
        global $interface_snv6_arr_cache;
3212

    
3213
	if (!is_array($lancfg))
3214
		return;
3215

    
3216
	/* If the interface is not configured via another, exit */
3217
	if (empty($lancfg['track6-interface']))
3218
		return;
3219

    
3220
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3221
	if (empty($wancfg)) {
3222
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3223
		return;
3224
	}
3225

    
3226
	if (!is_numeric($lancfg['track6-prefix-id']))
3227
		$lancfg['track6-prefix-id'] = 0;
3228

    
3229
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3230
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3231
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3232
		return;
3233
	}
3234
	$hexwanv4 = return_hex_ipv4($ip4address);
3235

    
3236
	/* create the long prefix notation for math, save the prefix length */
3237
	$sixto4prefix = "2002::";
3238
	$sixto4prefixlen = 16;
3239
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3240

    
3241
	/* binary presentation of the prefix for all 128 bits. */
3242
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3243

    
3244
	/* just save the left prefix length bits */
3245
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3246
	/* add the v4 address */
3247
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3248
	/* add the custom prefix id */
3249
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3250
	/* fill the rest out with zeros */
3251
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);;
3252

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

    
3256
	$lanif = get_real_interface($interface);
3257
	$oip = find_interface_ipv6($lanif);
3258
	if (is_ipaddrv6($oip))
3259
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3260
	unset($interface_ipv6_arr_cache[$lanif]);
3261
	unset($interface_snv6_arr_cache[$lanif]);
3262
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3263
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3264

    
3265
	return 0;
3266
}
3267

    
3268
function interface_track6_dhcp6_configure($interface = "lan", $lancfg) {
3269
	global $config, $g;
3270
	global $interface_ipv6_arr_cache;
3271
        global $interface_snv6_arr_cache;
3272

    
3273
	if (!is_array($lancfg))
3274
		return;
3275

    
3276
	/* If the interface is not configured via another, exit */
3277
	if (empty($lancfg['track6-interface']))
3278
		return;
3279

    
3280
	if (!is_numeric($lancfg['track6-prefix-id']))
3281
		$lancfg['track6-prefix-id'] = 0;
3282

    
3283
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3284
	if (empty($wancfg)) {
3285
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3286
		return;
3287
	}
3288

    
3289
	$lanif = get_real_interface($interface);
3290
	$oip = find_interface_ipv6($lanif);
3291
	if (is_ipaddrv6($oip))
3292
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3293
	unset($interface_ipv6_arr_cache[$lanif]);
3294
	unset($interface_snv6_arr_cache[$lanif]);
3295

    
3296
	if ($wancfg['ipaddrv6'] == "slaac") {
3297
		$ifcfgipv6 = get_interface_ipv6($lancfg['track6-interface']);
3298
		if (is_ipaddrv6($ifcfgipv6)) {
3299
			$dhcp6lanarr = explode(":", Net_IPv6::uncompress($ifcfgipv6));
3300
			$dhcp6lanarr[4] = 0;
3301
			$dhcp6lanarr[5] = 0;
3302
			$dhcp6lanarr[6] = 0;
3303
			$dhcp6lanarr[7] = 1;
3304
			$dhcp6lan =  Net_IPv6::compress(implode(":", $dhcp6lanarr));
3305
			log_error("dhcp6 {$interface} with ipv6 address {$dhcp6lan} based on {$lancfg['track6-interface']}");
3306
			mwexec("/sbin/ifconfig {$lanif} inet6 {$dhcp6lan} prefixlen 64");
3307
		}
3308
	}
3309

    
3310
	return 0;
3311
}
3312

    
3313
function interface_6rd_configure($interface = "wan", $wancfg) {
3314
	global $config, $g;
3315

    
3316
	/* because this is a tunnel interface we can only function
3317
	 *	with a public IPv4 address on the interface */
3318

    
3319
	if (!is_array($wancfg))
3320
		return;
3321

    
3322
	$wanif = get_real_interface($interface);
3323
	$ip4address = find_interface_ip($wanif);
3324
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3325
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3326
		return false;
3327
	}
3328
	$hexwanv4 = return_hex_ipv4($ip4address);
3329

    
3330
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3331
		$wancfg['prefix-6rd-v4plen'] = 0;
3332

    
3333
	/* create the long prefix notation for math, save the prefix length */
3334
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3335
	$rd6prefixlen = $rd6prefix[1];
3336
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3337

    
3338
	/* we need the hex form of the broker IPv4 address */
3339
	$hexbrv4 = return_hex_ipv4($wancfg['gateway-6rd']);
3340

    
3341
	/* binary presentation of the prefix for all 128 bits. */
3342
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3343

    
3344
	/* just save the left prefix length bits */
3345
	$rd6brprefixbin = substr($rd6prefixbin, 0, $rd6prefixlen);
3346
	/* if the prefix length is not 32 bits we need to shave bits off from the left of the v4 address. */
3347
	$rd6brprefixbin .= substr(sprintf("%032b", hexdec($hexbrv4)), $wancfg['prefix-6rd-v4plen'], 32);
3348
	/* fill out the rest with 0's */
3349
	$rd6brprefixbin = str_pad($rd6brprefixbin, 128, "0", STR_PAD_RIGHT);
3350

    
3351
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3352
	$rd6brgw = convert_128bit_to_ipv6($rd6brprefixbin);
3353

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

    
3361
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3362
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3363

    
3364
	/* XXX: need to extend to support variable prefix size for v4 */
3365
	if (!is_module_loaded("if_stf"))
3366
		mwexec("/sbin/kldload if_stf.ko");
3367
	$stfiface = "{$interface}_stf";
3368
	if (does_interface_exist($stfiface))
3369
		pfSense_interface_destroy($stfiface);
3370
	$tmpstfiface = pfSense_interface_create("stf");
3371
	pfSense_interface_rename($tmpstfiface, $stfiface);
3372
	pfSense_interface_flags($stfiface, IFF_LINK2);
3373
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3374
	if ($g['debug'])
3375
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3376

    
3377
	/* write out a default router file */
3378
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3379
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3380

    
3381
	$ip4gateway = get_interface_gateway($interface);
3382
	if (is_ipaddrv4($ip4gateway))
3383
		mwexec("/sbin/route change -host " . $wancfg['gateway-6rd'] . " {$ip4gateway}");
3384

    
3385
	/* configure dependent interfaces */
3386
	if (!$g['booting'])
3387
		link_interface_to_track6($interface, "update");
3388

    
3389
	return 0;
3390
}
3391

    
3392
function interface_6to4_configure($interface = "wan", $wancfg){
3393
	global $config, $g;
3394

    
3395
	/* because this is a tunnel interface we can only function
3396
	 *	with a public IPv4 address on the interface */
3397

    
3398
	if (!is_array($wancfg))
3399
		return;
3400

    
3401
	$wanif = get_real_interface($interface);
3402
	$ip4address = find_interface_ip($wanif);
3403
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3404
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3405
		return false;
3406
	}
3407

    
3408
	/* create the long prefix notation for math, save the prefix length */
3409
	$stfprefixlen = 16;
3410
	$stfprefix = Net_IPv6::uncompress("2002::");
3411
	$stfarr = explode(":", $stfprefix);
3412
	$v4prefixlen = "0";
3413

    
3414
	/* we need the hex form of the interface IPv4 address */
3415
	$ip4arr = explode(".", $ip4address);
3416
	$hexwanv4 = "";
3417
	foreach($ip4arr as $octet)
3418
		$hexwanv4 .= sprintf("%02x", $octet);
3419

    
3420
	/* we need the hex form of the broker IPv4 address */
3421
	$ip4arr = explode(".", "192.88.99.1");
3422
	$hexbrv4 = "";
3423
	foreach($ip4arr as $octet)
3424
		$hexbrv4 .= sprintf("%02x", $octet);
3425

    
3426
	/* binary presentation of the prefix for all 128 bits. */
3427
	$stfprefixbin = "";
3428
	foreach($stfarr as $element) {
3429
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3430
	}
3431
	/* just save the left prefix length bits */
3432
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3433

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

    
3438
	/* for the local subnet too. */
3439
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3440
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);;
3441

    
3442
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3443
	$stfbrarr = array();
3444
	$stfbrbinarr = array();
3445
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3446
	foreach($stfbrbinarr as $bin)
3447
		$stfbrarr[] = dechex(bindec($bin));
3448
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3449

    
3450
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3451
	$stflanarr = array();
3452
	$stflanbinarr = array();
3453
	$stflanbinarr = str_split($stflanbin, 16);
3454
	foreach($stflanbinarr as $bin)
3455
		$stflanarr[] = dechex(bindec($bin));
3456
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3457
	$stflanarr[7] = 1;
3458
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3459

    
3460
	/* setup the stf interface */
3461
	if (!is_module_loaded("if_stf"))
3462
		mwexec("/sbin/kldload if_stf.ko");
3463
	$stfiface = "{$interface}_stf";
3464
	if (does_interface_exist($stfiface))
3465
		pfSense_interface_destroy($stfiface);
3466
	$tmpstfiface = pfSense_interface_create("stf");
3467
	pfSense_interface_rename($tmpstfiface, $stfiface);
3468
	pfSense_interface_flags($stfiface, IFF_LINK2);
3469
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3470

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

    
3474
	/* write out a default router file */
3475
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3476
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3477

    
3478
	$ip4gateway = get_interface_gateway($interface);
3479
	if (is_ipaddrv4($ip4gateway))
3480
		mwexec("route change -host 192.88.99.1 {$ip4gateway}");
3481

    
3482
	if (!$g['booting'])
3483
		link_interface_to_track6($interface, "update");
3484

    
3485
	return 0;
3486
}
3487

    
3488
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3489
	global $config, $g;
3490

    
3491
	if (!is_array($wancfg))
3492
		return;
3493

    
3494
	$wanif = get_real_interface($interface);
3495
	$dhcp6cconf = "";
3496
	$dhcp6cconf .= "interface {$wanif} {\n";
3497

    
3498
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3499
	if($wancfg['ipaddrv6'] == "slaac") {
3500
		$dhcp6cconf .= "	information-only;\n";
3501
		$dhcp6cconf .= "	request domain-name-servers;\n";
3502
		$dhcp6cconf .= "	request domain-name;\n";
3503
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3504
		$dhcp6cconf .= "};\n";
3505
	} else {
3506

    
3507
		$dhcp6cconf .= " 	send ia-na 0;	# request stateful address\n";
3508
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3509
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3510
		$dhcp6cconf .= "request domain-name-servers;\n";
3511
		$dhcp6cconf .= "request domain-name;\n";
3512
		$dhcp6cconf .= "script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3513

    
3514
		$dhcp6cconf .= "};\n";
3515
		$dhcp6cconf .= "id-assoc na 0 { };\n";
3516
		if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3517
			/* Setup the prefix delegation */
3518
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3519
			$iflist = link_interface_to_track6($interface);
3520
			foreach ($iflist as $friendly => $ifcfg) {
3521
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3522
					if ($g['debug'])
3523
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3524
					$realif = get_real_interface($friendly);
3525
					$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3526
					$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3527
					$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3528
					$dhcp6cconf .= "	};\n";
3529
				}
3530
			}
3531
			unset($iflist, $ifcfg);
3532
			$dhcp6cconf .= "};\n";
3533
		}
3534
	}
3535
	/* wide-dhcp6c works for now. */
3536
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3537
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3538
		unset($dhcp6cconf);
3539
		return 1;
3540
	}
3541
	unset($dhcp6cconf);
3542

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

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

    
3572
	/* accept router advertisements for this interface */
3573
	mwexec("/sbin/sysctl -w net.inet6.ip6.accept_rtadv=1");
3574
	log_error("Accept router advertisements on interface {$wanif} ");
3575
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3576

    
3577
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3578
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid"))
3579
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3580
	mwexec("/usr/sbin/rtsold -m -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3581

    
3582
	/* NOTE: will be called from rtsold invoked script 
3583
	 * link_interface_to_track6($interface, "update");
3584
	 */
3585

    
3586
	return 0;
3587
}
3588

    
3589
function interface_dhcp_configure($interface = "wan") {
3590
	global $config, $g;
3591

    
3592
	$wancfg = $config['interfaces'][$interface];
3593
	$wanif = $wancfg['if'];
3594
	if (empty($wancfg))
3595
		$wancfg = array();
3596

    
3597
	/* generate dhclient_wan.conf */
3598
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3599
	if (!$fd) {
3600
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3601
		return 1;
3602
	}
3603

    
3604
	if ($wancfg['dhcphostname']) {
3605
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3606
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3607
	} else {
3608
		$dhclientconf_hostname = "";
3609
	}
3610

    
3611
	$wanif = get_real_interface($interface);
3612
	if (empty($wanif)) {
3613
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3614
		return 0;
3615
	}
3616
	$dhclientconf = "";
3617

    
3618
	$dhclientconf .= <<<EOD
3619
interface "{$wanif}" {
3620
timeout 60;
3621
retry 15;
3622
select-timeout 0;
3623
initial-interval 1;
3624
	{$dhclientconf_hostname}
3625
	script "/sbin/dhclient-script";
3626
}
3627

    
3628
EOD;
3629

    
3630
if(is_ipaddr($wancfg['alias-address'])) {
3631
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3632
	$dhclientconf .= <<<EOD
3633
alias {
3634
	interface  "{$wanif}";
3635
	fixed-address {$wancfg['alias-address']};
3636
	option subnet-mask {$subnetmask};
3637
}
3638

    
3639
EOD;
3640
}
3641
	fwrite($fd, $dhclientconf);
3642
	fclose($fd);
3643

    
3644
	/* bring wan interface up before starting dhclient */
3645
	if($wanif)
3646
		interfaces_bring_up($wanif);
3647
	else
3648
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3649

    
3650
	$pid = find_dhclient_process($wanif);
3651
	if ($pid)
3652
		posix_kill($pid, SIGTERM);
3653
	/* fire up dhclient */
3654
	mwexec("/sbin/dhclient -c {$g['varetc_path']}/dhclient_{$interface}.conf {$wanif} > {$g['tmp_path']}/{$wanif}_output 2> {$g['tmp_path']}/{$wanif}_error_output");
3655

    
3656
	return 0;
3657
}
3658

    
3659
function interfaces_group_setup() {
3660
	global $config;
3661

    
3662
	if (!is_array($config['ifgroups']['ifgroupentry']))
3663
		return;
3664

    
3665
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3666
		interface_group_setup($groupar);
3667

    
3668
	return;
3669
}
3670

    
3671
function interface_group_setup(&$groupname /* The parameter is an array */) {
3672
	global $config;
3673

    
3674
	if (!is_array($groupname))
3675
		return;
3676
	$members = explode(" ", $groupname['members']);
3677
	foreach($members as $ifs) {
3678
		$realif = get_real_interface($ifs);
3679
		if ($realif)
3680
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3681
	}
3682

    
3683
	return;
3684
}
3685

    
3686
function is_interface_group($if) {
3687
	global $config;
3688

    
3689
	if (is_array($config['ifgroups']['ifgroupentry']))
3690
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
3691
			if ($groupentry['ifname'] === $if)
3692
				return true;
3693
		}
3694

    
3695
	return false;
3696
}
3697

    
3698
function interface_group_add_member($interface, $groupname) {
3699
	$interface = get_real_interface($interface);
3700
	mwexec("/sbin/ifconfig {$interface} group {$groupname}", true);
3701
}
3702

    
3703
/* COMPAT Function */
3704
function convert_friendly_interface_to_real_interface_name($interface) {
3705
	return get_real_interface($interface);
3706
}
3707

    
3708
/* COMPAT Function */
3709
function get_real_wan_interface($interface = "wan") {
3710
	return get_real_interface($interface);
3711
}
3712

    
3713
/* COMPAT Function */
3714
function get_current_wan_address($interface = "wan") {
3715
	return get_interface_ip($interface);
3716
}
3717

    
3718
/*
3719
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
3720
 */
3721
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
3722
	global $config;
3723

    
3724
	if (stristr($interface, "_vip")) {
3725
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
3726
			if ($vip['mode'] == "carp")  {
3727
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3728
					return $vip['interface'];
3729
			}
3730
		}
3731
	}
3732

    
3733
	/* XXX: For speed reasons reference directly the interface array */
3734
	$ifdescrs = &$config['interfaces'];
3735
	//$ifdescrs = get_configured_interface_list(false, true);
3736

    
3737
	if (strstr($interface, "_stf"))
3738
		$interface = str_replace("_stf", "", $interface);
3739

    
3740
	foreach ($ifdescrs as $if => $ifname) {
3741
		if ($if == $interface || $config['interfaces'][$if]['if'] == $interface)
3742
			return $if;
3743

    
3744
		if (stristr($interface, "_wlan0") && $config['interfaces'][$if]['if'] == interface_get_wireless_base($interface))
3745
			return $if;
3746

    
3747
		// XXX: This case doesn't work anymore (segfaults - recursion?) - should be replaced with something else or just removed.
3748
		//      Not to be replaced with get_real_interface - causes slow interface listings here because of recursion!
3749
		/*
3750
		$int = get_parent_interface($if);
3751
		if ($int[0] == $interface)
3752
			return $ifname;
3753
		 */
3754
	}
3755

    
3756
	return NULL;
3757
}
3758

    
3759
/* attempt to resolve interface to friendly descr */
3760
function convert_friendly_interface_to_friendly_descr($interface) {
3761
	global $config;
3762

    
3763
	switch ($interface) {
3764
	case "l2tp":
3765
		$ifdesc = "L2TP";
3766
		break;
3767
	case "pptp":
3768
		$ifdesc = "PPTP";
3769
		break;
3770
	case "pppoe":
3771
		$ifdesc = "PPPoE";
3772
		break;
3773
	case "openvpn":
3774
		$ifdesc = "OpenVPN";
3775
		break;
3776
	case "enc0":
3777
	case "ipsec":
3778
		$ifdesc = "IPsec";
3779
		break;
3780
	default:
3781
		if (isset($config['interfaces'][$interface])) {
3782
			if (empty($config['interfaces'][$interface]['descr']))
3783
				$ifdesc = strtoupper($interface);
3784
			else
3785
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
3786
			break;
3787
		} else if (stristr($interface, "_vip")) {
3788
			if (is_array($config['virtualip']['vip'])) {
3789
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
3790
					if ($vip['mode'] == "carp")  {
3791
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3792
							return "{$vip['subnet']} - {$vip['descr']}";
3793
					}
3794
				}
3795
			}
3796
		} else {
3797
			/* if list */
3798
			$ifdescrs = get_configured_interface_with_descr(false, true);
3799
			foreach ($ifdescrs as $if => $ifname) {
3800
				if ($if == $interface || $ifname == $interface)
3801
					return $ifname;
3802
			}
3803
		}
3804
		break;
3805
	}
3806

    
3807
	return $ifdesc;
3808
}
3809

    
3810
function convert_real_interface_to_friendly_descr($interface) {
3811
	global $config;
3812

    
3813
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
3814

    
3815
	if ($ifdesc) {
3816
		$iflist = get_configured_interface_with_descr(false, true);
3817
		return $iflist[$ifdesc];
3818
	}
3819

    
3820
	return $interface;
3821
}
3822

    
3823
/*
3824
 *  get_parent_interface($interface):
3825
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
3826
 *				or virtual interface (i.e. vlan)
3827
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
3828
 *			-- returns $interface passed in if $interface parent is not found
3829
 *			-- returns empty array if an invalid interface is passed
3830
 *	(Only handles ppps and vlans now.)
3831
 */
3832
function get_parent_interface($interface) {
3833
	global $config;
3834

    
3835
	$parents = array();
3836
	//Check that we got a valid interface passed
3837
	$realif = get_real_interface($interface);
3838
	if ($realif == NULL)
3839
		return $parents;
3840

    
3841
	// If we got a real interface, find it's friendly assigned name
3842
	$interface = convert_real_interface_to_friendly_interface_name($interface);
3843

    
3844
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
3845
		$ifcfg = $config['interfaces'][$interface];
3846
		switch ($ifcfg['ipaddr']) {
3847
			case "ppp":
3848
			case "pppoe":
3849
			case "pptp":
3850
			case "l2tp":
3851
				if (empty($parents))
3852
					if (is_array($config['ppps']['ppp']))
3853
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
3854
							if ($ifcfg['if'] == $ppp['if']) {
3855
								$ports = explode(',', $ppp['ports']);
3856
								foreach ($ports as $pid => $parent_if)
3857
									$parents[$pid] = get_real_interface($parent_if);
3858
								break;
3859
							}
3860
						}
3861
				break;
3862
			case "dhcp":
3863
			case "static":
3864
			default:
3865
				// Handle _vlans
3866
				if (stristr($realif,"_vlan"))
3867
					if (is_array($config['vlans']['vlan']))
3868
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
3869
							if ($ifcfg['if'] == $vlan['vlanif']){
3870
								$parents[0] = $vlan['if'];
3871
								break;
3872
							}
3873
				break;
3874
		}
3875
	}
3876

    
3877
	if (empty($parents))
3878
		$parents[0] = $realif;
3879

    
3880
	return $parents;
3881
}
3882

    
3883
function interface_is_wireless_clone($wlif) {
3884
	if(!stristr($wlif, "_wlan")) {
3885
		return false;
3886
	} else {
3887
		return true;
3888
	}
3889
}
3890

    
3891
function interface_get_wireless_base($wlif) {
3892
	if(!stristr($wlif, "_wlan")) {
3893
		return $wlif;
3894
	} else {
3895
		return substr($wlif, 0, stripos($wlif, "_wlan"));
3896
	}
3897
}
3898

    
3899
function interface_get_wireless_clone($wlif) {
3900
	if(!stristr($wlif, "_wlan")) {
3901
		return $wlif . "_wlan0";
3902
	} else {
3903
		return $wlif;
3904
	}
3905
}
3906

    
3907
function get_real_interface($interface = "wan", $family = "all") {
3908
	global $config, $g;
3909

    
3910
	$wanif = NULL;
3911

    
3912
	switch ($interface) {
3913
	case "l2tp":
3914
		$wanif = "l2tp";
3915
		break;
3916
	case "pptp":
3917
		$wanif = "pptp";
3918
		break;
3919
	case "pppoe":
3920
		$wanif = "pppoe";
3921
		break;
3922
	case "openvpn":
3923
		$wanif = "openvpn";
3924
		break;
3925
	case "ipsec":
3926
	case "enc0":
3927
		$wanif = "enc0";
3928
		break;
3929
	case "ppp":
3930
		$wanif = "ppp";
3931
		break;
3932
	default:
3933
		// If a real interface was alread passed simply
3934
		// pass the real interface back.  This encourages
3935
		// the usage of this function in more cases so that
3936
		// we can combine logic for more flexibility.
3937
		if(does_interface_exist($interface)) {
3938
			$wanif = $interface;
3939
			break;
3940
		}
3941

    
3942
		if (empty($config['interfaces'][$interface]))
3943
			break;
3944

    
3945
		$cfg = &$config['interfaces'][$interface];
3946

    
3947
		if ($family == "inet6") {
3948
			switch ($cfg['ipaddrv6']) {
3949
			case "6rd":
3950
			case "6to4":
3951
				$wanif = "{$interface}_stf";
3952
				break;
3953
			default:
3954
				if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
3955
					$wanif = interface_get_wireless_clone($cfg['if']);
3956
				else
3957
					$wanif = $cfg['if'];
3958
				break;
3959
			}
3960
		} else {
3961
			// Wireless cloned NIC support (FreeBSD 8+)
3962
			// interface name format: $parentnic_wlanparentnic#
3963
			// example: ath0_wlan0
3964
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
3965
				$wanif = interface_get_wireless_clone($cfg['if']);
3966
			else
3967
				$wanif = $cfg['if'];
3968
		}
3969
		break;
3970
	}
3971

    
3972
	return $wanif;
3973
}
3974

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

    
4012
/*
4013
 * find_ip_interface($ip): return the interface where an ip is defined
4014
 *   (or if $bits is specified, where an IP within the subnet is defined)
4015
 */
4016
function find_ip_interface($ip, $bits = null) {
4017
	if (!is_ipaddr($ip))
4018
		return false;
4019
	
4020
	$isv6ip = is_ipaddrv6($ip);
4021
	
4022
	/* if list */
4023
	$ifdescrs = get_configured_interface_list();
4024

    
4025
	foreach ($ifdescrs as $ifdescr => $ifname) {
4026
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4027
		if (is_null($ifip))
4028
			continue;
4029
		if (is_null($bits)) {
4030
			if ($ip == $ifip) {
4031
				$int = get_real_interface($ifname);
4032
				return $int;
4033
			}
4034
		}
4035
		else {
4036
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4037
				$int = get_real_interface($ifname);
4038
				return $int;
4039
			}
4040
		}
4041
	}
4042

    
4043
	return false;
4044
}
4045

    
4046
/*
4047
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4048
 *   (or if $bits is specified, where an IP within the subnet is found)
4049
 */
4050
function find_virtual_ip_alias($ip, $bits = null) {
4051
	global $config;
4052
	
4053
	if (!is_array($config['virtualip']['vip'])) {
4054
		return false;
4055
	}
4056
	if (!is_ipaddr($ip))
4057
		return false;
4058
	
4059
	$isv6ip = is_ipaddrv6($ip);
4060
	
4061
	foreach ($config['virtualip']['vip'] as $vip) {
4062
		if ($vip['mode'] === "ipalias") {
4063
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4064
				continue;
4065
			if (is_null($bits)) {
4066
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4067
					return $vip;
4068
				}
4069
			}
4070
			else {
4071
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4072
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4073
					return $vip;
4074
				}
4075
			}
4076
		}
4077
	}
4078
	return false;
4079
}
4080

    
4081
/*
4082
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4083
 */
4084
function find_number_of_created_carp_interfaces() {
4085
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4086
}
4087

    
4088
function get_all_carp_interfaces() {
4089
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
4090
	$ints = explode(" ", $ints);
4091
	return $ints;
4092
}
4093

    
4094
/*
4095
 * find_carp_interface($ip): return the carp interface where an ip is defined
4096
 */
4097
function find_carp_interface($ip) {
4098
	global $config;
4099
	if (is_array($config['virtualip']['vip'])) {
4100
		foreach ($config['virtualip']['vip'] as $vip) {
4101
			if ($vip['mode'] == "carp") {
4102
				if(is_ipaddrv4($ip)) {
4103
					$carp_ip = get_interface_ip($vip['interface']);
4104
				}
4105
				if(is_ipaddrv6($ip)) {
4106
					$carp_ip = get_interface_ipv6($vip['interface']);
4107
				}
4108
				exec("/sbin/ifconfig", $output, $return);
4109
				foreach($output as $line) {
4110
					$elements = preg_split("/[ ]+/i", $line);
4111
					if(strstr($elements[0], "vip"))
4112
						$curif = str_replace(":", "", $elements[0]);
4113
					if(stristr($line, $ip)) {
4114
						$if = $curif;
4115
						continue;
4116
					}
4117
				}
4118

    
4119
				if ($if)
4120
					return $if;
4121
			}
4122
		}
4123
	}
4124
}
4125

    
4126
function link_carp_interface_to_parent($interface) {
4127
	global $config;
4128

    
4129
	if ($interface == "")
4130
		return;
4131

    
4132
	$carp_ip = get_interface_ip($interface);
4133
	$carp_ipv6 = get_interface_ipv6($interface);
4134

    
4135
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4136
		return;
4137

    
4138
	/* if list */
4139
	$ifdescrs = get_configured_interface_list();
4140
	foreach ($ifdescrs as $ifdescr => $ifname) {
4141
		/* check IPv4 */
4142
		if(is_ipaddrv4($carp_ip)) {
4143
			$interfaceip = get_interface_ip($ifname);
4144
			$subnet_bits = get_interface_subnet($ifname);
4145
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4146
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4147
				return $ifname;
4148
		}
4149
		/* Check IPv6 */
4150
		if(is_ipaddrv6($carp_ipv6)) {
4151
			$interfaceipv6 = get_interface_ipv6($ifname);
4152
			$prefixlen = get_interface_subnetv6($ifname);
4153
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4154
				return $ifname;
4155
		}
4156
	}
4157
	return "";
4158
}
4159

    
4160

    
4161
/****f* interfaces/link_ip_to_carp_interface
4162
 * NAME
4163
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4164
 * INPUTS
4165
 *   $ip
4166
 * RESULT
4167
 *   $carp_ints
4168
 ******/
4169
function link_ip_to_carp_interface($ip) {
4170
	global $config;
4171

    
4172
	if (!is_ipaddr($ip))
4173
		return;
4174

    
4175
	$carp_ints = "";
4176
	if (is_array($config['virtualip']['vip'])) {
4177
		$first = 0;
4178
		$carp_int = array();
4179
		foreach ($config['virtualip']['vip'] as $vip) {
4180
			if ($vip['mode'] == "carp") {
4181
				$carp_ip = $vip['subnet'];
4182
				$carp_sn = $vip['subnet_bits'];
4183
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4184
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4185
					$carp_int[] = "{$vip['interface']}_vip{$vip['vhid']}";
4186
				}
4187
			}
4188
		}
4189
		if (!empty($carp_int))
4190
			$carp_ints = implode(" ", array_unique($carp_int));
4191
	}
4192

    
4193
	return $carp_ints;
4194
}
4195

    
4196
function link_interface_to_track6($int, $action = "") {
4197
	global $config;
4198

    
4199
	if (empty($int))
4200
		return;
4201

    
4202
	if (is_array($config['interfaces'])) {
4203
		$list = array();
4204
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4205
			if (!isset($ifcfg['enable']))
4206
				continue;
4207
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4208
				if ($action == "update")
4209
					interface_track6_configure($ifname, $ifcfg);
4210
				else if ($action == "")
4211
					$list[$ifname] = $ifcfg;
4212
			}
4213
		}
4214
		return $list;
4215
	}
4216
}
4217

    
4218
function link_interface_to_vlans($int, $action = "") {
4219
	global $config;
4220

    
4221
	if (empty($int))
4222
		return;
4223

    
4224
	if (is_array($config['vlans']['vlan'])) {
4225
		$ifaces = array();
4226
		foreach ($config['vlans']['vlan'] as $vlan) {
4227
			if ($int == $vlan['if']) {
4228
				if ($action == "update") {
4229
					interfaces_bring_up($int);
4230
				} else if ($action == "")
4231
					$ifaces[$vlan['tag']] = $vlan;
4232
			}
4233
		}
4234
		if (!empty($ifaces))
4235
			return $ifaces;
4236
	}
4237
}
4238

    
4239
function link_interface_to_vips($int, $action = "") {
4240
	global $config;
4241

    
4242
	if (is_array($config['virtualip']['vip'])) {
4243
		$result = array();
4244
		foreach ($config['virtualip']['vip'] as $vip) {
4245
			if ($int == $vip['interface']) {
4246
				if ($action == "update")
4247
					interfaces_vips_configure($int);
4248
				else
4249
					$result[] = $vip;
4250
			}
4251
		}
4252
		return $result;
4253
	}
4254
}
4255

    
4256
/****f* interfaces/link_interface_to_bridge
4257
 * NAME
4258
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4259
 * INPUTS
4260
 *   $ip
4261
 * RESULT
4262
 *   bridge[0-99]
4263
 ******/
4264
function link_interface_to_bridge($int) {
4265
	global $config;
4266

    
4267
	if (is_array($config['bridges']['bridged'])) {
4268
		foreach ($config['bridges']['bridged'] as $bridge) {
4269
			if (in_array($int, explode(',', $bridge['members'])))
4270
				return "{$bridge['bridgeif']}";
4271
		}
4272
	}
4273
}
4274

    
4275
function link_interface_to_group($int) {
4276
	global $config;
4277

    
4278
	$result = array();
4279

    
4280
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4281
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4282
			if (in_array($int, explode(" ", $group['members'])))
4283
				$result[$group['ifname']] = $int;
4284
		}
4285
	}
4286

    
4287
	return $result;
4288
}
4289

    
4290
function link_interface_to_gre($interface) {
4291
	global $config;
4292

    
4293
	$result = array();
4294

    
4295
	if (is_array($config['gres']['gre'])) {
4296
		foreach ($config['gres']['gre'] as $gre)
4297
			if($gre['if'] == $interface)
4298
				$result[] = $gre;
4299
	}
4300

    
4301
	return $result;
4302
}
4303

    
4304
function link_interface_to_gif($interface) {
4305
	global $config;
4306

    
4307
	$result = array();
4308

    
4309
	if (is_array($config['gifs']['gif'])) {
4310
		foreach ($config['gifs']['gif'] as $gif)
4311
			if($gif['if'] == $interface)
4312
				$result[] = $gif;
4313
	}
4314

    
4315
	return $result;
4316
}
4317

    
4318
/*
4319
 * find_interface_ip($interface): return the interface ip (first found)
4320
 */
4321
function find_interface_ip($interface, $flush = false)
4322
{
4323
	global $interface_ip_arr_cache;
4324
	global $interface_sn_arr_cache;
4325

    
4326
	$interface = str_replace("\n", "", $interface);
4327

    
4328
	if (!does_interface_exist($interface))
4329
		return;
4330

    
4331
	/* Setup IP cache */
4332
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4333
		$ifinfo = pfSense_get_interface_addresses($interface);
4334
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4335
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4336
	}
4337

    
4338
	return $interface_ip_arr_cache[$interface];
4339
}
4340

    
4341
/*
4342
 * find_interface_ipv6($interface): return the interface ip (first found)
4343
 */
4344
function find_interface_ipv6($interface, $flush = false)
4345
{
4346
	global $interface_ipv6_arr_cache;
4347
	global $interface_snv6_arr_cache;
4348
	global $config;
4349

    
4350
	$interface = trim($interface);
4351
	$interface = get_real_interface($interface);
4352

    
4353
	if (!does_interface_exist($interface))
4354
		return;
4355

    
4356
	/* Setup IP cache */
4357
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4358
		// FIXME: Add IPv6 support to the pfSense module
4359
		$ifinfo = array();
4360
		exec("/sbin/ifconfig {$interface} inet6", $output);
4361
		foreach($output as $line) {
4362
			if(preg_match("/inet6/", $line)) {
4363
				$parts = explode(" ", $line);
4364
				if(! preg_match("/fe80::/", $parts[1])) {
4365
					$ifinfo['ipaddrv6'] = $parts[1];
4366
					if($parts[2] == "-->") {
4367
						$parts[5] = "126";
4368
						$ifinfo['subnetbitsv6'] = $parts[5];
4369
					} else {
4370
						$ifinfo['subnetbitsv6'] = $parts[3];
4371
					}
4372
					break;
4373
				}
4374
			}
4375
		}
4376
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddrv6'];
4377
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbitsv6'];
4378
	}
4379

    
4380
	return $interface_ipv6_arr_cache[$interface];
4381
}
4382

    
4383
/*
4384
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4385
 */
4386
function find_interface_ipv6_ll($interface, $flush = false)
4387
{
4388
	global $interface_llv6_arr_cache;
4389
	global $config;
4390

    
4391
	$interface = str_replace("\n", "", $interface);
4392

    
4393
	if (!does_interface_exist($interface))
4394
		return;
4395

    
4396
	/* Setup IP cache */
4397
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4398
		$ifinfo = pfSense_get_interface_addresses($interface);
4399
		// FIXME: Add IPv6 support to the pfSense module
4400
		exec("/sbin/ifconfig {$interface} inet6", $output);
4401
		foreach($output as $line) {
4402
			if(preg_match("/inet6/", $line)) {
4403
				$parts = explode(" ", $line);
4404
				if(preg_match("/fe80::/", $parts[1])) {
4405
					$partsaddress = explode("%", $parts[1]);
4406
					$ifinfo['linklocal'] = $partsaddress[0];
4407
				}
4408
			}
4409
		}
4410
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4411
	}
4412
	return $interface_llv6_arr_cache[$interface];
4413
}
4414

    
4415
function find_interface_subnet($interface, $flush = false)
4416
{
4417
	global $interface_sn_arr_cache;
4418
	global $interface_ip_arr_cache;
4419

    
4420
	$interface = str_replace("\n", "", $interface);
4421
	if (does_interface_exist($interface) == false)
4422
		return;
4423

    
4424
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4425
		$ifinfo = pfSense_get_interface_addresses($interface);
4426
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4427
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4428
	}
4429

    
4430
	return $interface_sn_arr_cache[$interface];
4431
}
4432

    
4433
function find_interface_subnetv6($interface, $flush = false)
4434
{
4435
	global $interface_snv6_arr_cache;
4436
	global $interface_ipv6_arr_cache;
4437

    
4438
	$interface = str_replace("\n", "", $interface);
4439
	if (does_interface_exist($interface) == false)
4440
		return;
4441

    
4442
	$foundv6 = false;
4443
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4444
		$ifinfo = array();
4445
		// FIXME: Add IPv6 support to the pfSense module
4446
		unset($output);
4447
		exec("/sbin/ifconfig {$interface} inet6", $output);
4448
		foreach($output as $line) {
4449
			$line = trim($line);
4450
			if(preg_match("/inet6/", $line)) {
4451
				$parts = explode(" ", $line);
4452
				if(! preg_match("/fe80::/", $parts[1])) {
4453
					$ifinfo['ipaddrv6'] = $parts[1];
4454
					if($parts[2] == "-->") {
4455
						$parts[5] = "126";
4456
						$ifinfo['subnetbitsv6'] = $parts[5];
4457
					} else {
4458
						$ifinfo['subnetbitsv6'] = $parts[3];
4459
					}
4460
					$foundv6 = true;
4461
					break;
4462
				}
4463
			}
4464
		}
4465
		if ($foundv6 === true) {
4466
			$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddrv6'];
4467
			$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbitsv6'];
4468
		} else
4469
			unset($interface_ipv6_arr_cache[$interface], $interface_snv6_arr_cache[$interface]);
4470
	}
4471

    
4472
	return $interface_snv6_arr_cache[$interface];
4473
}
4474

    
4475
function ip_in_interface_alias_subnet($interface, $ipalias) {
4476
	global $config;
4477

    
4478
	if (empty($interface) || !is_ipaddr($ipalias))
4479
		return false;
4480
	if (is_array($config['virtualip']['vip'])) {
4481
		foreach ($config['virtualip']['vip'] as $vip) {
4482
			switch ($vip['mode']) {
4483
			case "ipalias":
4484
				if ($vip['interface'] <> $interface)
4485
					break;
4486
				if (ip_in_subnet($ipalias, gen_subnet($vip['subnet'], $vip['subnet_bits']) . "/" . $vip['subnet_bits']))
4487
					return true;
4488
				break;
4489
			}
4490
		}
4491
	}
4492

    
4493
	return false;
4494
}
4495

    
4496
function get_interface_ip($interface = "wan")
4497
{
4498
	$realif = get_failover_interface($interface);
4499
	if (!$realif) {
4500
		if (preg_match("/^carp/i", $interface))
4501
			$realif = $interface;
4502
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4503
			$realif = $interface;
4504
		else
4505
			return null;
4506
	}
4507

    
4508
	$curip = find_interface_ip($realif);
4509
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4510
		return $curip;
4511
	else
4512
		return null;
4513
}
4514

    
4515
function get_interface_ipv6($interface = "wan", $flush = false)
4516
{
4517
	global $config;
4518

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

    
4527
	$curip = find_interface_ipv6($realif, $flush);
4528
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4529
		return $curip;
4530
	else
4531
		return null;
4532
}
4533

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

    
4546
	$curip = find_interface_ipv6_ll($realif);
4547
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4548
		return $curip;
4549
	else
4550
		return null;
4551
}
4552

    
4553
function get_interface_subnet($interface = "wan")
4554
{
4555
	$realif = get_real_interface($interface);
4556
	if (!$realif) {
4557
		if (preg_match("/^carp/i", $interface))
4558
			$realif = $interface;
4559
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4560
			$realif = $interface;
4561
		else
4562
			return null;
4563
	}
4564

    
4565
	$cursn = find_interface_subnet($realif);
4566
	if (!empty($cursn))
4567
		return $cursn;
4568

    
4569
	return null;
4570
}
4571

    
4572
function get_interface_subnetv6($interface = "wan")
4573
{
4574
	global $config;
4575

    
4576
	$realif = get_real_interface($interface, "inet6");
4577
	if (!$realif) {
4578
		if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4579
			$realif = $interface;
4580
		else
4581
			return null;
4582
	}
4583

    
4584
	$cursn = find_interface_subnetv6($realif);
4585
	if (!empty($cursn))
4586
		return $cursn;
4587

    
4588
	return null;
4589
}
4590

    
4591
/* return outside interfaces with a gateway */
4592
function get_interfaces_with_gateway() {
4593
	global $config;
4594

    
4595
	$ints = array();
4596

    
4597
	/* loop interfaces, check config for outbound */
4598
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4599
		switch ($ifname['ipaddr']) {
4600
			case "dhcp":
4601
			case "ppp";
4602
			case "pppoe":
4603
			case "pptp":
4604
			case "l2tp":
4605
			case "ppp";
4606
				$ints[$ifdescr] = $ifdescr;
4607
			break;
4608
			default:
4609
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
4610
				    !empty($ifname['gateway']))
4611
					$ints[$ifdescr] = $ifdescr;
4612
			break;
4613
		}
4614
	}
4615
	return $ints;
4616
}
4617

    
4618
/* return true if interface has a gateway */
4619
function interface_has_gateway($friendly) {
4620
	global $config;
4621

    
4622
	if (!empty($config['interfaces'][$friendly])) {
4623
		$ifname = &$config['interfaces'][$friendly];
4624
		switch ($ifname['ipaddr']) {
4625
			case "dhcp":
4626
			case "pppoe":
4627
			case "pptp":
4628
			case "l2tp":
4629
			case "ppp";
4630
				return true;
4631
			break;
4632
			default:
4633
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4634
					return true;
4635
				if (!empty($ifname['gateway']))
4636
					return true;
4637
			break;
4638
		}
4639
	}
4640

    
4641
	return false;
4642
}
4643

    
4644
/* return true if interface has a gateway */
4645
function interface_has_gatewayv6($friendly) {
4646
	global $config;
4647

    
4648
	if (!empty($config['interfaces'][$friendly])) {
4649
		$ifname = &$config['interfaces'][$friendly];
4650
		switch ($ifname['ipaddrv6']) {
4651
			case "slaac":
4652
			case "dhcp6":
4653
			case "6to4":
4654
			case "6rd":
4655
				return true;
4656
				break;
4657
			default:
4658
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4659
					return true;
4660
				if (!empty($ifname['gatewayv6']))
4661
					return true;
4662
				break;
4663
		}
4664
	}
4665

    
4666
	return false;
4667
}
4668

    
4669
/****f* interfaces/is_altq_capable
4670
 * NAME
4671
 *   is_altq_capable - Test if interface is capable of using ALTQ
4672
 * INPUTS
4673
 *   $int            - string containing interface name
4674
 * RESULT
4675
 *   boolean         - true or false
4676
 ******/
4677

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

    
4691
	$int_family = remove_ifindex($int);
4692

    
4693
	if (in_array($int_family, $capable))
4694
		return true;
4695
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
4696
		return true;
4697
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
4698
		return true;
4699
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
4700
		return true;
4701
	else
4702
		return false;
4703
}
4704

    
4705
/****f* interfaces/is_interface_wireless
4706
 * NAME
4707
 *   is_interface_wireless - Returns if an interface is wireless
4708
 * RESULT
4709
 *   $tmp       - Returns if an interface is wireless
4710
 ******/
4711
function is_interface_wireless($interface) {
4712
	global $config, $g;
4713

    
4714
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
4715
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
4716
		if (preg_match($g['wireless_regex'], $interface)) {
4717
			if (isset($config['interfaces'][$friendly]))
4718
				$config['interfaces'][$friendly]['wireless'] = array();
4719
			return true;
4720
		}
4721
		return false;
4722
	} else
4723
		return true;
4724
}
4725

    
4726
function get_wireless_modes($interface) {
4727
	/* return wireless modes and channels */
4728
	$wireless_modes = array();
4729

    
4730
	$cloned_interface = get_real_interface($interface);
4731

    
4732
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4733
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
4734
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4735
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
4736

    
4737
		$interface_channels = "";
4738
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4739
		$interface_channel_count = count($interface_channels);
4740

    
4741
		$c = 0;
4742
		while ($c < $interface_channel_count)
4743
		{
4744
			$channel_line = explode(",", $interface_channels["$c"]);
4745
			$wireless_mode = trim($channel_line[0]);
4746
			$wireless_channel = trim($channel_line[1]);
4747
			if(trim($wireless_mode) != "") {
4748
				/* if we only have 11g also set 11b channels */
4749
				if($wireless_mode == "11g") {
4750
					if(!isset($wireless_modes["11b"]))
4751
						$wireless_modes["11b"] = array();
4752
				} else if($wireless_mode == "11g ht") {
4753
					if(!isset($wireless_modes["11b"]))
4754
						$wireless_modes["11b"] = array();
4755
					if(!isset($wireless_modes["11g"]))
4756
						$wireless_modes["11g"] = array();
4757
					$wireless_mode = "11ng";
4758
				} else if($wireless_mode == "11a ht") {
4759
					if(!isset($wireless_modes["11a"]))
4760
						$wireless_modes["11a"] = array();
4761
					$wireless_mode = "11na";
4762
				}
4763
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
4764
			}
4765
			$c++;
4766
		}
4767
	}
4768
	return($wireless_modes);
4769
}
4770

    
4771
/* return channel numbers, frequency, max txpower, and max regulation txpower */
4772
function get_wireless_channel_info($interface) {
4773
	$wireless_channels = array();
4774

    
4775
	$cloned_interface = get_real_interface($interface);
4776

    
4777
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4778
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
4779
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4780
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
4781

    
4782
		$interface_channels = "";
4783
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4784

    
4785
		foreach ($interface_channels as $channel_line) {
4786
			$channel_line = explode(",", $channel_line);
4787
			if(!isset($wireless_channels[$channel_line[0]]))
4788
				$wireless_channels[$channel_line[0]] = $channel_line;
4789
		}
4790
	}
4791
	return($wireless_channels);
4792
}
4793

    
4794
/****f* interfaces/get_interface_mtu
4795
 * NAME
4796
 *   get_interface_mtu - Return the mtu of an interface
4797
 * RESULT
4798
 *   $tmp       - Returns the mtu of an interface
4799
 ******/
4800
function get_interface_mtu($interface) {
4801
	$mtu = pfSense_get_interface_addresses($interface);
4802
	return $mtu['mtu'];
4803
}
4804

    
4805
function get_interface_mac($interface) {
4806

    
4807
	$macinfo = pfSense_get_interface_addresses($interface);
4808
	return $macinfo["macaddr"];
4809
}
4810

    
4811
/****f* pfsense-utils/generate_random_mac_address
4812
 * NAME
4813
 *   generate_random_mac - generates a random mac address
4814
 * INPUTS
4815
 *   none
4816
 * RESULT
4817
 *   $mac - a random mac address
4818
 ******/
4819
function generate_random_mac_address() {
4820
	$mac = "02";
4821
	for($x=0; $x<5; $x++)
4822
		$mac .= ":" . dechex(rand(16, 255));
4823
	return $mac;
4824
}
4825

    
4826
/****f* interfaces/is_jumbo_capable
4827
 * NAME
4828
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
4829
 * INPUTS
4830
 *   $int             - string containing interface name
4831
 * RESULT
4832
 *   boolean          - true or false
4833
 ******/
4834
function is_jumbo_capable($iface) {
4835
	$iface = trim($iface);
4836
	$capable = pfSense_get_interface_addresses($iface);
4837

    
4838
	if (isset($capable['caps']['vlanmtu']))
4839
		return true;
4840

    
4841
	return false;
4842
}
4843

    
4844
function interface_setup_pppoe_reset_file($pppif, $iface="") {
4845
	global $g;
4846

    
4847
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
4848

    
4849
	if(!empty($iface) && !empty($pppif)){
4850
		$cron_cmd = <<<EOD
4851
#!/bin/sh
4852
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
4853
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
4854

    
4855
EOD;
4856

    
4857
		@file_put_contents($cron_file, $cron_cmd);
4858
		chmod($cron_file, 0755);
4859
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
4860
	} else
4861
		unlink_if_exists($cron_file);
4862
}
4863

    
4864
function get_interface_default_mtu($type = "ethernet") {
4865
	switch ($type) {
4866
	case "gre":
4867
		return 1476;
4868
		break;
4869
	case "gif":
4870
		return 1280;
4871
		break;
4872
	case "tun":
4873
	case "vlan":
4874
	case "tap":
4875
	case "ethernet":
4876
	default:
4877
		return 1500;
4878
		break;
4879
	}
4880

    
4881
	/* Never reached */
4882
	return 1500;
4883
}
4884

    
4885
function get_vip_descr($ipaddress) {
4886
	global $config;
4887

    
4888
	foreach ($config['virtualip']['vip'] as $vip) {
4889
		if ($vip['subnet'] == $ipaddress) {
4890
			return ($vip['descr']);
4891
		}
4892
	}
4893
	return "";
4894
}
4895

    
4896
function interfaces_staticarp_configure($if) {
4897
	global $config, $g;
4898
	if(isset($config['system']['developerspew'])) {
4899
		$mt = microtime();
4900
		echo "interfaces_staticarp_configure($if) being called $mt\n";
4901
	}
4902

    
4903
	$ifcfg = $config['interfaces'][$if];
4904

    
4905
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
4906
		return 0;
4907

    
4908
	/* Enable staticarp, if enabled */
4909
	if(isset($config['dhcpd'][$if]['staticarp'])) {
4910
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
4911
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4912
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
4913

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

    
4917
			}
4918

    
4919
		}
4920
	} else {
4921
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
4922
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4923
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
4924
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
4925
				if (isset($arpent['arp_table_static_entry'])) {
4926
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
4927
				}
4928
			}
4929
		}
4930
	}
4931

    
4932
	return 0;
4933
}
4934

    
4935
function get_failover_interface($interface, $family = "all") {
4936
	global $config;
4937
	/* shortcut to get_real_interface if we find it in the config */
4938
	if(is_array($config['interfaces'][$interface])) {
4939
		$wanif = get_real_interface($interface, $family);
4940
		return $wanif;
4941
	}
4942

    
4943
	/* compare against gateway groups */
4944
	$a_groups = return_gateway_groups_array();
4945
	if(is_array($a_groups[$interface])) {
4946
		/* we found a gateway group, fetch the interface or vip */
4947
		if($a_groups[$interface][0]['vip'] <> "")
4948
			$wanif = $a_groups[$interface][0]['vip'];
4949
		else
4950
			$wanif = $a_groups[$interface][0]['int'];
4951

    
4952
		return $wanif;
4953
	}
4954
	/* fall through to get_real_interface */
4955
	$wanif = get_real_interface($interface, $family);
4956
	return $wanif;
4957
}
4958

    
4959
function remove_ifindex($ifname) {
4960
	return preg_replace("/[0-9]+$/", "", $ifname);
4961
}
4962

    
4963
?>
(25-25/66)