Project

General

Profile

Download (145 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['caps']['txcsum']))
491
			$commontx = false;
492
		if (!isset($opts['caps']['rxcsum']))
493
			$commonrx = false;
494
		if (!isset($opts['caps']['tso4']))
495
			$commontso4 = false;
496
		if (!isset($opts['caps']['tso6']))
497
			$commontso6 = false;
498
		if (!isset($opts['caps']['lro']))
499
			$commonlro = false;
500
		if ($smallermtu == 0 && !empty($mtu))
501
			$smallermtu = $mtu;
502
		else if (!empty($mtu) && $mtu < $smallermtu)
503
			$smallermtu = $mtu;
504
	}
505
	if ($foundgif == false && $checkmember == 2)
506
		return;
507

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

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

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

    
544
	$checklist = get_configured_interface_list();
545

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
794
	$checklist = get_interface_list();
795

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

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

    
809
	interfaces_bring_up($laggif);
810

    
811
	return $laggif;
812
}
813

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

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

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

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

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

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

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

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

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

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

    
885
	return $greif;
886
}
887

    
888
function interfaces_gif_configure($checkparent = 0) {
889
	global $config;
890

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

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

    
917
	if (!is_array($gif))
918
		return -1;
919

    
920
	$realif = get_real_interface($gif['if']);
921
	$ipaddr = $gif['ipaddr'];
922

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

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

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

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

    
979

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

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

    
992
	return $gifif;
993
}
994

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

    
998
	if ($g['platform'] == 'jail')
999
		return;
1000

    
1001
	/* Set up our loopback interface */
1002
	interfaces_loopback_configure();
1003

    
1004
	/* create the unconfigured wireless clones */
1005
	interfaces_create_wireless_clones();
1006

    
1007
	/* set up LAGG virtual interfaces */
1008
	interfaces_lagg_configure();
1009

    
1010
	/* set up VLAN virtual interfaces */
1011
	interfaces_vlan_configure();
1012

    
1013
	interfaces_qinq_configure();
1014

    
1015
	$iflist = get_configured_interface_with_descr();
1016
	$delayed_list = array();
1017
	$bridge_list = array();
1018
	$track6_list = array();
1019

    
1020
	/* This is needed to speedup interfaces on bootup. */
1021
	$reload = false;
1022
	if (!$g['booting'])
1023
		$reload = true;
1024

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

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

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

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

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

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

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

    
1071
		interface_configure($if, $reload);
1072

    
1073
		if ($g['booting'])
1074
			echo gettext("done.") . "\n";
1075
	}
1076

    
1077
	/* bring up vip interfaces */
1078
	interfaces_vips_configure();
1079

    
1080
	/* set up GRE virtual interfaces */
1081
	interfaces_gre_configure(2);
1082

    
1083
	/* set up GIF virtual interfaces */
1084
	interfaces_gif_configure(2);
1085

    
1086
	foreach ($delayed_list as $if => $ifname) {
1087
		if ($g['booting'])
1088
			printf(gettext("Configuring %s interface..."), $ifname);
1089
		if ($g['debug'])
1090
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1091

    
1092
		interface_configure($if, $reload);
1093

    
1094
		if ($g['booting'])
1095
			echo gettext("done.") . "\n";
1096
	}
1097

    
1098
	/* set up BRIDGe virtual interfaces */
1099
	interfaces_bridge_configure(2);
1100

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

    
1107
		interface_configure($if, $reload);
1108

    
1109
		if ($g['booting'])
1110
			echo gettext("done.") . "\n";
1111
	}
1112

    
1113
	/* configure interface groups */
1114
	interfaces_group_setup();
1115

    
1116
	if (!$g['booting']) {
1117
		/* reconfigure static routes (kernel may have deleted them) */
1118
		system_routing_configure();
1119

    
1120
		/* reload IPsec tunnels */
1121
		vpn_ipsec_configure();
1122

    
1123
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1124
		services_dhcpd_configure();
1125

    
1126
		/* restart dnsmasq */
1127
		services_dnsmasq_configure();
1128

    
1129
		/* reload captive portal */
1130
		if (function_exists('captiveportal_init_rules'))
1131
			captiveportal_init_rules();
1132
	}
1133

    
1134
	return 0;
1135
}
1136

    
1137
function interface_reconfigure($interface = "wan", $reloadall = false) {
1138
	interface_bring_down($interface);
1139
	interface_configure($interface, $reloadall);
1140
}
1141

    
1142
function interface_vip_bring_down($vip) {
1143
	global $g;
1144

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

    
1168
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1169
	global $config, $g;
1170

    
1171
	if (!isset($config['interfaces'][$interface]))
1172
		return;
1173

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

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

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

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

    
1293
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1294
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1295
//	log_error("Checking for old router states: {$g['tmp_path']}/{$realif}_router = {$old_router}");
1296
	if (!empty($old_router)) {
1297
		log_error("Clearing states to old gateway {$old_router}.");
1298
		mwexec("/sbin/pfctl -i {$realif} -Fs -G {$old_router}");
1299
	}
1300

    
1301
	/* remove interface up file if it exists */
1302
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1303
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1304
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1305
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1306
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1307
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1308
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1309

    
1310
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1311
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1312
	if (is_array($ifcfg['wireless'])) {
1313
		kill_hostapd($realif);
1314
		mwexec(kill_wpasupplicant($realif));
1315
	}
1316

    
1317
	if ($destroy == true) {
1318
		if (preg_match("/^[a-z0-9]+_vip|^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif))
1319
			pfSense_interface_destroy($realif);
1320
	}
1321

    
1322
	return;
1323
}
1324

    
1325
function interfaces_ptpid_used($ptpid) {
1326
	global $config;
1327

    
1328
	if (is_array($config['ppps']['ppp']))
1329
		foreach ($config['ppps']['ppp'] as & $settings)
1330
			if ($ptpid == $settings['ptpid'])
1331
				return true;
1332

    
1333
	return false;
1334
}
1335

    
1336
function interfaces_ptpid_next() {
1337

    
1338
	$ptpid = 0;
1339
	while(interfaces_ptpid_used($ptpid))
1340
		$ptpid++;
1341

    
1342
	return $ptpid;
1343
}
1344

    
1345
function getMPDCRONSettings($pppif) {
1346
	global $config;
1347

    
1348
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1349
	if (is_array($config['cron']['item'])) {
1350
		foreach ($config['cron']['item'] as $i => $item) {
1351
			if (stripos($item['command'], $cron_cmd_file) !== false)
1352
				return array("ID" => $i, "ITEM" => $item);
1353
		}
1354
	}
1355

    
1356
	return NULL;
1357
}
1358

    
1359
function handle_pppoe_reset($post_array) {
1360
	global $config, $g;
1361

    
1362
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1363
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1364

    
1365
	if (!is_array($config['cron']['item']))
1366
		$config['cron']['item'] = array();
1367

    
1368
	$itemhash = getMPDCRONSettings($pppif);
1369

    
1370
	// reset cron items if necessary and return
1371
	if (empty($post_array['pppoe-reset-type'])) {
1372
		if (isset($itemhash))
1373
			unset($config['cron']['item'][$itemhash['ID']]);
1374
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1375
		return;
1376
	}
1377

    
1378
	if (empty($itemhash))
1379
		$itemhash = array();
1380
	$item = array();
1381
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1382
		$item['minute'] = $post_array['pppoe_resetminute'];
1383
		$item['hour'] = $post_array['pppoe_resethour'];
1384
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1385
			$date = explode("/", $post_array['pppoe_resetdate']);
1386
			$item['mday'] = $date[1];
1387
			$item['month'] = $date[0];
1388
		} else {
1389
			$item['mday'] = "*";
1390
			$item['month'] = "*";
1391
		}
1392
		$item['wday'] = "*";
1393
		$item['who'] = "root";
1394
		$item['command'] = $cron_cmd_file;
1395
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1396
		switch ($post_array['pppoe_pr_preset_val']) {
1397
		case "monthly":
1398
			$item['minute'] = "0";
1399
			$item['hour'] = "0";
1400
			$item['mday'] = "1";
1401
			$item['month'] = "*";
1402
			$item['wday'] = "*";
1403
			break;
1404
		case "weekly":
1405
			$item['minute'] = "0";
1406
			$item['hour'] = "0";
1407
			$item['mday'] = "*";
1408
			$item['month'] = "*";
1409
			$item['wday'] = "0";
1410
			break;
1411
		case "daily":
1412
			$item['minute'] = "0";
1413
			$item['hour'] = "0";
1414
			$item['mday'] = "*";
1415
			$item['month'] = "*";
1416
			$item['wday'] = "*";
1417
			break;
1418
		case "hourly":
1419
			$item['minute'] = "0";
1420
			$item['hour'] = "*";
1421
			$item['mday'] = "*";
1422
			$item['month'] = "*";
1423
			$item['wday'] = "*";
1424
			break;
1425
		} // end switch
1426
		$item['who'] = "root";
1427
		$item['command'] = $cron_cmd_file;
1428
	}
1429
	if (empty($item))
1430
		return;
1431
	if (isset($item['ID']))
1432
		$config['cron']['item'][$item['ID']] = $item;
1433
	else
1434
		$config['cron']['item'][] = $item;
1435
}
1436

    
1437
/*
1438
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1439
 * It writes the mpd config file to /var/etc every time the link is opened.
1440
 */
1441
function interface_ppps_configure($interface) {
1442
	global $config, $g;
1443

    
1444
	/* Return for unassigned interfaces. This is a minimum requirement. */
1445
	if (empty($config['interfaces'][$interface]))
1446
		return 0;
1447
	$ifcfg = $config['interfaces'][$interface];
1448
	if (!isset($ifcfg['enable']))
1449
		return 0;
1450

    
1451
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1452
	if(!is_dir("/var/spool/lock")) {
1453
		exec("/bin/mkdir -p /var/spool/lock");
1454
		exec("/bin/chmod a+rw /var/spool/lock/.");
1455
	}
1456
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1457
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1458
		mwexec("/bin/ln -s /usr/local/sbin/mpd.script {$g['varetc_path']}/.");
1459

    
1460
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1461
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1462
			if ($ifcfg['if'] == $ppp['if'])
1463
				break;
1464
		}
1465
	}
1466
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1467
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1468
		return 0;
1469
	}
1470
	$pppif = $ifcfg['if'];
1471
	if ($ppp['type'] == "ppp")
1472
		$type = "modem";
1473
	else
1474
		$type = $ppp['type'];
1475
	$upper_type = strtoupper($ppp['type']);
1476

    
1477
	if($g['booting']) {
1478
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1479
		echo "starting {$pppif} link...";
1480
		// Do not re-configure the interface if we are booting and it's already been started
1481
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1482
			return 0;
1483
	}
1484

    
1485
	$ports = explode(',',$ppp['ports']);
1486
	if ($type != "modem") {
1487
		foreach ($ports as $pid => $port) {
1488
			$ports[$pid] = get_real_interface($port);
1489
			if (empty($ports[$pid]))
1490
				return 0;
1491
		}
1492
	}
1493
	$localips = explode(',',$ppp['localip']);
1494
	$gateways = explode(',',$ppp['gateway']);
1495
	$subnets = explode(',',$ppp['subnet']);
1496

    
1497
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1498
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1499
	 */
1500
	foreach($ports as $pid => $port){
1501
		switch ($ppp['type']) {
1502
			case "pppoe":
1503
				/* Bring the parent interface up */
1504
				interfaces_bring_up($port);
1505
				pfSense_ngctl_attach(".", $port);
1506
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1507
				mwexec("ngctl msg {$port}: setautosrc 1");
1508
				break;
1509
			case "pptp":
1510
			case "l2tp":
1511
				/* configure interface */
1512
				if(is_ipaddr($localips[$pid])){
1513
					// Manually configure interface IP/subnet
1514
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1515
					interfaces_bring_up($port);
1516
				} else if (empty($localips[$pid]))
1517
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1518

    
1519
				if(!is_ipaddr($localips[$pid])){
1520
					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!");
1521
					$localips[$pid] = "0.0.0.0";
1522
				}
1523
				if(!is_ipaddr($gateways[$pid])){
1524
					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));
1525
					return 0;
1526
				}
1527
				pfSense_ngctl_attach(".", $port);
1528
				break;
1529
			case "ppp":
1530
				if (!file_exists("{$port}")) {
1531
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1532
					return 0;
1533
				}
1534
				break;
1535
			default:
1536
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1537
				break;
1538
		}
1539
	}
1540

    
1541
	if (is_array($ports) && count($ports) > 1)
1542
		$multilink = "enable";
1543
	else
1544
		$multilink = "disable";
1545

    
1546
	if ($type == "modem"){
1547
		if (is_ipaddr($ppp['localip']))
1548
			$localip = $ppp['localip'];
1549
		else
1550
			$localip = '0.0.0.0';
1551

    
1552
		if (is_ipaddr($ppp['gateway']))
1553
			$gateway = $ppp['gateway'];
1554
		else
1555
			$gateway = "10.64.64.{$pppid}";
1556
		$ranges = "{$localip}/0 {$gateway}/0";
1557

    
1558
		if (empty($ppp['apnum']))
1559
			$ppp['apnum'] = 1;
1560
	} else
