Projet

Général

Profil

Télécharger (146 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / etc / inc / interfaces.inc @ 466cabed

1
<?php
2
/*
3
	interfaces.inc
4
	Copyright (C) 2004-2008 Scott Ullrich
5
	Copyright (C) 2008-2009 Ermal Lu?i
6
	All rights reserved.
7

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

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

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

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

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

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

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

    
42
*/
43

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

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

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

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

    
68
	return $interface_arr_cache;
69
}
70

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

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

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

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

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

    
98

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

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

    
124
	return false;
125
}
126

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
267
	interfaces_bring_up($vlanif);
268

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

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

    
275
	return $vlanif;
276
}
277

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

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

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

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

    
298
	$vlanif = interface_vlan_configure($vlan);
299

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

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

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

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

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

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

    
351
	return $vlanif;
352
}
353

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

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

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

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

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

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

    
394
	return $vlanif;
395
}
396

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

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

    
403
	$iflist = get_configured_interface_list();
404

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

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

    
424
}
425

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

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

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

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

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

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

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

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

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

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

    
544
	$checklist = get_configured_interface_list();
545

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
794
	$checklist = get_interface_list();
795

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

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

    
809
	interfaces_bring_up($laggif);
810

    
811
	return $laggif;
812
}
813

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

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

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

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

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

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

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

    
859
	/* Do not change the order here for more see gre(4) NOTES section. */
860
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
861
	if((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
862
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
863
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
864
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
865
	} else {
866
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
867
	}
868
	if (isset($gre['link0']))
869
		pfSense_interface_flags($greif, IFF_LINK0);
870
	if (isset($gre['link1']))
871
		pfSense_interface_flags($greif, IFF_LINK1);
872
	if (isset($gre['link2']))
873
		pfSense_interface_flags($greif, IFF_LINK2);
874

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

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

    
887
	interfaces_bring_up($greif);
888

    
889
	return $greif;
890
}
891

    
892
function interfaces_gif_configure($checkparent = 0) {
893
	global $config;
894

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

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

    
921
	if (!is_array($gif))
922
		return -1;
923

    
924
	$realif = get_real_interface($gif['if']);
925
	$ipaddr = $gif['ipaddr'];
926

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

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

    
953
	/* Do not change the order here for more see gif(4) NOTES section. */
954
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
955
	if((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
956
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
957
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
958
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
959
	} else {
960
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
961
	}
962
	if (isset($gif['link0']))
963
		pfSense_interface_flags($gifif, IFF_LINK0);
964
	if (isset($gif['link1']))
965
		pfSense_interface_flags($gifif, IFF_LINK1);
966
	if($gifif)
967
		interfaces_bring_up($gifif);
968
	else
969
		log_error(gettext("could not bring gifif up -- variable not defined"));
970

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

    
985

    
986
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
987
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
988
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
989
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
990

    
991
	if (is_ipaddrv4($realifgw)) {
992
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
993
	}
994
	if (is_ipaddrv6($realifgw)) {
995
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
996
	}
997

    
998
	interfaces_bring_up($gifif);
999

    
1000
	return $gifif;
1001
}
1002

    
1003
function interfaces_configure() {
1004
	global $config, $g;
1005

    
1006
	if ($g['platform'] == 'jail')
1007
		return;
1008

    
1009
	/* Set up our loopback interface */
1010
	interfaces_loopback_configure();
1011

    
1012
	/* create the unconfigured wireless clones */
1013
	interfaces_create_wireless_clones();
1014

    
1015
	/* set up LAGG virtual interfaces */
1016
	interfaces_lagg_configure();
1017

    
1018
	/* set up VLAN virtual interfaces */
1019
	interfaces_vlan_configure();
1020

    
1021
	interfaces_qinq_configure();
1022

    
1023
	$iflist = get_configured_interface_with_descr();
1024
	$delayed_list = array();
1025
	$bridge_list = array();
1026
	$track6_list = array();
1027

    
1028
	/* This is needed to speedup interfaces on bootup. */
1029
	$reload = false;
1030
	if (!$g['booting'])
1031
		$reload = true;
1032

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

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

    
1058
	/*
1059
	 * NOTE: The following function parameter consists of
1060
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1061
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1062
	 */
1063

    
1064
	/* set up GRE virtual interfaces */
1065
	interfaces_gre_configure(1);
1066

    
1067
	/* set up GIF virtual interfaces */
1068
	interfaces_gif_configure(1);
1069

    
1070
	/* set up BRIDGe virtual interfaces */
1071
	interfaces_bridge_configure(1);
1072

    
1073
	foreach ($track6_list as $if => $ifname) {
1074
		if ($g['booting'])
1075
			printf(gettext("Configuring %s interface..."), $ifname);
1076
		if ($g['debug'])
1077
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1078

    
1079
		interface_configure($if, $reload);
1080

    
1081
		if ($g['booting'])
1082
			echo gettext("done.") . "\n";
1083
	}
1084

    
1085
	/* bring up vip interfaces */
1086
	interfaces_vips_configure();
1087

    
1088
	/* set up GRE virtual interfaces */
1089
	interfaces_gre_configure(2);
1090

    
1091
	/* set up GIF virtual interfaces */
1092
	interfaces_gif_configure(2);
1093

    
1094
	foreach ($delayed_list as $if => $ifname) {
1095
		if ($g['booting'])
1096
			printf(gettext("Configuring %s interface..."), $ifname);
1097
		if ($g['debug'])
1098
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1099

    
1100
		interface_configure($if, $reload);
1101

    
1102
		if ($g['booting'])
1103
			echo gettext("done.") . "\n";
1104
	}
1105

    
1106
	/* set up BRIDGe virtual interfaces */
1107
	interfaces_bridge_configure(2);
1108

    
1109
	foreach ($bridge_list as $if => $ifname) {
1110
		if ($g['booting'])
1111
			printf(gettext("Configuring %s interface..."), $ifname);
1112
		if($g['debug'])
1113
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1114

    
1115
		interface_configure($if, $reload);
1116

    
1117
		if ($g['booting'])
1118
			echo gettext("done.") . "\n";
1119
	}
1120

    
1121
	/* configure interface groups */
1122
	interfaces_group_setup();
1123

    
1124
	if (!$g['booting']) {
1125
		/* reconfigure static routes (kernel may have deleted them) */
1126
		system_routing_configure();
1127

    
1128
		/* reload IPsec tunnels */
1129
		vpn_ipsec_configure();
1130

    
1131
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1132
		services_dhcpd_configure();
1133

    
1134
		/* restart dnsmasq */
1135
		services_dnsmasq_configure();
1136

    
1137
		/* reload captive portal */
1138
		if (function_exists('captiveportal_init_rules'))
1139
			captiveportal_init_rules();
1140
	}
1141

    
1142
	return 0;
1143
}
1144

    
1145
function interface_reconfigure($interface = "wan", $reloadall = false) {
1146
	interface_bring_down($interface);
1147
	interface_configure($interface, $reloadall);
1148
}
1149

    
1150
function interface_vip_bring_down($vip) {
1151
	global $g;
1152

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

    
1176
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1177
	global $config, $g;
1178

    
1179
	if (!isset($config['interfaces'][$interface]))
1180
		return;
1181

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

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

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

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

    
1310
	if (!empty($track6) && is_array($track6)) {
1311
		if (!function_exists('services_dhcp_configure'))
1312
			require_once('services.inc');
1313
		/* Bring down radvd and dhcp6 on these interfaces */
1314
		services_dhcpd_configure('inet6', $track6);
1315
	}
1316

    
1317
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1318
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1319
//	log_error("Checking for old router states: {$g['tmp_path']}/{$realif}_router = {$old_router}");
1320
	if (!empty($old_router)) {
1321
		log_error("Clearing states to old gateway {$old_router}.");
1322
		mwexec("/sbin/pfctl -i " . escapeshellarg($realif) . " -Fs -G {$old_router}");
1323
	}
1324

    
1325
	/* remove interface up file if it exists */
1326
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1327
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1328
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1329
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1330
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1331
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1332
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1333

    
1334
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1335
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1336
	if (is_array($ifcfg['wireless'])) {
1337
		kill_hostapd($realif);
1338
		mwexec(kill_wpasupplicant($realif));
1339
	}
1340

    
1341
	if ($destroy == true) {
1342
		if (preg_match("/^[a-z0-9]+_vip|^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif))
1343
			pfSense_interface_destroy($realif);
1344
	}
1345

    
1346
	return;
1347
}
1348

    
1349
function interfaces_ptpid_used($ptpid) {
1350
	global $config;
1351

    
1352
	if (is_array($config['ppps']['ppp']))
1353
		foreach ($config['ppps']['ppp'] as & $settings)
1354
			if ($ptpid == $settings['ptpid'])
1355
				return true;
1356

    
1357
	return false;
1358
}
1359

    
1360
function interfaces_ptpid_next() {
1361

    
1362
	$ptpid = 0;
1363
	while(interfaces_ptpid_used($ptpid))
1364
		$ptpid++;
1365

    
1366
	return $ptpid;
1367
}
1368

    
1369
function getMPDCRONSettings($pppif) {
1370
	global $config;
1371

    
1372
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1373
	if (is_array($config['cron']['item'])) {
1374
		foreach ($config['cron']['item'] as $i => $item) {
1375
			if (stripos($item['command'], $cron_cmd_file) !== false)
1376
				return array("ID" => $i, "ITEM" => $item);
1377
		}
1378
	}
1379

    
1380
	return NULL;
1381
}
1382

    
1383
function handle_pppoe_reset($post_array) {
1384
	global $config, $g;
1385

    
1386
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1387
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1388

    
1389
	if (!is_array($config['cron']['item']))
1390
		$config['cron']['item'] = array();
1391

    
1392
	$itemhash = getMPDCRONSettings($pppif);
1393

    
1394
	// reset cron items if necessary and return
1395
	if (empty($post_array['pppoe-reset-type'])) {
1396
		if (isset($itemhash))
1397
			unset($config['cron']['item'][$itemhash['ID']]);
1398
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1399
		return;
1400
	}
1401

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

    
1461
/*
1462
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1463
 * It writes the mpd config file to /var/etc every time the link is opened.
1464
 */
1465
function interface_ppps_configure($interface) {
1466
	global $config, $g;
1467

    
1468
	/* Return for unassigned interfaces. This is a minimum requirement. */
1469
	if (empty($config['interfaces'][$interface]))
1470
		return 0;
1471
	$ifcfg = $config['interfaces'][$interface];
1472
	if (!isset($ifcfg['enable']))
1473
		return 0;
1474

    
1475
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1476
	if(!is_dir("/var/spool/lock")) {
1477
		mkdir("/var/spool/lock", 0777, true);
1478
	}
1479
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1480
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1481
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1482

    
1483
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1484
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1485
			if ($ifcfg['if'] == $ppp['if'])
1486
				break;
1487
		}
1488
	}
1489
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1490
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1491
		return 0;
1492
	}
1493
	$pppif = $ifcfg['if'];
1494
	if ($ppp['type'] == "ppp")
1495
		$type = "modem";
1496
	else
1497
		$type = $ppp['type'];
1498
	$upper_type = strtoupper($ppp['type']);
1499

    
1500
	if($g['booting']) {
1501
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1502
		echo "starting {$pppif} link...";
1503
		// Do not re-configure the interface if we are booting and it's already been started
1504
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1505
			return 0;
1506
	}
1507

    
1508
	$ports = explode(',',$ppp['ports']);
1509
	if ($type != "modem") {
1510
		foreach ($ports as $pid => $port) {
1511
			$ports[$pid] = get_real_interface($port);
1512
			if (empty($ports[$pid]))
1513
				return 0;
1514
		}
1515
	}
1516
	$localips = explode(',',$ppp['localip']);
1517
	$gateways = explode(',',$ppp['gateway']);
1518
	$subnets = explode(',',$ppp['subnet']);
1519

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

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

    
1564
	if (is_array($ports) && count($ports) > 1)
1565
		$multilink = "enable";
1566
	else
1567
		$multilink = "disable";
1568

    
1569
	if ($type == "modem"){
1570
		if (is_ipaddr($ppp['localip']))
1571
			$localip = $ppp['localip'];
1572
		else
1573
			$localip = '0.0.0.0';
1574

    
1575
		if (is_ipaddr($ppp['gateway']))
1576
			$gateway = $ppp['gateway'];
1577
		else
1578
			$gateway = "10.64.64.{$pppid}";
1579
		$ranges = "{$localip}/0 {$gateway}/0";
1580

    
1581
		if (empty($ppp['apnum']))
1582
			$ppp['apnum'] = 1;
1583
	} else
1584
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1585

    
1586
	if (isset($ppp['ondemand']))
1587
		$ondemand = "enable";
1588
	else
1589
		$ondemand = "disable";
1590
	if (!isset($ppp['idletimeout']))
1591
		$ppp['idletimeout'] = 0;
1592

    
1593
	if (empty($ppp['username']) && $type == "modem"){
1594
		$ppp['username'] = "user";
1595
		$ppp['password'] = "none";
1596
	}
1597
	if (empty($ppp['password']) && $type == "modem")
1598
		$passwd = "none";
1599
	else
1600
		$passwd = base64_decode($ppp['password']);
1601

    
1602
	$bandwidths = explode(',',$ppp['bandwidth']);
1603
	$defaultmtu = "1492";
1604
	if (!empty($ifcfg['mtu']))
1605
		$defaultmtu = intval($ifcfg['mtu']);
1606
	$mtus = explode(',',$ppp['mtu']);
1607
	$mrus = explode(',',$ppp['mru']);
1608

    
1609
	if (isset($ppp['mrru']))
1610
		$mrrus = explode(',',$ppp['mrru']);
1611

    
1612
	// Construct the mpd.conf file
1613
	$mpdconf = <<<EOD
1614
startup:
1615
	# configure the console
1616
	set console close
1617
	# configure the web server
1618
	set web close
1619

    
1620
default:
1621
{$ppp['type']}client:
1622
	create bundle static {$interface}
1623
	set bundle enable ipv6cp
1624
	set iface name {$pppif}
1625

    
1626
EOD;
1627
	$setdefaultgw = false;
1628
	$founddefaultgw = false;
1629
	if (is_array($config['gateways']['gateway_item'])) {
1630
		foreach($config['gateways']['gateway_item'] as $gateway) {
1631
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1632
				$setdefaultgw = true;
1633
				break;
1634
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1635
				$founddefaultgw = true;
1636
				break;
1637
			}
1638
		}
1639
	}
1640

    
1641
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1642
		$setdefaultgw = true;
1643
		$mpdconf .= <<<EOD
1644
	set iface route default
1645

    
1646
EOD;
1647
	}
