Project

General

Profile

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

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

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

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

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

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

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

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

    
42
*/
43

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

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

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

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

    
68
	return $interface_arr_cache;
69
}
70

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

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

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

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

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

    
98

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

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

    
124
	return false;
125
}
126

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
267
	interfaces_bring_up($vlanif);
268

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

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

    
275
	return $vlanif;
276
}
277

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

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

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

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

    
298
	$vlanif = interface_vlan_configure($vlan);
299

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

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

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

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

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

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

    
351
	return $vlanif;
352
}
353

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

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

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

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

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

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

    
394
	return $vlanif;
395
}
396

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

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

    
403
	$iflist = get_configured_interface_list();
404

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

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

    
424
}
425

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

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

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

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

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

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

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

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

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

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

    
544
	$checklist = get_configured_interface_list();
545

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
794
	$checklist = get_interface_list();
795

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

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

    
809
	interfaces_bring_up($laggif);
810

    
811
	return $laggif;
812
}
813

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

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

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

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

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

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

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

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

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

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

    
885
	return $greif;
886
}
887

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

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

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

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

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

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

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

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

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

    
979

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

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

    
992
	return $gifif;
993
}
994

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

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

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

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

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

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

    
1013
	interfaces_qinq_configure();
1014

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

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

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

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

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

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

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

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

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

    
1071
		interface_configure($if, $reload);
1072

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

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

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

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

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

    
1092
		interface_configure($if, $reload);
1093

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

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

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

    
1107
		interface_configure($if, $reload);
1108

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

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

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

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

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

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

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

    
1134
	return 0;
1135
}
1136

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1322
	return;
1323
}
1324

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

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

    
1333
	return false;
1334
}
1335

    
1336
function interfaces_ptpid_next() {
1337

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

    
1342
	return $ptpid;
1343
}
1344

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

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

    
1356
	return NULL;
1357
}
1358

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

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

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

    
1368
	$itemhash = getMPDCRONSettings($pppif);
1369

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

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

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

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

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

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

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

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

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

    
1519
				if(!is_ipaddr($localips[$pid])){
1520
					log_error("Could not get a Local IP address for PPTP/L2TP link on {$port} in interfaces_ppps_configure. Using 0.0.0.0 ip!");
1521
					$localips[$pid] = "0.0.0.0";
1522
				}
1523
				if(!is_ipaddr($gateways[$pid])){
1524
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $dhcp_gateway, $gway));
1525
					return 0;
1526
				}
1527
				pfSense_ngctl_attach(".", $port);
1528
				break;
1529
			case "ppp":
1530
				if (!file_exists("{$port}")) {
1531
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1532
					return 0;
1533
				}
1534
				break;
1535
			default:
1536
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1537
				break;
1538
		}
1539
	}
1540

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1629
EOD;
1630

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

    
1635
EOD;
1636

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

    
1644
EOD;
1645

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

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

    
1656
EOD;
1657

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

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

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

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

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

    
1684
EOD;
1685

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

    
1690
EOD;
1691

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

    
1696
EOD;
1697

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

    
1703
EOD;
1704

    
1705

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

    
1710
EOD;
1711

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

    
1717
EOD;
1718

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

    
1723
EOD;
1724

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

    
1729
EOD;
1730

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

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

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

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

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

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

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

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

    
1788
EOD;
1789

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

    
1795
EOD;
1796
		}
1797

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

    
1801

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

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

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

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

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

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

    
1876
	return 1;
1877
}
1878

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

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

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

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

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

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

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

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

    
1925
		sleep(1);
1926

    
1927
		/* XXX: Handle an issue with pfsync(4) and carp(4). In a cluster carp will come up before pfsync(4) has updated and so will cause issues
1928
		 * for existing sessions.
1929
		 */
1930
		log_error("waiting for pfsync...");
1931
		$i = 0;
1932
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1933
			$i++;
1934
			sleep(1);
1935
		}
1936
		log_error("pfsync done in $i seconds.");
1937
		log_error("Configuring CARP settings finalize...");
1938
	} else {
1939
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
1940
	}
1941

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2135
	if(is_ipaddrv4($vip['subnet'])) {
2136
		/* Ensure CARP IP really exists prior to loading up. */
2137
		$ww_subnet_ip = find_interface_ip($realif);
2138
		$ww_subnet_bits = find_interface_subnet($realif);
2139
		if (!ip_in_subnet($vip['subnet'], gen_subnet($ww_subnet_ip, $ww_subnet_bits) . "/" . $ww_subnet_bits) && !ip_in_interface_alias_subnet($vip['interface'], $vip['subnet'])) {
2140
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a matching real interface subnet for the virtual IP address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2141
			return;
2142
		}
2143
	}