1561
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1562

    
1563
	if (isset($ppp['ondemand']))
1564
		$ondemand = "enable";
1565
	else
1566
		$ondemand = "disable";
1567
	if (!isset($ppp['idletimeout']))
1568
		$ppp['idletimeout'] = 0;
1569

    
1570
	if (empty($ppp['username']) && $type == "modem"){
1571
		$ppp['username'] = "user";
1572
		$ppp['password'] = "none";
1573
	}
1574
	if (empty($ppp['password']) && $type == "modem")
1575
		$passwd = "none";
1576
	else
1577
		$passwd = base64_decode($ppp['password']);
1578

    
1579
	$bandwidths = explode(',',$ppp['bandwidth']);
1580
	$defaultmtu = "1492";
1581
	if (!empty($ifcfg['mtu']))
1582
		$defaultmtu = intval($ifcfg['mtu']);
1583
	$mtus = explode(',',$ppp['mtu']);
1584
	$mrus = explode(',',$ppp['mru']);
1585

    
1586
	if (isset($ppp['mrru']))
1587
		$mrrus = explode(',',$ppp['mrru']);
1588

    
1589
	// Construct the mpd.conf file
1590
	$mpdconf = <<<EOD
1591
startup:
1592
	# configure the console
1593
	set console close
1594
	# configure the web server
1595
	set web close
1596

    
1597
default:
1598
{$ppp['type']}client:
1599
	create bundle static {$interface}
1600
	set bundle enable ipv6cp
1601
	set iface name {$pppif}
1602

    
1603
EOD;
1604
	$setdefaultgw = false;
1605
	$founddefaultgw = false;
1606
	if (is_array($config['gateways']['gateway_item'])) {
1607
		foreach($config['gateways']['gateway_item'] as $gateway) {
1608
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1609
				$setdefaultgw = true;
1610
				break;
1611
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1612
				$founddefaultgw = true;
1613
				break;
1614
			}
1615
		}
1616
	}
1617

    
1618
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1619
		$setdefaultgw = true;
1620
		$mpdconf .= <<<EOD
1621
	set iface route default
1622

    
1623
EOD;
1624
	}
1625
	$mpdconf .= <<<EOD
1626
	set iface {$ondemand} on-demand
1627
	set iface idle {$ppp['idletimeout']}
1628

    
1629
EOD;
1630

    
1631
	if (isset($ppp['ondemand']))
1632
		$mpdconf .= <<<EOD
1633
	set iface addrs 10.10.1.1 10.10.1.2
1634

    
1635
EOD;
1636

    
1637
	if (isset($ppp['tcpmssfix']))
1638
		$tcpmss = "disable";
1639
	else
1640
		$tcpmss = "enable";
1641
		$mpdconf .= <<<EOD
1642
	set iface {$tcpmss} tcpmssfix
1643

    
1644
EOD;
1645

    
1646
	$mpdconf .= <<<EOD
1647
	set iface up-script /usr/local/sbin/ppp-linkup
1648
	set iface down-script /usr/local/sbin/ppp-linkdown
1649
	set ipcp ranges {$ranges}
1650

    
1651
EOD;
1652
	if (isset($ppp['vjcomp']))
1653
		$mpdconf .= <<<EOD
1654
	set ipcp no vjcomp
1655

    
1656
EOD;
1657

    
1658
	if (isset($config['system']['dnsallowoverride']))
1659
		$mpdconf .= <<<EOD
1660
	set ipcp enable req-pri-dns
1661
	set ipcp enable req-sec-dns
1662

    
1663
EOD;
1664
	if (!isset($ppp['verbose_log']))
1665
		$mpdconf .= <<<EOD
1666
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1667

    
1668
EOD;
1669
	foreach($ports as $pid => $port){
1670
		$port = get_real_interface($port);
1671
		$mpdconf .= <<<EOD
1672

    
1673
	create link static {$interface}_link{$pid} {$type}
1674
	set link action bundle {$interface}
1675
	set link {$multilink} multilink
1676
	set link keep-alive 10 60
1677
	set link max-redial 0
1678

    
1679
EOD;
1680
		if (isset($ppp['shortseq']))
1681
			$mpdconf .= <<<EOD
1682
	set link no shortseq
1683

    
1684
EOD;
1685

    
1686
		if (isset($ppp['acfcomp']))
1687
			$mpdconf .= <<<EOD
1688
	set link no acfcomp
1689

    
1690
EOD;
1691

    
1692
		if (isset($ppp['protocomp']))
1693
			$mpdconf .= <<<EOD
1694
	set link no protocomp
1695

    
1696
EOD;
1697

    
1698
		$mpdconf .= <<<EOD
1699
	set link disable chap pap
1700
	set link accept chap pap eap
1701
	set link disable incoming
1702

    
1703
EOD;
1704

    
1705

    
1706
		if (!empty($bandwidths[$pid]))
1707
			$mpdconf .= <<<EOD
1708
	set link bandwidth {$bandwidths[$pid]}
1709

    
1710
EOD;
1711

    
1712
		if (empty($mtus[$pid]))
1713
			$mtus[$pid] = $defaultmtu;
1714
			$mpdconf .= <<<EOD
1715
	set link mtu {$mtus[$pid]}
1716

    
1717
EOD;
1718

    
1719
		if (!empty($mrus[$pid]))
1720
			$mpdconf .= <<<EOD
1721
	set link mru {$mrus[$pid]}
1722

    
1723
EOD;
1724

    
1725
		if (!empty($mrrus[$pid]))
1726
			$mpdconf .= <<<EOD
1727
	set link mrru {$mrrus[$pid]}
1728

    
1729
EOD;
1730

    
1731
		$mpdconf .= <<<EOD
1732
	set auth authname "{$ppp['username']}"
1733
	set auth password {$passwd}
1734

    
1735
EOD;
1736
		if ($type == "modem") {
1737
			$mpdconf .= <<<EOD
1738
	set modem device {$ppp['ports']}
1739
	set modem script DialPeer
1740
	set modem idle-script Ringback
1741
	set modem watch -cd
1742
	set modem var \$DialPrefix "DT"
1743
	set modem var \$Telephone "{$ppp['phone']}"
1744

    
1745
EOD;
1746
		}
1747
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1748
			$mpdconf .= <<<EOD
1749
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1750

    
1751
EOD;
1752
		}
1753
		if (isset($ppp['initstr']) && $type == "modem") {
1754
			$initstr = base64_decode($ppp['initstr']);
1755
			$mpdconf .= <<<EOD
1756
	set modem var \$InitString "{$initstr}"
1757

    
1758
EOD;
1759
		}
1760
		if (isset($ppp['simpin']) && $type == "modem") {
1761
			if($ppp['pin-wait'] == "")
1762
				$ppp['pin-wait'] = 0;
1763
			$mpdconf .= <<<EOD
1764
	set modem var \$SimPin "{$ppp['simpin']}"
1765
	set modem var \$PinWait "{$ppp['pin-wait']}"
1766

    
1767
EOD;
1768
		}
1769
		if (isset($ppp['apn']) && $type == "modem") {
1770
			$mpdconf .= <<<EOD
1771
	set modem var \$APN "{$ppp['apn']}"
1772
	set modem var \$APNum "{$ppp['apnum']}"
1773

    
1774
EOD;
1775
		}
1776
		if ($type == "pppoe") {
1777
			// Send a null service name if none is set.
1778
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1779
			$mpdconf .= <<<EOD
1780
	set pppoe service "{$provider}"
1781

    
1782
EOD;
1783
		}
1784
		if ($type == "pppoe")
1785
			$mpdconf .= <<<EOD
1786
	set pppoe iface {$port}
1787

    
1788
EOD;
1789

    
1790
		if ($type == "pptp" || $type == "l2tp") {
1791
			$mpdconf .= <<<EOD
1792
	set {$type} self {$localips[$pid]}
1793
	set {$type} peer {$gateways[$pid]}
1794

    
1795
EOD;
1796
		}
1797

    
1798
		$mpdconf .= "\topen\n";
1799
	} //end foreach($port)
1800

    
1801

    
1802
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1803
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1804
		mwexec("/bin/ln -s {$g['conf_path']}/mpd_{$interface}.conf {$g['varetc_path']}/.");
1805
	else {
1806
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1807
		if (!$fd) {
1808
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1809
			return 0;
1810
		}
1811
		// Write out mpd_ppp.conf
1812
		fwrite($fd, $mpdconf);
1813
		fclose($fd);
1814
		unset($mpdconf);
1815
	}
1816

    
1817
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1818
	if (isset($ppp['uptime'])) {
1819
		if (!file_exists("/conf/{$pppif}.log")) {
1820
			conf_mount_rw();
1821
			mwexec("echo /dev/null > /conf/{$pppif}.log");
1822
			conf_mount_ro();
1823
		}
1824
	} else {
1825
		if (file_exists("/conf/{$pppif}.log")) {
1826
			conf_mount_rw();
1827
			mwexec("rm -f /conf/{$pppif}.log");
1828
			conf_mount_ro();
1829
		}
1830
	}
1831

    
1832
	/* clean up old lock files */
1833
	foreach($ports as $port) {
1834
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1835
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1836
	}
1837

    
1838
	/* fire up mpd */
1839
	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");
1840

    
1841
	// Check for PPPoE periodic reset request
1842
	if ($type == "pppoe") {
1843
		if (!empty($ppp['pppoe-reset-type']))
1844
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1845
		else
1846
			interface_setup_pppoe_reset_file($ppp['if']);
1847
	}
1848
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1849
	$i = 0;
1850
	while($i < 10) {
1851
		exec("/sbin/ifconfig {$ppp['if']} 2>&1", $out, $ret);
1852
		if($ret == 0)
1853
			break;
1854
		sleep(1);
1855
		$i++;
1856
	}
1857

    
1858
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
1859
	/* We should be able to launch the right version for each modem */
1860
	/* We can also guess the mondev from the manufacturer */
1861
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
1862
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
1863
	foreach($ports as $port) {
1864
		if(preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1865
			$mondev  = substr(basename($port), 0, -1);
1866
			$devlist = glob("/dev/{$mondev}?");
1867
			$mondev = basename(end($devlist));
1868
		}
1869
		if(preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1870
			$mondev  = substr(basename($port), 0, -1) . "1";
1871
		}
1872
		log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
1873
		mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
1874
	}
1875

    
1876
	return 1;
1877
}
1878

    
1879
function interfaces_carp_setup() {
1880
	global $g, $config;
1881

    
1882
	if (isset($config['system']['developerspew'])) {
1883
		$mt = microtime();
1884
		echo "interfaces_carp_setup() being called $mt\n";
1885
	}
1886

    
1887
	if ($g['booting']) {
1888
		echo gettext("Configuring CARP settings...");
1889
		mute_kernel_msgs();
1890
	}
1891

    
1892
	/* suck in configuration items */
1893
	if ($config['hasync']) {
1894
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1895
		$balanacing = $config['hasync']['balancing'];
1896
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1897
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1898
	} else {
1899
		unset($pfsyncinterface);
1900
		unset($balanacing);
1901
		unset($pfsyncenabled);
1902
	}
1903

    
1904
	if ($balanacing) {
1905
		mwexec("/sbin/sysctl net.inet.carp.arpbalance=1", true);
1906
		mwexec("/sbin/sysctl net.inet.carp.preempt=0", true);
1907
	} else
1908
		mwexec("/sbin/sysctl net.inet.carp.preempt=1", true);
1909

    
1910
	mwexec("sbin/sysctl net.inet.carp.log=1", true);
1911
	if (!empty($pfsyncinterface))
1912
		$carp_sync_int = get_real_interface($pfsyncinterface);
1913
	else
1914
		unset($carp_sync_int);
1915

    
1916
	/* setup pfsync interface */
1917
	if ($carp_sync_int and $pfsyncenabled) {
1918
		if (is_ipaddr($pfsyncpeerip))
1919
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1920
		else
1921
			$syncpeer = "-syncpeer";
1922

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

    
1925
		sleep(1);
1926

    
1927
		/* 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
1928
		 * for existing sessions.
1929
		 */
1930
		log_error("waiting for pfsync...");
1931
		$i = 0;
1932
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1933
			$i++;
1934
			sleep(1);
1935
		}
1936
		log_error("pfsync done in $i seconds.");
1937
		log_error("Configuring CARP settings finalize...");
1938
	} else {
1939
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
1940
	}
1941

    
1942
	if($config['virtualip']['vip'])
1943
		mwexec("/sbin/sysctl net.inet.carp.allow=1", true);
1944
	else
1945
		mwexec("/sbin/sysctl net.inet.carp.allow=0", true);
1946

    
1947
	if ($g['booting']) {
1948
		unmute_kernel_msgs();
1949
		echo gettext("done.") . "\n";
1950
	}
