Project

General

Profile

Download (143 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	interfaces.inc
4
	Copyright (C) 2004-2008 Scott Ullrich
5
	Copyright (C) 2008-2009 Ermal Lu?i
6
	All rights reserved.
7

    
8
	function interfaces_wireless_configure is
9
	Copyright (C) 2005 Espen Johansen
10
	All rights reserved.
11

    
12
	originally part of m0n0wall (http://m0n0.ch/wall)
13
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
14
	All rights reserved.
15

    
16
	Redistribution and use in source and binary forms, with or without
17
	modification, are permitted provided that the following conditions are met:
18

    
19
	1. Redistributions of source code must retain the above copyright notices,
20
	   this list of conditions and the following disclaimer.
21

    
22
	2. Redistributions in binary form must reproduce the above copyright
23
	   notices, this list of conditions and the following disclaimer in the
24
	   documentation and/or other materials provided with the distribution.
25

    
26
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
27
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
28
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
	POSSIBILITY OF SUCH DAMAGE.
36

    
37
	pfSense_BUILDER_BINARIES:	/sbin/dhclient	/bin/sh	/usr/bin/grep	/usr/bin/xargs	/usr/bin/awk	/usr/local/sbin/choparp
38
	pfSense_BUILDER_BINARIES:	/sbin/ifconfig	/sbin/route	/usr/sbin/ngctl	/usr/sbin/arp	/bin/kill	/usr/local/sbin/mpd5
39
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/dhcp6c
40
	pfSense_MODULE:	interfaces
41

    
42
*/
43

    
44
/* include all configuration functions */
45
require_once("globals.inc");
46
require_once("util.inc");
47
require_once("gwlb.inc");
48

    
49
function interfaces_bring_up($interface) {
50
	if(!$interface) {
51
		log_error(gettext("interfaces_bring_up() was called but no variable defined."));
52
		log_error( "Backtrace: " . debug_backtrace() );
53
		return;
54
	}
55
	pfSense_interface_flags($interface, IFF_UP);
56
}
57

    
58
/*
59
 * Return the interface array
60
 */
61
function get_interface_arr($flush = false) {
62
	global $interface_arr_cache;
63

    
64
	/* If the cache doesn't exist, build it */
65
	if (!isset($interface_arr_cache) or $flush)
66
		$interface_arr_cache = pfSense_interface_listget();
67

    
68
	return $interface_arr_cache;
69
}
70

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

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

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

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

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

    
98

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

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

    
124
	return false;
125
}
126

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
267
	interfaces_bring_up($vlanif);
268

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

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

    
275
	return $vlanif;
276
}
277

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

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

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

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

    
298
	$vlanif = interface_vlan_configure($vlan);
299

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

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

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

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

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

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

    
351
	return $vlanif;
352
}
353

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

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

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

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

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

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

    
394
	return $vlanif;
395
}
396

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

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

    
403
	$iflist = get_configured_interface_list();
404

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

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

    
424
}
425

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

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

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

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

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

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

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

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

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

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

    
544
	$checklist = get_configured_interface_list();
545

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

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

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

    
612
	if ($bridge['maxaddr'] <> "")
613
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr {$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($itemhash['ID']))
1432
		$config['cron']['item'][$itemhash['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
		$balancing = $config['hasync']['balancing'];
1896
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1897
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1898
	} else {
1899
		unset($pfsyncinterface);
1900
		unset($balancing);
1901
		unset($pfsyncenabled);
1902
	}
1903

    
1904
	if ($balancing) {
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']) && 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) && !empty($config['interfaces'][$assignedport]['mtu'])) {
2781
				if (intval($config['interfaces'][$assignedport]['mtu'])> $mtu)
2782
					$mtu = $portmtu;
2783
			}
2784
		}
2785
	}
2786

    
2787
	return $mtu;
2788
}
2789

    
2790
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2791
	global $config;
2792

    
2793
	if (!is_array($vlanifs))
2794
		return;
2795

    
2796
	/* All vlans need to use the same mtu value as their parent. */
2797
	foreach ($vlanifs as $vlan) {
2798
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2799
		if (!empty($assignedport)) {
2800
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
2801
				/*
2802
				* XXX: This is really never going to happen just keep the code for safety and readbility.
2803
				* It never happens since interface_vlan_mtu_configured finds the biggest mtu on vlans.
2804
				* Also if it has a lower mtu configured just respect user choice.
2805
				*/
2806
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2807
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2808
			} else {
2809
				if (get_interface_mtu($vlan['vlanif']) != $mtu)
2810
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2811
			}
2812
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2813
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
2814
	}
2815
}
2816

    
2817
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2818
	global $config, $g;
2819
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2820
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2821

    
2822
	$wancfg = $config['interfaces'][$interface];
2823

    
2824
	if (!isset($wancfg['enable']))
2825
		return;
2826

    
2827
	$realif = get_real_interface($interface);
2828
	$realhwif_array = get_parent_interface($interface);
2829
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2830
	$realhwif = $realhwif_array[0];
2831

    
2832
	if (!does_interface_exist($realif)) {
2833
		$matches = array();
2834
		if (preg_match('/^(.*)_vlan([0-9]+)$/', $realif, $matches))
2835
			if (is_array($config['vlans']['vlan']))
2836
				foreach ($config['vlans']['vlan'] as $vlan)
2837
					if ($vlan['if'] == $matches[1] && $vlan['tag'] == $matches[2]) {
2838
						interface_vlan_configure($vlan);
2839
						break;
2840
					}
2841
		unset($matches);
2842
	}
2843

    
2844
	/* Disable Accepting router advertisements unless specifically requested */
2845
	if ($g['debug'])
2846
		log_error("Deny router advertisements for interface {$interface}");
2847
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2848

    
2849
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2850
		/* remove all IPv4 and IPv6 addresses */
2851
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2852
		if (is_array($tmpifaces)) {
2853
			foreach ($tmpifaces as $tmpiface) {
2854
				if (strstr($iface, ":"))
2855
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2856
				else
2857
					pfSense_interface_deladdress($realif, $tmpiface);
2858
			}
2859
		}
2860

    
2861
		/* only bring down the interface when both v4 and v6 are set to NONE */
2862
		if(empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
2863
			interface_bring_down($interface);
2864
		}
2865
	}
2866

    
2867
	/* wireless configuration? */
2868
	if (is_array($wancfg['wireless']))
2869
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2870

    
2871
	$mac = get_interface_mac($realhwif);
2872
	/*
2873
	 * Don't try to reapply the spoofed MAC if it's already applied.
2874
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2875
	 * the interface config again, which attempts to spoof the MAC again,
2876
	 * which cycles the link again...
2877
	 */
2878
	if (!empty($wancfg['spoofmac']) && ($wancfg['spoofmac'] != $mac)) {
2879
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2880
			" link " . escapeshellarg($wancfg['spoofmac']));
2881

    
2882
		/*
2883
		 * All vlans need to spoof their parent mac address, too.  see
2884
		 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2885
		 */
2886
		if (is_array($config['vlans']['vlan'])) {
2887
			foreach ($config['vlans']['vlan'] as $vlan) {
2888
				if ($vlan['if'] == $realhwif)
2889
					mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2890
					" link " . escapeshellarg($wancfg['spoofmac']));
2891
			}
2892
		}
2893
	}  else {
2894

    
2895
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2896
			/*   this is not a valid mac address.  generate a
2897
			 *   temporary mac address so the machine can get online.
2898
			 */
2899
			echo gettext("Generating new MAC address.");
2900
			$random_mac = generate_random_mac_address();
2901
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2902
				" link " . escapeshellarg($random_mac));
2903
			$wancfg['spoofmac'] = $random_mac;
2904
			write_config();
2905
			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");
2906
		}
2907
	}
2908

    
2909
	/* media */
2910
	if (!empty($wancfg['media']) || !empty($wancfg['mediaopt'])) {
2911
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2912
		if ($wancfg['media'])
2913
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2914
		if ($wancfg['mediaopt'])
2915
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2916
		mwexec($cmd);
2917
	}