1648
	$mpdconf .= <<<EOD
1649
	set iface {$ondemand} on-demand
1650
	set iface idle {$ppp['idletimeout']}
1651

    
1652
EOD;
1653

    
1654
	if (isset($ppp['ondemand']))
1655
		$mpdconf .= <<<EOD
1656
	set iface addrs 10.10.1.1 10.10.1.2
1657

    
1658
EOD;
1659

    
1660
	if (isset($ppp['tcpmssfix']))
1661
		$tcpmss = "disable";
1662
	else
1663
		$tcpmss = "enable";
1664
		$mpdconf .= <<<EOD
1665
	set iface {$tcpmss} tcpmssfix
1666

    
1667
EOD;
1668

    
1669
	$mpdconf .= <<<EOD
1670
	set iface up-script /usr/local/sbin/ppp-linkup
1671
	set iface down-script /usr/local/sbin/ppp-linkdown
1672
	set ipcp ranges {$ranges}
1673

    
1674
EOD;
1675
	if (isset($ppp['vjcomp']))
1676
		$mpdconf .= <<<EOD
1677
	set ipcp no vjcomp
1678

    
1679
EOD;
1680

    
1681
	if (isset($config['system']['dnsallowoverride']))
1682
		$mpdconf .= <<<EOD
1683
	set ipcp enable req-pri-dns
1684
	set ipcp enable req-sec-dns
1685

    
1686
EOD;
1687
	if (!isset($ppp['verbose_log']))
1688
		$mpdconf .= <<<EOD
1689
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1690

    
1691
EOD;
1692
	foreach($ports as $pid => $port){
1693
		$port = get_real_interface($port);
1694
		$mpdconf .= <<<EOD
1695

    
1696
	create link static {$interface}_link{$pid} {$type}
1697
	set link action bundle {$interface}
1698
	set link {$multilink} multilink
1699
	set link keep-alive 10 60
1700
	set link max-redial 0
1701

    
1702
EOD;
1703
		if (isset($ppp['shortseq']))
1704
			$mpdconf .= <<<EOD
1705
	set link no shortseq
1706

    
1707
EOD;
1708

    
1709
		if (isset($ppp['acfcomp']))
1710
			$mpdconf .= <<<EOD
1711
	set link no acfcomp
1712

    
1713
EOD;
1714

    
1715
		if (isset($ppp['protocomp']))
1716
			$mpdconf .= <<<EOD
1717
	set link no protocomp
1718

    
1719
EOD;
1720

    
1721
		$mpdconf .= <<<EOD
1722
	set link disable chap pap
1723
	set link accept chap pap eap
1724
	set link disable incoming
1725

    
1726
EOD;
1727

    
1728

    
1729
		if (!empty($bandwidths[$pid]))
1730
			$mpdconf .= <<<EOD
1731
	set link bandwidth {$bandwidths[$pid]}
1732

    
1733
EOD;
1734

    
1735
		if (empty($mtus[$pid]))
1736
			$mtus[$pid] = $defaultmtu;
1737
			$mpdconf .= <<<EOD
1738
	set link mtu {$mtus[$pid]}
1739

    
1740
EOD;
1741

    
1742
		if (!empty($mrus[$pid]))
1743
			$mpdconf .= <<<EOD
1744
	set link mru {$mrus[$pid]}
1745

    
1746
EOD;
1747

    
1748
		if (!empty($mrrus[$pid]))
1749
			$mpdconf .= <<<EOD
1750
	set link mrru {$mrrus[$pid]}
1751

    
1752
EOD;
1753

    
1754
		$mpdconf .= <<<EOD
1755
	set auth authname "{$ppp['username']}"
1756
	set auth password {$passwd}
1757

    
1758
EOD;
1759
		if ($type == "modem") {
1760
			$mpdconf .= <<<EOD
1761
	set modem device {$ppp['ports']}
1762
	set modem script DialPeer
1763
	set modem idle-script Ringback
1764
	set modem watch -cd
1765
	set modem var \$DialPrefix "DT"
1766
	set modem var \$Telephone "{$ppp['phone']}"
1767

    
1768
EOD;
1769
		}
1770
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1771
			$mpdconf .= <<<EOD
1772
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1773

    
1774
EOD;
1775
		}
1776
		if (isset($ppp['initstr']) && $type == "modem") {
1777
			$initstr = base64_decode($ppp['initstr']);
1778
			$mpdconf .= <<<EOD
1779
	set modem var \$InitString "{$initstr}"
1780

    
1781
EOD;
1782
		}
1783
		if (isset($ppp['simpin']) && $type == "modem") {
1784
			if($ppp['pin-wait'] == "")
1785
				$ppp['pin-wait'] = 0;
1786
			$mpdconf .= <<<EOD
1787
	set modem var \$SimPin "{$ppp['simpin']}"
1788
	set modem var \$PinWait "{$ppp['pin-wait']}"
1789

    
1790
EOD;
1791
		}
1792
		if (isset($ppp['apn']) && $type == "modem") {
1793
			$mpdconf .= <<<EOD
1794
	set modem var \$APN "{$ppp['apn']}"
1795
	set modem var \$APNum "{$ppp['apnum']}"
1796

    
1797
EOD;
1798
		}
1799
		if ($type == "pppoe") {
1800
			// Send a null service name if none is set.
1801
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1802
			$mpdconf .= <<<EOD
1803
	set pppoe service "{$provider}"
1804

    
1805
EOD;
1806
		}
1807
		if ($type == "pppoe")
1808
			$mpdconf .= <<<EOD
1809
	set pppoe iface {$port}
1810

    
1811
EOD;
1812

    
1813
		if ($type == "pptp" || $type == "l2tp") {
1814
			$mpdconf .= <<<EOD
1815
	set {$type} self {$localips[$pid]}
1816
	set {$type} peer {$gateways[$pid]}
1817

    
1818
EOD;
1819
		}
1820

    
1821
		$mpdconf .= "\topen\n";
1822
	} //end foreach($port)
1823

    
1824

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

    
1840
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1841
	if (isset($ppp['uptime'])) {
1842
		if (!file_exists("/conf/{$pppif}.log")) {
1843
			conf_mount_rw();
1844
			file_put_contents("/conf/{$pppif}.log", '');
1845
			conf_mount_ro();
1846
		}
1847
	} else {
1848
		if (file_exists("/conf/{$pppif}.log")) {
1849
			conf_mount_rw();
1850
			@unlink("/conf/{$pppif}.log");
1851
			conf_mount_ro();
1852
		}
1853
	}
1854

    
1855
	/* clean up old lock files */
1856
	foreach($ports as $port) {
1857
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1858
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1859
	}
1860

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

    
1865
	// Check for PPPoE periodic reset request
1866
	if ($type == "pppoe") {
1867
		if (!empty($ppp['pppoe-reset-type']))
1868
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1869
		else
1870
			interface_setup_pppoe_reset_file($ppp['if']);
1871
	}
1872
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1873
	$i = 0;
1874
	while($i < 10) {
1875
		exec("/sbin/ifconfig " . escapeshellarg($ppp['if']) . " 2>&1", $out, $ret);
1876
		if($ret == 0)
1877
			break;
1878
		sleep(1);
1879
		$i++;
1880
	}
1881

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

    
1900
	return 1;
1901
}
1902

    
1903
function interfaces_carp_setup() {
1904
	global $g, $config;
1905

    
1906
	if (isset($config['system']['developerspew'])) {
1907
		$mt = microtime();
1908
		echo "interfaces_carp_setup() being called $mt\n";
1909
	}
1910

    
1911
	if ($g['booting']) {
1912
		echo gettext("Configuring CARP settings...");
1913
		mute_kernel_msgs();
1914
	}
1915

    
1916
	/* suck in configuration items */
1917
	if ($config['hasync']) {
1918
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1919
		$balancing = $config['hasync']['balancing'];
1920
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1921
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1922
	} else {
1923
		unset($pfsyncinterface);
1924
		unset($balancing);
1925
		unset($pfsyncenabled);
1926
	}
1927

    
1928
	if ($balancing) {
1929
		mwexec("/sbin/sysctl net.inet.carp.arpbalance=1", true);
1930
		mwexec("/sbin/sysctl net.inet.carp.preempt=0", true);
1931
	} else
1932
		mwexec("/sbin/sysctl net.inet.carp.preempt=1", true);
1933

    
1934
	mwexec("sbin/sysctl net.inet.carp.log=1", true);
1935
	if (!empty($pfsyncinterface))
1936
		$carp_sync_int = get_real_interface($pfsyncinterface);
1937
	else
1938
		unset($carp_sync_int);
1939

    
1940
	/* setup pfsync interface */
1941
	if ($carp_sync_int and $pfsyncenabled) {
1942
		if (is_ipaddr($pfsyncpeerip))
1943
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1944
		else
1945
			$syncpeer = "-syncpeer";
1946

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

    
1949
		sleep(1);
1950

    
1951
		/* 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
1952
		 * for existing sessions.
1953
		 */
1954
		log_error("waiting for pfsync...");
1955
		$i = 0;
1956
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1957
			$i++;
1958
			sleep(1);
1959
		}
1960
		log_error("pfsync done in $i seconds.");
1961
		log_error("Configuring CARP settings finalize...");
1962
	} else {
1963
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
1964
	}
1965

    
1966
	if($config['virtualip']['vip'])
1967
		mwexec("/sbin/sysctl net.inet.carp.allow=1", true);
1968
	else
1969
		mwexec("/sbin/sysctl net.inet.carp.allow=0", true);
1970

    
1971
	if ($g['booting']) {
1972
		unmute_kernel_msgs();
1973
		echo gettext("done.") . "\n";
1974
	}
1975
}
1976

    
1977
function interface_proxyarp_configure($interface = "") {
1978
	global $config, $g;
1979
	if(isset($config['system']['developerspew'])) {
1980
		$mt = microtime();
1981
		echo "interface_proxyarp_configure() being called $mt\n";
1982
	}
1983

    
1984
	/* kill any running choparp */
1985
	if (empty($interface))
1986
		killbyname("choparp");
1987
	else {
1988
		$vipif = get_real_interface($interface);
1989
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1990
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1991
	}
1992

    
1993
	$paa = array();
1994
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1995

    
1996
		/* group by interface */
1997
		foreach ($config['virtualip']['vip'] as $vipent) {
1998
			if ($vipent['mode'] === "proxyarp") {
1999
				if ($vipent['interface'])
2000
					$proxyif = $vipent['interface'];
2001
				else
2002
					$proxyif = "wan";
2003

    
2004
				if (!empty($interface) && $interface != $proxyif)
2005
					continue;
2006

    
2007
				if (!is_array($paa[$proxyif]))
2008
					$paa[$proxyif] = array();
2009

    
2010
				$paa[$proxyif][] = $vipent;
2011
			}
2012
		}
2013
	}
2014

    
2015
	if (!empty($interface)) {
2016
		if (is_array($paa[$interface])) {
2017
			$paaifip = get_interface_ip($interface);
2018
			if (!is_ipaddr($paaifip))
2019
				return;
2020
			$args = get_real_interface($interface) . " auto";
2021
			foreach ($paa[$interface] as $paent) {
2022
				if (isset($paent['subnet']))
2023
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2024
				else if (isset($paent['range']))
2025
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2026
			}
2027
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2028
		}
2029
	} else if (count($paa) > 0) {
2030
		foreach ($paa as $paif => $paents)  {
2031
			$paaifip = get_interface_ip($paif);
2032
			if (!is_ipaddr($paaifip))
2033
				continue;
2034
			$args = get_real_interface($paif) . " auto";
2035
			foreach ($paents as $paent) {
2036
				if (isset($paent['subnet']))
2037
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2038
				else if (isset($paent['range']))
2039
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2040
			}
2041
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2042
		}
2043
	}
2044
}
2045

    
2046
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2047
	global $g, $config;
2048

    
2049
	if (is_array($config['virtualip']['vip'])) {
2050
		foreach ($config['virtualip']['vip'] as $vip) {
2051
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2052
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2053
					interface_vip_bring_down($vip);
2054
				else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2055
					interface_vip_bring_down($vip);
2056
			}
2057
		}
2058
	}