1951
}
1952

    
1953
function interface_proxyarp_configure($interface = "") {
1954
	global $config, $g;
1955
	if(isset($config['system']['developerspew'])) {
1956
		$mt = microtime();
1957
		echo "interface_proxyarp_configure() being called $mt\n";
1958
	}
1959

    
1960
	/* kill any running choparp */
1961
	if (empty($interface))
1962
		killbyname("choparp");
1963
	else {
1964
		$vipif = get_real_interface($interface);
1965
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1966
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1967
	}
1968

    
1969
	$paa = array();
1970
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1971

    
1972
		/* group by interface */
1973
		foreach ($config['virtualip']['vip'] as $vipent) {
1974
			if ($vipent['mode'] === "proxyarp") {
1975
				if ($vipent['interface'])
1976
					$proxyif = $vipent['interface'];
1977
				else
1978
					$proxyif = "wan";
1979

    
1980
				if (!empty($interface) && $interface != $proxyif)
1981
					continue;
1982

    
1983
				if (!is_array($paa[$proxyif]))
1984
					$paa[$proxyif] = array();
1985

    
1986
				$paa[$proxyif][] = $vipent;
1987
			}
1988
		}
1989
	}
1990

    
1991
	if (!empty($interface)) {
1992
		if (is_array($paa[$interface])) {
1993
			$paaifip = get_interface_ip($interface);
1994
			if (!is_ipaddr($paaifip))
1995
				return;
1996
			$args = get_real_interface($interface) . " auto";
1997
			foreach ($paa[$interface] as $paent) {
1998
				if (isset($paent['subnet']))
1999
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2000
				else if (isset($paent['range']))
2001
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2002
			}
2003
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2004
		}
2005
	} else if (count($paa) > 0) {
2006
		foreach ($paa as $paif => $paents)  {
2007
			$paaifip = get_interface_ip($paif);
2008
			if (!is_ipaddr($paaifip))
2009
				continue;
2010
			$args = get_real_interface($paif) . " auto";
2011
			foreach ($paents as $paent) {
2012
				if (isset($paent['subnet']))
2013
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2014
				else if (isset($paent['range']))
2015
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2016
			}
2017
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2018
		}
2019
	}
2020
}
2021

    
2022
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2023
	global $g, $config;
2024

    
2025
	if (is_array($config['virtualip']['vip'])) {
2026
		foreach ($config['virtualip']['vip'] as $vip) {
2027
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2028
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2029
					interface_vip_bring_down($vip);
2030
				else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2031
					interface_vip_bring_down($vip);
2032
			}
2033
		}
2034
	}
2035
}
2036

    
2037
function interfaces_vips_configure($interface = "") {
2038
	global $g, $config;
2039
	if(isset($config['system']['developerspew'])) {
2040
		$mt = microtime();
2041
		echo "interfaces_vips_configure() being called $mt\n";
2042
	}
2043
	$paa = array();
2044
	if(is_array($config['virtualip']['vip'])) {
2045
		$carp_setuped = false;
2046
		$anyproxyarp = false;
2047
		foreach ($config['virtualip']['vip'] as $vip) {
2048
			switch ($vip['mode']) {
2049
			case "proxyarp":
2050
				/* nothing it is handled on interface_proxyarp_configure() */
2051
				if ($interface <> "" && $vip['interface'] <> $interface)
2052
					continue;
2053
				$anyproxyarp = true;
2054
				break;
2055
			case "ipalias":
2056
				if ($interface <> "" && $vip['interface'] <> $interface)
2057
					continue;
2058
				interface_ipalias_configure($vip);
2059
				break;
2060
			case "carp":
2061
				if ($interface <> "" && $vip['interface'] <> $interface)
2062
					continue;
2063
				if ($carp_setuped == false)
2064
					$carp_setuped = true;
2065
				interface_carp_configure($vip);
2066
				break;
2067
			}
2068
		}
2069
		if ($carp_setuped == true)
2070
			interfaces_carp_setup();
2071
		if ($anyproxyarp == true)
2072
			interface_proxyarp_configure();
2073
	}
2074
}
2075

    
2076
function interface_ipalias_configure(&$vip) {
2077
	if ($vip['mode'] == "ipalias") {
2078
		$if = get_real_interface($vip['interface']);
2079
		$af = "inet";
2080
		if(is_ipaddrv6($vip['subnet']))
2081
			$af = "inet6";
2082
		mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
2083
	}
2084
}
2085

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

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

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

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

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

    
2125
	/*
2126
	 * ensure the interface containing the VIP really exists
2127
	 * prevents a panic if the interface is missing or invalid
2128
	 */
2129
	$realif = get_real_interface($vip['interface']);
2130
	if (!does_interface_exist($realif)) {
2131
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2132
		return;
2133
	}
2134

    
2135
	if(is_ipaddrv4($vip['subnet'])) {
2136
		/* Ensure CARP IP really exists prior to loading up. */
2137
		$ww_subnet_ip = find_interface_ip($realif);
2138
		$ww_subnet_bits = find_interface_subnet($realif);
2139
		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'])) {
2140
			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", "");
2141
			return;
2142
		}
2143
	}
2144
	if(is_ipaddrv6($vip['subnet'])) {
2145
		/* Ensure CARP IP really exists prior to loading up. */
2146
		$ww_subnet_ip = find_interface_ipv6($realif);
2147
		$ww_subnet_bits = find_interface_subnetv6($realif);
2148
		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'])) {
2149
			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", "");
2150
			return;
2151
		}
2152
	}
2153

    
2154
	// set the vip interface to the vhid
2155
	$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
2156

    
2157
	/* create the carp interface and setup */
2158
	if (does_interface_exist($vipif)) {
2159
		pfSense_interface_flags($vipif, -IFF_UP);
2160
	} else {
2161
		$carpif = pfSense_interface_create("carp");
2162
		pfSense_interface_rename($carpif, $vipif);
2163
		pfSense_ngctl_name("{$carpif}:", $vipif);
2164
	}
2165

    
2166
	/* invalidate interface cache */
2167
	get_interface_arr(true);
2168

    
2169
	$vip_password = $vip['password'];
2170
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2171
	if ($vip['password'] != "")
2172
		$password = " pass {$vip_password}";
2173

    
2174
	$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2175
	$advbase = "";
2176
	if (!empty($vip['advbase']))
2177
		$advbase = "advbase {$vip['advbase']}";
2178

    
2179
	if(is_ipaddrv4($vip['subnet'])) {
2180
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2181
		mwexec("/sbin/ifconfig {$vipif} {$vip['subnet']}/{$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2182
	}
2183
	if(is_ipaddrv6($vip['subnet'])) {
2184
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2185
		mwexec("/sbin/ifconfig {$vipif} inet6 {$vip['subnet']} prefixlen {$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2186
	}
2187

    
2188
	interfaces_bring_up($vipif);
2189

    
2190
	return $vipif;
2191
}
2192

    
2193
function interface_wireless_clone($realif, $wlcfg) {
2194
	global $config, $g;
2195
	/*   Check to see if interface has been cloned as of yet.
2196
	 *   If it has not been cloned then go ahead and clone it.
2197
	 */
2198
	$needs_clone = false;
2199
	if(is_array($wlcfg['wireless']))
2200
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2201
	else
2202
		$wlcfg_mode = $wlcfg['mode'];
2203
	switch($wlcfg_mode) {
2204
	case "hostap":
2205
		$mode = "wlanmode hostap";
2206
		break;
2207
	case "adhoc":
2208
		$mode = "wlanmode adhoc";
2209
		break;
2210
	default:
2211
		$mode = "";
2212
		break;
2213
	}
2214
	$baseif = interface_get_wireless_base($wlcfg['if']);
2215
	if(does_interface_exist($realif)) {
2216
		exec("/sbin/ifconfig {$realif}", $output, $ret);
2217
		$ifconfig_str = implode($output);
2218
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
2219
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2220
			$needs_clone = true;
2221
		}
2222
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
2223
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2224
			$needs_clone = true;
2225
		}
2226
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2227
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2228
			$needs_clone = true;
2229
		}
2230
	} else {
2231
		$needs_clone = true;
2232
	}
2233

    
2234
	if($needs_clone == true) {
2235
		/* remove previous instance if it exists */
2236
		if(does_interface_exist($realif))
2237
			pfSense_interface_destroy($realif);
2238

    
2239
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2240
		// Create the new wlan interface. FreeBSD returns the new interface name.
2241
		// example:  wlan2
2242
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2243
		if($ret <> 0) {
2244
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2245
			return false;
2246
		}
2247
		$newif = trim($out[0]);
2248
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2249
		pfSense_interface_rename($newif, $realif);
2250
		// FIXME: not sure what ngctl is for. Doesn't work.
2251
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
2252
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2253
	}
2254
	return true;
2255
}
2256

    
2257
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2258
	global $config, $g;
2259

    
2260
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2261
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2262
				 'regdomain', 'regcountry', 'reglocation');
2263

    
2264
	if(!is_interface_wireless($ifcfg['if']))
2265
		return;
2266

    
2267
	$baseif = interface_get_wireless_base($ifcfg['if']);
2268

    
2269
	// Sync shared settings for assigned clones
2270
	$iflist = get_configured_interface_list(false, true);
2271
	foreach ($iflist as $if) {
2272
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2273
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2274
				foreach ($shared_settings as $setting) {
2275
					if ($sync_changes) {
2276
						if (isset($ifcfg['wireless'][$setting]))
2277
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2278
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2279
							unset($config['interfaces'][$if]['wireless'][$setting]);
2280
					} else {
2281
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2282
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2283
						else if (isset($ifcfg['wireless'][$setting]))
2284
							unset($ifcfg['wireless'][$setting]);
2285
					}
2286
				}
2287
				if (!$sync_changes)
2288
					break;
2289
			}
2290
		}
2291
	}
2292

    
2293
	// Read or write settings at shared area
2294
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2295
		foreach ($shared_settings as $setting) {
2296
			if ($sync_changes) {
2297
				if (isset($ifcfg['wireless'][$setting]))
2298
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2299
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2300
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2301
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2302
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2303
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2304
				else if (isset($ifcfg['wireless'][$setting]))
2305
					unset($ifcfg['wireless'][$setting]);
2306
			}
2307
		}
2308
	}
2309

    
2310
	// Sync the mode on the clone creation page with the configured mode on the interface
2311
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2312
		foreach ($config['wireless']['clone'] as &$clone) {
2313
			if ($clone['cloneif'] == $ifcfg['if']) {
2314
				if ($sync_changes) {
2315
					$clone['mode'] = $ifcfg['wireless']['mode'];
2316
				} else {
2317
					$ifcfg['wireless']['mode'] = $clone['mode'];
2318
				}
2319
				break;
2320
			}
2321
		}
2322
		unset($clone);
2323
	}
2324
}
2325

    
2326
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2327
	global $config, $g;
2328

    
2329
	/*    open up a shell script that will be used to output the commands.
2330
	 *    since wireless is changing a lot, these series of commands are fragile
2331
	 *    and will sometimes need to be verified by a operator by executing the command
2332
	 *    and returning the output of the command to the developers for inspection.  please
2333
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2334
	 */
2335

    
2336
	// Remove script file
2337
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2338

    
2339
	// Clone wireless nic if needed.
2340
	interface_wireless_clone($if, $wl);
2341

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

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

    
2349
	/* set values for /path/program */
2350
	$hostapd = "/usr/sbin/hostapd";
2351
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2352
	$ifconfig = "/sbin/ifconfig";
2353
	$sysctl = "/sbin/sysctl";
2354
	$killall = "/usr/bin/killall";
2355

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

    
2358
	$wlcmd = array();
2359
	$wl_sysctl = array();
2360
	/* Make sure it's up */
2361
	$wlcmd[] = "up";
2362
	/* Set a/b/g standard */
2363
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2364
	$wlcmd[] = "mode " . escapeshellarg($standard);
2365

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

    
2371
	/* Set ssid */
2372
	if($wlcfg['ssid'])
2373
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2374

    
2375
	/* Set 802.11g protection mode */
2376
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2377

    
2378
	/* set wireless channel value */
2379
	if(isset($wlcfg['channel'])) {
2380
		if($wlcfg['channel'] == "0") {
2381
			$wlcmd[] = "channel any";
2382
		} else {
2383
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2384
		}
2385
	}
2386

    
2387
	/* Set antenna diversity value */
2388
	if(isset($wlcfg['diversity']))
2389
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2390

    
2391
	/* Set txantenna value */
2392
	if(isset($wlcfg['txantenna']))
2393
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2394

    
2395
	/* Set rxantenna value */
2396
	if(isset($wlcfg['rxantenna']))
2397
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2398

    
2399
	/* set Distance value */
2400
	if($wlcfg['distance'])
2401
		$distance = escapeshellarg($wlcfg['distance']);
2402

    
2403
	/* Set wireless hostap mode */