2918
	$options = pfSense_get_interface_addresses($realhwif);
2919

    
2920
	/* skip vlans for checksumming and polling */
2921
	if (!stristr($realif, "_vlan") && is_array($options)) {
2922
		$flags_on = 0;
2923
		$flags_off = 0;
2924
		if(isset($config['system']['disablechecksumoffloading'])) {
2925
			if (isset($options['encaps']['txcsum']))
2926
				$flags_off |= IFCAP_TXCSUM;
2927
			if (isset($options['encaps']['rxcsum']))
2928
				$flags_off |= IFCAP_RXCSUM;
2929
		} else {
2930
			if (isset($options['caps']['txcsum']))
2931
				$flags_on |= IFCAP_TXCSUM;
2932
			if (isset($options['caps']['rxcsum']))
2933
				$flags_on |= IFCAP_RXCSUM;
2934
		}
2935

    
2936
		if(isset($config['system']['disablesegmentationoffloading']))
2937
			$flags_off |= IFCAP_TSO;
2938
		else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6']))
2939
			$flags_on |= IFCAP_TSO;
2940

    
2941
		if(isset($config['system']['disablelargereceiveoffloading']))
2942
			$flags_off |= IFCAP_LRO;
2943
		else if (isset($options['caps']['lro']))
2944
			$flags_on |= IFCAP_LRO;
2945

    
2946
		/* if the NIC supports polling *AND* it is enabled in the GUI */
2947
		if (!isset($config['system']['polling']))
2948
			$flags_off |= IFCAP_POLLING;
2949
		else if (isset($options['caps']['polling']))
2950
			$flags_on |= IFCAP_POLLING;
2951

    
2952
		pfSense_interface_capabilities($realhwif, -$flags_off);
2953
		pfSense_interface_capabilities($realhwif, $flags_on);
2954
	}
2955

    
2956
	/* invalidate interface/ip/sn cache */
2957
	get_interface_arr(true);
2958
	unset($interface_ip_arr_cache[$realif]);
2959
	unset($interface_sn_arr_cache[$realif]);
2960
	unset($interface_ipv6_arr_cache[$realif]);
2961
	unset($interface_snv6_arr_cache[$realif]);
2962

    
2963
	switch ($wancfg['ipaddr']) {
2964
		case 'dhcp':
2965
			interface_dhcp_configure($interface);
2966
			break;
2967
		case 'pppoe':
2968
		case 'l2tp':
2969
		case 'pptp':
2970
		case 'ppp':
2971
			interface_ppps_configure($interface);
2972
			break;
2973
		default:
2974
			if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
2975
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
2976
			} else if (substr($realif, 0, 3) == "gre") {
2977
				if (is_array($config['gres']['gre'])) {
2978
					foreach ($config['gres']['gre'] as $gre)
2979
						if ($gre['greif'] == $realif)
2980
							interface_gre_configure($gre);
2981
				}
2982
			} else if (substr($realif, 0, 3) == "gif") {
2983
				if (is_array($config['gifs']['gif'])) {
2984
					foreach ($config['gifs']['gif'] as $gif)
2985
						if($gif['gifif'] == $realif)
2986
							interface_gif_configure($gif);
2987
				}
2988
			} else if (substr($realif, 0, 4) == "ovpn") {
2989
				/* XXX: Should be done anything?! */
2990
			}
2991
			break;
2992
	}
2993

    
2994
	switch ($wancfg['ipaddrv6']) {
2995
		case 'slaac':
2996
		case 'dhcp6':
2997
			interface_dhcpv6_configure($interface, $wancfg);
2998
			break;
2999
		case '6rd':
3000
			interface_6rd_configure($interface, $wancfg);
3001
			break;
3002
		case '6to4':
3003
			interface_6to4_configure($interface, $wancfg);
3004
			break;
3005
		case 'track6':
3006
			interface_track6_configure($interface, $wancfg);
3007
			break;
3008
		default:
3009
			if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3010
				//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3011
				// FIXME: Add IPv6 Support to the pfSense module
3012
				mwexec("/sbin/ifconfig {$realif} inet6 {$wancfg['ipaddrv6']} prefixlen {$wancfg['subnetv6']} ");
3013
			}
3014
			break;
3015
	}
3016

    
3017
	if (!empty($wancfg['mtu'])) {
3018
		if (stristr($realif, "_vlan")) {
3019
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3020
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
3021
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3022
			else 
3023
				$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
3024

    
3025
			if ($wancfg['mtu'] > $parentmtu) {
3026
				if (get_interface_mtu($realhwif) != $wancfg['mtu'])
3027
					pfSense_interface_mtu($realhwif, $wancfg['mtu']);
3028

    
3029
				/* All vlans need to use the same mtu value as their parent. */
3030
				interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $wancfg['mtu']);
3031
			} else
3032
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3033
		} else {
3034
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3035
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3036

    
3037
			/* This case is needed when the parent of vlans is being configured */
3038
			interface_vlan_adapt_mtu(link_interface_to_vlans($realif), $wancfg['mtu']);
3039
		}
3040
		/* XXX: What about gre/gif/lagg/.. ? */
3041
	}
3042

    
3043
	if (does_interface_exist($wancfg['if']))
3044
		interfaces_bring_up($wancfg['if']);
3045

    
3046
	interface_netgraph_needed($interface);
3047

    
3048
	if (!$g['booting']) {
3049
		link_interface_to_vips($interface, "update");
3050

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

    
3056
		unset($gif);
3057
		$gif = link_interface_to_gif($interface);
3058
		if (!empty($gif))
3059
			array_walk($gif, 'interface_gif_configure');
3060

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

    
3068
		$grouptmp = link_interface_to_group($interface);
3069
		if (!empty($grouptmp))
3070
			array_walk($grouptmp, 'interface_group_add_member');
3071

    
3072
		if ($interface == "lan")
3073
			/* make new hosts file */
3074
			system_hosts_generate();
3075

    
3076
		if ($reloadall == true) {
3077

    
3078
			/* reconfigure static routes (kernel may have deleted them) */
3079
			system_routing_configure($interface);
3080

    
3081
			/* reload ipsec tunnels */
3082
			vpn_ipsec_configure();
3083

    
3084
			/* restart dnsmasq */
3085
			services_dnsmasq_configure();
3086

    
3087
			/* update dyndns */
3088
			send_event("service reload dyndns {$interface}");
3089

    
3090
			/* reload captive portal */
3091
			captiveportal_init_rules();
3092
		}
3093
	}
3094

    
3095
	interfaces_staticarp_configure($interface);
3096
	return 0;
3097
}
3098

    
3099
function interface_track6_configure($interface = "lan", $wancfg) {
3100
	global $config, $g;
3101

    
3102
	if (!is_array($wancfg))
3103
		return;
3104

    
3105
	if (!isset($wancfg['enable']))
3106
		return;
3107

    
3108
	/* If the interface is not configured via another, exit */
3109
	if (empty($wancfg['track6-interface']))
3110
		return;
3111

    
3112
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3113
	$realif = get_real_interface($interface);
3114
	$linklocal = find_interface_ipv6_ll($realif);
3115
	if (!empty($linklocal))
3116
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3117
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3118
	/* XXX: Probably should remove? */
3119
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3120

    
3121
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3122
	if (!isset($trackcfg['enable'])) {
3123
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3124
		return;
3125
	}
3126

    
3127
	switch($trackcfg['ipaddrv6']) {
3128
	case "6to4":
3129
		if ($g['debug'])
3130
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3131
		interface_track6_6to4_configure($interface, $wancfg);
3132
		break;
3133
	case "6rd":
3134
		if ($g['debug'])
3135
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3136
		interface_track6_6rd_configure($interface, $wancfg);
3137
		break;
3138
	}
3139

    
3140
	if (!$g['booting']) {
3141
		if (!function_exists('services_dhcpd_configure'))
3142
			require_once("services.inc");
3143

    
3144
		services_dhcpd_configure("inet6");
3145
	}
3146

    
3147
	return 0;
3148
}
3149

    
3150
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3151
	global $config, $g;