2059
}
2060

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

    
2100
function interface_ipalias_configure(&$vip) {
2101
	global $config;
2102

    
2103
	if ($vip['mode'] != "ipalias")
2104
		return;
2105

    
2106
	if ($vip['interface'] != 'lo0' && !isset($config['interfaces'][$vip['interface']]))
2107
		return;
2108

    
2109
	if ($vip['interface'] != 'lo0' && !isset($config['interfaces'][$vip['interface']]['enable']))
2110
		return;
2111

    
2112
	$if = get_real_interface($vip['interface']);
2113
	$af = "inet";
2114
	if(is_ipaddrv6($vip['subnet']))
2115
		$af = "inet6";
2116
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
2117
}
2118

    
2119
function interface_reload_carps($cif) {
2120
	global $config;
2121

    
2122
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2123
	if (empty($carpifs))
2124
		return;
2125

    
2126
	$carps = explode(" ", $carpifs);
2127
	if(is_array($config['virtualip']['vip'])) {
2128
		$viparr = &$config['virtualip']['vip'];
2129
		foreach ($viparr as $vip) {
2130
			if (in_array($vip['carpif'], $carps)) {
2131
				switch ($vip['mode']) {
2132
				case "carp":
2133
					interface_vip_bring_down($vip);
2134
					sleep(1);
2135
					interface_carp_configure($vip);
2136
					break;
2137
				case "ipalias":
2138
					interface_vip_bring_down($vip);
2139
					sleep(1);
2140
					interface_ipalias_configure($vip);
2141
					break;
2142
				}
2143
			}
2144
		}
2145
	}
2146
}
2147

    
2148
function interface_carp_configure(&$vip) {
2149
	global $config, $g;
2150
	if(isset($config['system']['developerspew'])) {
2151
		$mt = microtime();
2152
		echo "interface_carp_configure() being called $mt\n";
2153
	}
2154

    
2155
	if ($vip['mode'] != "carp")
2156
		return;
2157

    
2158
	/*
2159
	 * ensure the interface containing the VIP really exists
2160
	 * prevents a panic if the interface is missing or invalid
2161
	 */
2162
	$realif = get_real_interface($vip['interface']);
2163
	if (!does_interface_exist($realif)) {
2164
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2165
		return;
2166
	}
2167

    
2168
	if(is_ipaddrv4($vip['subnet'])) {
2169
		/* Ensure CARP IP really exists prior to loading up. */
2170
		$ww_subnet_ip = find_interface_ip($realif);
2171
		$ww_subnet_bits = find_interface_subnet($realif);
2172
		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'])) {
2173
			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", "");
2174
			return;
2175
		}
2176
	}
2177
	if(is_ipaddrv6($vip['subnet'])) {
2178
		/* Ensure CARP IP really exists prior to loading up. */
2179
		$ww_subnet_ip = find_interface_ipv6($realif);
2180
		$ww_subnet_bits = find_interface_subnetv6($realif);
2181
		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'])) {
2182
			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", "");
2183
			return;
2184
		}
2185
	}
2186

    
2187
	// set the vip interface to the vhid
2188
	$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
2189

    
2190
	/* create the carp interface and setup */
2191
	if (does_interface_exist($vipif)) {
2192
		pfSense_interface_flags($vipif, -IFF_UP);
2193
	} else {
2194
		$carpif = pfSense_interface_create("carp");
2195
		pfSense_interface_rename($carpif, $vipif);
2196
		pfSense_ngctl_name("{$carpif}:", $vipif);
2197
	}
2198

    
2199
	/* invalidate interface cache */
2200
	get_interface_arr(true);
2201

    
2202
	$vip_password = $vip['password'];
2203
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2204
	if ($vip['password'] != "")
2205
		$password = " pass {$vip_password}";
2206

    
2207
	$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2208
	$advbase = "";
2209
	if (!empty($vip['advbase']))
2210
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2211

    
2212
	if(is_ipaddrv4($vip['subnet'])) {
2213
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2214
		mwexec("/sbin/ifconfig {$vipif} {$vip['subnet']}/{$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2215
	}
2216
	if(is_ipaddrv6($vip['subnet'])) {
2217
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2218
		mwexec("/sbin/ifconfig {$vipif} inet6 {$vip['subnet']} prefixlen {$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2219
	}
2220

    
2221
	interfaces_bring_up($vipif);
2222

    
2223
	return $vipif;
2224
}
2225

    
2226
function interface_wireless_clone($realif, $wlcfg) {
2227
	global $config, $g;
2228
	/*   Check to see if interface has been cloned as of yet.
2229
	 *   If it has not been cloned then go ahead and clone it.
2230
	 */
2231
	$needs_clone = false;
2232
	if(is_array($wlcfg['wireless']))
2233
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2234
	else
2235
		$wlcfg_mode = $wlcfg['mode'];
2236
	switch($wlcfg_mode) {
2237
	case "hostap":
2238
		$mode = "wlanmode hostap";
2239
		break;
2240
	case "adhoc":
2241
		$mode = "wlanmode adhoc";
2242
		break;
2243
	default:
2244
		$mode = "";
2245
		break;
2246
	}
2247
	$baseif = interface_get_wireless_base($wlcfg['if']);
2248
	if(does_interface_exist($realif)) {
2249
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2250
		$ifconfig_str = implode($output);
2251
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
2252
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2253
			$needs_clone = true;
2254
		}
2255
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
2256
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2257
			$needs_clone = true;
2258
		}
2259
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2260
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2261
			$needs_clone = true;
2262
		}
2263
	} else {
2264
		$needs_clone = true;
2265
	}
2266

    
2267
	if($needs_clone == true) {
2268
		/* remove previous instance if it exists */
2269
		if(does_interface_exist($realif))
2270
			pfSense_interface_destroy($realif);
2271

    
2272
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2273
		// Create the new wlan interface. FreeBSD returns the new interface name.
2274
		// example:  wlan2
2275
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2276
		if($ret <> 0) {
2277
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2278
			return false;
2279
		}
2280
		$newif = trim($out[0]);
2281
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2282
		pfSense_interface_rename($newif, $realif);
2283
		// FIXME: not sure what ngctl is for. Doesn't work.
2284
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
2285
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2286
	}
2287
	return true;
2288
}
2289

    
2290
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2291
	global $config, $g;
2292

    
2293
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2294
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2295
				 'regdomain', 'regcountry', 'reglocation');
2296

    
2297
	if(!is_interface_wireless($ifcfg['if']))
2298
		return;
2299

    
2300
	$baseif = interface_get_wireless_base($ifcfg['if']);
2301

    
2302
	// Sync shared settings for assigned clones
2303
	$iflist = get_configured_interface_list(false, true);
2304
	foreach ($iflist as $if) {
2305
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2306
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2307
				foreach ($shared_settings as $setting) {
2308
					if ($sync_changes) {
2309
						if (isset($ifcfg['wireless'][$setting]))
2310
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2311
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2312
							unset($config['interfaces'][$if]['wireless'][$setting]);
2313
					} else {
2314
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2315
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2316
						else if (isset($ifcfg['wireless'][$setting]))
2317
							unset($ifcfg['wireless'][$setting]);
2318
					}
2319
				}
2320
				if (!$sync_changes)
2321
					break;
2322
			}
2323
		}
2324
	}
2325

    
2326
	// Read or write settings at shared area
2327
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2328
		foreach ($shared_settings as $setting) {
2329
			if ($sync_changes) {
2330
				if (isset($ifcfg['wireless'][$setting]))
2331
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2332
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2333
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2334
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2335
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2336
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2337
				else if (isset($ifcfg['wireless'][$setting]))
2338
					unset($ifcfg['wireless'][$setting]);
2339
			}
2340
		}
2341
	}
2342

    
2343
	// Sync the mode on the clone creation page with the configured mode on the interface
2344
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2345
		foreach ($config['wireless']['clone'] as &$clone) {
2346
			if ($clone['cloneif'] == $ifcfg['if']) {
2347
				if ($sync_changes) {
2348
					$clone['mode'] = $ifcfg['wireless']['mode'];
2349
				} else {
2350
					$ifcfg['wireless']['mode'] = $clone['mode'];
2351
				}
2352
				break;
2353
			}
2354
		}
2355
		unset($clone);
2356
	}
2357
}
2358

    
2359
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2360
	global $config, $g;
2361

    
2362
	/*    open up a shell script that will be used to output the commands.
2363
	 *    since wireless is changing a lot, these series of commands are fragile
2364
	 *    and will sometimes need to be verified by a operator by executing the command
2365
	 *    and returning the output of the command to the developers for inspection.  please
2366
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2367
	 */
2368

    
2369
	// Remove script file
2370
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2371

    
2372
	// Clone wireless nic if needed.
2373
	interface_wireless_clone($if, $wl);
2374

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

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

    
2382
	/* set values for /path/program */
2383
	$hostapd = "/usr/sbin/hostapd";
2384
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2385
	$ifconfig = "/sbin/ifconfig";
2386
	$sysctl = "/sbin/sysctl";
2387
	$killall = "/usr/bin/killall";
2388

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

    
2391
	$wlcmd = array();
2392
	$wl_sysctl = array();
2393
	/* Make sure it's up */
2394
	$wlcmd[] = "up";
2395
	/* Set a/b/g standard */
2396
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2397
	$wlcmd[] = "mode " . escapeshellarg($standard);
2398

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

    
2404
	/* Set ssid */
2405
	if($wlcfg['ssid'])
2406
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2407

    
2408
	/* Set 802.11g protection mode */
2409
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2410

    
2411
	/* set wireless channel value */
2412
	if(isset($wlcfg['channel'])) {
2413
		if($wlcfg['channel'] == "0") {
2414
			$wlcmd[] = "channel any";
2415
		} else {
2416
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2417
		}
2418
	}
2419

    
2420
	/* Set antenna diversity value */
2421
	if(isset($wlcfg['diversity']))
2422
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2423

    
2424
	/* Set txantenna value */
2425
	if(isset($wlcfg['txantenna']))
2426
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2427

    
2428
	/* Set rxantenna value */
2429
	if(isset($wlcfg['rxantenna']))
2430
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2431

    
2432
	/* set Distance value */
2433
	if($wlcfg['distance'])
2434
		$distance = escapeshellarg($wlcfg['distance']);
2435

    
2436
	/* Set wireless hostap mode */
2437
	if ($wlcfg['mode'] == "hostap") {
2438
		$wlcmd[] = "mediaopt hostap";
2439
	} else {
2440
		$wlcmd[] = "-mediaopt hostap";
2441
	}
2442

    
2443
	/* Set wireless adhoc mode */
2444
	if ($wlcfg['mode'] == "adhoc") {
2445
		$wlcmd[] = "mediaopt adhoc";
2446
	} else {
2447
		$wlcmd[] = "-mediaopt adhoc";
2448
	}
2449

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

    
2452
	/* handle hide ssid option */
2453
	if(isset($wlcfg['hidessid']['enable'])) {
2454
		$wlcmd[] = "hidessid";
2455
	} else {
2456
		$wlcmd[] = "-hidessid";
2457
	}
2458

    
2459
	/* handle pureg (802.11g) only option */
2460
	if(isset($wlcfg['pureg']['enable'])) {
2461
		$wlcmd[] = "mode 11g pureg";
2462
	} else {
2463
		$wlcmd[] = "-pureg";
2464
	}
2465

    
2466
	/* handle puren (802.11n) only option */
2467
	if(isset($wlcfg['puren']['enable'])) {
2468
		$wlcmd[] = "puren";
2469
	} else {
2470
		$wlcmd[] = "-puren";
2471
	}
2472

    
2473
	/* enable apbridge option */
2474
	if(isset($wlcfg['apbridge']['enable'])) {
2475
		$wlcmd[] = "apbridge";
2476
	} else {
2477
		$wlcmd[] = "-apbridge";
2478
	}
2479

    
2480
	/* handle turbo option */
2481
	if(isset($wlcfg['turbo']['enable'])) {
2482
		$wlcmd[] = "mediaopt turbo";
2483
	} else {
2484
		$wlcmd[] = "-mediaopt turbo";
2485
	}
2486

    
2487
	/* handle txpower setting */
2488
	/* if($wlcfg['txpower'] <> "")
2489
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2490
	*/
2491
	/* handle wme option */
2492
	if(isset($wlcfg['wme']['enable'])) {
2493
		$wlcmd[] = "wme";
2494
	} else {
2495
		$wlcmd[] = "-wme";
2496
	}
2497

    
2498
	/* set up wep if enabled */
2499
	$wepset = "";
2500
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2501
		switch($wlcfg['wpa']['auth_algs']) {
2502
			case "1":
2503
				$wepset .= "authmode open wepmode on ";
2504
				break;
2505
			case "2":
2506
				$wepset .= "authmode shared wepmode on ";
2507
				break;
2508
			case "3":
2509
				$wepset .= "authmode mixed wepmode on ";
2510
		}
2511
		$i = 1;
2512
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2513
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2514
			if (isset($wepkey['txkey'])) {
2515
				$wlcmd[] = "weptxkey {$i} ";
2516
			}
2517
			$i++;
2518
		}
2519
		$wlcmd[] = $wepset;
2520
	} else {
2521
		$wlcmd[] = "authmode open wepmode off ";
2522
	}
2523

    
2524
	kill_hostapd($if);
2525
	mwexec(kill_wpasupplicant("{$if}"));
2526

    
2527
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2528
	conf_mount_rw();