2404
	if ($wlcfg['mode'] == "hostap") {
2405
		$wlcmd[] = "mediaopt hostap";
2406
	} else {
2407
		$wlcmd[] = "-mediaopt hostap";
2408
	}
2409

    
2410
	/* Set wireless adhoc mode */
2411
	if ($wlcfg['mode'] == "adhoc") {
2412
		$wlcmd[] = "mediaopt adhoc";
2413
	} else {
2414
		$wlcmd[] = "-mediaopt adhoc";
2415
	}
2416

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

    
2419
	/* handle hide ssid option */
2420
	if(isset($wlcfg['hidessid']['enable'])) {
2421
		$wlcmd[] = "hidessid";
2422
	} else {
2423
		$wlcmd[] = "-hidessid";
2424
	}
2425

    
2426
	/* handle pureg (802.11g) only option */
2427
	if(isset($wlcfg['pureg']['enable'])) {
2428
		$wlcmd[] = "mode 11g pureg";
2429
	} else {
2430
		$wlcmd[] = "-pureg";
2431
	}
2432

    
2433
	/* handle puren (802.11n) only option */
2434
	if(isset($wlcfg['puren']['enable'])) {
2435
		$wlcmd[] = "puren";
2436
	} else {
2437
		$wlcmd[] = "-puren";
2438
	}
2439

    
2440
	/* enable apbridge option */
2441
	if(isset($wlcfg['apbridge']['enable'])) {
2442
		$wlcmd[] = "apbridge";
2443
	} else {
2444
		$wlcmd[] = "-apbridge";
2445
	}
2446

    
2447
	/* handle turbo option */
2448
	if(isset($wlcfg['turbo']['enable'])) {
2449
		$wlcmd[] = "mediaopt turbo";
2450
	} else {
2451
		$wlcmd[] = "-mediaopt turbo";
2452
	}
2453

    
2454
	/* handle txpower setting */
2455
	/* if($wlcfg['txpower'] <> "")
2456
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2457
	*/
2458
	/* handle wme option */
2459
	if(isset($wlcfg['wme']['enable'])) {
2460
		$wlcmd[] = "wme";
2461
	} else {
2462
		$wlcmd[] = "-wme";
2463
	}
2464

    
2465
	/* set up wep if enabled */
2466
	$wepset = "";
2467
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2468
		switch($wlcfg['wpa']['auth_algs']) {
2469
			case "1":
2470
				$wepset .= "authmode open wepmode on ";
2471
				break;
2472
			case "2":
2473
				$wepset .= "authmode shared wepmode on ";
2474
				break;
2475
			case "3":
2476
				$wepset .= "authmode mixed wepmode on ";
2477
		}
2478
		$i = 1;
2479
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2480
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2481
			if (isset($wepkey['txkey'])) {
2482
				$wlcmd[] = "weptxkey {$i} ";
2483
			}
2484
			$i++;
2485
		}
2486
		$wlcmd[] = $wepset;
2487
	} else {
2488
		$wlcmd[] = "authmode open wepmode off ";
2489
	}
2490

    
2491
	kill_hostapd($if);
2492
	mwexec(kill_wpasupplicant("{$if}"));
2493

    
2494
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2495
	conf_mount_rw();
2496

    
2497
	switch ($wlcfg['mode']) {
2498
		case 'bss':
2499
			if (isset($wlcfg['wpa']['enable'])) {
2500
				$wpa .= <<<EOD
2501
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2502
ctrl_interface_group=0
2503
ap_scan=1
2504
#fast_reauth=1
2505
network={
2506
ssid="{$wlcfg['ssid']}"
2507
scan_ssid=1
2508
priority=5
2509
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2510
psk="{$wlcfg['wpa']['passphrase']}"
2511
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2512
group={$wlcfg['wpa']['wpa_pairwise']}
2513
}
2514
EOD;
2515

    
2516
				$fd = fopen("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", "w");
2517
				fwrite($fd, "{$wpa}");
2518
				fclose($fd);
2519
			}
2520
			break;
2521
		case 'hostap':
2522
			if($wlcfg['wpa']['passphrase'])
2523
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2524
			else
2525
				$wpa_passphrase = "";
2526
			if (isset($wlcfg['wpa']['enable'])) {
2527
				$wpa .= <<<EOD
2528
interface={$if}
2529
driver=bsd
2530
logger_syslog=-1
2531
logger_syslog_level=0
2532
logger_stdout=-1
2533
logger_stdout_level=0
2534
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2535
ctrl_interface={$g['varrun_path']}/hostapd
2536
ctrl_interface_group=wheel
2537
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2538
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2539
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2540
ssid={$wlcfg['ssid']}
2541
debug={$wlcfg['wpa']['debug_mode']}
2542
auth_algs={$wlcfg['wpa']['auth_algs']}
2543
wpa={$wlcfg['wpa']['wpa_mode']}
2544
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2545
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2546
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2547
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2548
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2549
{$wpa_passphrase}
2550

    
2551
EOD;
2552

    
2553
if (isset($wlcfg['wpa']['rsn_preauth'])) {
2554
	$wpa .= <<<EOD
2555
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2556
rsn_preauth=1
2557
rsn_preauth_interfaces={$if}
2558

    
2559
EOD;
2560

    
2561
}
2562
				if($wlcfg['auth_server_addr'] && $wlcfg['auth_server_shared_secret']) {
2563
					$auth_server_port = "1812";
2564
					if($wlcfg['auth_server_port'])
2565
						$auth_server_port = $wlcfg['auth_server_port'];
2566
					$auth_server_port2 = "1812";
2567
					if($wlcfg['auth_server_port2'])
2568
						$auth_server_port2 = $wlcfg['auth_server_port2'];
2569
					$wpa .= <<<EOD
2570

    
2571
ieee8021x=1
2572
auth_server_addr={$wlcfg['auth_server_addr']}
2573
auth_server_port={$auth_server_port}
2574
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2575
auth_server_addr={$wlcfg['auth_server_addr2']}
2576
auth_server_port={$auth_server_port2}
2577
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2578

    
2579
EOD;
2580
				} else {
2581
					$wpa .= "ieee8021x={$wlcfg['wpa']['ieee8021x']}\n";
2582
				}
2583

    
2584
				$fd = fopen("{$g['varetc_path']}/hostapd_{$if}.conf", "w");
2585
				fwrite($fd, "{$wpa}");
2586
				fclose($fd);
2587

    
2588
			}
2589
			break;
2590
	}
2591

    
2592
	/*
2593
	 *    all variables are set, lets start up everything
2594
	 */
2595

    
2596
	$baseif = interface_get_wireless_base($if);
2597
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2598
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2599

    
2600
	/* set sysctls for the wireless interface */
2601
	if (!empty($wl_sysctl)) {
2602
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2603
		foreach ($wl_sysctl as $wl_sysctl_line) {
2604
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2605
		}
2606
	}
2607

    
2608
	/* set ack timers according to users preference (if he/she has any) */
2609
	if($distance) {
2610
		fwrite($fd_set, "# Enable ATH distance settings\n");
2611
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2612
	}
2613

    
2614
	if (isset($wlcfg['wpa']['enable'])) {
2615
		if ($wlcfg['mode'] == "bss") {
2616
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2617
		}
2618
		if ($wlcfg['mode'] == "hostap") {
2619
			/* add line to script to restore old mac to make hostapd happy */
2620
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2621
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2622
				if (is_macaddr($if_oldmac))
2623
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2624
						" link " . escapeshellarg($if_oldmac) . "\n");
2625
			}
2626

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

    
2629
			/* add line to script to restore spoofed mac after running hostapd */
2630
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2631
				if ($wl['spoofmac'])
2632
					$if_curmac = $wl['spoofmac'];
2633
				else
2634
					$if_curmac = get_interface_mac($if);
2635
				if (is_macaddr($if_curmac))
2636
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2637
						" link " . escapeshellarg($if_curmac) . "\n");
2638
			}
2639
		}
2640
	}
2641

    
2642
	fclose($fd_set);
2643
	conf_mount_ro();
2644

    
2645
	/* Making sure regulatory settings have actually changed
2646
	 * before applying, because changing them requires bringing
2647
	 * down all wireless networks on the interface. */
2648
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2649
	$ifconfig_str = implode($output);
2650
	unset($output);
2651
	$reg_changing = false;
2652

    
2653
	/* special case for the debug country code */
2654
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2655
		$reg_changing = true;
2656
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2657
		$reg_changing = true;
2658
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2659
		$reg_changing = true;
2660
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2661
		$reg_changing = true;
2662
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2663
		$reg_changing = true;
2664

    
2665
	if ($reg_changing) {
2666
		/* set regulatory domain */
2667
		if($wlcfg['regdomain'])
2668
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2669

    
2670
		/* set country */
2671
		if($wlcfg['regcountry'])
2672
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2673

    
2674
		/* set location */
2675
		if($wlcfg['reglocation'])
2676
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2677

    
2678
		$wlregcmd_args = implode(" ", $wlregcmd);
2679

    
2680
		/* build a complete list of the wireless clones for this interface */
2681
		$clone_list = array();
2682
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2683
			$clone_list[] = interface_get_wireless_clone($baseif);
2684
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2685
			foreach ($config['wireless']['clone'] as $clone) {
2686
				if ($clone['if'] == $baseif)
2687
					$clone_list[] = $clone['cloneif'];
2688
			}
2689
		}
2690

    
2691
		/* find which clones are up and bring them down */
2692
		$clones_up = array();
2693
		foreach ($clone_list as $clone_if) {
2694
			$clone_status = pfSense_get_interface_addresses($clone_if);
2695
			if ($clone_status['status'] == 'up') {
2696
				$clones_up[] = $clone_if;
2697
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2698
			}
2699
		}
2700

    
2701
		/* apply the regulatory settings */
2702
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2703

    
2704
		/* bring the clones back up that were previously up */
2705
		foreach ($clones_up as $clone_if) {
2706
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2707

    
2708
			/*
2709
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2710
			 * is in infrastructure mode, and WPA is enabled.
2711
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2712
			 */
2713
			if ($clone_if != $if) {
2714
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2715
				if ( !empty($friendly_if)
2716
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2717
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2718
					mwexec("/bin/sh {$g['tmp_path']}/{$clone_if}_setup.sh");
2719
				}
2720
			}
2721
		}
2722
	}
2723

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

    
2728
	/* configure wireless */
2729
	$wlcmd_args = implode(" ", $wlcmd);
2730
	mwexec("/sbin/ifconfig {$if} $wlcmd_args", false);
2731

    
2732

    
2733
	sleep(1);
2734
	/* execute hostapd and wpa_supplicant if required in shell */
2735
	mwexec("/bin/sh {$g['tmp_path']}/{$if}_setup.sh");
2736

    
2737
	return 0;
2738

    
2739
}
2740

    
2741
function kill_hostapd($interface) {
2742
	global $g;
2743

    
2744
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2745
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2746
}
2747

    
2748
function kill_wpasupplicant($interface) {
2749
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2750
}
2751

    
2752
function find_dhclient_process($interface) {
2753
	if ($interface)
2754
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2755
	else
2756
		$pid = 0;
2757

    
2758
	return intval($pid);
2759
}
2760

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

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

    
2769
	return intval($pid);
2770
}
2771

    
2772
function interface_vlan_mtu_configured($realhwif, $mtu) {
2773
	global $config;
2774

    
2775
	if (is_array($config['vlans']['vlan'])) {
2776
		foreach ($config['vlans']['vlan'] as $vlan) {
2777
			if ($vlan['if'] != $realhwif)
2778
				continue;
2779
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2780
			if (!empty($assignedport)) {
2781
				$portmtu = $config['interfaces'][$assignedport]['mtu'];
2782
				if (!empty($portmtu) && $portmtu > $mtu)
2783
					$mtu = $portmtu;
2784
			}
2785
		}
2786
	}
2787

    
2788
	return $mtu;
2789
}
2790

    
2791
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2792
	global $config, $g;
2793
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2794
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2795

    
2796
	$wancfg = $config['interfaces'][$interface];
2797

    
2798
	if (!isset($wancfg['enable']))
2799
		return;
2800

    
2801
	$realif = get_real_interface($interface);
2802
	$realhwif_array = get_parent_interface($interface);
2803
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2804
	$realhwif = $realhwif_array[0];
2805

    
2806
	/* Disable Accepting router advertisements unless specifically requested */
2807
	if ($g['debug'])
2808
		log_error("Deny router advertisements for interface {$interface}");
2809
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2810

    
2811
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2812
		/* remove all IPv4 and IPv6 addresses */
2813
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2814
		if (is_array($tmpifaces)) {
2815
			foreach ($tmpifaces as $tmpiface) {
2816
				if (strstr($iface, ":"))
2817
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$iface} delete");
2818
				else
2819
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet {$iface} delete");
2820
			}
2821
		}
2822

    
2823
		/* only bring down the interface when both v4 and v6 are set to NONE */
2824
		if(empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
2825
			interface_bring_down($interface);
2826
		}
2827
	}