3152
	global $interface_ipv6_arr_cache;
3153
	global $interface_snv6_arr_cache;
3154

    
3155
	if (!is_array($lancfg))
3156
		return;
3157

    
3158
	/* If the interface is not configured via another, exit */
3159
	if (empty($lancfg['track6-interface']))
3160
		return;
3161

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

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

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

    
3180
	/* binary presentation of the prefix for all 128 bits. */
3181
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3182

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

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

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

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

    
3208
	return 0;
3209
}
3210

    
3211
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3212
	global $config, $g;
3213
	global $interface_ipv6_arr_cache;
3214
	global $interface_snv6_arr_cache;
3215

    
3216
	if (!is_array($lancfg))
3217
		return;
3218

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

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

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

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

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

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

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

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

    
3265
	return 0;
3266
}
3267

    
3268
function interface_6rd_configure($interface = "wan", $wancfg) {
3269
	global $config, $g;
3270

    
3271
	/* because this is a tunnel interface we can only function
3272
	 *	with a public IPv4 address on the interface */
3273

    
3274
	if (!is_array($wancfg))
3275
		return;
3276

    
3277
	$wanif = get_real_interface($interface);
3278
	$ip4address = find_interface_ip($wanif);
3279
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3280
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3281
		return false;
3282
	}
3283
	$hexwanv4 = return_hex_ipv4($ip4address);
3284

    
3285
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3286
		$wancfg['prefix-6rd-v4plen'] = 0;
3287

    
3288
	/* create the long prefix notation for math, save the prefix length */
3289
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3290
	$rd6prefixlen = $rd6prefix[1];
3291
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3292

    
3293
	/* binary presentation of the prefix for all 128 bits. */
3294
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3295

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

    
3303
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3304
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3305

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

    
3308
	/* XXX: need to extend to support variable prefix size for v4 */
3309
	if (!is_module_loaded("if_stf"))
3310
		mwexec("/sbin/kldload if_stf.ko");
3311
	$stfiface = "{$interface}_stf";
3312
	if (does_interface_exist($stfiface))
3313
		pfSense_interface_destroy($stfiface);
3314
	$tmpstfiface = pfSense_interface_create("stf");
3315
	pfSense_interface_rename($tmpstfiface, $stfiface);
3316
	pfSense_interface_flags($stfiface, IFF_LINK2);
3317
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3318
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3319
	if ($wancfg['prefix-6rd-v4plen'] > 0 && $wancfg['prefix-6rd-v4plen'] < 32)
3320
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/{$wancfg['prefix-6rd-v4plen']}");
3321
	if ($g['debug'])
3322
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3323

    
3324
	/* write out a default router file */
3325
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3326
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3327

    
3328
	$ip4gateway = get_interface_gateway($interface);
3329
	if (is_ipaddrv4($ip4gateway))
3330
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3331

    
3332
	/* configure dependent interfaces */
3333
	if (!$g['booting'])
3334
		link_interface_to_track6($interface, "update");
3335

    
3336
	return 0;
3337
}
3338

    
3339
function interface_6to4_configure($interface = "wan", $wancfg){
3340
	global $config, $g;
3341

    
3342
	/* because this is a tunnel interface we can only function
3343
	 *	with a public IPv4 address on the interface */
3344

    
3345
	if (!is_array($wancfg))
3346
		return;
3347

    
3348
	$wanif = get_real_interface($interface);
3349
	$ip4address = find_interface_ip($wanif);
3350
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3351
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3352
		return false;
3353
	}
3354

    
3355
	/* create the long prefix notation for math, save the prefix length */
3356
	$stfprefixlen = 16;
3357
	$stfprefix = Net_IPv6::uncompress("2002::");
3358
	$stfarr = explode(":", $stfprefix);
3359
	$v4prefixlen = "0";
3360

    
3361
	/* we need the hex form of the interface IPv4 address */
3362
	$ip4arr = explode(".", $ip4address);
3363
	$hexwanv4 = "";
3364
	foreach($ip4arr as $octet)
3365
		$hexwanv4 .= sprintf("%02x", $octet);
3366

    
3367
	/* we need the hex form of the broker IPv4 address */
3368
	$ip4arr = explode(".", "192.88.99.1");
3369
	$hexbrv4 = "";
3370
	foreach($ip4arr as $octet)
3371
		$hexbrv4 .= sprintf("%02x", $octet);
3372

    
3373
	/* binary presentation of the prefix for all 128 bits. */
3374
	$stfprefixbin = "";
3375
	foreach($stfarr as $element) {
3376
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3377
	}
3378
	/* just save the left prefix length bits */
3379
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3380

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

    
3385
	/* for the local subnet too. */
3386
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3387
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);;
3388

    
3389
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3390
	$stfbrarr = array();
3391
	$stfbrbinarr = array();
3392
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3393
	foreach($stfbrbinarr as $bin)
3394
		$stfbrarr[] = dechex(bindec($bin));
3395
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3396

    
3397
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3398
	$stflanarr = array();
3399
	$stflanbinarr = array();
3400
	$stflanbinarr = str_split($stflanbin, 16);
3401
	foreach($stflanbinarr as $bin)
3402
		$stflanarr[] = dechex(bindec($bin));
3403
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3404
	$stflanarr[7] = 1;
3405
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3406

    
3407
	/* setup the stf interface */
3408
	if (!is_module_loaded("if_stf"))
3409
		mwexec("/sbin/kldload if_stf.ko");
3410
	$stfiface = "{$interface}_stf";
3411
	if (does_interface_exist($stfiface))
3412
		pfSense_interface_destroy($stfiface);
3413
	$tmpstfiface = pfSense_interface_create("stf");
3414
	pfSense_interface_rename($tmpstfiface, $stfiface);
3415
	pfSense_interface_flags($stfiface, IFF_LINK2);
3416
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3417

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

    
3421
	/* write out a default router file */
3422
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3423
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3424

    
3425
	$ip4gateway = get_interface_gateway($interface);
3426
	if (is_ipaddrv4($ip4gateway))
3427
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3428

    
3429
	if (!$g['booting'])
3430
		link_interface_to_track6($interface, "update");
3431

    
3432
	return 0;
3433
}
3434

    
3435
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3436
	global $config, $g;
3437

    
3438
	if (!is_array($wancfg))
3439
		return;
3440

    
3441
	$wanif = get_real_interface($interface, "inet6");
3442
	$dhcp6cconf = "";
3443
	$dhcp6cconf .= "interface {$wanif} {\n";
3444

    
3445
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3446
	if($wancfg['ipaddrv6'] == "slaac") {
3447
		$dhcp6cconf .= "	information-only;\n";
3448
		$dhcp6cconf .= "	request domain-name-servers;\n";
3449
		$dhcp6cconf .= "	request domain-name;\n";
3450
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3451
		$dhcp6cconf .= "};\n";
3452
	} else {
3453
		/* skip address request if this is set */
3454
		if(!isset($wancfg['dhcp6prefixonly']))
3455
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3456
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3457
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3458

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

    
3463
		$dhcp6cconf .= "};\n";
3464

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

    
3468
		if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3469
			/* Setup the prefix delegation */
3470
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3471
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3472
			if (isset($wancfg['dhcp6-ia-pd-send-hint']))
3473
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3474
			$iflist = link_interface_to_track6($interface);
3475
			foreach ($iflist as $friendly => $ifcfg) {
3476
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3477
					if ($g['debug'])
3478
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3479
					$realif = get_real_interface($friendly);
3480
					$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3481
					$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3482
					$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3483
					$dhcp6cconf .= "	};\n";
3484
				}
3485
			}
3486
			unset($preflen, $iflist, $ifcfg);
3487
			$dhcp6cconf .= "};\n";
3488
		}
3489
	}
3490
	/* wide-dhcp6c works for now. */
3491
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3492
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3493
		unset($dhcp6cconf);
3494
		return 1;
3495
	}
3496
	unset($dhcp6cconf);