2529

    
2530
	switch ($wlcfg['mode']) {
2531
	case 'bss':
2532
		if (isset($wlcfg['wpa']['enable'])) {
2533
			$wpa .= <<<EOD
2534
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2535
ctrl_interface_group=0
2536
ap_scan=1
2537
#fast_reauth=1
2538
network={
2539
ssid="{$wlcfg['ssid']}"
2540
scan_ssid=1
2541
priority=5
2542
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2543
psk="{$wlcfg['wpa']['passphrase']}"
2544
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2545
group={$wlcfg['wpa']['wpa_pairwise']}
2546
}
2547
EOD;
2548

    
2549
			@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2550
			unset($wpa);
2551
		}
2552
		break;
2553
	case 'hostap':
2554
		if (!empty($wlcfg['wpa']['passphrase']))
2555
			$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2556
		else
2557
			$wpa_passphrase = "";
2558
		if (isset($wlcfg['wpa']['enable'])) {
2559
			$wpa .= <<<EOD
2560
interface={$if}
2561
driver=bsd
2562
logger_syslog=-1
2563
logger_syslog_level=0
2564
logger_stdout=-1
2565
logger_stdout_level=0
2566
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2567
ctrl_interface={$g['varrun_path']}/hostapd
2568
ctrl_interface_group=wheel
2569
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2570
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2571
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2572
ssid={$wlcfg['ssid']}
2573
debug={$wlcfg['wpa']['debug_mode']}
2574
auth_algs={$wlcfg['wpa']['auth_algs']}
2575
wpa={$wlcfg['wpa']['wpa_mode']}
2576
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2577
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2578
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2579
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2580
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2581
{$wpa_passphrase}
2582

    
2583
EOD;
2584

    
2585
			if (isset($wlcfg['wpa']['rsn_preauth'])) {
2586
				$wpa .= <<<EOD
2587
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2588
rsn_preauth=1
2589
rsn_preauth_interfaces={$if}
2590

    
2591
EOD;
2592
			}
2593
			if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2594
				$wpa .= "ieee8021x=1\n";
2595

    
2596
			if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2597
				$auth_server_port = "1812";
2598
				if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port']))
2599
					$auth_server_port = intval($wlcfg['auth_server_port']);
2600
				$wpa .= <<<EOD
2601

    
2602
auth_server_addr={$wlcfg['auth_server_addr']}
2603
auth_server_port={$auth_server_port}
2604
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2605

    
2606
EOD;
2607
				if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2608
					$auth_server_port2 = "1812";
2609
					if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2']))
2610
						$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2611

    
2612
					$wpa .= <<<EOD
2613
auth_server_addr={$wlcfg['auth_server_addr2']}
2614
auth_server_port={$auth_server_port2}
2615
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2616

    
2617
EOD;
2618
					}
2619
				}
2620
			}
2621

    
2622
			@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2623
			unset($wpa);
2624
		}
2625
		break;
2626
	}
2627

    
2628
	/*
2629
	 *    all variables are set, lets start up everything
2630
	 */
2631

    
2632
	$baseif = interface_get_wireless_base($if);
2633
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2634
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2635

    
2636
	/* set sysctls for the wireless interface */
2637
	if (!empty($wl_sysctl)) {
2638
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2639
		foreach ($wl_sysctl as $wl_sysctl_line) {
2640
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2641
		}
2642
	}
2643

    
2644
	/* set ack timers according to users preference (if he/she has any) */
2645
	if($distance) {
2646
		fwrite($fd_set, "# Enable ATH distance settings\n");
2647
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2648
	}
2649

    
2650
	if (isset($wlcfg['wpa']['enable'])) {
2651
		if ($wlcfg['mode'] == "bss") {
2652
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2653
		}
2654
		if ($wlcfg['mode'] == "hostap") {
2655
			/* add line to script to restore old mac to make hostapd happy */
2656
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2657
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2658
				if (is_macaddr($if_oldmac))
2659
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2660
						" link " . escapeshellarg($if_oldmac) . "\n");
2661
			}
2662

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

    
2665
			/* add line to script to restore spoofed mac after running hostapd */
2666
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2667
				if ($wl['spoofmac'])
2668
					$if_curmac = $wl['spoofmac'];
2669
				else
2670
					$if_curmac = get_interface_mac($if);
2671
				if (is_macaddr($if_curmac))
2672
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2673
						" link " . escapeshellarg($if_curmac) . "\n");
2674
			}
2675
		}
2676
	}
2677

    
2678
	fclose($fd_set);
2679
	conf_mount_ro();
2680

    
2681
	/* Making sure regulatory settings have actually changed
2682
	 * before applying, because changing them requires bringing
2683
	 * down all wireless networks on the interface. */
2684
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2685
	$ifconfig_str = implode($output);
2686
	unset($output);
2687
	$reg_changing = false;
2688

    
2689
	/* special case for the debug country code */
2690
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2691
		$reg_changing = true;
2692
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2693
		$reg_changing = true;
2694
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2695
		$reg_changing = true;
2696
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2697
		$reg_changing = true;
2698
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2699
		$reg_changing = true;
2700

    
2701
	if ($reg_changing) {
2702
		/* set regulatory domain */
2703
		if($wlcfg['regdomain'])
2704
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2705

    
2706
		/* set country */
2707
		if($wlcfg['regcountry'])
2708
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2709

    
2710
		/* set location */
2711
		if($wlcfg['reglocation'])
2712
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2713

    
2714
		$wlregcmd_args = implode(" ", $wlregcmd);
2715

    
2716
		/* build a complete list of the wireless clones for this interface */
2717
		$clone_list = array();
2718
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2719
			$clone_list[] = interface_get_wireless_clone($baseif);
2720
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2721
			foreach ($config['wireless']['clone'] as $clone) {
2722
				if ($clone['if'] == $baseif)
2723
					$clone_list[] = $clone['cloneif'];
2724
			}
2725
		}
2726

    
2727
		/* find which clones are up and bring them down */
2728
		$clones_up = array();
2729
		foreach ($clone_list as $clone_if) {
2730
			$clone_status = pfSense_get_interface_addresses($clone_if);
2731
			if ($clone_status['status'] == 'up') {
2732
				$clones_up[] = $clone_if;
2733
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2734
			}
2735
		}
2736

    
2737
		/* apply the regulatory settings */
2738
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2739

    
2740
		/* bring the clones back up that were previously up */
2741
		foreach ($clones_up as $clone_if) {
2742
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2743

    
2744
			/*
2745
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2746
			 * is in infrastructure mode, and WPA is enabled.
2747
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2748
			 */
2749
			if ($clone_if != $if) {
2750
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2751
				if ( !empty($friendly_if)
2752
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2753
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2754
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2755
				}
2756
			}
2757
		}
2758
	}
2759

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

    
2764
	/* configure wireless */
2765
	$wlcmd_args = implode(" ", $wlcmd);
2766
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2767
	unset($wlcmd_args, $wlcmd);
2768

    
2769

    
2770
	sleep(1);
2771
	/* execute hostapd and wpa_supplicant if required in shell */
2772
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2773

    
2774
	return 0;
2775

    
2776
}
2777

    
2778
function kill_hostapd($interface) {
2779
	global $g;
2780

    
2781
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2782
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2783
}
2784

    
2785
function kill_wpasupplicant($interface) {
2786
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2787
}
2788

    
2789
function find_dhclient_process($interface) {
2790
	if ($interface)
2791
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2792
	else
2793
		$pid = 0;
2794

    
2795
	return intval($pid);
2796
}
2797

    
2798
function find_dhcp6c_process($interface) {
2799
	global $g;
2800

    
2801
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid"))
2802
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2803
	else
2804
		return(false);
2805

    
2806
	return intval($pid);
2807
}
2808

    
2809
function interface_vlan_mtu_configured($realhwif, $mtu) {
2810
	global $config;
2811

    
2812
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
2813
		foreach ($config['vlans']['vlan'] as $vlan) {
2814
			if ($vlan['if'] != $realhwif)
2815
				continue;
2816
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2817
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
2818
				if (intval($config['interfaces'][$assignedport]['mtu'])> $mtu)
2819
					$mtu = $portmtu;
2820
			}
2821
		}
2822
	}
2823

    
2824
	return $mtu;
2825
}
2826

    
2827
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2828
	global $config;
2829

    
2830
	if (!is_array($vlanifs))
2831
		return;
2832

    
2833
	/* All vlans need to use the same mtu value as their parent. */
2834
	foreach ($vlanifs as $vlan) {
2835
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2836
		if (!empty($assignedport)) {
2837
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
2838
				/*
2839
				* XXX: This is really never going to happen just keep the code for safety and readbility.
2840
				* It never happens since interface_vlan_mtu_configured finds the biggest mtu on vlans.
2841
				* Also if it has a lower mtu configured just respect user choice.
2842
				*/
2843
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2844
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2845
			} else {
2846
				if (get_interface_mtu($vlan['vlanif']) != $mtu)
2847
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2848
			}
2849
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2850
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
2851
	}
2852
}
2853

    
2854
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2855
	global $config, $g;
2856
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2857
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2858

    
2859
	$wancfg = $config['interfaces'][$interface];
2860

    
2861
	if (!isset($wancfg['enable']))
2862
		return;
2863

    
2864
	$realif = get_real_interface($interface);
2865
	$realhwif_array = get_parent_interface($interface);
2866
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2867
	$realhwif = $realhwif_array[0];
2868

    
2869
	if (!does_interface_exist($realif)) {
2870
		$matches = array();
2871
		if (preg_match('/^(.*)_vlan([0-9]+)$/', $realif, $matches))
2872
			if (is_array($config['vlans']['vlan']))
2873
				foreach ($config['vlans']['vlan'] as $vlan)
2874
					if ($vlan['if'] == $matches[1] && $vlan['tag'] == $matches[2]) {
2875
						interface_vlan_configure($vlan);
2876
						break;
2877
					}
2878
		unset($matches);
2879
	}
2880

    
2881
	/* Disable Accepting router advertisements unless specifically requested */
2882
	if ($g['debug'])
2883
		log_error("Deny router advertisements for interface {$interface}");
2884
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2885

    
2886
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2887
		/* remove all IPv4 and IPv6 addresses */
2888
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2889
		if (is_array($tmpifaces)) {
2890
			foreach ($tmpifaces as $tmpiface) {
2891
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
2892
					if (!is_linklocal($tmpiface))
2893
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2894
				} else {
2895
					if (is_subnetv4($tmpiface)) {
2896
						$tmpip = explode('/', $tmpiface);
2897
						$tmpip = $tmpip[0];
2898
					} else
2899
						$tmpip = $tmpiface;
2900
					pfSense_interface_deladdress($realif, $tmpip);
2901
				}
2902
			}
2903
		}
2904

    
2905
		/* only bring down the interface when both v4 and v6 are set to NONE */
2906
		if(empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
2907
			interface_bring_down($interface);
2908
		}
2909
	}
2910

    
2911
	/* wireless configuration? */
2912
	if (is_array($wancfg['wireless']))
2913
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2914

    
2915
	$mac = get_interface_mac($realhwif);
2916
	/*
2917
	 * Don't try to reapply the spoofed MAC if it's already applied.
2918
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2919
	 * the interface config again, which attempts to spoof the MAC again,
2920
	 * which cycles the link again...
2921
	 */
2922
	if (!empty($wancfg['spoofmac']) && ($wancfg['spoofmac'] != $mac)) {
2923
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2924
			" link " . escapeshellarg($wancfg['spoofmac']));
2925

    
2926
		/*
2927
		 * All vlans need to spoof their parent mac address, too.  see
2928
		 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2929
		 */
2930
		if (is_array($config['vlans']['vlan'])) {
2931
			foreach ($config['vlans']['vlan'] as $vlan) {
2932
				if ($vlan['if'] == $realhwif)
2933
					mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2934
					" link " . escapeshellarg($wancfg['spoofmac']));
2935
			}
2936
		}
2937
	}  else {
2938

    
2939
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2940
			/*   this is not a valid mac address.  generate a
2941
			 *   temporary mac address so the machine can get online.
2942
			 */
2943
			echo gettext("Generating new MAC address.");
2944
			$random_mac = generate_random_mac_address();
2945
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2946
				" link " . escapeshellarg($random_mac));
2947
			$wancfg['spoofmac'] = $random_mac;
2948
			write_config();
2949
			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");
2950
		}
2951
	}
2952

    
2953
	/* media */
2954
	if (!empty($wancfg['media']) || !empty($wancfg['mediaopt'])) {
2955
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2956
		if ($wancfg['media'])
2957
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2958
		if ($wancfg['mediaopt'])
2959
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2960
		mwexec($cmd);
2961
	}
2962
	$options = pfSense_get_interface_addresses($realhwif);
2963

    
2964
	/* skip vlans for checksumming and polling */
2965
	if (!stristr($realif, "_vlan") && is_array($options)) {
2966
		$flags_on = 0;
2967
		$flags_off = 0;
2968
		if(isset($config['system']['disablechecksumoffloading'])) {
2969
			if (isset($options['encaps']['txcsum']))
2970
				$flags_off |= IFCAP_TXCSUM;
2971
			if (isset($options['encaps']['rxcsum']))
2972
				$flags_off |= IFCAP_RXCSUM;
2973
		} else {
2974
			if (isset($options['caps']['txcsum']))
2975
				$flags_on |= IFCAP_TXCSUM;
2976
			if (isset($options['caps']['rxcsum']))
2977
				$flags_on |= IFCAP_RXCSUM;
2978
		}
2979

    
2980
		if(isset($config['system']['disablesegmentationoffloading']))
2981
			$flags_off |= IFCAP_TSO;
2982
		else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6']))
2983
			$flags_on |= IFCAP_TSO;
2984

    
2985
		if(isset($config['system']['disablelargereceiveoffloading']))
2986
			$flags_off |= IFCAP_LRO;
2987
		else if (isset($options['caps']['lro']))
2988
			$flags_on |= IFCAP_LRO;
2989

    
2990
		/* if the NIC supports polling *AND* it is enabled in the GUI */
2991
		if (!isset($config['system']['polling']))
2992
			$flags_off |= IFCAP_POLLING;
2993
		else if (isset($options['caps']['polling']))
2994
			$flags_on |= IFCAP_POLLING;
2995

    
2996
		pfSense_interface_capabilities($realhwif, -$flags_off);
2997
		pfSense_interface_capabilities($realhwif, $flags_on);
2998
	}
2999

    
3000
	/* invalidate interface/ip/sn cache */
3001
	get_interface_arr(true);
3002
	unset($interface_ip_arr_cache[$realif]);
3003
	unset($interface_sn_arr_cache[$realif]);
3004
	unset($interface_ipv6_arr_cache[$realif]);
3005
	unset($interface_snv6_arr_cache[$realif]);
3006

    
3007
	$tunnelif = substr($realif, 0, 3);