2828

    
2829
	/* wireless configuration? */
2830
	if (is_array($wancfg['wireless']))
2831
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2832

    
2833
	$mac = get_interface_mac($realhwif);
2834
	/*
2835
	 * Don't try to reapply the spoofed MAC if it's already applied.
2836
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2837
	 * the interface config again, which attempts to spoof the MAC again,
2838
	 * which cycles the link again...
2839
	 */
2840
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
2841
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2842
			" link " . escapeshellarg($wancfg['spoofmac']));
2843

    
2844
		/*
2845
		 * All vlans need to spoof their parent mac address, too.  see
2846
		 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2847
		 */
2848
		if (is_array($config['vlans']['vlan'])) {
2849
			foreach ($config['vlans']['vlan'] as $vlan) {
2850
				if ($vlan['if'] == $realhwif)
2851
					mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2852
					" link " . escapeshellarg($wancfg['spoofmac']));
2853
			}
2854
		}
2855
	}  else {
2856

    
2857
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2858
			/*   this is not a valid mac address.  generate a
2859
			 *   temporary mac address so the machine can get online.
2860
			 */
2861
			echo gettext("Generating new MAC address.");
2862
			$random_mac = generate_random_mac_address();
2863
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2864
				" link " . escapeshellarg($random_mac));
2865
			$wancfg['spoofmac'] = $random_mac;
2866
			write_config();
2867
			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");
2868
		}
2869
	}
2870

    
2871
	/* media */
2872
	if ($wancfg['media'] || $wancfg['mediaopt']) {
2873
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2874
		if ($wancfg['media'])
2875
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2876
		if ($wancfg['mediaopt'])
2877
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2878
		mwexec($cmd);
2879
	}
2880
	$options = pfSense_get_interface_addresses($realhwif);
2881

    
2882
	/* skip vlans for checksumming and polling */
2883
	if (!stristr($realif, "_vlan") && is_array($options)) {
2884
		$flags_on = 0;
2885
		$flags_off = 0;
2886
		if(isset($config['system']['disablechecksumoffloading'])) {
2887
			if (isset($options['encaps']['txcsum']))
2888
				$flags_off |= IFCAP_TXCSUM;
2889
			if (isset($options['encaps']['rxcsum']))
2890
				$flags_off |= IFCAP_RXCSUM;
2891
		} else {
2892
			if (isset($options['caps']['txcsum']))
2893
				$flags_on |= IFCAP_TXCSUM;
2894
			if (isset($options['caps']['rxcsum']))
2895
				$flags_on |= IFCAP_RXCSUM;
2896
		}
2897

    
2898
		if(isset($config['system']['disablesegmentationoffloading']))
2899
			$flags_off |= IFCAP_TSO;
2900
		else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6']))
2901
			$flags_on |= IFCAP_TSO;
2902

    
2903
		if(isset($config['system']['disablelargereceiveoffloading']))
2904
			$flags_off |= IFCAP_LRO;
2905
		else if (isset($options['caps']['lro']))
2906
			$flags_on |= IFCAP_LRO;
2907

    
2908
		/* if the NIC supports polling *AND* it is enabled in the GUI */
2909
		if (!isset($config['system']['polling']))
2910
			$flags_off |= IFCAP_POLLING;
2911
		else if (isset($options['caps']['polling']))
2912
			$flags_on |= IFCAP_POLLING;
2913

    
2914
		pfSense_interface_capabilities($realhwif, -$flags_off);
2915
		pfSense_interface_capabilities($realhwif, $flags_on);
2916
	}
2917

    
2918
	/* invalidate interface/ip/sn cache */
2919
	get_interface_arr(true);
2920
	unset($interface_ip_arr_cache[$realif]);
2921
	unset($interface_sn_arr_cache[$realif]);
2922
	unset($interface_ipv6_arr_cache[$realif]);
2923
	unset($interface_snv6_arr_cache[$realif]);
2924

    
2925
	switch ($wancfg['ipaddr']) {
2926
		case 'dhcp':
2927
			interface_dhcp_configure($interface);
2928
			break;
2929
		case 'pppoe':
2930
		case 'l2tp':
2931
		case 'pptp':
2932
		case 'ppp':
2933
			interface_ppps_configure($interface);
2934
			break;
2935
		default:
2936
			if (is_ipaddr($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
2937
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
2938
			} else if (substr($realif, 0, 3) == "gre") {
2939
				if (is_array($config['gres']['gre'])) {
2940
					foreach ($config['gres']['gre'] as $gre)
2941
						if ($gre['greif'] == $realif)
2942
							interface_gre_configure($gre);
2943
				}
2944
			} else if (substr($realif, 0, 3) == "gif") {
2945
				if (is_array($config['gifs']['gif'])) {
2946
					foreach ($config['gifs']['gif'] as $gif)
2947
						if($gif['gifif'] == $realif)
2948
							interface_gif_configure($gif);
2949
				}
2950
			} else if (substr($realif, 0, 4) == "ovpn") {
2951
				/* XXX: Should be done anything?! */
2952
			}
2953
			break;
2954
	}
2955

    
2956
	switch ($wancfg['ipaddrv6']) {
2957
		case 'slaac':
2958
		case 'dhcp6':
2959
			interface_dhcpv6_configure($interface, $wancfg);
2960
			break;
2961
		case '6rd':
2962
			interface_6rd_configure($interface, $wancfg);
2963
			break;
2964
		case '6to4':
2965
			interface_6to4_configure($interface, $wancfg);
2966
			break;
2967
		case 'track6':
2968
			interface_track6_configure($interface, $wancfg);
2969
			break;
2970
		default:
2971
			if (is_ipaddr($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
2972
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
2973
				// FIXME: Add IPv6 Support to the pfSense module
2974
				mwexec("/sbin/ifconfig {$realif} inet6 {$wancfg['ipaddrv6']} prefixlen {$wancfg['subnetv6']} ");
2975
			}
2976
			break;
2977
	}
2978

    
2979
	$mtu = get_interface_default_mtu(remove_ifindex($realhwif));
2980
	$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
2981
	if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
2982
		$mtu = $config['interfaces'][$assignedparent]['mtu'];
2983

    
2984
	$vlanifs = link_interface_to_vlans($realhwif);
2985
	if (empty($vlanifs))
2986
		$vlanifs = array();
2987

    
2988
	if (!empty($wancfg['mtu'])) {
2989
		if (stristr($realif, "_vlan")) {
2990
			if (!empty($assignedparent)) {
2991
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
2992
				if (empty($parentmtu))
2993
					$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
2994
				if ($wancfg['mtu'] > $parentmtu) {
2995
					if (get_interface_mtu($realhwif) != $wancfg['mtu'])
2996
						pfSense_interface_mtu($realhwif, $wancfg['mtu']);
2997

    
2998
					/* All vlans need to use the same mtu value as their parent. */
2999
					foreach ($vlanifs as $vlan) {
3000
						if ($vlan['vlanif'] == $realif)
3001
							continue;
3002
						$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3003
						if (!empty($assignedport)) {
3004
							$portmtu = $config['interfaces'][$assignedport]['mtu'];
3005
							if (empty($portmtu) && (get_interface_mtu($vlan['vlanif']) != $wancfg['mtu']))
3006
								pfSense_interface_mtu($vlan['vlanif'], $wancfg['mtu']);
3007
						} else if (get_interface_mtu($vlan['vlanif']) != $wancfg['mtu'])
3008
							pfSense_interface_mtu($vlan['vlanif'], $wancfg['mtu']);
3009
					}
3010
				}
3011
			} else {
3012
				/* Parent is not assigned, back to default */
3013
				if (get_interface_mtu($realhwif) != $mtu)
3014
					pfSense_interface_mtu($realhwif, $mtu);
3015

    
3016
				/* All vlans need to use the same mtu value as their parent. */
3017
				foreach ($vlanifs as $vlan) {
3018
					if ($vlan['vlanif'] == $realif)
3019
						continue;
3020
					$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3021
					if (!empty($assignedport)) {
3022
						$portmtu = $config['interfaces'][$assignedport]['mtu'];
3023
						if (empty($portmtu) && (get_interface_mtu($vlan['vlanif']) != $mtu))
3024
							pfSense_interface_mtu($vlan['vlanif'], $mtu);
3025
					} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
3026
						pfSense_interface_mtu($vlan['vlanif'], $mtu);
3027
				}
3028

    
3029
				if (get_interface_mtu($realif) != $wancfg['mtu'])
3030
					pfSense_interface_mtu($realif, $wancfg['mtu']);
3031
			}
3032
		} else {
3033
			foreach ($vlanifs as $vlan) {
3034
				$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3035
				if (empty($assignedport)) {
3036
					if (get_interface_mtu($vlan['vlanif']) != $wancfg['mtu'])
3037
						pfSense_interface_mtu($vlan['vlanif'], $wancfg['mtu']);
3038
				} else {
3039
					$vlanmtu = $config['interfaces'][$assignedport]['mtu'];
3040
					if ((empty($vlanmtu) || ($vlanmtu >= $wancfg['mtu'])) && (get_interface_mtu($vlan['vlanif']) != $wancfg['mtu']))
3041
						pfSense_interface_mtu($vlan['vlanif'], $wancfg['mtu']);
3042
				}
3043
			}
3044
		}
3045
		if ($wancfg['mtu'] != get_interface_mtu($realif))
3046
			pfSense_interface_mtu($realif, $wancfg['mtu']);
3047
	} else if (stristr($realif, "_vlan")) {
3048
		/* XXX: This is really dangerous for example with vlans changing their parent mtu! */
3049
		$bigmtu = interface_vlan_mtu_configured($realhwif, $mtu);
3050
		if ($mtu < $bigmtu)
3051
			$mtu = $bigmtu;
3052

    
3053
		if (get_interface_mtu($realhwif) != $mtu)
3054
			pfSense_interface_mtu($realhwif, $mtu);
3055

    
3056
		/* All vlans need to use the same mtu value as their parent. */
3057
		foreach ($vlanifs as $vlan) {
3058
			if ($vlan['vlanif'] == $realif)
3059
				continue;
3060
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3061
			if (!empty($assignedport)) {
3062
				$portmtu = $config['interfaces'][$assignedport]['mtu'];
3063
				if (empty($portmtu) && (get_interface_mtu($vlan['vlanif']) != $mtu))
3064
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
3065
			} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
3066
				pfSense_interface_mtu($vlan['vlanif'], $mtu);
3067
		}
3068
		if (get_interface_mtu($realif) != $mtu)
3069
			pfSense_interface_mtu($realif, $mtu);
3070
	} else {
3071
		/* All vlans need to use the same mtu value as their parent. */
3072
		foreach ($vlanifs as $vlan) {
3073
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3074
			if (!empty($assignedport)) {
3075
				$portmtu = $config['interfaces'][$assignedport]['mtu'];
3076
				if (empty($portmtu) && (get_interface_mtu($vlan['vlanif']) != $mtu))
3077
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
3078
			} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
3079
				pfSense_interface_mtu($vlan['vlanif'], $mtu);
3080
		}
3081
		if ($mtu != get_interface_mtu($realhwif))
3082
			pfSense_interface_mtu($realhwif, $mtu);
3083
	}
3084

    
3085
	unset($vlanifs);
3086

    
3087
	if(does_interface_exist($wancfg['if']))
3088
		interfaces_bring_up($wancfg['if']);
3089

    
3090
	interface_netgraph_needed($interface);
3091

    
3092
	if (!$g['booting']) {
3093
		link_interface_to_vips($interface, "update");
3094

    
3095
		unset($gre);
3096
		$gre = link_interface_to_gre($interface);
3097
		if (!empty($gre))
3098
			array_walk($gre, 'interface_gre_configure');
3099

    
3100
		unset($gif);
3101
		$gif = link_interface_to_gif($interface);
3102
		if (!empty($gif))
3103
			array_walk($gif, 'interface_gif_configure');
3104

    
3105
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3106
			unset($bridgetmp);
3107
			$bridgetmp = link_interface_to_bridge($interface);
3108
			if (!empty($bridgetmp))
3109
				interface_bridge_add_member($bridgetmp, $realif);
3110
		}
3111

    
3112
		$grouptmp = link_interface_to_group($interface);
3113
		if (!empty($grouptmp))
3114
			array_walk($grouptmp, 'interface_group_add_member');
3115

    
3116
		if ($interface == "lan")
3117
			/* make new hosts file */
3118
			system_hosts_generate();
3119

    
3120
		if ($reloadall == true) {
3121

    
3122
			/* reconfigure static routes (kernel may have deleted them) */
3123
			system_routing_configure($interface);
3124

    
3125
			/* reload ipsec tunnels */
3126
			vpn_ipsec_configure();
3127

    
3128
			/* restart dnsmasq */
3129
			services_dnsmasq_configure();
3130

    
3131
			/* update dyndns */
3132
			send_event("service reload dyndns {$interface}");
3133

    
3134
			/* reload captive portal */
3135
			captiveportal_init_rules();
3136
		}
3137
	}
3138

    
3139
	interfaces_staticarp_configure($interface);
3140
	return 0;
3141
}
3142

    
3143
function interface_track6_configure($interface = "lan", $wancfg) {
3144
	global $config, $g;
3145

    
3146
	if (!is_array($wancfg))
3147
		return;
3148

    
3149
	if (!isset($wancfg['enable']))
3150
		return;
3151

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

    
3156
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3157
	$realif = get_real_interface($interface);
3158
	$linklocal = find_interface_ipv6_ll($realif);
3159
	if (!empty($linklocal))
3160
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3161
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3162
	/* XXX: Probably should remove? */
3163
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3164

    
3165
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3166
	if (!isset($trackcfg['enable'])) {
3167
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3168
		return;
3169
	}
3170

    
3171
	switch($trackcfg['ipaddrv6']) {
3172
	case "6to4":
3173
		if ($g['debug'])
3174
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3175
		interface_track6_6to4_configure($interface, $wancfg);
3176
		break;
3177
	case "6rd":
3178
		if ($g['debug'])
3179
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3180
		interface_track6_6rd_configure($interface, $wancfg);
3181
		break;
3182
	}
3183

    
3184
	if (!$g['booting']) {
3185
		if (!function_exists('services_dhcpd_configure'))
3186
			require_once("services.inc");
3187

    
3188
		services_dhcpd_configure("inet6");
3189
	}
3190

    
3191
	return 0;
3192
}
3193

    
3194
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3195
	global $config, $g;
