Projet

Général

Profil

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

univnautes / etc / inc / interfaces.inc @ e912bfae

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

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

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

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

    
1347
	return;
1348
}
1349

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

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

    
1358
	return false;
1359
}
1360

    
1361
function interfaces_ptpid_next() {
1362

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

    
1367
	return $ptpid;
1368
}
1369

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

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

    
1381
	return NULL;
1382
}
1383

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

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

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

    
1393
	$itemhash = getMPDCRONSettings($pppif);
1394

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1653
EOD;
1654

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

    
1659
EOD;
1660

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

    
1668
EOD;
1669

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

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

    
1680
EOD;
1681

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

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

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

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

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

    
1708
EOD;
1709

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

    
1714
EOD;
1715

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

    
1720
EOD;
1721

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

    
1727
EOD;
1728

    
1729

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

    
1734
EOD;
1735

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

    
1741
EOD;
1742

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

    
1747
EOD;
1748

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

    
1753
EOD;
1754

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

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

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

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

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

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

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

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

    
1812
EOD;
1813

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

    
1819
EOD;
1820
		}
1821

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

    
1825

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

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

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

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

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

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

    
1901
	return 1;
1902
}
1903

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

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

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

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

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

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

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

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

    
1950
		sleep(1);
1951

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2222
	interfaces_bring_up($vipif);
2223

    
2224
	return $vipif;
2225
}
2226

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2584
EOD;
2585

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

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

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

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

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

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

    
2618
EOD;
2619
					}
2620
				}
2621
			}
2622

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2770

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

    
2775
	return 0;
2776

    
2777
}
2778

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

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

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

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

    
2796
	return intval($pid);
2797
}
2798

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

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

    
2807
	return intval($pid);
2808
}
2809

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

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

    
2825
	return $mtu;
2826
}
2827

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3094
	interface_netgraph_needed($interface);
3095

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

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

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

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

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

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

    
3124
		if ($reloadall == true) {
3125

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3206
		services_dhcpd_configure("inet6");
3207
	}
3208

    
3209
	return 0;
3210
}
3211

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

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

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

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

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

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

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

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

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

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

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

    
3270
	return 0;
3271
}
3272

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

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

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

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

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

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

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

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

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

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

    
3327
	return 0;
3328
}
3329

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3398
	return 0;
3399
}
3400

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3494
	return 0;
3495
}
3496

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3607
	return 0;
3608
}
3609

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

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

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

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

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

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

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

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

    
3657
}
3658

    
3659
EOD;
3660

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

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

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

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

    
3684
	return 0;
3685
}
3686

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

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

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

    
3696
	return;
3697
}
3698

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

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

    
3711
	return;
3712
}
3713

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

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

    
3723
	return false;
3724
}
3725

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

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

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

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

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

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

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

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

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

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

    
3781
	return NULL;
3782
}
3783

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

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

    
3832
	return $ifdesc;
3833
}
3834

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

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

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

    
3845
	return $interface;
3846
}
3847

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

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

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

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

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

    
3906
	return $parents;
3907
}
3908

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

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

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

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

    
3936
	$wanif = NULL;
3937

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

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

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

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

    
4025
	return $wanif;
4026
}
4027

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

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

    
4073
	$isv6ip = is_ipaddrv6($ip);
4074

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

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

    
4096
	return false;
4097
}
4098

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

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

    
4112
	$isv6ip = is_ipaddrv6($ip);
4113

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

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

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

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

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

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

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

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

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

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

    
4213

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

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

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

    
4246
	return $carp_ints;
4247
}
4248

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

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

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

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

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

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

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

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

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

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

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

    
4331
	$result = array();
4332

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

    
4340
	return $result;
4341
}
4342

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

    
4346
	$result = array();
4347

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

    
4354
	return $result;
4355
}
4356

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

    
4360
	$result = array();
4361

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

    
4368
	return $result;
4369
}
4370

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4498
	return false;
4499
}
4500

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

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

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

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

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

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

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

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

    
4570
	$curip = find_interface_ipv6_ll($realif);
4571
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4572
		return $curip;
4573
	else
4574
		return null;
4575
}
4576

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

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

    
4592
	return null;
4593
}
4594

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

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

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

    
4610
	return null;
4611
}
4612

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

    
4617
	$ints = array();
4618

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

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

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

    
4663
	return false;
4664
}
4665

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

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

    
4691
	return false;
4692
}
4693

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

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

    
4716
	$int_family = remove_ifindex($int);
4717

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

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

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

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

    
4755
	$cloned_interface = get_real_interface($interface);
4756

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

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

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

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

    
4799
	$cloned_interface = get_real_interface($interface);
4800

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

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

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

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

    
4829
function get_interface_mac($interface) {
4830

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

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

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

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

    
4865
	return false;
4866
}
4867

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

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

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

    
4879
EOD;
4880

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

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

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

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

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

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

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

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

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

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

    
4941
			}
4942

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

    
4956
	return 0;
4957
}
4958

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

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

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

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

    
4985
?>
(25-25/66)