3008
	switch ($wancfg['ipaddr']) {
3009
		case 'dhcp':
3010
			interface_dhcp_configure($interface);
3011
			break;
3012
		case 'pppoe':
3013
		case 'l2tp':
3014
		case 'pptp':
3015
		case 'ppp':
3016
			interface_ppps_configure($interface);
3017
			break;
3018
		default:
3019
			if ($tunnelif == "gre") {
3020
				if (is_array($config['gres']['gre'])) {
3021
					foreach ($config['gres']['gre'] as $gre)
3022
						if ($gre['greif'] == $realif)
3023
							interface_gre_configure($gre);
3024
				}
3025
			} else if ($tunnelif == "gif") {
3026
				if (is_array($config['gifs']['gif'])) {
3027
					foreach ($config['gifs']['gif'] as $gif)
3028
						if($gif['gifif'] == $realif)
3029
							interface_gif_configure($gif);
3030
				}
3031
			} else if (substr($realif, 0, 4) == "ovpn") {
3032
				/* XXX: Should be done anything?! */
3033
			} else if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3034
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3035
			}
3036
			break;
3037
	}
3038

    
3039
	switch ($wancfg['ipaddrv6']) {
3040
		case 'slaac':
3041
		case 'dhcp6':
3042
			interface_dhcpv6_configure($interface, $wancfg);
3043
			break;
3044
		case '6rd':
3045
			interface_6rd_configure($interface, $wancfg);
3046
			break;
3047
		case '6to4':
3048
			interface_6to4_configure($interface, $wancfg);
3049
			break;
3050
		case 'track6':
3051
			interface_track6_configure($interface, $wancfg, $linkupevent);
3052
			break;
3053
		default:
3054
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3055
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3056
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3057
					// FIXME: Add IPv6 Support to the pfSense module
3058
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3059
				}
3060
			}
3061
			break;
3062
	}
3063

    
3064
	if (!empty($wancfg['mtu'])) {
3065
		if (stristr($realif, "_vlan")) {
3066
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3067
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
3068
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3069
			else 
3070
				$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
3071

    
3072
			if ($wancfg['mtu'] > $parentmtu) {
3073
				if (get_interface_mtu($realhwif) != $wancfg['mtu'])
3074
					pfSense_interface_mtu($realhwif, $wancfg['mtu']);
3075

    
3076
				/* All vlans need to use the same mtu value as their parent. */
3077
				interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $wancfg['mtu']);
3078
			} else
3079
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3080
		} else {
3081
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3082
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3083

    
3084
			/* This case is needed when the parent of vlans is being configured */
3085
			interface_vlan_adapt_mtu(link_interface_to_vlans($realif), $wancfg['mtu']);
3086
		}
3087
		/* XXX: What about gre/gif/lagg/.. ? */
3088
	}
3089

    
3090
	if (does_interface_exist($wancfg['if']))
3091
		interfaces_bring_up($wancfg['if']);
3092

    
3093
	interface_netgraph_needed($interface);
3094

    
3095
	if (!$g['booting']) {
3096
		link_interface_to_vips($interface, "update");
3097

    
3098
		unset($gre);
3099
		$gre = link_interface_to_gre($interface);
3100
		if (!empty($gre))
3101
			array_walk($gre, 'interface_gre_configure');
3102

    
3103
		unset($gif);
3104
		$gif = link_interface_to_gif($interface);
3105
		if (!empty($gif))
3106
			array_walk($gif, 'interface_gif_configure');
3107

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

    
3115
		$grouptmp = link_interface_to_group($interface);
3116
		if (!empty($grouptmp))
3117
			array_walk($grouptmp, 'interface_group_add_member');
3118

    
3119
		if ($interface == "lan")
3120
			/* make new hosts file */
3121
			system_hosts_generate();
3122

    
3123
		if ($reloadall == true) {
3124

    
3125
			/* reconfigure static routes (kernel may have deleted them) */
3126
			system_routing_configure($interface);
3127

    
3128
			/* reload ipsec tunnels */
3129
			vpn_ipsec_configure();
3130

    
3131
			/* restart dnsmasq */
3132
			services_dnsmasq_configure();
3133

    
3134
			/* update dyndns */
3135
			send_event("service reload dyndns {$interface}");
3136

    
3137
			/* reload captive portal */
3138
			captiveportal_init_rules();
3139
		}
3140
	}
3141

    
3142
	interfaces_staticarp_configure($interface);
3143
	return 0;
3144
}
3145

    
3146
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3147
	global $config, $g;
3148

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

    
3152
	if (!isset($wancfg['enable']))
3153
		return;
3154

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

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

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

    
3174
	switch($trackcfg['ipaddrv6']) {
3175
	case "6to4":
3176
		if ($g['debug'])
3177
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3178
		interface_track6_6to4_configure($interface, $wancfg);
3179
		break;
3180
	case "6rd":
3181
		if ($g['debug'])
3182
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3183
		interface_track6_6rd_configure($interface, $wancfg);
3184
		break;
3185
	case "dhcp6":
3186
		if ($linkupevent == true) {
3187
			/* 
3188
			 * NOTE: Usually come here from rc.linkup calling so just call directly intead of generating event
3189
			 *      Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3190
			 *
3191
			 * XXX: Probably DHCPv6 client should handle this autmagically itself?
3192
			 */
3193
			$parentrealif = get_real_interface($wancfg['track6-interface']);
3194
			$pidv6 = find_dhcp6c_process($parentrealif);
3195
			if($pidv6)
3196
				posix_kill($pidv6, SIGHUP);
3197
		}
3198
		break;
3199
	}
3200

    
3201
	if (!$g['booting'] && $linkupevent == false) {
3202
		if (!function_exists('services_dhcpd_configure'))
3203
			require_once("services.inc");
3204

    
3205
		services_dhcpd_configure("inet6");
3206
	}
3207

    
3208
	return 0;
3209
}
3210

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

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

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

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

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

    
3236
	/* create the long prefix notation for math, save the prefix length */
3237
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3238
	$rd6prefixlen = $rd6prefix[1];
3239
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3240

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

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

    
3249
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3250
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3251
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3252
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3253
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3254
	/* fill the rest out with zeros */
3255
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);;
3256

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

    
3260
	$lanif = get_real_interface($interface);
3261
	$oip = find_interface_ipv6($lanif);
3262
	if (is_ipaddrv6($oip))
3263
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3264
	unset($interface_ipv6_arr_cache[$lanif]);
3265
	unset($interface_snv6_arr_cache[$lanif]);
3266
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3267
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3268

    
3269
	return 0;
3270
}
3271

    
3272
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3273
	global $config, $g;
3274
	global $interface_ipv6_arr_cache;
3275
	global $interface_snv6_arr_cache;
3276

    
3277
	if (!is_array($lancfg))
3278
		return;
3279

    
3280
	/* If the interface is not configured via another, exit */
3281
	if (empty($lancfg['track6-interface']))
3282
		return;
3283

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

    
3290
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3291
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3292
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3293
		return;
3294
	}
3295
	$hexwanv4 = return_hex_ipv4($ip4address);
3296

    
3297
	/* create the long prefix notation for math, save the prefix length */
3298
	$sixto4prefix = "2002::";
3299
	$sixto4prefixlen = 16;
3300
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3301

    
3302
	/* binary presentation of the prefix for all 128 bits. */
3303
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3304

    
3305
	/* just save the left prefix length bits */
3306
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3307
	/* add the v4 address */
3308
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3309
	/* add the custom prefix id */
3310
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3311
	/* fill the rest out with zeros */
3312
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);;
3313

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

    
3317
	$lanif = get_real_interface($interface);
3318
	$oip = find_interface_ipv6($lanif);
3319
	if (is_ipaddrv6($oip))
3320
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3321
	unset($interface_ipv6_arr_cache[$lanif]);
3322
	unset($interface_snv6_arr_cache[$lanif]);
3323
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3324
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3325

    
3326
	return 0;
3327
}
3328

    
3329
function interface_6rd_configure($interface = "wan", $wancfg) {
3330
	global $config, $g;
3331

    
3332
	/* because this is a tunnel interface we can only function
3333
	 *	with a public IPv4 address on the interface */
3334

    
3335
	if (!is_array($wancfg))
3336
		return;
3337

    
3338
	$wanif = get_real_interface($interface);
3339
	$ip4address = find_interface_ip($wanif);
3340
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3341
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3342
		return false;
3343
	}
3344
	$hexwanv4 = return_hex_ipv4($ip4address);
3345

    
3346
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3347
		$wancfg['prefix-6rd-v4plen'] = 0;
3348

    
3349
	/* create the long prefix notation for math, save the prefix length */
3350
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3351
	$rd6prefixlen = $rd6prefix[1];
3352
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3353

    
3354
	/* binary presentation of the prefix for all 128 bits. */
3355
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3356

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

    
3364
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3365
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3366

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

    
3369
	/* XXX: need to extend to support variable prefix size for v4 */
3370
	if (!is_module_loaded("if_stf"))
3371
		mwexec("/sbin/kldload if_stf.ko");
3372
	$stfiface = "{$interface}_stf";
3373
	if (does_interface_exist($stfiface))
3374
		pfSense_interface_destroy($stfiface);
3375
	$tmpstfiface = pfSense_interface_create("stf");
3376
	pfSense_interface_rename($tmpstfiface, $stfiface);
3377
	pfSense_interface_flags($stfiface, IFF_LINK2);
3378
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3379
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3380
	if ($wancfg['prefix-6rd-v4plen'] > 0 && $wancfg['prefix-6rd-v4plen'] < 32)
3381
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/{$wancfg['prefix-6rd-v4plen']}");
3382
	if ($g['debug'])
3383
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3384

    
3385
	/* write out a default router file */
3386
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3387
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3388

    
3389
	$ip4gateway = get_interface_gateway($interface);
3390
	if (is_ipaddrv4($ip4gateway))
3391
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3392

    
3393
	/* configure dependent interfaces */
3394
	if (!$g['booting'])
3395
		link_interface_to_track6($interface, "update");
3396

    
3397
	return 0;
3398
}
3399

    
3400
function interface_6to4_configure($interface = "wan", $wancfg){
3401
	global $config, $g;
3402

    
3403
	/* because this is a tunnel interface we can only function
3404
	 *	with a public IPv4 address on the interface */
3405

    
3406
	if (!is_array($wancfg))
3407
		return;
3408

    
3409
	$wanif = get_real_interface($interface);
3410
	$ip4address = find_interface_ip($wanif);
3411
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3412
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3413
		return false;
3414
	}
3415

    
3416
	/* create the long prefix notation for math, save the prefix length */
3417
	$stfprefixlen = 16;
3418
	$stfprefix = Net_IPv6::uncompress("2002::");
3419
	$stfarr = explode(":", $stfprefix);
3420
	$v4prefixlen = "0";
3421

    
3422
	/* we need the hex form of the interface IPv4 address */
3423
	$ip4arr = explode(".", $ip4address);
3424
	$hexwanv4 = "";
3425
	foreach($ip4arr as $octet)
3426
		$hexwanv4 .= sprintf("%02x", $octet);
3427

    
3428
	/* we need the hex form of the broker IPv4 address */
3429
	$ip4arr = explode(".", "192.88.99.1");
3430
	$hexbrv4 = "";
3431
	foreach($ip4arr as $octet)
3432
		$hexbrv4 .= sprintf("%02x", $octet);
3433

    
3434
	/* binary presentation of the prefix for all 128 bits. */
3435
	$stfprefixbin = "";
3436
	foreach($stfarr as $element) {
3437
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3438
	}
3439
	/* just save the left prefix length bits */
3440
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3441

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

    
3446
	/* for the local subnet too. */
3447
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3448
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);;
3449

    
3450
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3451
	$stfbrarr = array();
3452
	$stfbrbinarr = array();
3453
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3454
	foreach($stfbrbinarr as $bin)
3455
		$stfbrarr[] = dechex(bindec($bin));
3456
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3457

    
3458
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3459
	$stflanarr = array();
3460
	$stflanbinarr = array();
3461
	$stflanbinarr = str_split($stflanbin, 16);
3462
	foreach($stflanbinarr as $bin)
3463
		$stflanarr[] = dechex(bindec($bin));
3464
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3465
	$stflanarr[7] = 1;
3466
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3467

    
3468
	/* setup the stf interface */
3469
	if (!is_module_loaded("if_stf"))
3470
		mwexec("/sbin/kldload if_stf.ko");
3471
	$stfiface = "{$interface}_stf";
3472
	if (does_interface_exist($stfiface))
3473
		pfSense_interface_destroy($stfiface);
3474
	$tmpstfiface = pfSense_interface_create("stf");
3475
	pfSense_interface_rename($tmpstfiface, $stfiface);
3476
	pfSense_interface_flags($stfiface, IFF_LINK2);
3477
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3478

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

    
3482
	/* write out a default router file */
3483
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3484
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3485

    
3486
	$ip4gateway = get_interface_gateway($interface);
3487
	if (is_ipaddrv4($ip4gateway))
3488
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3489

    
3490
	if (!$g['booting'])
3491
		link_interface_to_track6($interface, "update");
3492

    
3493
	return 0;
3494
}
3495

    
3496
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3497
	global $config, $g;
3498

    
3499
	if (!is_array($wancfg))
3500
		return;
3501

    
3502
	$wanif = get_real_interface($interface, "inet6");
3503
	$dhcp6cconf = "";
3504
	$dhcp6cconf .= "interface {$wanif} {\n";
3505

    
3506
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3507
	if($wancfg['ipaddrv6'] == "slaac") {
3508
		$dhcp6cconf .= "	information-only;\n";
3509
		$dhcp6cconf .= "	request domain-name-servers;\n";
3510
		$dhcp6cconf .= "	request domain-name;\n";
3511
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3512
		$dhcp6cconf .= "};\n";
3513
	} else {
3514
		/* skip address request if this is set */
3515
		if(!isset($wancfg['dhcp6prefixonly']))
3516
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3517
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3518
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3519

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

    
3524
		$dhcp6cconf .= "};\n";
3525

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

    
3529
		if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3530
			/* Setup the prefix delegation */
3531
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3532
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3533
			if (isset($wancfg['dhcp6-ia-pd-send-hint']))
3534
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3535
			$iflist = link_interface_to_track6($interface);
3536
			foreach ($iflist as $friendly => $ifcfg) {
3537
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3538
					if ($g['debug'])
3539
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3540
					$realif = get_real_interface($friendly);
3541
					$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3542
					$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3543
					$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3544
					$dhcp6cconf .= "	};\n";
3545
				}
3546
			}