3196
	global $interface_ipv6_arr_cache;
3197
	global $interface_snv6_arr_cache;
3198

    
3199
	if (!is_array($lancfg))
3200
		return;
3201

    
3202
	/* If the interface is not configured via another, exit */
3203
	if (empty($lancfg['track6-interface']))
3204
		return;
3205

    
3206
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3207
	if (empty($wancfg)) {
3208
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3209
		return;
3210
	}
3211

    
3212
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3213
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3214
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3215
		return;
3216
	}
3217
	$hexwanv4 = return_hex_ipv4($ip4address);
3218

    
3219
	/* create the long prefix notation for math, save the prefix length */
3220
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3221
	$rd6prefixlen = $rd6prefix[1];
3222
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3223

    
3224
	/* binary presentation of the prefix for all 128 bits. */
3225
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3226

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

    
3232
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3233
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3234
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3235
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3236
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3237
	/* fill the rest out with zeros */
3238
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);;
3239

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

    
3243
	$lanif = get_real_interface($interface);
3244
	$oip = find_interface_ipv6($lanif);
3245
	if (is_ipaddrv6($oip))
3246
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3247
	unset($interface_ipv6_arr_cache[$lanif]);
3248
	unset($interface_snv6_arr_cache[$lanif]);
3249
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3250
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3251

    
3252
	return 0;
3253
}
3254

    
3255
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3256
	global $config, $g;
3257
	global $interface_ipv6_arr_cache;
3258
	global $interface_snv6_arr_cache;
3259

    
3260
	if (!is_array($lancfg))
3261
		return;
3262

    
3263
	/* If the interface is not configured via another, exit */
3264
	if (empty($lancfg['track6-interface']))
3265
		return;
3266

    
3267
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3268
	if (empty($wancfg)) {
3269
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3270
		return;
3271
	}
3272

    
3273
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3274
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3275
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3276
		return;
3277
	}
3278
	$hexwanv4 = return_hex_ipv4($ip4address);
3279

    
3280
	/* create the long prefix notation for math, save the prefix length */
3281
	$sixto4prefix = "2002::";
3282
	$sixto4prefixlen = 16;
3283
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3284

    
3285
	/* binary presentation of the prefix for all 128 bits. */
3286
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3287

    
3288
	/* just save the left prefix length bits */
3289
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3290
	/* add the v4 address */
3291
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3292
	/* add the custom prefix id */
3293
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3294
	/* fill the rest out with zeros */
3295
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);;
3296

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

    
3300
	$lanif = get_real_interface($interface);
3301
	$oip = find_interface_ipv6($lanif);
3302
	if (is_ipaddrv6($oip))
3303
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3304
	unset($interface_ipv6_arr_cache[$lanif]);
3305
	unset($interface_snv6_arr_cache[$lanif]);
3306
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3307
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3308

    
3309
	return 0;
3310
}
3311

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

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

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

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

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

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

    
3337
	/* binary presentation of the prefix for all 128 bits. */
3338
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3339

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

    
3347
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3348
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3349

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

    
3352
	/* XXX: need to extend to support variable prefix size for v4 */
3353
	if (!is_module_loaded("if_stf"))
3354
		mwexec("/sbin/kldload if_stf.ko");
3355
	$stfiface = "{$interface}_stf";
3356
	if (does_interface_exist($stfiface))
3357
		pfSense_interface_destroy($stfiface);
3358
	$tmpstfiface = pfSense_interface_create("stf");
3359
	pfSense_interface_rename($tmpstfiface, $stfiface);
3360
	pfSense_interface_flags($stfiface, IFF_LINK2);
3361
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3362
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3363
	if ($wancfg['prefix-6rd-v4plen'] > 0 && $wancfg['prefix-6rd-v4plen'] < 32)
3364
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/{$wancfg['prefix-6rd-v4plen']}");
3365
	if ($g['debug'])
3366
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3367

    
3368
	/* write out a default router file */
3369
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3370
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3371

    
3372
	$ip4gateway = get_interface_gateway($interface);
3373
	if (is_ipaddrv4($ip4gateway))
3374
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3375

    
3376
	/* configure dependent interfaces */
3377
	if (!$g['booting'])
3378
		link_interface_to_track6($interface, "update");
3379

    
3380
	return 0;
3381
}
3382

    
3383
function interface_6to4_configure($interface = "wan", $wancfg){
3384
	global $config, $g;
3385

    
3386
	/* because this is a tunnel interface we can only function
3387
	 *	with a public IPv4 address on the interface */
3388

    
3389
	if (!is_array($wancfg))
3390
		return;
3391

    
3392
	$wanif = get_real_interface($interface);
3393
	$ip4address = find_interface_ip($wanif);
3394
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3395
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3396
		return false;
3397
	}
3398

    
3399
	/* create the long prefix notation for math, save the prefix length */
3400
	$stfprefixlen = 16;
3401
	$stfprefix = Net_IPv6::uncompress("2002::");
3402
	$stfarr = explode(":", $stfprefix);
3403
	$v4prefixlen = "0";
3404

    
3405
	/* we need the hex form of the interface IPv4 address */
3406
	$ip4arr = explode(".", $ip4address);
3407
	$hexwanv4 = "";
3408
	foreach($ip4arr as $octet)
3409
		$hexwanv4 .= sprintf("%02x", $octet);
3410

    
3411
	/* we need the hex form of the broker IPv4 address */
3412
	$ip4arr = explode(".", "192.88.99.1");
3413
	$hexbrv4 = "";
3414
	foreach($ip4arr as $octet)
3415
		$hexbrv4 .= sprintf("%02x", $octet);
3416

    
3417
	/* binary presentation of the prefix for all 128 bits. */
3418
	$stfprefixbin = "";
3419
	foreach($stfarr as $element) {
3420
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3421
	}
3422
	/* just save the left prefix length bits */
3423
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3424

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

    
3429
	/* for the local subnet too. */
3430
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3431
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);;
3432

    
3433
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3434
	$stfbrarr = array();
3435
	$stfbrbinarr = array();
3436
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3437
	foreach($stfbrbinarr as $bin)
3438
		$stfbrarr[] = dechex(bindec($bin));
3439
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3440

    
3441
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3442
	$stflanarr = array();
3443
	$stflanbinarr = array();
3444
	$stflanbinarr = str_split($stflanbin, 16);
3445
	foreach($stflanbinarr as $bin)
3446
		$stflanarr[] = dechex(bindec($bin));
3447
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3448
	$stflanarr[7] = 1;
3449
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3450

    
3451
	/* setup the stf interface */
3452
	if (!is_module_loaded("if_stf"))
3453
		mwexec("/sbin/kldload if_stf.ko");
3454
	$stfiface = "{$interface}_stf";
3455
	if (does_interface_exist($stfiface))
3456
		pfSense_interface_destroy($stfiface);
3457
	$tmpstfiface = pfSense_interface_create("stf");
3458
	pfSense_interface_rename($tmpstfiface, $stfiface);
3459
	pfSense_interface_flags($stfiface, IFF_LINK2);
3460
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3461

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

    
3465
	/* write out a default router file */
3466
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3467
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3468

    
3469
	$ip4gateway = get_interface_gateway($interface);
3470
	if (is_ipaddrv4($ip4gateway))
3471
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3472

    
3473
	if (!$g['booting'])
3474
		link_interface_to_track6($interface, "update");
3475

    
3476
	return 0;
3477
}
3478

    
3479
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3480
	global $config, $g;
3481

    
3482
	if (!is_array($wancfg))
3483
		return;
3484

    
3485
	$wanif = get_real_interface($interface, "inet6");
3486
	$dhcp6cconf = "";
3487
	$dhcp6cconf .= "interface {$wanif} {\n";
3488

    
3489
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3490
	if($wancfg['ipaddrv6'] == "slaac") {
3491
		$dhcp6cconf .= "	information-only;\n";
3492
		$dhcp6cconf .= "	request domain-name-servers;\n";
3493
		$dhcp6cconf .= "	request domain-name;\n";
3494
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3495
		$dhcp6cconf .= "};\n";
3496
	} else {
3497
		/* skip address request if this is set */
3498
		if(!isset($wancfg['dhcp6prefixonly']))
3499
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3500
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3501
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3502

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

    
3507
		$dhcp6cconf .= "};\n";
3508

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

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

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

    
3554
	$rtsoldscript = "#!/bin/sh\n";
3555
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3556
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3557
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3558
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3559
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3560
	$rtsoldscript .= "\t/bin/sleep 1\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
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3564
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3565
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3566
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3567
		unset($rtsoldscript);
3568
		return 1;
3569
	}
3570
	unset($rtsoldscript);
3571
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3572

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

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

    
3585
	/* NOTE: will be called from rtsold invoked script
3586
	 * link_interface_to_track6($interface, "update");
3587
	 */
3588

    
3589
	return 0;
3590
}
3591

    
3592
function interface_dhcp_configure($interface = "wan") {
3593
	global $config, $g;
3594

    
3595
	$wancfg = $config['interfaces'][$interface];
3596
	$wanif = $wancfg['if'];
3597
	if (empty($wancfg))
3598
		$wancfg = array();
3599

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

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

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

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

    
3631
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3632
	$dhclientconf .= <<<EOD
3633

    
3634
	reject {$wancfg['dhcprejectfrom']};
3635
EOD;
3636
}
3637
	$dhclientconf .= <<<EOD
3638

    
3639
}
3640

    
3641
EOD;
3642

    
3643
if(is_ipaddr($wancfg['alias-address'])) {
3644
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3645
	$dhclientconf .= <<<EOD
3646
alias {
3647
	interface  "{$wanif}";
3648
	fixed-address {$wancfg['alias-address']};
3649
	option subnet-mask {$subnetmask};
3650
}
3651

    
3652
EOD;
3653
}
3654
	fwrite($fd, $dhclientconf);
3655
	fclose($fd);
3656

    
3657
	/* bring wan interface up before starting dhclient */
3658
	if($wanif)
3659
		interfaces_bring_up($wanif);
3660
	else
3661
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3662

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

    
3666
	return 0;
3667
}
3668

    
3669
function interfaces_group_setup() {
3670
	global $config;
3671

    
3672
	if (!is_array($config['ifgroups']['ifgroupentry']))
3673
		return;
3674

    
3675
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3676
		interface_group_setup($groupar);
3677

    
3678
	return;
3679
}
3680

    
3681
function interface_group_setup(&$groupname /* The parameter is an array */) {
3682
	global $config;
3683

    
3684
	if (!is_array($groupname))
3685
		return;
3686
	$members = explode(" ", $groupname['members']);
3687
	foreach($members as $ifs) {
3688
		$realif = get_real_interface($ifs);
3689
		if ($realif)
3690
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3691
	}
3692

    
3693
	return;
3694
}
3695

    
3696
function is_interface_group($if) {
3697
	global $config;
3698

    
3699
	if (is_array($config['ifgroups']['ifgroupentry']))
3700
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
3701
			if ($groupentry['ifname'] === $if)
3702
				return true;
3703
		}
3704

    
3705
	return false;
3706
}
3707

    
3708
function interface_group_add_member($interface, $groupname) {
3709
	$interface = get_real_interface($interface);
3710
	mwexec("/sbin/ifconfig {$interface} group {$groupname}", true);
3711
}
3712

    
3713
/* COMPAT Function */
3714
function convert_friendly_interface_to_real_interface_name($interface) {
3715
	return get_real_interface($interface);
3716
}
3717

    
3718
/* COMPAT Function */
3719
function get_real_wan_interface($interface = "wan") {
3720
	return get_real_interface($interface);
3721
}
3722

    
3723
/* COMPAT Function */
3724
function get_current_wan_address($interface = "wan") {
3725
	return get_interface_ip($interface);
3726
}
3727

    
3728
/*
3729
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
3730
 */