3497

    
3498
	$dhcp6cscript = "#!/bin/sh\n";
3499
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3500
	$dhcp6cscript .= "/etc/rc.newwanipv6 {$wanif} \n";
3501
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3502
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3503
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3504
		unset($dhcp6cscript);
3505
		return 1;
3506
	}
3507
	unset($dhcp6cscript);
3508
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3509

    
3510
	$rtsoldscript = "#!/bin/sh\n";
3511
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3512
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3513
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3514
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3515
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3516
	$rtsoldscript .= "\t/bin/sleep 1\n";
3517
	$rtsoldscript .= "fi\n";
3518
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3519
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3520
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3521
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3522
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3523
		unset($rtsoldscript);
3524
		return 1;
3525
	}
3526
	unset($rtsoldscript);
3527
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3528

    
3529
	/* accept router advertisements for this interface */
3530
	mwexec("/sbin/sysctl -w net.inet6.ip6.accept_rtadv=1");
3531
	log_error("Accept router advertisements on interface {$wanif} ");
3532
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3533

    
3534
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3535
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3536
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3537
		sleep(2);
3538
	}
3539
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3540

    
3541
	/* NOTE: will be called from rtsold invoked script
3542
	 * link_interface_to_track6($interface, "update");
3543
	 */
3544

    
3545
	return 0;
3546
}
3547

    
3548
function interface_dhcp_configure($interface = "wan") {
3549
	global $config, $g;
3550

    
3551
	$wancfg = $config['interfaces'][$interface];
3552
	$wanif = $wancfg['if'];
3553
	if (empty($wancfg))
3554
		$wancfg = array();
3555

    
3556
	/* generate dhclient_wan.conf */
3557
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3558
	if (!$fd) {
3559
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3560
		return 1;
3561
	}
3562

    
3563
	if ($wancfg['dhcphostname']) {
3564
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3565
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3566
	} else {
3567
		$dhclientconf_hostname = "";
3568
	}
3569

    
3570
	$wanif = get_real_interface($interface);
3571
	if (empty($wanif)) {
3572
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3573
		return 0;
3574
	}
3575
	$dhclientconf = "";
3576

    
3577
	$dhclientconf .= <<<EOD
3578
interface "{$wanif}" {
3579
timeout 60;
3580
retry 15;
3581
select-timeout 0;
3582
initial-interval 1;
3583
	{$dhclientconf_hostname}
3584
	script "/sbin/dhclient-script";
3585
EOD;
3586

    
3587
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3588
	$dhclientconf .= <<<EOD
3589

    
3590
	reject {$wancfg['dhcprejectfrom']};
3591
EOD;
3592
}
3593
	$dhclientconf .= <<<EOD
3594

    
3595
}
3596

    
3597
EOD;
3598

    
3599
if(is_ipaddr($wancfg['alias-address'])) {
3600
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3601
	$dhclientconf .= <<<EOD
3602
alias {
3603
	interface  "{$wanif}";
3604
	fixed-address {$wancfg['alias-address']};
3605
	option subnet-mask {$subnetmask};
3606
}
3607

    
3608
EOD;
3609
}
3610
	fwrite($fd, $dhclientconf);
3611
	fclose($fd);
3612

    
3613
	/* bring wan interface up before starting dhclient */
3614
	if($wanif)
3615
		interfaces_bring_up($wanif);
3616
	else
3617
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3618

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

    
3622
	return 0;
3623
}
3624

    
3625
function interfaces_group_setup() {
3626
	global $config;
3627

    
3628
	if (!is_array($config['ifgroups']['ifgroupentry']))
3629
		return;
3630

    
3631
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3632
		interface_group_setup($groupar);
3633

    
3634
	return;
3635
}
3636

    
3637
function interface_group_setup(&$groupname /* The parameter is an array */) {
3638
	global $config;
3639

    
3640
	if (!is_array($groupname))
3641
		return;
3642
	$members = explode(" ", $groupname['members']);
3643
	foreach($members as $ifs) {
3644
		$realif = get_real_interface($ifs);
3645
		if ($realif)
3646
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3647
	}
3648

    
3649
	return;
3650
}
3651

    
3652
function is_interface_group($if) {
3653
	global $config;
3654

    
3655
	if (is_array($config['ifgroups']['ifgroupentry']))
3656
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
3657
			if ($groupentry['ifname'] === $if)
3658
				return true;
3659
		}
3660

    
3661
	return false;
3662
}
3663

    
3664
function interface_group_add_member($interface, $groupname) {
3665
	$interface = get_real_interface($interface);
3666
	mwexec("/sbin/ifconfig {$interface} group {$groupname}", true);
3667
}
3668

    
3669
/* COMPAT Function */
3670
function convert_friendly_interface_to_real_interface_name($interface) {
3671
	return get_real_interface($interface);
3672
}
3673

    
3674
/* COMPAT Function */
3675
function get_real_wan_interface($interface = "wan") {
3676
	return get_real_interface($interface);
3677
}
3678

    
3679
/* COMPAT Function */
3680
function get_current_wan_address($interface = "wan") {
3681
	return get_interface_ip($interface);
3682
}
3683

    
3684
/*
3685
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
3686
 */
3687
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
3688
	global $config;
3689

    
3690
	if (stristr($interface, "_vip")) {
3691
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
3692
			if ($vip['mode'] == "carp")  {
3693
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3694
					return $vip['interface'];
3695
			}
3696
		}
3697
	}
3698

    
3699
	/* XXX: For speed reasons reference directly the interface array */
3700
	$ifdescrs = &$config['interfaces'];
3701
	//$ifdescrs = get_configured_interface_list(false, true);
3702

    
3703
	foreach ($ifdescrs as $if => $ifname) {
3704
		if ($if == $interface || $config['interfaces'][$if]['if'] == $interface)
3705
			return $if;
3706

    
3707
		if (get_real_interface($if) == $interface)
3708
			return $if;
3709

    
3710
		// XXX: This case doesn't work anymore (segfaults - recursion?) - should be replaced with something else or just removed.
3711
		//      Not to be replaced with get_real_interface - causes slow interface listings here because of recursion!
3712
		/*
3713
		$int = get_parent_interface($if);
3714
		if ($int[0] == $interface)
3715
			return $ifname;
3716
		*/
3717
	}
3718

    
3719
	return NULL;
3720
}
3721

    
3722
/* attempt to resolve interface to friendly descr */
3723
function convert_friendly_interface_to_friendly_descr($interface) {
3724
	global $config;
3725

    
3726
	switch ($interface) {
3727
	case "l2tp":
3728
		$ifdesc = "L2TP";
3729
		break;
3730
	case "pptp":
3731
		$ifdesc = "PPTP";
3732
		break;
3733
	case "pppoe":
3734
		$ifdesc = "PPPoE";
3735
		break;
3736
	case "openvpn":
3737
		$ifdesc = "OpenVPN";
3738
		break;
3739
	case "enc0":
3740
	case "ipsec":
3741
		$ifdesc = "IPsec";
3742
		break;
3743
	default:
3744
		if (isset($config['interfaces'][$interface])) {
3745
			if (empty($config['interfaces'][$interface]['descr']))
3746
				$ifdesc = strtoupper($interface);
3747
			else
3748
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
3749
			break;
3750
		} else if (stristr($interface, "_vip")) {
3751
			if (is_array($config['virtualip']['vip'])) {
3752
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
3753
					if ($vip['mode'] == "carp")  {
3754
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3755
							return "{$vip['subnet']} - {$vip['descr']}";
3756
					}
3757
				}
3758
			}
3759
		} else {
3760
			/* if list */
3761
			$ifdescrs = get_configured_interface_with_descr(false, true);
3762
			foreach ($ifdescrs as $if => $ifname) {
3763
				if ($if == $interface || $ifname == $interface)
3764
					return $ifname;
3765
			}
3766
		}
3767
		break;
3768
	}
3769

    
3770
	return $ifdesc;