3547
			unset($preflen, $iflist, $ifcfg);
3548
			$dhcp6cconf .= "};\n";
3549
		}
3550
	}
3551
	/* wide-dhcp6c works for now. */
3552
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3553
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3554
		unset($dhcp6cconf);
3555
		return 1;
3556
	}
3557
	unset($dhcp6cconf);
3558

    
3559
	$dhcp6cscript = "#!/bin/sh\n";
3560
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3561
	$dhcp6cscript .= "/etc/rc.newwanipv6 {$wanif} \n";
3562
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3563
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3564
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3565
		unset($dhcp6cscript);
3566
		return 1;
3567
	}
3568
	unset($dhcp6cscript);
3569
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3570

    
3571
	$rtsoldscript = "#!/bin/sh\n";
3572
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3573
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3574
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3575
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3576
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3577
	$rtsoldscript .= "\t/bin/sleep 1\n";
3578
	$rtsoldscript .= "fi\n";
3579
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3580
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3581
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3582
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3583
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3584
		unset($rtsoldscript);
3585
		return 1;
3586
	}
3587
	unset($rtsoldscript);
3588
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3589

    
3590
	/* accept router advertisements for this interface */
3591
	mwexec("/sbin/sysctl -w net.inet6.ip6.accept_rtadv=1");
3592
	log_error("Accept router advertisements on interface {$wanif} ");
3593
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3594

    
3595
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3596
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3597
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3598
		sleep(2);
3599
	}
3600
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3601

    
3602
	/* NOTE: will be called from rtsold invoked script
3603
	 * link_interface_to_track6($interface, "update");
3604
	 */
3605

    
3606
	return 0;
3607
}
3608

    
3609
function interface_dhcp_configure($interface = "wan") {
3610
	global $config, $g;
3611

    
3612
	$wancfg = $config['interfaces'][$interface];
3613
	$wanif = $wancfg['if'];
3614
	if (empty($wancfg))
3615
		$wancfg = array();
3616

    
3617
	/* generate dhclient_wan.conf */
3618
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3619
	if (!$fd) {
3620
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3621
		return 1;
3622
	}
3623

    
3624
	if ($wancfg['dhcphostname']) {
3625
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3626
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3627
	} else {
3628
		$dhclientconf_hostname = "";
3629
	}
3630

    
3631
	$wanif = get_real_interface($interface);
3632
	if (empty($wanif)) {
3633
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3634
		return 0;
3635
	}
3636
	$dhclientconf = "";
3637

    
3638
	$dhclientconf .= <<<EOD
3639
interface "{$wanif}" {
3640
timeout 60;
3641
retry 15;
3642
select-timeout 0;
3643
initial-interval 1;
3644
	{$dhclientconf_hostname}
3645
	script "/sbin/dhclient-script";
3646
EOD;
3647

    
3648
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3649
	$dhclientconf .= <<<EOD
3650

    
3651
	reject {$wancfg['dhcprejectfrom']};
3652
EOD;
3653
}
3654
	$dhclientconf .= <<<EOD
3655

    
3656
}
3657

    
3658
EOD;
3659

    
3660
if(is_ipaddr($wancfg['alias-address'])) {
3661
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3662
	$dhclientconf .= <<<EOD
3663
alias {
3664
	interface  "{$wanif}";
3665
	fixed-address {$wancfg['alias-address']};
3666
	option subnet-mask {$subnetmask};
3667
}
3668

    
3669
EOD;
3670
}
3671
	fwrite($fd, $dhclientconf);
3672
	fclose($fd);
3673

    
3674
	/* bring wan interface up before starting dhclient */
3675
	if($wanif)
3676
		interfaces_bring_up($wanif);
3677
	else
3678
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3679

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

    
3683
	return 0;
3684
}
3685

    
3686
function interfaces_group_setup() {
3687
	global $config;
3688

    
3689
	if (!is_array($config['ifgroups']['ifgroupentry']))
3690
		return;
3691

    
3692
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3693
		interface_group_setup($groupar);
3694

    
3695
	return;
3696
}
3697

    
3698
function interface_group_setup(&$groupname /* The parameter is an array */) {
3699
	global $config;
3700

    
3701
	if (!is_array($groupname))
3702
		return;
3703
	$members = explode(" ", $groupname['members']);
3704
	foreach($members as $ifs) {
3705
		$realif = get_real_interface($ifs);
3706
		if ($realif)
3707
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3708
	}
3709

    
3710
	return;
3711
}
3712

    
3713
function is_interface_group($if) {
3714
	global $config;
3715

    
3716
	if (is_array($config['ifgroups']['ifgroupentry']))
3717
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
3718
			if ($groupentry['ifname'] === $if)
3719
				return true;
3720
		}
3721

    
3722
	return false;
3723
}
3724

    
3725
function interface_group_add_member($interface, $groupname) {
3726
	$interface = get_real_interface($interface);
3727
	mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
3728
}
3729

    
3730
/* COMPAT Function */
3731
function convert_friendly_interface_to_real_interface_name($interface) {
3732
	return get_real_interface($interface);
3733
}
3734

    
3735
/* COMPAT Function */
3736
function get_real_wan_interface($interface = "wan") {
3737
	return get_real_interface($interface);
3738
}
3739

    
3740
/* COMPAT Function */
3741
function get_current_wan_address($interface = "wan") {
3742
	return get_interface_ip($interface);
3743
}
3744

    
3745
/*
3746
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
3747
 */
3748
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
3749
	global $config;
3750

    
3751
	if (stristr($interface, "_vip")) {
3752
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
3753
			if ($vip['mode'] == "carp")  {
3754
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3755
					return $vip['interface'];
3756
			}
3757
		}
3758
	}
3759

    
3760
	/* XXX: For speed reasons reference directly the interface array */
3761
	$ifdescrs = &$config['interfaces'];
3762
	//$ifdescrs = get_configured_interface_list(false, true);
3763

    
3764
	foreach ($ifdescrs as $if => $ifname) {
3765
		if ($if == $interface || $ifname['if'] == $interface)
3766
			return $if;
3767

    
3768
		if (get_real_interface($if) == $interface)
3769
			return $if;
3770

    
3771
		$int = get_parent_interface($if, true);
3772
		if (is_array($int)) {
3773
			foreach ($int as $iface) {
3774
				if ($iface == $interface)
3775
					return $if;
3776
			}
3777
		}
3778
	}
3779

    
3780
	return NULL;
3781
}
3782

    
3783
/* attempt to resolve interface to friendly descr */
3784
function convert_friendly_interface_to_friendly_descr($interface) {
3785
	global $config;
3786

    
3787
	switch ($interface) {
3788
	case "l2tp":
3789
		$ifdesc = "L2TP";
3790
		break;
3791
	case "pptp":
3792
		$ifdesc = "PPTP";
3793
		break;
3794
	case "pppoe":
3795
		$ifdesc = "PPPoE";
3796
		break;
3797
	case "openvpn":
3798
		$ifdesc = "OpenVPN";
3799
		break;
3800
	case "enc0":
3801
	case "ipsec":
3802
		$ifdesc = "IPsec";
3803
		break;
3804
	default:
3805
		if (isset($config['interfaces'][$interface])) {
3806
			if (empty($config['interfaces'][$interface]['descr']))
3807
				$ifdesc = strtoupper($interface);
3808
			else
3809
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
3810
			break;
3811
		} else if (stristr($interface, "_vip")) {
3812
			if (is_array($config['virtualip']['vip'])) {
3813
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
3814
					if ($vip['mode'] == "carp")  {
3815
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3816
							return "{$vip['subnet']} - {$vip['descr']}";
3817
					}
3818
				}
3819
			}
3820
		} else {
3821
			/* if list */
3822
			$ifdescrs = get_configured_interface_with_descr(false, true);
3823
			foreach ($ifdescrs as $if => $ifname) {
3824
				if ($if == $interface || $ifname == $interface)
3825
					return $ifname;
3826
			}
3827
		}
3828
		break;
3829
	}
3830

    
3831
	return $ifdesc;
3832
}
3833

    
3834
function convert_real_interface_to_friendly_descr($interface) {
3835
	global $config;
3836

    
3837
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
3838

    
3839
	if ($ifdesc) {
3840
		$iflist = get_configured_interface_with_descr(false, true);
3841
		return $iflist[$ifdesc];
3842
	}
3843

    
3844
	return $interface;
3845
}
3846

    
3847
/*
3848
 *  get_parent_interface($interface):
3849
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
3850
 *				or virtual interface (i.e. vlan)
3851
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
3852
 *			-- returns $interface passed in if $interface parent is not found
3853
 *			-- returns empty array if an invalid interface is passed
3854
 *	(Only handles ppps and vlans now.)
3855
 */
3856
function get_parent_interface($interface, $avoidrecurse = false) {
3857
	global $config;
3858

    
3859
	$parents = array();
3860
	//Check that we got a valid interface passed
3861
	$realif = get_real_interface($interface);
3862
	if ($realif == NULL)
3863
		return $parents;
3864

    
3865
	// If we got a real interface, find it's friendly assigned name
3866
	if ($interface == $realif && $avoidrecurse == false)
3867
		$interface = convert_real_interface_to_friendly_interface_name($interface);
3868

    
3869
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
3870
		$ifcfg = $config['interfaces'][$interface];
3871
		switch ($ifcfg['ipaddr']) {
3872
			case "ppp":
3873
			case "pppoe":
3874
			case "pptp":
3875
			case "l2tp":
3876
				if (empty($parents))
3877
					if (is_array($config['ppps']['ppp']))
3878
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
3879
							if ($ifcfg['if'] == $ppp['if']) {
3880
								$ports = explode(',', $ppp['ports']);
3881
								foreach ($ports as $pid => $parent_if)
3882
									$parents[$pid] = get_real_interface($parent_if);
3883
								break;
3884
							}
3885
						}
3886
				break;
3887
			case "dhcp":
3888
			case "static":
3889
			default:
3890
				// Handle _vlans
3891
				if (stristr($realif,"_vlan"))
3892
					if (is_array($config['vlans']['vlan']))
3893
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
3894
							if ($ifcfg['if'] == $vlan['vlanif']){
3895
								$parents[0] = $vlan['if'];
3896
								break;
3897
							}
3898
				break;
3899
		}
3900
	}
3901

    
3902
	if (empty($parents))
3903
		$parents[0] = $realif;
3904

    
3905
	return $parents;
3906
}
3907

    
3908
function interface_is_wireless_clone($wlif) {
3909
	if(!stristr($wlif, "_wlan")) {
3910
		return false;
3911
	} else {
3912
		return true;
3913
	}
3914
}
3915

    
3916
function interface_get_wireless_base($wlif) {
3917
	if(!stristr($wlif, "_wlan")) {
3918
		return $wlif;
3919
	} else {
3920
		return substr($wlif, 0, stripos($wlif, "_wlan"));
3921
	}
3922
}
3923

    
3924
function interface_get_wireless_clone($wlif) {
3925
	if(!stristr($wlif, "_wlan")) {
3926
		return $wlif . "_wlan0";
3927
	} else {
3928
		return $wlif;
3929
	}
3930
}
3931

    
3932
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
3933
	global $config, $g;
3934

    
3935
	$wanif = NULL;
3936

    
3937
	switch ($interface) {
3938
	case "l2tp":
3939
		$wanif = "l2tp";
3940
		break;
3941
	case "pptp":
3942
		$wanif = "pptp";
3943
		break;
3944
	case "pppoe":
3945
		$wanif = "pppoe";
3946
		break;
3947
	case "openvpn":
3948
		$wanif = "openvpn";
3949
		break;
3950
	case "ipsec":
3951
	case "enc0":
3952
		$wanif = "enc0";
3953
		break;
3954
	case "ppp":
3955
		$wanif = "ppp";
3956
		break;
3957
	default:
3958
		// If a real interface was alread passed simply
3959
		// pass the real interface back.  This encourages
3960
		// the usage of this function in more cases so that
3961
		// we can combine logic for more flexibility.
3962
		if(does_interface_exist($interface, $flush)) {
3963
			$wanif = $interface;
3964
			break;
3965
		}
3966

    
3967
		if (empty($config['interfaces'][$interface]))
3968
			break;
3969

    
3970
		$cfg = &$config['interfaces'][$interface];
3971

    
3972
		if ($family == "inet6") {
3973
			switch ($cfg['ipaddrv6']) {
3974
			case "6rd":
3975
			case "6to4":
3976
				$wanif = "{$interface}_stf";
3977
				break;
3978
			case 'pppoe':
3979
			case 'ppp':
3980
			case 'l2tp':
3981
			case 'pptp':
3982
				if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
3983
					$wanif = interface_get_wireless_clone($cfg['if']);
3984
				else
3985
					$wanif = $cfg['if'];
3986
				break;
3987
			default:
3988
				switch ($cfg['ipaddr']) {
3989
				case 'pppoe':
3990
				case 'ppp':
3991
				case 'l2tp':
3992
				case 'pptp':
3993
					if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false)
3994
						$wanif = $cfg['if'];
3995
					else {
3996
						$parents = get_parent_interface($interface);
3997
						if (!empty($parents[0]))
3998
							$wanif = $parents[0];
3999
						else
4000
							$wanif = $cfg['if'];
4001
					}
4002
					break;
4003
				default:
4004
					if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4005
						$wanif = interface_get_wireless_clone($cfg['if']);
4006
					else
4007
						$wanif = $cfg['if'];
4008
					break;
4009
				}
4010
				break;
4011
			}
4012
		} else {
4013
			// Wireless cloned NIC support (FreeBSD 8+)
4014
			// interface name format: $parentnic_wlanparentnic#
4015
			// example: ath0_wlan0
4016
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4017
				$wanif = interface_get_wireless_clone($cfg['if']);
4018
			else
4019
				$wanif = $cfg['if'];
4020
		}