3731
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
3732
	global $config;
3733

    
3734
	if (stristr($interface, "_vip")) {
3735
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
3736
			if ($vip['mode'] == "carp")  {
3737
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3738
					return $vip['interface'];
3739
			}
3740
		}
3741
	}
3742

    
3743
	/* XXX: For speed reasons reference directly the interface array */
3744
	$ifdescrs = &$config['interfaces'];
3745
	//$ifdescrs = get_configured_interface_list(false, true);
3746

    
3747
	foreach ($ifdescrs as $if => $ifname) {
3748
		if ($if == $interface || $config['interfaces'][$if]['if'] == $interface)
3749
			return $if;
3750

    
3751
		if (get_real_interface($if) == $interface)
3752
			return $if;
3753

    
3754
		// XXX: This case doesn't work anymore (segfaults - recursion?) - should be replaced with something else or just removed.
3755
		//      Not to be replaced with get_real_interface - causes slow interface listings here because of recursion!
3756
		/*
3757
		$int = get_parent_interface($if);
3758
		if ($int[0] == $interface)
3759
			return $ifname;
3760
		*/
3761
	}
3762

    
3763
	return NULL;
3764
}
3765

    
3766
/* attempt to resolve interface to friendly descr */
3767
function convert_friendly_interface_to_friendly_descr($interface) {
3768
	global $config;
3769

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

    
3814
	return $ifdesc;
3815
}
3816

    
3817
function convert_real_interface_to_friendly_descr($interface) {
3818
	global $config;
3819

    
3820
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
3821

    
3822
	if ($ifdesc) {
3823
		$iflist = get_configured_interface_with_descr(false, true);
3824
		return $iflist[$ifdesc];
3825
	}
3826

    
3827
	return $interface;
3828
}
3829

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

    
3842
	$parents = array();
3843
	//Check that we got a valid interface passed
3844
	$realif = get_real_interface($interface);
3845
	if ($realif == NULL)
3846
		return $parents;
3847

    
3848
	// If we got a real interface, find it's friendly assigned name
3849
	if ($interface == $realif)
3850
		$interface = convert_real_interface_to_friendly_interface_name($interface);
3851

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

    
3885
	if (empty($parents))
3886
		$parents[0] = $realif;
3887

    
3888
	return $parents;
3889
}
3890

    
3891
function interface_is_wireless_clone($wlif) {
3892
	if(!stristr($wlif, "_wlan")) {
3893
		return false;
3894
	} else {
3895
		return true;
3896
	}
3897
}
3898

    
3899
function interface_get_wireless_base($wlif) {
3900
	if(!stristr($wlif, "_wlan")) {
3901
		return $wlif;
3902
	} else {
3903
		return substr($wlif, 0, stripos($wlif, "_wlan"));
3904
	}
3905
}
3906

    
3907
function interface_get_wireless_clone($wlif) {
3908
	if(!stristr($wlif, "_wlan")) {
3909
		return $wlif . "_wlan0";
3910
	} else {
3911
		return $wlif;
3912
	}
3913
}
3914

    
3915
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false) {
3916
	global $config, $g;
3917

    
3918
	$wanif = NULL;
3919

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

    
3950
		if (empty($config['interfaces'][$interface]))
3951
			break;
3952

    
3953
		$cfg = &$config['interfaces'][$interface];
3954

    
3955
		if ($family == "inet6") {
3956
			switch ($cfg['ipaddrv6']) {
3957
			case "6rd":
3958
			case "6to4":
3959
				$wanif = "{$interface}_stf";
3960
				break;
3961
			case 'pppoe':
3962
			case 'ppp':
3963
			case 'l2tp':
3964
			case 'pptp':
3965
				if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
3966
					$wanif = interface_get_wireless_clone($cfg['if']);
3967
				else
3968
					$wanif = $cfg['if'];
3969
				break;
3970
			default:
3971
				switch ($cfg['ipaddr']) {
3972
				case 'pppoe':
3973
				case 'ppp':
3974
				case 'l2tp':
3975
				case 'pptp':
3976
					if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false)
3977
						$wanif = $cfg['if'];
3978
					else {
3979
						$parents = get_parent_interface($interface);
3980
						if (!empty($parents[0]))
3981
							$wanif = $parents[0];
3982
						else
3983
							$wanif = $cfg['if'];
3984
					}
3985
					break;
3986
				default:
3987
					if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
3988
						$wanif = interface_get_wireless_clone($cfg['if']);
3989
					else
3990
						$wanif = $cfg['if'];
3991
					break;
3992
				}
3993
				break;
3994
			}
3995
		} else {
3996
			// Wireless cloned NIC support (FreeBSD 8+)
3997
			// interface name format: $parentnic_wlanparentnic#
3998
			// example: ath0_wlan0
3999
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4000
				$wanif = interface_get_wireless_clone($cfg['if']);
4001
			else
4002
				$wanif = $cfg['if'];
4003
		}
4004
		break;
4005
	}
4006

    
4007
	return $wanif;
4008
}
4009

    
4010
/* Guess the physical interface by providing a IP address */
4011
function guess_interface_from_ip($ipaddress) {
4012
	if(! is_ipaddr($ipaddress)) {
4013
		return false;
4014
	}
4015
	if(is_ipaddrv4($ipaddress)) {
4016
		/* create a route table we can search */
4017
		exec("netstat -rnWf inet", $output, $ret);
4018
		foreach($output as $line) {
4019
			if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
4020
				$fields = preg_split("/[ ]+/", $line);
4021
				if(ip_in_subnet($ipaddress, $fields[0])) {
4022
					return $fields[6];
4023
				}
4024
			}
4025
		}
4026
	}
4027
	/* FIXME: This works from cursory testing, regexp might need fine tuning */
4028
	if(is_ipaddrv6($ipaddress)) {
4029
		/* create a route table we can search */
4030
		exec("netstat -rnWf inet6", $output, $ret);
4031
		foreach($output as $line) {
4032
			if(preg_match("/[0-9a-f]+[:]+[0-9a-f]+[:]+[\/][0-9]+/", $line)) {
4033
				$fields = preg_split("/[ ]+/", $line);
4034
				if(ip_in_subnet($ipaddress, $fields[0])) {
4035
					return $fields[6];
4036
				}
4037
			}
4038
		}
4039
	}
4040
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
4041
	if(empty($ret)) {
4042
		return false;
4043
	}
4044
	return $ret;
4045
}
4046

    
4047
/*
4048
 * find_ip_interface($ip): return the interface where an ip is defined
4049
 *   (or if $bits is specified, where an IP within the subnet is defined)
4050
 */
4051
function find_ip_interface($ip, $bits = null) {
4052
	if (!is_ipaddr($ip))
4053
		return false;
4054

    
4055
	$isv6ip = is_ipaddrv6($ip);
4056

    
4057
	/* if list */
4058
	$ifdescrs = get_configured_interface_list();
4059

    
4060
	foreach ($ifdescrs as $ifdescr => $ifname) {
4061
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4062
		if (is_null($ifip))
4063
			continue;
4064
		if (is_null($bits)) {
4065
			if ($ip == $ifip) {
4066
				$int = get_real_interface($ifname);
4067
				return $int;
4068
			}
4069
		}
4070
		else {
4071
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4072
				$int = get_real_interface($ifname);
4073
				return $int;
4074
			}
4075
		}
4076
	}
4077

    
4078
	return false;
4079
}
4080

    
4081
/*
4082
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4083
 *   (or if $bits is specified, where an IP within the subnet is found)
4084
 */
4085
function find_virtual_ip_alias($ip, $bits = null) {
4086
	global $config;
4087

    
4088
	if (!is_array($config['virtualip']['vip'])) {
4089
		return false;
4090
	}
4091
	if (!is_ipaddr($ip))
4092
		return false;
4093

    
4094
	$isv6ip = is_ipaddrv6($ip);
4095

    
4096
	foreach ($config['virtualip']['vip'] as $vip) {
4097
		if ($vip['mode'] === "ipalias") {
4098
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4099
				continue;
4100
			if (is_null($bits)) {
4101
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4102
					return $vip;
4103
				}
4104
			}
4105
			else {
4106
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4107
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4108
					return $vip;
4109
				}
4110
			}
4111
		}
4112
	}
4113
	return false;
4114
}
4115

    
4116
/*
4117
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4118
 */
4119
function find_number_of_created_carp_interfaces() {
4120
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4121
}
4122

    
4123
function get_all_carp_interfaces() {
4124
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
4125
	$ints = explode(" ", $ints);
4126
	return $ints;
4127
}
4128

    
4129
/*
4130
 * find_carp_interface($ip): return the carp interface where an ip is defined
4131
 */
4132
function find_carp_interface($ip) {
4133
	global $config;
4134
	if (is_array($config['virtualip']['vip'])) {
4135
		foreach ($config['virtualip']['vip'] as $vip) {
4136
			if ($vip['mode'] == "carp") {
4137
				if(is_ipaddrv4($ip)) {
4138
					$carp_ip = get_interface_ip($vip['interface']);
4139
				}
4140
				if(is_ipaddrv6($ip)) {
4141
					$carp_ip = get_interface_ipv6($vip['interface']);
4142
				}
4143
				exec("/sbin/ifconfig", $output, $return);
4144
				foreach($output as $line) {
4145
					$elements = preg_split("/[ ]+/i", $line);
4146
					if(strstr($elements[0], "vip"))
4147
						$curif = str_replace(":", "", $elements[0]);
4148
					if(stristr($line, $ip)) {
4149
						$if = $curif;
4150
						continue;
4151
					}
4152
				}
4153

    
4154
				if ($if)
4155
					return $if;
4156
			}
4157
		}
4158
	}
4159
}
4160

    
4161
function link_carp_interface_to_parent($interface) {
4162
	global $config;
4163

    
4164
	if ($interface == "")
4165
		return;
4166

    
4167
	$carp_ip = get_interface_ip($interface);
4168
	$carp_ipv6 = get_interface_ipv6($interface);
4169

    
4170
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4171
		return;
4172

    
4173
	/* if list */
4174
	$ifdescrs = get_configured_interface_list();
4175
	foreach ($ifdescrs as $ifdescr => $ifname) {
4176
		/* check IPv4 */
4177
		if(is_ipaddrv4($carp_ip)) {
4178
			$interfaceip = get_interface_ip($ifname);
4179
			$subnet_bits = get_interface_subnet($ifname);
4180
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4181
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4182
				return $ifname;
4183
		}
4184
		/* Check IPv6 */
4185
		if(is_ipaddrv6($carp_ipv6)) {
4186
			$interfaceipv6 = get_interface_ipv6($ifname);
4187
			$prefixlen = get_interface_subnetv6($ifname);
4188
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4189
				return $ifname;
4190
		}
4191
	}
4192
	return "";
4193
}
4194

    
4195

    
4196
/****f* interfaces/link_ip_to_carp_interface
4197
 * NAME
4198
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4199
 * INPUTS
4200
 *   $ip
4201
 * RESULT
4202
 *   $carp_ints
4203
 ******/
4204
function link_ip_to_carp_interface($ip) {
4205
	global $config;
4206

    
4207
	if (!is_ipaddr($ip))
4208
		return;
4209

    
4210
	$carp_ints = "";
4211
	if (is_array($config['virtualip']['vip'])) {
4212
		$first = 0;
4213
		$carp_int = array();
4214
		foreach ($config['virtualip']['vip'] as $vip) {
4215
			if ($vip['mode'] == "carp") {
4216
				$carp_ip = $vip['subnet'];
4217
				$carp_sn = $vip['subnet_bits'];
4218
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4219
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4220
					$carp_int[] = "{$vip['interface']}_vip{$vip['vhid']}";
4221
				}
4222
			}
4223
		}
4224
		if (!empty($carp_int))
4225
			$carp_ints = implode(" ", array_unique($carp_int));
4226
	}
4227

    
4228
	return $carp_ints;
4229
}
4230

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

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

    
4237
	if (is_array($config['interfaces'])) {
4238
		$list = array();
4239
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4240
			if (!isset($ifcfg['enable']))
4241
				continue;
4242
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4243
				if ($action == "update")
4244
					interface_track6_configure($ifname, $ifcfg);
4245
				else if ($action == "")
4246
					$list[$ifname] = $ifcfg;
4247
			}
4248
		}
4249
		return $list;
4250
	}