3771
}
3772

    
3773
function convert_real_interface_to_friendly_descr($interface) {
3774
	global $config;
3775

    
3776
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
3777

    
3778
	if ($ifdesc) {
3779
		$iflist = get_configured_interface_with_descr(false, true);
3780
		return $iflist[$ifdesc];
3781
	}
3782

    
3783
	return $interface;
3784
}
3785

    
3786
/*
3787
 *  get_parent_interface($interface):
3788
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
3789
 *				or virtual interface (i.e. vlan)
3790
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
3791
 *			-- returns $interface passed in if $interface parent is not found
3792
 *			-- returns empty array if an invalid interface is passed
3793
 *	(Only handles ppps and vlans now.)
3794
 */
3795
function get_parent_interface($interface) {
3796
	global $config;
3797

    
3798
	$parents = array();
3799
	//Check that we got a valid interface passed
3800
	$realif = get_real_interface($interface);
3801
	if ($realif == NULL)
3802
		return $parents;
3803

    
3804
	// If we got a real interface, find it's friendly assigned name
3805
	if ($interface == $realif)
3806
		$interface = convert_real_interface_to_friendly_interface_name($interface);
3807

    
3808
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
3809
		$ifcfg = $config['interfaces'][$interface];
3810
		switch ($ifcfg['ipaddr']) {
3811
			case "ppp":
3812
			case "pppoe":
3813
			case "pptp":
3814
			case "l2tp":
3815
				if (empty($parents))
3816
					if (is_array($config['ppps']['ppp']))
3817
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
3818
							if ($ifcfg['if'] == $ppp['if']) {
3819
								$ports = explode(',', $ppp['ports']);
3820
								foreach ($ports as $pid => $parent_if)
3821
									$parents[$pid] = get_real_interface($parent_if);
3822
								break;
3823
							}
3824
						}
3825
				break;
3826
			case "dhcp":
3827
			case "static":
3828
			default:
3829
				// Handle _vlans
3830
				if (stristr($realif,"_vlan"))
3831
					if (is_array($config['vlans']['vlan']))
3832
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
3833
							if ($ifcfg['if'] == $vlan['vlanif']){
3834
								$parents[0] = $vlan['if'];
3835
								break;
3836
							}
3837
				break;
3838
		}
3839
	}
3840

    
3841
	if (empty($parents))
3842
		$parents[0] = $realif;
3843

    
3844
	return $parents;
3845
}
3846

    
3847
function interface_is_wireless_clone($wlif) {
3848
	if(!stristr($wlif, "_wlan")) {
3849
		return false;
3850
	} else {
3851
		return true;
3852
	}
3853
}
3854

    
3855
function interface_get_wireless_base($wlif) {
3856
	if(!stristr($wlif, "_wlan")) {
3857
		return $wlif;
3858
	} else {
3859
		return substr($wlif, 0, stripos($wlif, "_wlan"));
3860
	}
3861
}
3862

    
3863
function interface_get_wireless_clone($wlif) {
3864
	if(!stristr($wlif, "_wlan")) {
3865
		return $wlif . "_wlan0";
3866
	} else {
3867
		return $wlif;
3868
	}
3869
}
3870

    
3871
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
3872
	global $config, $g;
3873

    
3874
	$wanif = NULL;
3875

    
3876
	switch ($interface) {
3877
	case "l2tp":
3878
		$wanif = "l2tp";
3879
		break;
3880
	case "pptp":
3881
		$wanif = "pptp";
3882
		break;
3883
	case "pppoe":
3884
		$wanif = "pppoe";
3885
		break;
3886
	case "openvpn":
3887
		$wanif = "openvpn";
3888
		break;
3889
	case "ipsec":
3890
	case "enc0":
3891
		$wanif = "enc0";
3892
		break;
3893
	case "ppp":
3894
		$wanif = "ppp";
3895
		break;
3896
	default:
3897
		// If a real interface was alread passed simply
3898
		// pass the real interface back.  This encourages
3899
		// the usage of this function in more cases so that
3900
		// we can combine logic for more flexibility.
3901
		if(does_interface_exist($interface, $flush)) {
3902
			$wanif = $interface;
3903
			break;
3904
		}
3905

    
3906
		if (empty($config['interfaces'][$interface]))
3907
			break;
3908

    
3909
		$cfg = &$config['interfaces'][$interface];
3910

    
3911
		if ($family == "inet6") {
3912
			switch ($cfg['ipaddrv6']) {
3913
			case "6rd":
3914
			case "6to4":
3915
				$wanif = "{$interface}_stf";
3916
				break;
3917
			case 'pppoe':
3918
			case 'ppp':
3919
			case 'l2tp':
3920
			case 'pptp':
3921
				if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
3922
					$wanif = interface_get_wireless_clone($cfg['if']);
3923
				else
3924
					$wanif = $cfg['if'];
3925
				break;
3926
			default:
3927
				switch ($cfg['ipaddr']) {
3928
				case 'pppoe':
3929
				case 'ppp':
3930
				case 'l2tp':
3931
				case 'pptp':
3932
					if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false)
3933
						$wanif = $cfg['if'];
3934
					else {
3935
						$parents = get_parent_interface($interface);
3936
						if (!empty($parents[0]))
3937
							$wanif = $parents[0];
3938
						else
3939
							$wanif = $cfg['if'];
3940
					}
3941
					break;
3942
				default:
3943
					if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
3944
						$wanif = interface_get_wireless_clone($cfg['if']);
3945
					else
3946
						$wanif = $cfg['if'];
3947
					break;
3948
				}
3949
				break;
3950
			}
3951
		} else {
3952
			// Wireless cloned NIC support (FreeBSD 8+)
3953
			// interface name format: $parentnic_wlanparentnic#
3954
			// example: ath0_wlan0
3955
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
3956
				$wanif = interface_get_wireless_clone($cfg['if']);
3957
			else
3958
				$wanif = $cfg['if'];
3959
		}
3960
		break;
3961
	}
3962

    
3963
	return $wanif;
3964
}
3965

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

    
4003
/*
4004
 * find_ip_interface($ip): return the interface where an ip is defined
4005
 *   (or if $bits is specified, where an IP within the subnet is defined)
4006
 */
4007
function find_ip_interface($ip, $bits = null) {
4008
	if (!is_ipaddr($ip))
4009
		return false;
4010

    
4011
	$isv6ip = is_ipaddrv6($ip);
4012

    
4013
	/* if list */
4014
	$ifdescrs = get_configured_interface_list();
4015

    
4016
	foreach ($ifdescrs as $ifdescr => $ifname) {
4017
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4018
		if (is_null($ifip))
4019
			continue;
4020
		if (is_null($bits)) {
4021
			if ($ip == $ifip) {
4022
				$int = get_real_interface($ifname);
4023
				return $int;
4024
			}
4025
		}
4026
		else {
4027
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4028
				$int = get_real_interface($ifname);
4029
				return $int;
4030
			}
4031
		}
4032
	}
4033

    
4034
	return false;
4035
}
4036

    
4037
/*
4038
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4039
 *   (or if $bits is specified, where an IP within the subnet is found)
4040
 */
4041
function find_virtual_ip_alias($ip, $bits = null) {
4042
	global $config;
4043

    
4044
	if (!is_array($config['virtualip']['vip'])) {
4045
		return false;
4046
	}
4047
	if (!is_ipaddr($ip))
4048
		return false;
4049

    
4050
	$isv6ip = is_ipaddrv6($ip);
4051

    
4052
	foreach ($config['virtualip']['vip'] as $vip) {
4053
		if ($vip['mode'] === "ipalias") {
4054
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4055
				continue;
4056
			if (is_null($bits)) {
4057
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4058
					return $vip;
4059
				}
4060
			}
4061
			else {
4062
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4063
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4064
					return $vip;
4065
				}
4066
			}
4067
		}
4068
	}
4069
	return false;
4070
}
4071

    
4072
/*
4073
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4074
 */
4075
function find_number_of_created_carp_interfaces() {
4076
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4077
}
4078

    
4079
function get_all_carp_interfaces() {
4080
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
4081
	$ints = explode(" ", $ints);
4082
	return $ints;
4083
}
4084

    
4085
/*
4086
 * find_carp_interface($ip): return the carp interface where an ip is defined
4087
 */