4021
		break;
4022
	}
4023

    
4024
	return $wanif;
4025
}
4026

    
4027
/* Guess the physical interface by providing a IP address */
4028
function guess_interface_from_ip($ipaddress) {
4029
	if(! is_ipaddr($ipaddress)) {
4030
		return false;
4031
	}
4032
	if(is_ipaddrv4($ipaddress)) {
4033
		/* create a route table we can search */
4034
		exec("netstat -rnWf inet", $output, $ret);
4035
		foreach($output as $line) {
4036
			if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
4037
				$fields = preg_split("/[ ]+/", $line);
4038
				if(ip_in_subnet($ipaddress, $fields[0])) {
4039
					return $fields[6];
4040
				}
4041
			}
4042
		}
4043
	}
4044
	/* FIXME: This works from cursory testing, regexp might need fine tuning */
4045
	if(is_ipaddrv6($ipaddress)) {
4046
		/* create a route table we can search */
4047
		exec("netstat -rnWf inet6", $output, $ret);
4048
		foreach($output as $line) {
4049
			if(preg_match("/[0-9a-f]+[:]+[0-9a-f]+[:]+[\/][0-9]+/", $line)) {
4050
				$fields = preg_split("/[ ]+/", $line);
4051
				if(ip_in_subnet($ipaddress, $fields[0])) {
4052
					return $fields[6];
4053
				}
4054
			}
4055
		}
4056
	}
4057
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
4058
	if(empty($ret)) {
4059
		return false;
4060
	}
4061
	return $ret;
4062
}
4063

    
4064
/*
4065
 * find_ip_interface($ip): return the interface where an ip is defined
4066
 *   (or if $bits is specified, where an IP within the subnet is defined)
4067
 */
4068
function find_ip_interface($ip, $bits = null) {
4069
	if (!is_ipaddr($ip))
4070
		return false;
4071

    
4072
	$isv6ip = is_ipaddrv6($ip);
4073

    
4074
	/* if list */
4075
	$ifdescrs = get_configured_interface_list();
4076

    
4077
	foreach ($ifdescrs as $ifdescr => $ifname) {
4078
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4079
		if (is_null($ifip))
4080
			continue;
4081
		if (is_null($bits)) {
4082
			if ($ip == $ifip) {
4083
				$int = get_real_interface($ifname);
4084
				return $int;
4085
			}
4086
		}
4087
		else {
4088
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4089
				$int = get_real_interface($ifname);
4090
				return $int;
4091
			}
4092
		}
4093
	}
4094

    
4095
	return false;
4096
}
4097

    
4098
/*
4099
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4100
 *   (or if $bits is specified, where an IP within the subnet is found)
4101
 */
4102
function find_virtual_ip_alias($ip, $bits = null) {
4103
	global $config;
4104

    
4105
	if (!is_array($config['virtualip']['vip'])) {
4106
		return false;
4107
	}
4108
	if (!is_ipaddr($ip))
4109
		return false;
4110

    
4111
	$isv6ip = is_ipaddrv6($ip);
4112

    
4113
	foreach ($config['virtualip']['vip'] as $vip) {
4114
		if ($vip['mode'] === "ipalias") {
4115
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4116
				continue;
4117
			if (is_null($bits)) {
4118
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4119
					return $vip;
4120
				}
4121
			}
4122
			else {
4123
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4124
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4125
					return $vip;
4126
				}
4127
			}
4128
		}
4129
	}
4130
	return false;
4131
}
4132

    
4133
/*
4134
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4135
 */
4136
function find_number_of_created_carp_interfaces() {
4137
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4138
}
4139

    
4140
function get_all_carp_interfaces() {
4141
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
4142
	$ints = explode(" ", $ints);
4143
	return $ints;
4144
}
4145

    
4146
/*
4147
 * find_carp_interface($ip): return the carp interface where an ip is defined
4148
 */
4149
function find_carp_interface($ip) {
4150
	global $config;
4151
	if (is_array($config['virtualip']['vip'])) {
4152
		foreach ($config['virtualip']['vip'] as $vip) {
4153
			if ($vip['mode'] == "carp") {
4154
				if(is_ipaddrv4($ip)) {
4155
					$carp_ip = get_interface_ip($vip['interface']);
4156
				}
4157
				if(is_ipaddrv6($ip)) {
4158
					$carp_ip = get_interface_ipv6($vip['interface']);
4159
				}
4160
				exec("/sbin/ifconfig", $output, $return);
4161
				foreach($output as $line) {
4162
					$elements = preg_split("/[ ]+/i", $line);
4163
					if(strstr($elements[0], "vip"))
4164
						$curif = str_replace(":", "", $elements[0]);
4165
					if(stristr($line, $ip)) {
4166
						$if = $curif;
4167
						continue;
4168
					}
4169
				}
4170

    
4171
				if ($if)
4172
					return $if;
4173
			}
4174
		}
4175
	}
4176
}
4177

    
4178
function link_carp_interface_to_parent($interface) {
4179
	global $config;
4180

    
4181
	if (empty($interface))
4182
		return;
4183

    
4184
	$carp_ip = get_interface_ip($interface);
4185
	$carp_ipv6 = get_interface_ipv6($interface);
4186

    
4187
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4188
		return;
4189

    
4190
	/* if list */
4191
	$ifdescrs = get_configured_interface_list();
4192
	foreach ($ifdescrs as $ifdescr => $ifname) {
4193
		/* check IPv4 */
4194
		if(is_ipaddrv4($carp_ip)) {
4195
			$interfaceip = get_interface_ip($ifname);
4196
			$subnet_bits = get_interface_subnet($ifname);
4197
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4198
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4199
				return $ifname;
4200
		}
4201
		/* Check IPv6 */
4202
		if(is_ipaddrv6($carp_ipv6)) {
4203
			$interfaceipv6 = get_interface_ipv6($ifname);
4204
			$prefixlen = get_interface_subnetv6($ifname);
4205
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4206
				return $ifname;
4207
		}
4208
	}
4209
	return "";
4210
}
4211

    
4212

    
4213
/****f* interfaces/link_ip_to_carp_interface
4214
 * NAME
4215
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4216
 * INPUTS
4217
 *   $ip
4218
 * RESULT
4219
 *   $carp_ints
4220
 ******/
4221
function link_ip_to_carp_interface($ip) {
4222
	global $config;
4223

    
4224
	if (!is_ipaddr($ip))
4225
		return;
4226

    
4227
	$carp_ints = "";
4228
	if (is_array($config['virtualip']['vip'])) {
4229
		$first = 0;
4230
		$carp_int = array();
4231
		foreach ($config['virtualip']['vip'] as $vip) {
4232
			if ($vip['mode'] == "carp") {
4233
				$carp_ip = $vip['subnet'];
4234
				$carp_sn = $vip['subnet_bits'];
4235
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4236
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4237
					$carp_int[] = "{$vip['interface']}_vip{$vip['vhid']}";
4238
				}
4239
			}
4240
		}
4241
		if (!empty($carp_int))
4242
			$carp_ints = implode(" ", array_unique($carp_int));
4243
	}
4244

    
4245
	return $carp_ints;
4246
}
4247

    
4248
function link_interface_to_track6($int, $action = "") {
4249
	global $config;
4250

    
4251
	if (empty($int))
4252
		return;
4253

    
4254
	if (is_array($config['interfaces'])) {
4255
		$list = array();
4256
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4257
			if (!isset($ifcfg['enable']))
4258
				continue;
4259
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4260
				if ($action == "update")
4261
					interface_track6_configure($ifname, $ifcfg);
4262
				else if ($action == "")
4263
					$list[$ifname] = $ifcfg;
4264
			}
4265
		}
4266
		return $list;
4267
	}
4268
}
4269

    
4270
function link_interface_to_vlans($int, $action = "") {
4271
	global $config;
4272

    
4273
	if (empty($int))
4274
		return;
4275

    
4276
	if (is_array($config['vlans']['vlan'])) {
4277
		$ifaces = array();
4278
		foreach ($config['vlans']['vlan'] as $vlan) {
4279
			if ($int == $vlan['if']) {
4280
				if ($action == "update") {
4281
					interfaces_bring_up($int);
4282
				} else if ($action == "")
4283
					$ifaces[$vlan['tag']] = $vlan;
4284
			}
4285
		}
4286
		if (!empty($ifaces))
4287
			return $ifaces;
4288
	}
4289
}
4290

    
4291
function link_interface_to_vips($int, $action = "") {
4292
	global $config;
4293

    
4294
	if (is_array($config['virtualip']['vip'])) {
4295
		$result = array();
4296
		foreach ($config['virtualip']['vip'] as $vip) {
4297
			if ($int == $vip['interface']) {
4298
				if ($action == "update")
4299
					interfaces_vips_configure($int);
4300
				else
4301
					$result[] = $vip;
4302
			}
4303
		}
4304
		return $result;
4305
	}
4306
}
4307

    
4308
/****f* interfaces/link_interface_to_bridge
4309
 * NAME
4310
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4311
 * INPUTS
4312
 *   $ip
4313
 * RESULT
4314
 *   bridge[0-99]
4315
 ******/
4316
function link_interface_to_bridge($int) {
4317
	global $config;
4318

    
4319
	if (is_array($config['bridges']['bridged'])) {
4320
		foreach ($config['bridges']['bridged'] as $bridge) {
4321
			if (in_array($int, explode(',', $bridge['members'])))
4322
				return "{$bridge['bridgeif']}";
4323
		}
4324
	}
4325
}
4326

    
4327
function link_interface_to_group($int) {
4328
	global $config;
4329

    
4330
	$result = array();
4331

    
4332
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4333
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4334
			if (in_array($int, explode(" ", $group['members'])))
4335
				$result[$group['ifname']] = $int;
4336
		}
4337
	}
4338

    
4339
	return $result;
4340
}
4341

    
4342
function link_interface_to_gre($interface) {
4343
	global $config;
4344

    
4345
	$result = array();
4346

    
4347
	if (is_array($config['gres']['gre'])) {
4348
		foreach ($config['gres']['gre'] as $gre)
4349
			if($gre['if'] == $interface)
4350
				$result[] = $gre;
4351
	}
4352

    
4353
	return $result;
4354
}
4355

    
4356
function link_interface_to_gif($interface) {
4357
	global $config;
4358

    
4359
	$result = array();
4360

    
4361
	if (is_array($config['gifs']['gif'])) {
4362
		foreach ($config['gifs']['gif'] as $gif)
4363
			if($gif['if'] == $interface)
4364
				$result[] = $gif;
4365
	}
4366

    
4367
	return $result;
4368
}
4369

    
4370
/*
4371
 * find_interface_ip($interface): return the interface ip (first found)
4372
 */
4373
function find_interface_ip($interface, $flush = false) {
4374
	global $interface_ip_arr_cache;
4375
	global $interface_sn_arr_cache;
4376

    
4377
	$interface = str_replace("\n", "", $interface);
4378

    
4379
	if (!does_interface_exist($interface))
4380
		return;
4381

    
4382
	/* Setup IP cache */
4383
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4384
		$ifinfo = pfSense_get_interface_addresses($interface);
4385
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4386
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4387
	}
4388

    
4389
	return $interface_ip_arr_cache[$interface];
4390
}
4391

    
4392
/*
4393
 * find_interface_ipv6($interface): return the interface ip (first found)
4394
 */
4395
function find_interface_ipv6($interface, $flush = false) {
4396
	global $interface_ipv6_arr_cache;
4397
	global $interface_snv6_arr_cache;
4398
	global $config;
4399

    
4400
	$interface = trim($interface);
4401
	$interface = get_real_interface($interface);
4402

    
4403
	if (!does_interface_exist($interface))
4404
		return;
4405

    
4406
	/* Setup IP cache */
4407
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4408
		$ifinfo = pfSense_get_interface_addresses($interface);
4409
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4410
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4411
	}
4412

    
4413
	return $interface_ipv6_arr_cache[$interface];
4414
}
4415

    
4416
/*
4417
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4418
 */
4419
function find_interface_ipv6_ll($interface, $flush = false) {
4420
	global $interface_llv6_arr_cache;
4421
	global $config;
4422

    
4423
	$interface = str_replace("\n", "", $interface);
4424

    
4425
	if (!does_interface_exist($interface))
4426
		return;
4427

    
4428
	/* Setup IP cache */
4429
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4430
		$ifinfo = pfSense_getall_interface_addresses($interface);
4431
		foreach($ifinfo as $line) {
4432
			if (strstr($line, ":")) {
4433
				$parts = explode("/", $line);
4434
				if(is_linklocal($parts[0])) {
4435
					$ifinfo['linklocal'] = $parts[0];
4436
				}
4437
			}
4438
		}
4439
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4440
	}
4441
	return $interface_llv6_arr_cache[$interface];
4442
}
4443

    
4444
function find_interface_subnet($interface, $flush = false) {
4445
	global $interface_sn_arr_cache;
4446
	global $interface_ip_arr_cache;
4447

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

    
4452
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4453
		$ifinfo = pfSense_get_interface_addresses($interface);
4454
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4455
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4456
	}
4457

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

    
4461
function find_interface_subnetv6($interface, $flush = false) {
4462
	global $interface_snv6_arr_cache;
4463
	global $interface_ipv6_arr_cache;
4464

    
4465
	$interface = str_replace("\n", "", $interface);
4466
	if (does_interface_exist($interface) == false)
4467
		return;
4468

    
4469
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4470
		$ifinfo = pfSense_get_interface_addresses($interface);
4471
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4472
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4473
	}