4251
}
4252

    
4253
function link_interface_to_vlans($int, $action = "") {
4254
	global $config;
4255

    
4256
	if (empty($int))
4257
		return;
4258

    
4259
	if (is_array($config['vlans']['vlan'])) {
4260
		$ifaces = array();
4261
		foreach ($config['vlans']['vlan'] as $vlan) {
4262
			if ($int == $vlan['if']) {
4263
				if ($action == "update") {
4264
					interfaces_bring_up($int);
4265
				} else if ($action == "")
4266
					$ifaces[$vlan['tag']] = $vlan;
4267
			}
4268
		}
4269
		if (!empty($ifaces))
4270
			return $ifaces;
4271
	}
4272
}
4273

    
4274
function link_interface_to_vips($int, $action = "") {
4275
	global $config;
4276

    
4277
	if (is_array($config['virtualip']['vip'])) {
4278
		$result = array();
4279
		foreach ($config['virtualip']['vip'] as $vip) {
4280
			if ($int == $vip['interface']) {
4281
				if ($action == "update")
4282
					interfaces_vips_configure($int);
4283
				else
4284
					$result[] = $vip;
4285
			}
4286
		}
4287
		return $result;
4288
	}
4289
}
4290

    
4291
/****f* interfaces/link_interface_to_bridge
4292
 * NAME
4293
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4294
 * INPUTS
4295
 *   $ip
4296
 * RESULT
4297
 *   bridge[0-99]
4298
 ******/
4299
function link_interface_to_bridge($int) {
4300
	global $config;
4301

    
4302
	if (is_array($config['bridges']['bridged'])) {
4303
		foreach ($config['bridges']['bridged'] as $bridge) {
4304
			if (in_array($int, explode(',', $bridge['members'])))
4305
				return "{$bridge['bridgeif']}";
4306
		}
4307
	}
4308
}
4309

    
4310
function link_interface_to_group($int) {
4311
	global $config;
4312

    
4313
	$result = array();
4314

    
4315
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4316
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4317
			if (in_array($int, explode(" ", $group['members'])))
4318
				$result[$group['ifname']] = $int;
4319
		}
4320
	}
4321

    
4322
	return $result;
4323
}
4324

    
4325
function link_interface_to_gre($interface) {
4326
	global $config;
4327

    
4328
	$result = array();
4329

    
4330
	if (is_array($config['gres']['gre'])) {
4331
		foreach ($config['gres']['gre'] as $gre)
4332
			if($gre['if'] == $interface)
4333
				$result[] = $gre;
4334
	}
4335

    
4336
	return $result;
4337
}
4338

    
4339
function link_interface_to_gif($interface) {
4340
	global $config;
4341

    
4342
	$result = array();
4343

    
4344
	if (is_array($config['gifs']['gif'])) {
4345
		foreach ($config['gifs']['gif'] as $gif)
4346
			if($gif['if'] == $interface)
4347
				$result[] = $gif;
4348
	}
4349

    
4350
	return $result;
4351
}
4352

    
4353
/*
4354
 * find_interface_ip($interface): return the interface ip (first found)
4355
 */
4356
function find_interface_ip($interface, $flush = false) {
4357
	global $interface_ip_arr_cache;
4358
	global $interface_sn_arr_cache;
4359

    
4360
	$interface = str_replace("\n", "", $interface);
4361

    
4362
	if (!does_interface_exist($interface))
4363
		return;
4364

    
4365
	/* Setup IP cache */
4366
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4367
		$ifinfo = pfSense_get_interface_addresses($interface);
4368
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4369
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4370
	}
4371

    
4372
	return $interface_ip_arr_cache[$interface];
4373
}
4374

    
4375
/*
4376
 * find_interface_ipv6($interface): return the interface ip (first found)
4377
 */
4378
function find_interface_ipv6($interface, $flush = false) {
4379
	global $interface_ipv6_arr_cache;
4380
	global $interface_snv6_arr_cache;
4381
	global $config;
4382

    
4383
	$interface = trim($interface);
4384
	$interface = get_real_interface($interface);
4385

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

    
4389
	/* Setup IP cache */
4390
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4391
		$ifinfo = pfSense_get_interface_addresses($interface);
4392
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4393
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4394
	}
4395

    
4396
	return $interface_ipv6_arr_cache[$interface];
4397
}
4398

    
4399
/*
4400
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4401
 */
4402
function find_interface_ipv6_ll($interface, $flush = false) {
4403
	global $interface_llv6_arr_cache;
4404
	global $config;
4405

    
4406
	$interface = str_replace("\n", "", $interface);
4407

    
4408
	if (!does_interface_exist($interface))
4409
		return;
4410

    
4411
	/* Setup IP cache */
4412
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4413
		$ifinfo = pfSense_getall_interface_addresses($interface);
4414
		foreach($ifinfo as $line) {
4415
			if (strstr($line, ":")) {
4416
				$parts = explode("/", $line);
4417
				if(is_linklocal($parts[0])) {
4418
					$ifinfo['linklocal'] = $parts[0];
4419
				}
4420
			}
4421
		}
4422
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4423
	}
4424
	return $interface_llv6_arr_cache[$interface];
4425
}
4426

    
4427
function find_interface_subnet($interface, $flush = false) {
4428
	global $interface_sn_arr_cache;
4429
	global $interface_ip_arr_cache;
4430

    
4431
	$interface = str_replace("\n", "", $interface);
4432
	if (does_interface_exist($interface) == false)
4433
		return;
4434

    
4435
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4436
		$ifinfo = pfSense_get_interface_addresses($interface);
4437
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4438
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4439
	}
4440

    
4441
	return $interface_sn_arr_cache[$interface];
4442
}
4443

    
4444
function find_interface_subnetv6($interface, $flush = false) {
4445
	global $interface_snv6_arr_cache;
4446
	global $interface_ipv6_arr_cache;
4447

    
4448
	$interface = str_replace("\n", "", $interface);
4449
	if (does_interface_exist($interface) == false)
4450
		return;
4451

    
4452
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4453
		$ifinfo = pfSense_get_interface_addresses($interface);
4454
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4455
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4456
	}
4457

    
4458
	return $interface_snv6_arr_cache[$interface];
4459
}
4460

    
4461
function ip_in_interface_alias_subnet($interface, $ipalias) {
4462
	global $config;
4463

    
4464
	if (empty($interface) || !is_ipaddr($ipalias))
4465
		return false;
4466
	if (is_array($config['virtualip']['vip'])) {
4467
		foreach ($config['virtualip']['vip'] as $vip) {
4468
			switch ($vip['mode']) {
4469
			case "ipalias":
4470
				if ($vip['interface'] <> $interface)
4471
					break;
4472
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4473
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4474
					return true;
4475
				break;
4476
			}
4477
		}
4478
	}
4479

    
4480
	return false;
4481
}
4482

    
4483
function get_interface_ip($interface = "wan") {
4484
	$realif = get_failover_interface($interface);
4485
	if (!$realif) {
4486
		if (preg_match("/^carp/i", $interface))
4487
			$realif = $interface;
4488
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4489
			$realif = $interface;
4490
		else
4491
			return null;
4492
	}
4493

    
4494
	$curip = find_interface_ip($realif);
4495
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4496
		return $curip;
4497
	else
4498
		return null;
4499
}
4500

    
4501
function get_interface_ipv6($interface = "wan", $flush = false) {
4502
	global $config;
4503

    
4504
	$realif = get_failover_interface($interface, "inet6");
4505
	if (!$realif) {
4506
		if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4507
			$realif = $interface;
4508
		else
4509
			return null;
4510
	}
4511

    
4512
	/*
4513
	 * NOTE: On the case when only the prefix is requested,
4514
	 * the communication on WAN will be done over link-local.
4515
	 */
4516
	if (is_array($config['interfaces'][$interface])) {
4517
		switch ($config['interfaces'][$interface]['ipaddr']) {
4518
		case 'pppoe':
4519
		case 'l2tp':
4520
		case 'pptp':
4521
		case 'ppp':
4522
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4523
				$realif = get_real_interface($interface, "inet6", true);
4524
			break;
4525
		}
4526
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4527
			$curip = find_interface_ipv6_ll($realif, $flush);
4528
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4529
				return $curip;
4530
		}
4531
	}
4532

    
4533
	$curip = find_interface_ipv6($realif, $flush);
4534
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4535
		return $curip;
4536
	else
4537
		return null;
4538
}
4539

    
4540
function get_interface_linklocal($interface = "wan") {
4541

    
4542
	$realif = get_failover_interface($interface, "inet6");
4543
	if (!$realif) {
4544
		if (preg_match("/^carp/i", $interface))
4545
			$realif = $interface;
4546
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4547
			$realif = $interface;
4548
		else
4549
			return null;
4550
	}
4551

    
4552
	$curip = find_interface_ipv6_ll($realif);
4553
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4554
		return $curip;
4555
	else
4556
		return null;
4557
}
4558

    
4559
function get_interface_subnet($interface = "wan") {
4560
	$realif = get_real_interface($interface);
4561
	if (!$realif) {
4562
		if (preg_match("/^carp/i", $interface))
4563
			$realif = $interface;
4564
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4565
			$realif = $interface;
4566
		else
4567
			return null;
4568
	}
4569

    
4570
	$cursn = find_interface_subnet($realif);
4571
	if (!empty($cursn))
4572
		return $cursn;
4573

    
4574
	return null;
4575
}
4576

    
4577
function get_interface_subnetv6($interface = "wan") {
4578
	global $config;
4579

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

    
4588
	$cursn = find_interface_subnetv6($realif);
4589
	if (!empty($cursn))
4590
		return $cursn;
4591

    
4592
	return null;
4593
}
4594

    
4595
/* return outside interfaces with a gateway */
4596
function get_interfaces_with_gateway() {
4597
	global $config;
4598

    
4599
	$ints = array();
4600

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

    
4622
/* return true if interface has a gateway */
4623
function interface_has_gateway($friendly) {
4624
	global $config;
4625

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

    
4645
	return false;
4646
}
4647

    
4648
/* return true if interface has a gateway */
4649
function interface_has_gatewayv6($friendly) {
4650
	global $config;
4651

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

    
4670
	return false;
4671
}
4672

    
4673
/****f* interfaces/is_altq_capable
4674
 * NAME
4675
 *   is_altq_capable - Test if interface is capable of using ALTQ
4676
 * INPUTS
4677
 *   $int            - string containing interface name
4678
 * RESULT
4679
 *   boolean         - true or false
4680
 ******/
4681

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

    
4695
	$int_family = remove_ifindex($int);
4696

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

    
4709
/****f* interfaces/is_interface_wireless
4710
 * NAME
4711
 *   is_interface_wireless - Returns if an interface is wireless
4712
 * RESULT
4713
 *   $tmp       - Returns if an interface is wireless
4714
 ******/
4715
function is_interface_wireless($interface) {
4716
	global $config, $g;
4717

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

    
4730
function get_wireless_modes($interface) {
4731
	/* return wireless modes and channels */
4732
	$wireless_modes = array();
4733

    
4734
	$cloned_interface = get_real_interface($interface);
4735

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

    
4741
		$interface_channels = "";
4742
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4743
		$interface_channel_count = count($interface_channels);
4744

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

    
4774
/* return channel numbers, frequency, max txpower, and max regulation txpower */
4775
function get_wireless_channel_info($interface) {
4776
	$wireless_channels = array();
4777

    
4778
	$cloned_interface = get_real_interface($interface);
4779

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

    
4785
		$interface_channels = "";
4786
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4787

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

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

    
4808
function get_interface_mac($interface) {
4809

    
4810
	$macinfo = pfSense_get_interface_addresses($interface);
4811
	return $macinfo["macaddr"];
4812
}
4813

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

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

    
4841
	if (isset($capable['caps']['vlanmtu']))
4842
		return true;
4843

    
4844
	return false;
4845
}
4846

    
4847
function interface_setup_pppoe_reset_file($pppif, $iface="") {
4848
	global $g;
4849

    
4850
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
4851

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

    
4858
EOD;
4859

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

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

    
4884
	/* Never reached */
4885
	return 1500;
4886
}
4887

    
4888
function get_vip_descr($ipaddress) {
4889
	global $config;
4890

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

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

    
4906
	$ifcfg = $config['interfaces'][$if];
4907

    
4908
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
4909
		return 0;
4910

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

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

    
4920
			}
4921

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

    
4935
	return 0;
4936
}
4937

    
4938
function get_failover_interface($interface, $family = "all") {
4939
	global $config;
4940

    
4941
	/* shortcut to get_real_interface if we find it in the config */
4942
	if (is_array($config['interfaces'][$interface])) {
4943
		return get_real_interface($interface, $family);
4944
	}
4945

    
4946
	/* compare against gateway groups */
4947
	$a_groups = return_gateway_groups_array();
4948
	if (is_array($a_groups[$interface])) {
4949
		/* we found a gateway group, fetch the interface or vip */
4950
		if ($a_groups[$interface][0]['vip'] <> "")
4951
			return $a_groups[$interface][0]['vip'];
4952
		else
4953
			return $a_groups[$interface][0]['int'];
4954
	}
4955
	/* fall through to get_real_interface */
4956
	/* XXX: Really needed? */
4957
	return get_real_interface($interface, $family);
4958
}
4959

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

    
4964
?>
(25-25/66)