4088
function find_carp_interface($ip) {
4089
	global $config;
4090
	if (is_array($config['virtualip']['vip'])) {
4091
		foreach ($config['virtualip']['vip'] as $vip) {
4092
			if ($vip['mode'] == "carp") {
4093
				if(is_ipaddrv4($ip)) {
4094
					$carp_ip = get_interface_ip($vip['interface']);
4095
				}
4096
				if(is_ipaddrv6($ip)) {
4097
					$carp_ip = get_interface_ipv6($vip['interface']);
4098
				}
4099
				exec("/sbin/ifconfig", $output, $return);
4100
				foreach($output as $line) {
4101
					$elements = preg_split("/[ ]+/i", $line);
4102
					if(strstr($elements[0], "vip"))
4103
						$curif = str_replace(":", "", $elements[0]);
4104
					if(stristr($line, $ip)) {
4105
						$if = $curif;
4106
						continue;
4107
					}
4108
				}
4109

    
4110
				if ($if)
4111
					return $if;
4112
			}
4113
		}
4114
	}
4115
}
4116

    
4117
function link_carp_interface_to_parent($interface) {
4118
	global $config;
4119

    
4120
	if ($interface == "")
4121
		return;
4122

    
4123
	$carp_ip = get_interface_ip($interface);
4124
	$carp_ipv6 = get_interface_ipv6($interface);
4125

    
4126
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4127
		return;
4128

    
4129
	/* if list */
4130
	$ifdescrs = get_configured_interface_list();
4131
	foreach ($ifdescrs as $ifdescr => $ifname) {
4132
		/* check IPv4 */
4133
		if(is_ipaddrv4($carp_ip)) {
4134
			$interfaceip = get_interface_ip($ifname);
4135
			$subnet_bits = get_interface_subnet($ifname);
4136
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4137
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4138
				return $ifname;
4139
		}
4140
		/* Check IPv6 */
4141
		if(is_ipaddrv6($carp_ipv6)) {
4142
			$interfaceipv6 = get_interface_ipv6($ifname);
4143
			$prefixlen = get_interface_subnetv6($ifname);
4144
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4145
				return $ifname;
4146
		}
4147
	}
4148
	return "";
4149
}
4150

    
4151

    
4152
/****f* interfaces/link_ip_to_carp_interface
4153
 * NAME
4154
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4155
 * INPUTS
4156
 *   $ip
4157
 * RESULT
4158
 *   $carp_ints
4159
 ******/
4160
function link_ip_to_carp_interface($ip) {
4161
	global $config;
4162

    
4163
	if (!is_ipaddr($ip))
4164
		return;
4165

    
4166
	$carp_ints = "";
4167
	if (is_array($config['virtualip']['vip'])) {
4168
		$first = 0;
4169
		$carp_int = array();
4170
		foreach ($config['virtualip']['vip'] as $vip) {
4171
			if ($vip['mode'] == "carp") {
4172
				$carp_ip = $vip['subnet'];
4173
				$carp_sn = $vip['subnet_bits'];
4174
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4175
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4176
					$carp_int[] = "{$vip['interface']}_vip{$vip['vhid']}";
4177
				}
4178
			}
4179
		}
4180
		if (!empty($carp_int))
4181
			$carp_ints = implode(" ", array_unique($carp_int));
4182
	}
4183

    
4184
	return $carp_ints;
4185
}
4186

    
4187
function link_interface_to_track6($int, $action = "") {
4188
	global $config;
4189

    
4190
	if (empty($int))
4191
		return;
4192

    
4193
	if (is_array($config['interfaces'])) {
4194
		$list = array();
4195
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4196
			if (!isset($ifcfg['enable']))
4197
				continue;
4198
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4199
				if ($action == "update")
4200
					interface_track6_configure($ifname, $ifcfg);
4201
				else if ($action == "")
4202
					$list[$ifname] = $ifcfg;
4203
			}
4204
		}
4205
		return $list;
4206
	}
4207
}
4208

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

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

    
4215
	if (is_array($config['vlans']['vlan'])) {
4216
		$ifaces = array();
4217
		foreach ($config['vlans']['vlan'] as $vlan) {
4218
			if ($int == $vlan['if']) {
4219
				if ($action == "update") {
4220
					interfaces_bring_up($int);
4221
				} else if ($action == "")
4222
					$ifaces[$vlan['tag']] = $vlan;
4223
			}
4224
		}
4225
		if (!empty($ifaces))
4226
			return $ifaces;
4227
	}
4228
}
4229

    
4230
function link_interface_to_vips($int, $action = "") {
4231
	global $config;
4232

    
4233
	if (is_array($config['virtualip']['vip'])) {
4234
		$result = array();
4235
		foreach ($config['virtualip']['vip'] as $vip) {
4236
			if ($int == $vip['interface']) {
4237
				if ($action == "update")
4238
					interfaces_vips_configure($int);
4239
				else
4240
					$result[] = $vip;
4241
			}
4242
		}
4243
		return $result;
4244
	}
4245
}
4246

    
4247
/****f* interfaces/link_interface_to_bridge
4248
 * NAME
4249
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4250
 * INPUTS
4251
 *   $ip
4252
 * RESULT
4253
 *   bridge[0-99]
4254
 ******/
4255
function link_interface_to_bridge($int) {
4256
	global $config;
4257

    
4258
	if (is_array($config['bridges']['bridged'])) {
4259
		foreach ($config['bridges']['bridged'] as $bridge) {
4260
			if (in_array($int, explode(',', $bridge['members'])))
4261
				return "{$bridge['bridgeif']}";
4262
		}
4263
	}
4264
}
4265

    
4266
function link_interface_to_group($int) {
4267
	global $config;
4268

    
4269
	$result = array();
4270

    
4271
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4272
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4273
			if (in_array($int, explode(" ", $group['members'])))
4274
				$result[$group['ifname']] = $int;
4275
		}
4276
	}
4277

    
4278
	return $result;
4279
}
4280

    
4281
function link_interface_to_gre($interface) {
4282
	global $config;
4283

    
4284
	$result = array();
4285

    
4286
	if (is_array($config['gres']['gre'])) {
4287
		foreach ($config['gres']['gre'] as $gre)
4288
			if($gre['if'] == $interface)
4289
				$result[] = $gre;
4290
	}
4291

    
4292
	return $result;
4293
}
4294

    
4295
function link_interface_to_gif($interface) {
4296
	global $config;
4297

    
4298
	$result = array();
4299

    
4300
	if (is_array($config['gifs']['gif'])) {
4301
		foreach ($config['gifs']['gif'] as $gif)
4302
			if($gif['if'] == $interface)
4303
				$result[] = $gif;
4304
	}
4305

    
4306
	return $result;
4307
}
4308

    
4309
/*
4310
 * find_interface_ip($interface): return the interface ip (first found)
4311
 */
4312
function find_interface_ip($interface, $flush = false) {
4313
	global $interface_ip_arr_cache;
4314
	global $interface_sn_arr_cache;
4315

    
4316
	$interface = str_replace("\n", "", $interface);
4317

    
4318
	if (!does_interface_exist($interface))
4319
		return;
4320

    
4321
	/* Setup IP cache */
4322
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4323
		$ifinfo = pfSense_get_interface_addresses($interface);
4324
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4325
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4326
	}
4327

    
4328
	return $interface_ip_arr_cache[$interface];
4329
}
4330

    
4331
/*
4332
 * find_interface_ipv6($interface): return the interface ip (first found)
4333
 */
4334
function find_interface_ipv6($interface, $flush = false) {
4335
	global $interface_ipv6_arr_cache;
4336
	global $interface_snv6_arr_cache;
4337
	global $config;
4338

    
4339
	$interface = trim($interface);
4340
	$interface = get_real_interface($interface);
4341

    
4342
	if (!does_interface_exist($interface))
4343
		return;
4344

    
4345
	/* Setup IP cache */
4346
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4347
		$ifinfo = pfSense_get_interface_addresses($interface);
4348
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4349
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4350
	}