4474

    
4475
	return $interface_snv6_arr_cache[$interface];
4476
}
4477

    
4478
function ip_in_interface_alias_subnet($interface, $ipalias) {
4479
	global $config;
4480

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

    
4497
	return false;
4498
}
4499

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

    
4511
	$curip = find_interface_ip($realif);
4512
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4513
		return $curip;
4514
	else
4515
		return null;
4516
}
4517

    
4518
function get_interface_ipv6($interface = "wan", $flush = false) {
4519
	global $config;
4520

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

    
4529
	/*
4530
	 * NOTE: On the case when only the prefix is requested,
4531
	 * the communication on WAN will be done over link-local.
4532
	 */
4533
	if (is_array($config['interfaces'][$interface])) {
4534
		switch ($config['interfaces'][$interface]['ipaddr']) {
4535
		case 'pppoe':
4536
		case 'l2tp':
4537
		case 'pptp':
4538
		case 'ppp':
4539
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4540
				$realif = get_real_interface($interface, "inet6", true);
4541
			break;
4542
		}
4543
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4544
			$curip = find_interface_ipv6_ll($realif, $flush);
4545
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4546
				return $curip;
4547
		}
4548
	}
4549

    
4550
	$curip = find_interface_ipv6($realif, $flush);
4551
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4552
		return $curip;
4553
	else
4554
		return null;
4555
}
4556

    
4557
function get_interface_linklocal($interface = "wan") {
4558

    
4559
	$realif = get_failover_interface($interface, "inet6");
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
	$curip = find_interface_ipv6_ll($realif);
4570
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4571
		return $curip;
4572
	else
4573
		return null;
4574
}
4575

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

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

    
4591
	return null;
4592
}
4593

    
4594
function get_interface_subnetv6($interface = "wan") {
4595
	global $config;
4596

    
4597
	$realif = get_real_interface($interface, "inet6");
4598
	if (!$realif) {
4599
		if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4600
			$realif = $interface;
4601
		else
4602
			return null;
4603
	}
4604

    
4605
	$cursn = find_interface_subnetv6($realif);
4606
	if (!empty($cursn))
4607
		return $cursn;
4608

    
4609
	return null;
4610
}
4611

    
4612
/* return outside interfaces with a gateway */
4613
function get_interfaces_with_gateway() {
4614
	global $config;
4615

    
4616
	$ints = array();
4617

    
4618
	/* loop interfaces, check config for outbound */
4619
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4620
		switch ($ifname['ipaddr']) {
4621
			case "dhcp":
4622
			case "ppp";
4623
			case "pppoe":
4624
			case "pptp":
4625
			case "l2tp":
4626
			case "ppp";
4627
				$ints[$ifdescr] = $ifdescr;
4628
			break;
4629
			default:
4630
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
4631
				    !empty($ifname['gateway']))
4632
					$ints[$ifdescr] = $ifdescr;
4633
			break;
4634
		}
4635
	}
4636
	return $ints;
4637
}
4638

    
4639
/* return true if interface has a gateway */
4640
function interface_has_gateway($friendly) {
4641
	global $config;
4642

    
4643
	if (!empty($config['interfaces'][$friendly])) {
4644
		$ifname = &$config['interfaces'][$friendly];
4645
		switch ($ifname['ipaddr']) {
4646
			case "dhcp":
4647
			case "pppoe":
4648
			case "pptp":
4649
			case "l2tp":
4650
			case "ppp";
4651
				return true;
4652
			break;
4653
			default:
4654
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4655
					return true;
4656
				if (!empty($ifname['gateway']))
4657
					return true;
4658
			break;
4659
		}
4660
	}
4661

    
4662
	return false;
4663
}
4664

    
4665
/* return true if interface has a gateway */
4666
function interface_has_gatewayv6($friendly) {
4667
	global $config;
4668

    
4669
	if (!empty($config['interfaces'][$friendly])) {
4670
		$ifname = &$config['interfaces'][$friendly];
4671
		switch ($ifname['ipaddrv6']) {
4672
			case "slaac":
4673
			case "dhcp6":
4674
			case "6to4":
4675
			case "6rd":
4676
				return true;
4677
				break;
4678
			default:
4679
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4680
					return true;
4681
				$tunnelif = substr($ifname['if'], 0, 3);
4682
				if ($tunnelif == "gif" || $tunnelif == "gre")
4683
					return true;
4684
				if (!empty($ifname['gatewayv6']))
4685
					return true;
4686
				break;
4687
		}
4688
	}
4689

    
4690
	return false;
4691
}
4692

    
4693
/****f* interfaces/is_altq_capable
4694
 * NAME
4695
 *   is_altq_capable - Test if interface is capable of using ALTQ
4696
 * INPUTS
4697
 *   $int            - string containing interface name
4698
 * RESULT
4699
 *   boolean         - true or false
4700
 ******/
4701

    
4702
function is_altq_capable($int) {
4703
	/* Per:
4704
	 * http://www.freebsd.org/cgi/man.cgi?query=altq&apropos=0&sektion=0&manpath=FreeBSD+8.3-RELEASE&arch=default&format=html
4705
	 * Only the following drivers have ALTQ support
4706
	 */
4707
	$capable = array("ae", "age", "alc", "ale", "an", "ath", "aue", "axe", "awi", "bce",
4708
			"bfe", "bge", "bridge", "cas", "dc", "de", "ed", "em", "ep", "epair", "et", "fxp", "gem",
4709
			"hme", "igb", "ipw", "iwi", "ixgbe", "jme", "le", "lem", "msk", "mxge", "my", "nfe",
4710
			"nge", "npe", "nve", "ral", "re", "rl", "rum", "run", "bwn", "sf", "sge", "sis", "sk",
4711
			"ste", "stge", "ti", "txp", "udav", "ural", "vge", "vr", "vte", "wi", "xl",
4712
			"ndis", "tun", "ovpns", "ovpnc", "vlan", "pppoe", "pptp", "ng",
4713
			"l2tp", "ppp", "vtnet");
4714

    
4715
	$int_family = remove_ifindex($int);
4716

    
4717
	if (in_array($int_family, $capable))
4718
		return true;
4719
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
4720
		return true;
4721
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
4722
		return true;
4723
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
4724
		return true;
4725
	else
4726
		return false;
4727
}
4728

    
4729
/****f* interfaces/is_interface_wireless
4730
 * NAME
4731
 *   is_interface_wireless - Returns if an interface is wireless
4732
 * RESULT
4733
 *   $tmp       - Returns if an interface is wireless
4734
 ******/
4735
function is_interface_wireless($interface) {
4736
	global $config, $g;
4737

    
4738
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
4739
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
4740
		if (preg_match($g['wireless_regex'], $interface)) {
4741
			if (isset($config['interfaces'][$friendly]))
4742
				$config['interfaces'][$friendly]['wireless'] = array();
4743
			return true;
4744
		}
4745
		return false;
4746
	} else
4747
		return true;
4748
}
4749

    
4750
function get_wireless_modes($interface) {
4751
	/* return wireless modes and channels */
4752
	$wireless_modes = array();
4753

    
4754
	$cloned_interface = get_real_interface($interface);
4755

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

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

    
4765
		$c = 0;
4766
		while ($c < $interface_channel_count) {
4767
			$channel_line = explode(",", $interface_channels["$c"]);
4768
			$wireless_mode = trim($channel_line[0]);
4769
			$wireless_channel = trim($channel_line[1]);
4770
			if(trim($wireless_mode) != "") {
4771
				/* if we only have 11g also set 11b channels */
4772
				if($wireless_mode == "11g") {
4773
					if(!isset($wireless_modes["11b"]))
4774
						$wireless_modes["11b"] = array();
4775
				} else if($wireless_mode == "11g ht") {
4776
					if(!isset($wireless_modes["11b"]))
4777
						$wireless_modes["11b"] = array();
4778
					if(!isset($wireless_modes["11g"]))
4779
						$wireless_modes["11g"] = array();
4780
					$wireless_mode = "11ng";
4781
				} else if($wireless_mode == "11a ht") {
4782
					if(!isset($wireless_modes["11a"]))
4783
						$wireless_modes["11a"] = array();
4784
					$wireless_mode = "11na";
4785
				}
4786
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
4787
			}
4788
			$c++;
4789
		}
4790
	}
4791
	return($wireless_modes);
4792
}
4793

    
4794
/* return channel numbers, frequency, max txpower, and max regulation txpower */
4795
function get_wireless_channel_info($interface) {
4796
	$wireless_channels = array();
4797

    
4798
	$cloned_interface = get_real_interface($interface);
4799

    
4800
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4801
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
4802
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4803
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
4804

    
4805
		$interface_channels = "";
4806
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4807

    
4808
		foreach ($interface_channels as $channel_line) {
4809
			$channel_line = explode(",", $channel_line);
4810
			if(!isset($wireless_channels[$channel_line[0]]))
4811
				$wireless_channels[$channel_line[0]] = $channel_line;
4812
		}
4813
	}
4814
	return($wireless_channels);
4815
}
4816

    
4817
/****f* interfaces/get_interface_mtu
4818
 * NAME
4819
 *   get_interface_mtu - Return the mtu of an interface
4820
 * RESULT
4821
 *   $tmp       - Returns the mtu of an interface
4822
 ******/
4823
function get_interface_mtu($interface) {
4824
	$mtu = pfSense_get_interface_addresses($interface);
4825
	return $mtu['mtu'];
4826
}
4827

    
4828
function get_interface_mac($interface) {
4829

    
4830
	$macinfo = pfSense_get_interface_addresses($interface);
4831
	return $macinfo["macaddr"];
4832
}
4833

    
4834
/****f* pfsense-utils/generate_random_mac_address
4835
 * NAME
4836
 *   generate_random_mac - generates a random mac address
4837
 * INPUTS
4838
 *   none
4839
 * RESULT
4840
 *   $mac - a random mac address
4841
 ******/
4842
function generate_random_mac_address() {
4843
	$mac = "02";
4844
	for($x=0; $x<5; $x++)
4845
		$mac .= ":" . dechex(rand(16, 255));
4846
	return $mac;
4847
}
4848

    
4849
/****f* interfaces/is_jumbo_capable
4850
 * NAME
4851
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
4852
 * INPUTS
4853
 *   $int             - string containing interface name
4854
 * RESULT
4855
 *   boolean          - true or false
4856
 ******/
4857
function is_jumbo_capable($iface) {
4858
	$iface = trim($iface);
4859
	$capable = pfSense_get_interface_addresses($iface);
4860

    
4861
	if (isset($capable['caps']['vlanmtu']))
4862
		return true;
4863

    
4864
	return false;
4865
}
4866

    
4867
function interface_setup_pppoe_reset_file($pppif, $iface="") {
4868
	global $g;
4869

    
4870
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
4871

    
4872
	if(!empty($iface) && !empty($pppif)){
4873
		$cron_cmd = <<<EOD
4874
#!/bin/sh
4875
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
4876
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
4877

    
4878
EOD;
4879

    
4880
		@file_put_contents($cron_file, $cron_cmd);
4881
		chmod($cron_file, 0755);
4882
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
4883
	} else
4884
		unlink_if_exists($cron_file);
4885
}
4886

    
4887
function get_interface_default_mtu($type = "ethernet") {
4888
	switch ($type) {
4889
	case "gre":
4890
		return 1476;
4891
		break;
4892
	case "gif":
4893
		return 1280;
4894
		break;
4895
	case "tun":
4896
	case "vlan":
4897
	case "tap":
4898
	case "ethernet":
4899
	default:
4900
		return 1500;
4901
		break;
4902
	}
4903

    
4904
	/* Never reached */
4905
	return 1500;
4906
}
4907

    
4908
function get_vip_descr($ipaddress) {
4909
	global $config;
4910

    
4911
	foreach ($config['virtualip']['vip'] as $vip) {
4912
		if ($vip['subnet'] == $ipaddress) {
4913
			return ($vip['descr']);
4914
		}
4915
	}
4916
	return "";
4917
}
4918

    
4919
function interfaces_staticarp_configure($if) {
4920
	global $config, $g;
4921
	if(isset($config['system']['developerspew'])) {
4922
		$mt = microtime();
4923
		echo "interfaces_staticarp_configure($if) being called $mt\n";
4924
	}
4925

    
4926
	$ifcfg = $config['interfaces'][$if];
4927

    
4928
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
4929
		return 0;
4930

    
4931
	/* Enable staticarp, if enabled */
4932
	if(isset($config['dhcpd'][$if]['staticarp'])) {
4933
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
4934
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4935
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
4936

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

    
4940
			}
4941

    
4942
		}
4943
	} else {
4944
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
4945
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4946
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
4947
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
4948
				if (isset($arpent['arp_table_static_entry'])) {
4949
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
4950
				}
4951
			}
4952
		}
4953
	}
4954

    
4955
	return 0;
4956
}
4957

    
4958
function get_failover_interface($interface, $family = "all") {
4959
	global $config;
4960

    
4961
	/* shortcut to get_real_interface if we find it in the config */
4962
	if (is_array($config['interfaces'][$interface])) {
4963
		return get_real_interface($interface, $family);
4964
	}
4965

    
4966
	/* compare against gateway groups */
4967
	$a_groups = return_gateway_groups_array();
4968
	if (is_array($a_groups[$interface])) {
4969
		/* we found a gateway group, fetch the interface or vip */
4970
		if ($a_groups[$interface][0]['vip'] <> "")
4971
			return $a_groups[$interface][0]['vip'];
4972
		else
4973
			return $a_groups[$interface][0]['int'];
4974
	}
4975
	/* fall through to get_real_interface */
4976
	/* XXX: Really needed? */
4977
	return get_real_interface($interface, $family);
4978
}
4979

    
4980
function remove_ifindex($ifname) {
4981
	return preg_replace("/[0-9]+$/", "", $ifname);
4982
}
4983

    
4984
?>
(25-25/66)