2144
	if(is_ipaddrv6($vip['subnet'])) {
2145
		/* Ensure CARP IP really exists prior to loading up. */
2146
		$ww_subnet_ip = find_interface_ipv6($realif);
2147
		$ww_subnet_bits = find_interface_subnetv6($realif);
2148
		if (!ip_in_subnet($vip['subnet'], gen_subnetv6($ww_subnet_ip, $ww_subnet_bits) . "/" . $ww_subnet_bits) && !ip_in_interface_alias_subnet($vip['interface'], $vip['subnet'])) {
2149
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a matching real interface subnet for the virtual IPv6 address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2150
			return;
2151
		}
2152
	}
2153

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

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

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

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

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

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

    
2188
	interfaces_bring_up($vipif);
2189

    
2190
	return $vipif;
2191
}
2192

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2551
EOD;
2552

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

    
2559
EOD;
2560

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

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

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

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

    
2588
			}
2589
			break;
2590
	}
2591

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2732

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

    
2737
	return 0;
2738

    
2739
}
2740

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

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

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

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

    
2758
	return intval($pid);
2759
}
2760

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

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

    
2769
	return intval($pid);
2770
}
2771

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

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

    
2788
	return $mtu;
2789
}
2790

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

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

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

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

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

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

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

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

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

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

    
2857
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2858
			/*   this is not a valid mac address.  generate a
2859
			 *   temporary mac address so the machine can get online.
2860
			 */
2861
			echo gettext("Generating new MAC address.");
2862
			$random_mac = generate_random_mac_address();
2863
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2864
				" link " . escapeshellarg($random_mac));
2865
			$wancfg['spoofmac'] = $random_mac;
2866
			write_config();
2867
			file_notice("MAC Address altered", sprintf(gettext('The INVALID MAC address (ff:ff:ff:ff:ff:ff) on interface %1$s has been automatically replaced with %2$s'), $realif, $random_mac), "Interfaces");
2868
		}
2869
	}
2870

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3085
	unset($vlanifs);
3086

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

    
3090
	interface_netgraph_needed($interface);
3091

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

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

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

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

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

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

    
3120
		if ($reloadall == true) {
3121

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3188
		services_dhcpd_configure("inet6");
3189
	}
3190

    
3191
	return 0;
3192
}
3193

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

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

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

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

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

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

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

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

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

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

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

    
3252
	return 0;
3253
}
3254

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

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

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

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

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

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

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

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

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

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

    
3309
	return 0;
3310
}
3311

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3380
	return 0;
3381
}
3382

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3476
	return 0;
3477
}
3478

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3588
	return 0;
3589
}
3590

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

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

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

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

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

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

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

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

    
3638
}
3639

    
3640
EOD;
3641

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

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

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

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

    
3665
	return 0;
3666
}
3667

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

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

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

    
3677
	return;
3678
}
3679

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

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

    
3692
	return;
3693
}
3694

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

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

    
3704
	return false;
3705
}
3706

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

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

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

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

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

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

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

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

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

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

    
3762
	return NULL;
3763
}
3764

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

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

    
3813
	return $ifdesc;
3814
}
3815

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

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

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

    
3826
	return $interface;
3827
}
3828

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

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

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

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

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

    
3887
	return $parents;
3888
}
3889

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

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

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

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

    
3917
	$wanif = NULL;
3918

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

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

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

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

    
4006
	return $wanif;
4007
}
4008

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

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

    
4054
	$isv6ip = is_ipaddrv6($ip);
4055

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

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

    
4077
	return false;
4078
}
4079

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

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

    
4093
	$isv6ip = is_ipaddrv6($ip);
4094

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

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

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

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

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

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

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

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

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

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

    
4194

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

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

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

    
4227
	return $carp_ints;
4228
}
4229

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

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

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

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

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

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

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

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

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

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

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

    
4312
	$result = array();
4313

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

    
4321
	return $result;
4322
}
4323

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

    
4327
	$result = array();
4328

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

    
4335
	return $result;
4336
}
4337

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

    
4341
	$result = array();
4342

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

    
4349
	return $result;
4350
}
4351

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4479
	return false;
4480
}
4481

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

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

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

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

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

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

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

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

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

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

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

    
4573
	return null;
4574
}
4575

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

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

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

    
4591
	return null;
4592
}
4593

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

    
4598
	$ints = array();
4599

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

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

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

    
4644
	return false;
4645
}
4646

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

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

    
4669
	return false;
4670
}
4671

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

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

    
4694
	$int_family = remove_ifindex($int);
4695

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

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

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

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

    
4733
	$cloned_interface = get_real_interface($interface);
4734

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

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

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

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

    
4777
	$cloned_interface = get_real_interface($interface);
4778

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

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

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

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

    
4807
function get_interface_mac($interface) {
4808

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

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

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

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

    
4843
	return false;
4844
}
4845

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

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

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

    
4857
EOD;
4858

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

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

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

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

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

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

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

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

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

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

    
4919
			}
4920

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

    
4934
	return 0;
4935
}
4936

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

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

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

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

    
4963
?>
(25-25/66)