4351

    
4352
	return $interface_ipv6_arr_cache[$interface];
4353
}
4354

    
4355
/*
4356
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4357
 */
4358
function find_interface_ipv6_ll($interface, $flush = false) {
4359
	global $interface_llv6_arr_cache;
4360
	global $config;
4361

    
4362
	$interface = str_replace("\n", "", $interface);
4363

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

    
4367
	/* Setup IP cache */
4368
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4369
		$ifinfo = pfSense_getall_interface_addresses($interface);
4370
		foreach($ifinfo as $line) {
4371
			if (strstr($line, ":")) {
4372
				$parts = explode("/", $line);
4373
				if(is_linklocal($parts[0])) {
4374
					$ifinfo['linklocal'] = $parts[0];
4375
				}
4376
			}
4377
		}
4378
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4379
	}
4380
	return $interface_llv6_arr_cache[$interface];
4381
}
4382

    
4383
function find_interface_subnet($interface, $flush = false) {
4384
	global $interface_sn_arr_cache;
4385
	global $interface_ip_arr_cache;
4386

    
4387
	$interface = str_replace("\n", "", $interface);
4388
	if (does_interface_exist($interface) == false)
4389
		return;
4390

    
4391
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4392
		$ifinfo = pfSense_get_interface_addresses($interface);
4393
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4394
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4395
	}
4396

    
4397
	return $interface_sn_arr_cache[$interface];
4398
}
4399

    
4400
function find_interface_subnetv6($interface, $flush = false) {
4401
	global $interface_snv6_arr_cache;
4402
	global $interface_ipv6_arr_cache;
4403

    
4404
	$interface = str_replace("\n", "", $interface);
4405
	if (does_interface_exist($interface) == false)
4406
		return;
4407

    
4408
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4409
		$ifinfo = pfSense_get_interface_addresses($interface);
4410
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4411
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4412
	}
4413

    
4414
	return $interface_snv6_arr_cache[$interface];
4415
}
4416

    
4417
function ip_in_interface_alias_subnet($interface, $ipalias) {
4418
	global $config;
4419

    
4420
	if (empty($interface) || !is_ipaddr($ipalias))
4421
		return false;
4422
	if (is_array($config['virtualip']['vip'])) {
4423
		foreach ($config['virtualip']['vip'] as $vip) {
4424
			switch ($vip['mode']) {
4425
			case "ipalias":
4426
				if ($vip['interface'] <> $interface)
4427
					break;
4428
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4429
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4430
					return true;
4431
				break;
4432
			}
4433
		}
4434
	}
4435

    
4436
	return false;
4437
}
4438

    
4439
function get_interface_ip($interface = "wan") {
4440
	$realif = get_failover_interface($interface);
4441
	if (!$realif) {
4442
		if (preg_match("/^carp/i", $interface))
4443
			$realif = $interface;
4444
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4445
			$realif = $interface;
4446
		else
4447
			return null;
4448
	}
4449

    
4450
	$curip = find_interface_ip($realif);
4451
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4452
		return $curip;
4453
	else
4454
		return null;
4455
}
4456

    
4457
function get_interface_ipv6($interface = "wan", $flush = false) {
4458
	global $config;
4459

    
4460
	$realif = get_failover_interface($interface, "inet6");
4461
	if (!$realif) {
4462
		if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4463
			$realif = $interface;
4464
		else
4465
			return null;
4466
	}
4467

    
4468
	/*
4469
	 * NOTE: On the case when only the prefix is requested,
4470
	 * the communication on WAN will be done over link-local.
4471
	 */
4472
	if (is_array($config['interfaces'][$interface])) {
4473
		switch ($config['interfaces'][$interface]['ipaddr']) {
4474
		case 'pppoe':
4475
		case 'l2tp':
4476
		case 'pptp':
4477
		case 'ppp':
4478
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4479
				$realif = get_real_interface($interface, "inet6", true);
4480
			break;
4481
		}
4482
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4483
			$curip = find_interface_ipv6_ll($realif, $flush);
4484
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4485
				return $curip;
4486
		}
4487
	}
4488

    
4489
	$curip = find_interface_ipv6($realif, $flush);
4490
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4491
		return $curip;
4492
	else
4493
		return null;
4494
}
4495

    
4496
function get_interface_linklocal($interface = "wan") {
4497

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

    
4508
	$curip = find_interface_ipv6_ll($realif);
4509
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4510
		return $curip;
4511
	else
4512
		return null;
4513
}
4514

    
4515
function get_interface_subnet($interface = "wan") {
4516
	$realif = get_real_interface($interface);
4517
	if (!$realif) {
4518
		if (preg_match("/^carp/i", $interface))
4519
			$realif = $interface;
4520
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4521
			$realif = $interface;
4522
		else
4523
			return null;
4524
	}
4525

    
4526
	$cursn = find_interface_subnet($realif);
4527
	if (!empty($cursn))
4528
		return $cursn;
4529

    
4530
	return null;
4531
}
4532

    
4533
function get_interface_subnetv6($interface = "wan") {
4534
	global $config;
4535

    
4536
	$realif = get_real_interface($interface, "inet6");
4537
	if (!$realif) {
4538
		if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4539
			$realif = $interface;
4540
		else
4541
			return null;
4542
	}
4543

    
4544
	$cursn = find_interface_subnetv6($realif);
4545
	if (!empty($cursn))
4546
		return $cursn;
4547

    
4548
	return null;
4549
}
4550

    
4551
/* return outside interfaces with a gateway */
4552
function get_interfaces_with_gateway() {
4553
	global $config;
4554

    
4555
	$ints = array();
4556

    
4557
	/* loop interfaces, check config for outbound */
4558
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4559
		switch ($ifname['ipaddr']) {
4560
			case "dhcp":
4561
			case "ppp";
4562
			case "pppoe":
4563
			case "pptp":
4564
			case "l2tp":
4565
			case "ppp";
4566
				$ints[$ifdescr] = $ifdescr;
4567
			break;
4568
			default:
4569
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
4570
				    !empty($ifname['gateway']))
4571
					$ints[$ifdescr] = $ifdescr;
4572
			break;
4573
		}
4574
	}
4575
	return $ints;
4576
}
4577

    
4578
/* return true if interface has a gateway */
4579
function interface_has_gateway($friendly) {
4580
	global $config;
4581

    
4582
	if (!empty($config['interfaces'][$friendly])) {
4583
		$ifname = &$config['interfaces'][$friendly];
4584
		switch ($ifname['ipaddr']) {
4585
			case "dhcp":
4586
			case "pppoe":
4587
			case "pptp":
4588
			case "l2tp":
4589
			case "ppp";
4590
				return true;
4591
			break;
4592
			default:
4593
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4594
					return true;
4595
				if (!empty($ifname['gateway']))
4596
					return true;
4597
			break;
4598
		}
4599
	}
4600

    
4601
	return false;
4602
}
4603

    
4604
/* return true if interface has a gateway */
4605
function interface_has_gatewayv6($friendly) {
4606
	global $config;
4607

    
4608
	if (!empty($config['interfaces'][$friendly])) {
4609
		$ifname = &$config['interfaces'][$friendly];
4610
		switch ($ifname['ipaddrv6']) {
4611
			case "slaac":
4612
			case "dhcp6":
4613
			case "6to4":
4614
			case "6rd":
4615
				return true;
4616
				break;
4617
			default:
4618
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4619
					return true;
4620
				if (!empty($ifname['gatewayv6']))
4621
					return true;
4622
				break;
4623
		}
4624
	}
4625

    
4626
	return false;
4627
}
4628

    
4629
/****f* interfaces/is_altq_capable
4630
 * NAME
4631
 *   is_altq_capable - Test if interface is capable of using ALTQ
4632
 * INPUTS
4633
 *   $int            - string containing interface name
4634
 * RESULT
4635
 *   boolean         - true or false
4636
 ******/
4637

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

    
4651
	$int_family = remove_ifindex($int);
4652

    
4653
	if (in_array($int_family, $capable))
4654
		return true;
4655
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
4656
		return true;
4657
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
4658
		return true;
4659
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
4660
		return true;
4661
	else
4662
		return false;
4663
}
4664

    
4665
/****f* interfaces/is_interface_wireless
4666
 * NAME
4667
 *   is_interface_wireless - Returns if an interface is wireless
4668
 * RESULT
4669
 *   $tmp       - Returns if an interface is wireless
4670
 ******/
4671
function is_interface_wireless($interface) {
4672
	global $config, $g;
4673

    
4674
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
4675
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
4676
		if (preg_match($g['wireless_regex'], $interface)) {
4677
			if (isset($config['interfaces'][$friendly]))
4678
				$config['interfaces'][$friendly]['wireless'] = array();
4679
			return true;
4680
		}
4681
		return false;
4682
	} else
4683
		return true;
4684
}
4685

    
4686
function get_wireless_modes($interface) {
4687
	/* return wireless modes and channels */
4688
	$wireless_modes = array();
4689

    
4690
	$cloned_interface = get_real_interface($interface);
4691

    
4692
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4693
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
4694
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4695
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
4696

    
4697
		$interface_channels = "";
4698
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4699
		$interface_channel_count = count($interface_channels);
4700

    
4701
		$c = 0;
4702
		while ($c < $interface_channel_count) {
4703
			$channel_line = explode(",", $interface_channels["$c"]);
4704
			$wireless_mode = trim($channel_line[0]);
4705
			$wireless_channel = trim($channel_line[1]);
4706
			if(trim($wireless_mode) != "") {
4707
				/* if we only have 11g also set 11b channels */
4708
				if($wireless_mode == "11g") {
4709
					if(!isset($wireless_modes["11b"]))
4710
						$wireless_modes["11b"] = array();
4711
				} else if($wireless_mode == "11g ht") {
4712
					if(!isset($wireless_modes["11b"]))
4713
						$wireless_modes["11b"] = array();
4714
					if(!isset($wireless_modes["11g"]))
4715
						$wireless_modes["11g"] = array();
4716
					$wireless_mode = "11ng";
4717
				} else if($wireless_mode == "11a ht") {
4718
					if(!isset($wireless_modes["11a"]))
4719
						$wireless_modes["11a"] = array();
4720
					$wireless_mode = "11na";
4721
				}
4722
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
4723
			}
4724
			$c++;
4725
		}
4726
	}
4727
	return($wireless_modes);
4728
}
4729

    
4730
/* return channel numbers, frequency, max txpower, and max regulation txpower */
4731
function get_wireless_channel_info($interface) {
4732
	$wireless_channels = 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 txpower";
4738
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4739
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
4740

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

    
4744
		foreach ($interface_channels as $channel_line) {
4745
			$channel_line = explode(",", $channel_line);
4746
			if(!isset($wireless_channels[$channel_line[0]]))
4747
				$wireless_channels[$channel_line[0]] = $channel_line;
4748
		}
4749
	}
4750
	return($wireless_channels);
4751
}
4752

    
4753
/****f* interfaces/get_interface_mtu
4754
 * NAME
4755
 *   get_interface_mtu - Return the mtu of an interface
4756
 * RESULT
4757
 *   $tmp       - Returns the mtu of an interface
4758
 ******/
4759
function get_interface_mtu($interface) {
4760
	$mtu = pfSense_get_interface_addresses($interface);
4761
	return $mtu['mtu'];
4762
}
4763

    
4764
function get_interface_mac($interface) {
4765

    
4766
	$macinfo = pfSense_get_interface_addresses($interface);
4767
	return $macinfo["macaddr"];
4768
}
4769

    
4770
/****f* pfsense-utils/generate_random_mac_address
4771
 * NAME
4772
 *   generate_random_mac - generates a random mac address
4773
 * INPUTS
4774
 *   none
4775
 * RESULT
4776
 *   $mac - a random mac address
4777
 ******/
4778
function generate_random_mac_address() {
4779
	$mac = "02";
4780
	for($x=0; $x<5; $x++)
4781
		$mac .= ":" . dechex(rand(16, 255));
4782
	return $mac;
4783
}
4784

    
4785
/****f* interfaces/is_jumbo_capable
4786
 * NAME
4787
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
4788
 * INPUTS
4789
 *   $int             - string containing interface name
4790
 * RESULT
4791
 *   boolean          - true or false
4792
 ******/
4793
function is_jumbo_capable($iface) {
4794
	$iface = trim($iface);
4795
	$capable = pfSense_get_interface_addresses($iface);
4796

    
4797
	if (isset($capable['caps']['vlanmtu']))
4798
		return true;
4799

    
4800
	return false;
4801
}
4802

    
4803
function interface_setup_pppoe_reset_file($pppif, $iface="") {
4804
	global $g;
4805

    
4806
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
4807

    
4808
	if(!empty($iface) && !empty($pppif)){
4809
		$cron_cmd = <<<EOD
4810
#!/bin/sh
4811
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
4812
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
4813

    
4814
EOD;
4815

    
4816
		@file_put_contents($cron_file, $cron_cmd);
4817
		chmod($cron_file, 0755);
4818
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
4819
	} else
4820
		unlink_if_exists($cron_file);
4821
}
4822

    
4823
function get_interface_default_mtu($type = "ethernet") {
4824
	switch ($type) {
4825
	case "gre":
4826
		return 1476;
4827
		break;
4828
	case "gif":
4829
		return 1280;
4830
		break;
4831
	case "tun":
4832
	case "vlan":
4833
	case "tap":
4834
	case "ethernet":
4835
	default:
4836
		return 1500;
4837
		break;
4838
	}
4839

    
4840
	/* Never reached */
4841
	return 1500;
4842
}
4843

    
4844
function get_vip_descr($ipaddress) {
4845
	global $config;
4846

    
4847
	foreach ($config['virtualip']['vip'] as $vip) {
4848
		if ($vip['subnet'] == $ipaddress) {
4849
			return ($vip['descr']);
4850
		}
4851
	}
4852
	return "";
4853
}
4854

    
4855
function interfaces_staticarp_configure($if) {
4856
	global $config, $g;
4857
	if(isset($config['system']['developerspew'])) {
4858
		$mt = microtime();
4859
		echo "interfaces_staticarp_configure($if) being called $mt\n";
4860
	}
4861

    
4862
	$ifcfg = $config['interfaces'][$if];
4863

    
4864
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
4865
		return 0;
4866

    
4867
	/* Enable staticarp, if enabled */
4868
	if(isset($config['dhcpd'][$if]['staticarp'])) {
4869
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
4870
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4871
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
4872

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

    
4876
			}
4877

    
4878
		}
4879
	} else {
4880
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
4881
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4882
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
4883
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
4884
				if (isset($arpent['arp_table_static_entry'])) {
4885
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
4886
				}
4887
			}
4888
		}
4889
	}
4890

    
4891
	return 0;
4892
}
4893

    
4894
function get_failover_interface($interface, $family = "all") {
4895
	global $config;
4896

    
4897
	/* shortcut to get_real_interface if we find it in the config */
4898
	if (is_array($config['interfaces'][$interface])) {
4899
		return get_real_interface($interface, $family);
4900
	}
4901

    
4902
	/* compare against gateway groups */
4903
	$a_groups = return_gateway_groups_array();
4904
	if (is_array($a_groups[$interface])) {
4905
		/* we found a gateway group, fetch the interface or vip */
4906
		if ($a_groups[$interface][0]['vip'] <> "")
4907
			return $a_groups[$interface][0]['vip'];
4908
		else
4909
			return $a_groups[$interface][0]['int'];
4910
	}
4911
	/* fall through to get_real_interface */
4912
	/* XXX: Really needed? */
4913
	return get_real_interface($interface, $family);
4914
}
4915

    
4916
function remove_ifindex($ifname) {
4917
	return preg_replace("/[0-9]+$/", "", $ifname);
4918
}
4919

    
4920
?>
(25-25/66)