Projet

Général

Profil

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

univnautes / etc / inc / interfaces.inc @ 2bf2a1c4

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
			if ($destroy == true) {
1245
				interface_ipalias_cleanup($interface);
1246
				pfSense_interface_flags($realif, -IFF_UP);
1247
			}
1248
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1249
		}
1250
		break;
1251
	default:
1252
		if(does_interface_exist("$realif")) {
1253
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1254
			if ($destroy == true) {
1255
				interface_ipalias_cleanup($interface);
1256
				pfSense_interface_flags($realif, -IFF_UP);
1257
			}
1258
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1259
		}
1260
		break;
1261
	}
1262

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

    
1315
	if (!empty($track6) && is_array($track6)) {
1316
		if (!function_exists('services_dhcp_configure'))
1317
			require_once('services.inc');
1318
		/* Bring down radvd and dhcp6 on these interfaces */
1319
		services_dhcpd_configure('inet6', $track6);
1320
	}
1321

    
1322
	$old_router = '';
1323
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1324
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1325
//	log_error("Checking for old router states: {$g['tmp_path']}/{$realif}_router = {$old_router}");
1326
	if (!empty($old_router)) {
1327
		log_error("Clearing states to old gateway {$old_router}.");
1328
		mwexec("/sbin/pfctl -i " . escapeshellarg($realif) . " -Fs");
1329
	}
1330

    
1331
	/* remove interface up file if it exists */
1332
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1333
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1334
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1335
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1336
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1337
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1338
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1339

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

    
1347
	if ($destroy == true) {
1348
		if (preg_match("/^[a-z0-9]+_vip|^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif))
1349
			pfSense_interface_destroy($realif);
1350
	}
1351

    
1352
	return;
1353
}
1354

    
1355
function interfaces_ptpid_used($ptpid) {
1356
	global $config;
1357

    
1358
	if (is_array($config['ppps']['ppp']))
1359
		foreach ($config['ppps']['ppp'] as & $settings)
1360
			if ($ptpid == $settings['ptpid'])
1361
				return true;
1362

    
1363
	return false;
1364
}
1365

    
1366
function interfaces_ptpid_next() {
1367

    
1368
	$ptpid = 0;
1369
	while(interfaces_ptpid_used($ptpid))
1370
		$ptpid++;
1371

    
1372
	return $ptpid;
1373
}
1374

    
1375
function getMPDCRONSettings($pppif) {
1376
	global $config;
1377

    
1378
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1379
	if (is_array($config['cron']['item'])) {
1380
		foreach ($config['cron']['item'] as $i => $item) {
1381
			if (stripos($item['command'], $cron_cmd_file) !== false)
1382
				return array("ID" => $i, "ITEM" => $item);
1383
		}
1384
	}
1385

    
1386
	return NULL;
1387
}
1388

    
1389
function handle_pppoe_reset($post_array) {
1390
	global $config, $g;
1391

    
1392
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1393
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1394

    
1395
	if (!is_array($config['cron']['item']))
1396
		$config['cron']['item'] = array();
1397

    
1398
	$itemhash = getMPDCRONSettings($pppif);
1399

    
1400
	// reset cron items if necessary and return
1401
	if (empty($post_array['pppoe-reset-type'])) {
1402
		if (isset($itemhash))
1403
			unset($config['cron']['item'][$itemhash['ID']]);
1404
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1405
		return;
1406
	}
1407

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

    
1467
/*
1468
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1469
 * It writes the mpd config file to /var/etc every time the link is opened.
1470
 */
1471
function interface_ppps_configure($interface) {
1472
	global $config, $g;
1473

    
1474
	/* Return for unassigned interfaces. This is a minimum requirement. */
1475
	if (empty($config['interfaces'][$interface]))
1476
		return 0;
1477
	$ifcfg = $config['interfaces'][$interface];
1478
	if (!isset($ifcfg['enable']))
1479
		return 0;
1480

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

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

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

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

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

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

    
1570
	if (is_array($ports) && count($ports) > 1)
1571
		$multilink = "enable";
1572
	else
1573
		$multilink = "disable";
1574

    
1575
	if ($type == "modem"){
1576
		if (is_ipaddr($ppp['localip']))
1577
			$localip = $ppp['localip'];
1578
		else
1579
			$localip = '0.0.0.0';
1580

    
1581
		if (is_ipaddr($ppp['gateway']))
1582
			$gateway = $ppp['gateway'];
1583
		else
1584
			$gateway = "10.64.64.{$pppid}";
1585
		$ranges = "{$localip}/0 {$gateway}/0";
1586

    
1587
		if (empty($ppp['apnum']))
1588
			$ppp['apnum'] = 1;
1589
	} else
1590
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1591

    
1592
	if (isset($ppp['ondemand']))
1593
		$ondemand = "enable";
1594
	else
1595
		$ondemand = "disable";
1596
	if (!isset($ppp['idletimeout']))
1597
		$ppp['idletimeout'] = 0;
1598

    
1599
	if (empty($ppp['username']) && $type == "modem"){
1600
		$ppp['username'] = "user";
1601
		$ppp['password'] = "none";
1602
	}
1603
	if (empty($ppp['password']) && $type == "modem")
1604
		$passwd = "none";
1605
	else
1606
		$passwd = base64_decode($ppp['password']);
1607

    
1608
	$bandwidths = explode(',',$ppp['bandwidth']);
1609
	$defaultmtu = "1492";
1610
	if (!empty($ifcfg['mtu']))
1611
		$defaultmtu = intval($ifcfg['mtu']);
1612
	$mtus = explode(',',$ppp['mtu']);
1613
	$mrus = explode(',',$ppp['mru']);
1614

    
1615
	if (isset($ppp['mrru']))
1616
		$mrrus = explode(',',$ppp['mrru']);
1617

    
1618
	// Construct the mpd.conf file
1619
	$mpdconf = <<<EOD
1620
startup:
1621
	# configure the console
1622
	set console close
1623
	# configure the web server
1624
	set web close
1625

    
1626
default:
1627
{$ppp['type']}client:
1628
	create bundle static {$interface}
1629
	set bundle enable ipv6cp
1630
	set iface name {$pppif}
1631

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

    
1647
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1648
		$setdefaultgw = true;
1649
		$mpdconf .= <<<EOD
1650
	set iface route default
1651

    
1652
EOD;
1653
	}
1654
	$mpdconf .= <<<EOD
1655
	set iface {$ondemand} on-demand
1656
	set iface idle {$ppp['idletimeout']}
1657

    
1658
EOD;
1659

    
1660
	if (isset($ppp['ondemand']))
1661
		$mpdconf .= <<<EOD
1662
	set iface addrs 10.10.1.1 10.10.1.2
1663

    
1664
EOD;
1665

    
1666
	if (isset($ppp['tcpmssfix']))
1667
		$tcpmss = "disable";
1668
	else
1669
		$tcpmss = "enable";
1670
		$mpdconf .= <<<EOD
1671
	set iface {$tcpmss} tcpmssfix
1672

    
1673
EOD;
1674

    
1675
	$mpdconf .= <<<EOD
1676
	set iface up-script /usr/local/sbin/ppp-linkup
1677
	set iface down-script /usr/local/sbin/ppp-linkdown
1678
	set ipcp ranges {$ranges}
1679

    
1680
EOD;
1681
	if (isset($ppp['vjcomp']))
1682
		$mpdconf .= <<<EOD
1683
	set ipcp no vjcomp
1684

    
1685
EOD;
1686

    
1687
	if (isset($config['system']['dnsallowoverride']))
1688
		$mpdconf .= <<<EOD
1689
	set ipcp enable req-pri-dns
1690
	set ipcp enable req-sec-dns
1691

    
1692
EOD;
1693
	if (!isset($ppp['verbose_log']))
1694
		$mpdconf .= <<<EOD
1695
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1696

    
1697
EOD;
1698
	foreach($ports as $pid => $port){
1699
		$port = get_real_interface($port);
1700
		$mpdconf .= <<<EOD
1701

    
1702
	create link static {$interface}_link{$pid} {$type}
1703
	set link action bundle {$interface}
1704
	set link {$multilink} multilink
1705
	set link keep-alive 10 60
1706
	set link max-redial 0
1707

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

    
1713
EOD;
1714

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

    
1719
EOD;
1720

    
1721
		if (isset($ppp['protocomp']))
1722
			$mpdconf .= <<<EOD
1723
	set link no protocomp
1724

    
1725
EOD;
1726

    
1727
		$mpdconf .= <<<EOD
1728
	set link disable chap pap
1729
	set link accept chap pap eap
1730
	set link disable incoming
1731

    
1732
EOD;
1733

    
1734

    
1735
		if (!empty($bandwidths[$pid]))
1736
			$mpdconf .= <<<EOD
1737
	set link bandwidth {$bandwidths[$pid]}
1738

    
1739
EOD;
1740

    
1741
		if (empty($mtus[$pid]))
1742
			$mtus[$pid] = $defaultmtu;
1743
			$mpdconf .= <<<EOD
1744
	set link mtu {$mtus[$pid]}
1745

    
1746
EOD;
1747

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

    
1752
EOD;
1753

    
1754
		if (!empty($mrrus[$pid]))
1755
			$mpdconf .= <<<EOD
1756
	set link mrru {$mrrus[$pid]}
1757

    
1758
EOD;
1759

    
1760
		$mpdconf .= <<<EOD
1761
	set auth authname "{$ppp['username']}"
1762
	set auth password {$passwd}
1763

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

    
1774
EOD;
1775
		}
1776
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1777
			$mpdconf .= <<<EOD
1778
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1779

    
1780
EOD;
1781
		}
1782
		if (isset($ppp['initstr']) && $type == "modem") {
1783
			$initstr = base64_decode($ppp['initstr']);
1784
			$mpdconf .= <<<EOD
1785
	set modem var \$InitString "{$initstr}"
1786

    
1787
EOD;
1788
		}
1789
		if (isset($ppp['simpin']) && $type == "modem") {
1790
			if($ppp['pin-wait'] == "")
1791
				$ppp['pin-wait'] = 0;
1792
			$mpdconf .= <<<EOD
1793
	set modem var \$SimPin "{$ppp['simpin']}"
1794
	set modem var \$PinWait "{$ppp['pin-wait']}"
1795

    
1796
EOD;
1797
		}
1798
		if (isset($ppp['apn']) && $type == "modem") {
1799
			$mpdconf .= <<<EOD
1800
	set modem var \$APN "{$ppp['apn']}"
1801
	set modem var \$APNum "{$ppp['apnum']}"
1802

    
1803
EOD;
1804
		}
1805
		if ($type == "pppoe") {
1806
			// Send a null service name if none is set.
1807
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1808
			$mpdconf .= <<<EOD
1809
	set pppoe service "{$provider}"
1810

    
1811
EOD;
1812
		}
1813
		if ($type == "pppoe")
1814
			$mpdconf .= <<<EOD
1815
	set pppoe iface {$port}
1816

    
1817
EOD;
1818

    
1819
		if ($type == "pptp" || $type == "l2tp") {
1820
			$mpdconf .= <<<EOD
1821
	set {$type} self {$localips[$pid]}
1822
	set {$type} peer {$gateways[$pid]}
1823

    
1824
EOD;
1825
		}
1826

    
1827
		$mpdconf .= "\topen\n";
1828
	} //end foreach($port)
1829

    
1830

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

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

    
1861
	/* clean up old lock files */
1862
	foreach($ports as $port) {
1863
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1864
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1865
	}
1866

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

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

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

    
1906
	return 1;
1907
}
1908

    
1909
function interfaces_carp_setup() {
1910
	global $g, $config;
1911

    
1912
	if (isset($config['system']['developerspew'])) {
1913
		$mt = microtime();
1914
		echo "interfaces_carp_setup() being called $mt\n";
1915
	}
1916

    
1917
	if ($g['booting']) {
1918
		echo gettext("Configuring CARP settings...");
1919
		mute_kernel_msgs();
1920
	}
1921

    
1922
	/* suck in configuration items */
1923
	if ($config['hasync']) {
1924
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1925
		$balancing = $config['hasync']['balancing'];
1926
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1927
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1928
	} else {
1929
		unset($pfsyncinterface);
1930
		unset($balancing);
1931
		unset($pfsyncenabled);
1932
	}
1933

    
1934
	if ($balancing) {
1935
		mwexec("/sbin/sysctl net.inet.carp.arpbalance=1", true);
1936
		mwexec("/sbin/sysctl net.inet.carp.preempt=0", true);
1937
	} else
1938
		mwexec("/sbin/sysctl net.inet.carp.preempt=1", true);
1939

    
1940
	mwexec("sbin/sysctl net.inet.carp.log=1", true);
1941
	if (!empty($pfsyncinterface))
1942
		$carp_sync_int = get_real_interface($pfsyncinterface);
1943
	else
1944
		unset($carp_sync_int);
1945

    
1946
	/* setup pfsync interface */
1947
	if ($carp_sync_int and $pfsyncenabled) {
1948
		if (is_ipaddr($pfsyncpeerip))
1949
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1950
		else
1951
			$syncpeer = "-syncpeer";
1952

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

    
1955
		sleep(1);
1956

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

    
1972
	if($config['virtualip']['vip'])
1973
		mwexec("/sbin/sysctl net.inet.carp.allow=1", true);
1974
	else
1975
		mwexec("/sbin/sysctl net.inet.carp.allow=0", true);
1976

    
1977
	if ($g['booting']) {
1978
		unmute_kernel_msgs();
1979
		echo gettext("done.") . "\n";
1980
	}
1981
}
1982

    
1983
function interface_proxyarp_configure($interface = "") {
1984
	global $config, $g;
1985
	if(isset($config['system']['developerspew'])) {
1986
		$mt = microtime();
1987
		echo "interface_proxyarp_configure() being called $mt\n";
1988
	}
1989

    
1990
	/* kill any running choparp */
1991
	if (empty($interface))
1992
		killbyname("choparp");
1993
	else {
1994
		$vipif = get_real_interface($interface);
1995
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1996
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1997
	}
1998

    
1999
	$paa = array();
2000
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2001

    
2002
		/* group by interface */
2003
		foreach ($config['virtualip']['vip'] as $vipent) {
2004
			if ($vipent['mode'] === "proxyarp") {
2005
				if ($vipent['interface'])
2006
					$proxyif = $vipent['interface'];
2007
				else
2008
					$proxyif = "wan";
2009

    
2010
				if (!empty($interface) && $interface != $proxyif)
2011
					continue;
2012

    
2013
				if (!is_array($paa[$proxyif]))
2014
					$paa[$proxyif] = array();
2015

    
2016
				$paa[$proxyif][] = $vipent;
2017
			}
2018
		}
2019
	}
2020

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

    
2052
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2053
	global $g, $config;
2054

    
2055
	if (is_array($config['virtualip']['vip'])) {
2056
		foreach ($config['virtualip']['vip'] as $vip) {
2057
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2058
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2059
					interface_vip_bring_down($vip);
2060
				else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2061
					interface_vip_bring_down($vip);
2062
			}
2063
		}
2064
	}
2065
}
2066

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

    
2106
function interface_ipalias_configure(&$vip) {
2107
	global $config;
2108

    
2109
	if ($vip['mode'] != "ipalias")
2110
		return;
2111

    
2112
	$if = get_real_interface($vip['interface']);
2113

    
2114
	if ($vip['interface'] != 'lo0' && stristr($if, "_vip") === false) {
2115
		if (!isset($config['interfaces'][$vip['interface']]))
2116
			return;
2117

    
2118
		if (!isset($config['interfaces'][$vip['interface']]['enable']))
2119
			return;
2120
	}
2121

    
2122
	$af = "inet";
2123
	if(is_ipaddrv6($vip['subnet']))
2124
		$af = "inet6";
2125
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
2126
}
2127

    
2128
function interface_reload_carps($cif) {
2129
	global $config;
2130

    
2131
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2132
	if (empty($carpifs))
2133
		return;
2134

    
2135
	$carps = explode(" ", $carpifs);
2136
	if(is_array($config['virtualip']['vip'])) {
2137
		$viparr = &$config['virtualip']['vip'];
2138
		foreach ($viparr as $vip) {
2139
			if (in_array($vip['carpif'], $carps)) {
2140
				switch ($vip['mode']) {
2141
				case "carp":
2142
					interface_vip_bring_down($vip);
2143
					sleep(1);
2144
					interface_carp_configure($vip);
2145
					break;
2146
				case "ipalias":
2147
					interface_vip_bring_down($vip);
2148
					sleep(1);
2149
					interface_ipalias_configure($vip);
2150
					break;
2151
				}
2152
			}
2153
		}
2154
	}
2155
}
2156

    
2157
function interface_carp_configure(&$vip) {
2158
	global $config, $g;
2159
	if(isset($config['system']['developerspew'])) {
2160
		$mt = microtime();
2161
		echo "interface_carp_configure() being called $mt\n";
2162
	}
2163

    
2164
	if ($vip['mode'] != "carp")
2165
		return;
2166

    
2167
	/*
2168
	 * ensure the interface containing the VIP really exists
2169
	 * prevents a panic if the interface is missing or invalid
2170
	 */
2171
	$realif = get_real_interface($vip['interface']);
2172
	if (!does_interface_exist($realif)) {
2173
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2174
		return;
2175
	}
2176

    
2177
	if(is_ipaddrv4($vip['subnet'])) {
2178
		/* Ensure CARP IP really exists prior to loading up. */
2179
		$ww_subnet_ip = find_interface_ip($realif);
2180
		$ww_subnet_bits = find_interface_subnet($realif);
2181
		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'])) {
2182
			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", "");
2183
			return;
2184
		}
2185
	}
2186
	if(is_ipaddrv6($vip['subnet'])) {
2187
		/* Ensure CARP IP really exists prior to loading up. */
2188
		$ww_subnet_ip = find_interface_ipv6($realif);
2189
		$ww_subnet_bits = find_interface_subnetv6($realif);
2190
		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'])) {
2191
			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", "");
2192
			return;
2193
		}
2194
	}
2195

    
2196
	// set the vip interface to the vhid
2197
	$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
2198

    
2199
	/* create the carp interface and setup */
2200
	if (does_interface_exist($vipif)) {
2201
		pfSense_interface_flags($vipif, -IFF_UP);
2202
	} else {
2203
		$carpif = pfSense_interface_create("carp");
2204
		pfSense_interface_rename($carpif, $vipif);
2205
		pfSense_ngctl_name("{$carpif}:", $vipif);
2206
	}
2207

    
2208
	/* invalidate interface cache */
2209
	get_interface_arr(true);
2210

    
2211
	$vip_password = $vip['password'];
2212
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2213
	if ($vip['password'] != "")
2214
		$password = " pass {$vip_password}";
2215

    
2216
	$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2217
	$advbase = "";
2218
	if (!empty($vip['advbase']))
2219
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2220

    
2221
	if(is_ipaddrv4($vip['subnet'])) {
2222
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2223
		mwexec("/sbin/ifconfig {$vipif} {$vip['subnet']}/{$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2224
	}
2225
	if(is_ipaddrv6($vip['subnet'])) {
2226
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2227
		mwexec("/sbin/ifconfig {$vipif} inet6 {$vip['subnet']} prefixlen {$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2228
	}
2229

    
2230
	interfaces_bring_up($vipif);
2231

    
2232
	if (isset($config['virtualip']['vip']) && is_array($config['virtualip']['vip'])) {
2233
		foreach ($config['virtualip']['vip'] as &$vip_alias) {
2234
			if ($vip_alias['interface'] == $vipif)
2235
				interface_ipalias_configure($vip_alias);
2236
		}
2237
	}
2238

    
2239
	return $vipif;
2240
}
2241

    
2242
function interface_wireless_clone($realif, $wlcfg) {
2243
	global $config, $g;
2244
	/*   Check to see if interface has been cloned as of yet.
2245
	 *   If it has not been cloned then go ahead and clone it.
2246
	 */
2247
	$needs_clone = false;
2248
	if(is_array($wlcfg['wireless']))
2249
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2250
	else
2251
		$wlcfg_mode = $wlcfg['mode'];
2252
	switch($wlcfg_mode) {
2253
	case "hostap":
2254
		$mode = "wlanmode hostap";
2255
		break;
2256
	case "adhoc":
2257
		$mode = "wlanmode adhoc";
2258
		break;
2259
	default:
2260
		$mode = "";
2261
		break;
2262
	}
2263
	$baseif = interface_get_wireless_base($wlcfg['if']);
2264
	if(does_interface_exist($realif)) {
2265
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2266
		$ifconfig_str = implode($output);
2267
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
2268
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2269
			$needs_clone = true;
2270
		}
2271
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
2272
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2273
			$needs_clone = true;
2274
		}
2275
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2276
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2277
			$needs_clone = true;
2278
		}
2279
	} else {
2280
		$needs_clone = true;
2281
	}
2282

    
2283
	if($needs_clone == true) {
2284
		/* remove previous instance if it exists */
2285
		if(does_interface_exist($realif))
2286
			pfSense_interface_destroy($realif);
2287

    
2288
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2289
		// Create the new wlan interface. FreeBSD returns the new interface name.
2290
		// example:  wlan2
2291
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2292
		if($ret <> 0) {
2293
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2294
			return false;
2295
		}
2296
		$newif = trim($out[0]);
2297
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2298
		pfSense_interface_rename($newif, $realif);
2299
		// FIXME: not sure what ngctl is for. Doesn't work.
2300
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
2301
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2302
	}
2303
	return true;
2304
}
2305

    
2306
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2307
	global $config, $g;
2308

    
2309
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2310
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2311
				 'regdomain', 'regcountry', 'reglocation');
2312

    
2313
	if(!is_interface_wireless($ifcfg['if']))
2314
		return;
2315

    
2316
	$baseif = interface_get_wireless_base($ifcfg['if']);
2317

    
2318
	// Sync shared settings for assigned clones
2319
	$iflist = get_configured_interface_list(false, true);
2320
	foreach ($iflist as $if) {
2321
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2322
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2323
				foreach ($shared_settings as $setting) {
2324
					if ($sync_changes) {
2325
						if (isset($ifcfg['wireless'][$setting]))
2326
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2327
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2328
							unset($config['interfaces'][$if]['wireless'][$setting]);
2329
					} else {
2330
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2331
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2332
						else if (isset($ifcfg['wireless'][$setting]))
2333
							unset($ifcfg['wireless'][$setting]);
2334
					}
2335
				}
2336
				if (!$sync_changes)
2337
					break;
2338
			}
2339
		}
2340
	}
2341

    
2342
	// Read or write settings at shared area
2343
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2344
		foreach ($shared_settings as $setting) {
2345
			if ($sync_changes) {
2346
				if (isset($ifcfg['wireless'][$setting]))
2347
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2348
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2349
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2350
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2351
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2352
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2353
				else if (isset($ifcfg['wireless'][$setting]))
2354
					unset($ifcfg['wireless'][$setting]);
2355
			}
2356
		}
2357
	}
2358

    
2359
	// Sync the mode on the clone creation page with the configured mode on the interface
2360
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2361
		foreach ($config['wireless']['clone'] as &$clone) {
2362
			if ($clone['cloneif'] == $ifcfg['if']) {
2363
				if ($sync_changes) {
2364
					$clone['mode'] = $ifcfg['wireless']['mode'];
2365
				} else {
2366
					$ifcfg['wireless']['mode'] = $clone['mode'];
2367
				}
2368
				break;
2369
			}
2370
		}
2371
		unset($clone);
2372
	}
2373
}
2374

    
2375
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2376
	global $config, $g;
2377

    
2378
	/*    open up a shell script that will be used to output the commands.
2379
	 *    since wireless is changing a lot, these series of commands are fragile
2380
	 *    and will sometimes need to be verified by a operator by executing the command
2381
	 *    and returning the output of the command to the developers for inspection.  please
2382
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2383
	 */
2384

    
2385
	// Remove script file
2386
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2387

    
2388
	// Clone wireless nic if needed.
2389
	interface_wireless_clone($if, $wl);
2390

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

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

    
2398
	/* set values for /path/program */
2399
	$hostapd = "/usr/sbin/hostapd";
2400
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2401
	$ifconfig = "/sbin/ifconfig";
2402
	$sysctl = "/sbin/sysctl";
2403
	$killall = "/usr/bin/killall";
2404

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

    
2407
	$wlcmd = array();
2408
	$wl_sysctl = array();
2409
	/* Make sure it's up */
2410
	$wlcmd[] = "up";
2411
	/* Set a/b/g standard */
2412
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2413
	$wlcmd[] = "mode " . escapeshellarg($standard);
2414

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

    
2420
	/* Set ssid */
2421
	if($wlcfg['ssid'])
2422
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2423

    
2424
	/* Set 802.11g protection mode */
2425
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2426

    
2427
	/* set wireless channel value */
2428
	if(isset($wlcfg['channel'])) {
2429
		if($wlcfg['channel'] == "0") {
2430
			$wlcmd[] = "channel any";
2431
		} else {
2432
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2433
		}
2434
	}
2435

    
2436
	/* Set antenna diversity value */
2437
	if(isset($wlcfg['diversity']))
2438
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2439

    
2440
	/* Set txantenna value */
2441
	if(isset($wlcfg['txantenna']))
2442
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2443

    
2444
	/* Set rxantenna value */
2445
	if(isset($wlcfg['rxantenna']))
2446
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2447

    
2448
	/* set Distance value */
2449
	if($wlcfg['distance'])
2450
		$distance = escapeshellarg($wlcfg['distance']);
2451

    
2452
	/* Set wireless hostap mode */
2453
	if ($wlcfg['mode'] == "hostap") {
2454
		$wlcmd[] = "mediaopt hostap";
2455
	} else {
2456
		$wlcmd[] = "-mediaopt hostap";
2457
	}
2458

    
2459
	/* Set wireless adhoc mode */
2460
	if ($wlcfg['mode'] == "adhoc") {
2461
		$wlcmd[] = "mediaopt adhoc";
2462
	} else {
2463
		$wlcmd[] = "-mediaopt adhoc";
2464
	}
2465

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

    
2468
	/* handle hide ssid option */
2469
	if(isset($wlcfg['hidessid']['enable'])) {
2470
		$wlcmd[] = "hidessid";
2471
	} else {
2472
		$wlcmd[] = "-hidessid";
2473
	}
2474

    
2475
	/* handle pureg (802.11g) only option */
2476
	if(isset($wlcfg['pureg']['enable'])) {
2477
		$wlcmd[] = "mode 11g pureg";
2478
	} else {
2479
		$wlcmd[] = "-pureg";
2480
	}
2481

    
2482
	/* handle puren (802.11n) only option */
2483
	if(isset($wlcfg['puren']['enable'])) {
2484
		$wlcmd[] = "puren";
2485
	} else {
2486
		$wlcmd[] = "-puren";
2487
	}
2488

    
2489
	/* enable apbridge option */
2490
	if(isset($wlcfg['apbridge']['enable'])) {
2491
		$wlcmd[] = "apbridge";
2492
	} else {
2493
		$wlcmd[] = "-apbridge";
2494
	}
2495

    
2496
	/* handle turbo option */
2497
	if(isset($wlcfg['turbo']['enable'])) {
2498
		$wlcmd[] = "mediaopt turbo";
2499
	} else {
2500
		$wlcmd[] = "-mediaopt turbo";
2501
	}
2502

    
2503
	/* handle txpower setting */
2504
	/* if($wlcfg['txpower'] <> "")
2505
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2506
	*/
2507
	/* handle wme option */
2508
	if(isset($wlcfg['wme']['enable'])) {
2509
		$wlcmd[] = "wme";
2510
	} else {
2511
		$wlcmd[] = "-wme";
2512
	}
2513

    
2514
	/* set up wep if enabled */
2515
	$wepset = "";
2516
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2517
		switch($wlcfg['wpa']['auth_algs']) {
2518
			case "1":
2519
				$wepset .= "authmode open wepmode on ";
2520
				break;
2521
			case "2":
2522
				$wepset .= "authmode shared wepmode on ";
2523
				break;
2524
			case "3":
2525
				$wepset .= "authmode mixed wepmode on ";
2526
		}
2527
		$i = 1;
2528
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2529
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2530
			if (isset($wepkey['txkey'])) {
2531
				$wlcmd[] = "weptxkey {$i} ";
2532
			}
2533
			$i++;
2534
		}
2535
		$wlcmd[] = $wepset;
2536
	} else {
2537
		$wlcmd[] = "authmode open wepmode off ";
2538
	}
2539

    
2540
	kill_hostapd($if);
2541
	mwexec(kill_wpasupplicant("{$if}"));
2542

    
2543
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2544
	conf_mount_rw();
2545

    
2546
	switch ($wlcfg['mode']) {
2547
	case 'bss':
2548
		if (isset($wlcfg['wpa']['enable'])) {
2549
			$wpa .= <<<EOD
2550
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2551
ctrl_interface_group=0
2552
ap_scan=1
2553
#fast_reauth=1
2554
network={
2555
ssid="{$wlcfg['ssid']}"
2556
scan_ssid=1
2557
priority=5
2558
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2559
psk="{$wlcfg['wpa']['passphrase']}"
2560
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2561
group={$wlcfg['wpa']['wpa_pairwise']}
2562
}
2563
EOD;
2564

    
2565
			@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2566
			unset($wpa);
2567
		}
2568
		break;
2569
	case 'hostap':
2570
		if (!empty($wlcfg['wpa']['passphrase']))
2571
			$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2572
		else
2573
			$wpa_passphrase = "";
2574
		if (isset($wlcfg['wpa']['enable'])) {
2575
			$wpa .= <<<EOD
2576
interface={$if}
2577
driver=bsd
2578
logger_syslog=-1
2579
logger_syslog_level=0
2580
logger_stdout=-1
2581
logger_stdout_level=0
2582
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2583
ctrl_interface={$g['varrun_path']}/hostapd
2584
ctrl_interface_group=wheel
2585
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2586
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2587
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2588
ssid={$wlcfg['ssid']}
2589
debug={$wlcfg['wpa']['debug_mode']}
2590
auth_algs={$wlcfg['wpa']['auth_algs']}
2591
wpa={$wlcfg['wpa']['wpa_mode']}
2592
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2593
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2594
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2595
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2596
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2597
{$wpa_passphrase}
2598

    
2599
EOD;
2600

    
2601
			if (isset($wlcfg['wpa']['rsn_preauth'])) {
2602
				$wpa .= <<<EOD
2603
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2604
rsn_preauth=1
2605
rsn_preauth_interfaces={$if}
2606

    
2607
EOD;
2608
			}
2609
			if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2610
				$wpa .= "ieee8021x=1\n";
2611

    
2612
			if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2613
				$auth_server_port = "1812";
2614
				if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port']))
2615
					$auth_server_port = intval($wlcfg['auth_server_port']);
2616
				$wpa .= <<<EOD
2617

    
2618
auth_server_addr={$wlcfg['auth_server_addr']}
2619
auth_server_port={$auth_server_port}
2620
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2621

    
2622
EOD;
2623
				if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2624
					$auth_server_port2 = "1812";
2625
					if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2']))
2626
						$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2627

    
2628
					$wpa .= <<<EOD
2629
auth_server_addr={$wlcfg['auth_server_addr2']}
2630
auth_server_port={$auth_server_port2}
2631
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2632

    
2633
EOD;
2634
					}
2635
				}
2636
			}
2637

    
2638
			@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2639
			unset($wpa);
2640
		}
2641
		break;
2642
	}
2643

    
2644
	/*
2645
	 *    all variables are set, lets start up everything
2646
	 */
2647

    
2648
	$baseif = interface_get_wireless_base($if);
2649
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2650
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2651

    
2652
	/* set sysctls for the wireless interface */
2653
	if (!empty($wl_sysctl)) {
2654
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2655
		foreach ($wl_sysctl as $wl_sysctl_line) {
2656
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2657
		}
2658
	}
2659

    
2660
	/* set ack timers according to users preference (if he/she has any) */
2661
	if($distance) {
2662
		fwrite($fd_set, "# Enable ATH distance settings\n");
2663
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2664
	}
2665

    
2666
	if (isset($wlcfg['wpa']['enable'])) {
2667
		if ($wlcfg['mode'] == "bss") {
2668
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2669
		}
2670
		if ($wlcfg['mode'] == "hostap") {
2671
			/* add line to script to restore old mac to make hostapd happy */
2672
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2673
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2674
				if (is_macaddr($if_oldmac))
2675
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2676
						" link " . escapeshellarg($if_oldmac) . "\n");
2677
			}
2678

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

    
2681
			/* add line to script to restore spoofed mac after running hostapd */
2682
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2683
				if ($wl['spoofmac'])
2684
					$if_curmac = $wl['spoofmac'];
2685
				else
2686
					$if_curmac = get_interface_mac($if);
2687
				if (is_macaddr($if_curmac))
2688
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2689
						" link " . escapeshellarg($if_curmac) . "\n");
2690
			}
2691
		}
2692
	}
2693

    
2694
	fclose($fd_set);
2695
	conf_mount_ro();
2696

    
2697
	/* Making sure regulatory settings have actually changed
2698
	 * before applying, because changing them requires bringing
2699
	 * down all wireless networks on the interface. */
2700
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2701
	$ifconfig_str = implode($output);
2702
	unset($output);
2703
	$reg_changing = false;
2704

    
2705
	/* special case for the debug country code */
2706
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2707
		$reg_changing = true;
2708
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2709
		$reg_changing = true;
2710
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2711
		$reg_changing = true;
2712
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2713
		$reg_changing = true;
2714
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2715
		$reg_changing = true;
2716

    
2717
	if ($reg_changing) {
2718
		/* set regulatory domain */
2719
		if($wlcfg['regdomain'])
2720
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2721

    
2722
		/* set country */
2723
		if($wlcfg['regcountry'])
2724
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2725

    
2726
		/* set location */
2727
		if($wlcfg['reglocation'])
2728
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2729

    
2730
		$wlregcmd_args = implode(" ", $wlregcmd);
2731

    
2732
		/* build a complete list of the wireless clones for this interface */
2733
		$clone_list = array();
2734
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2735
			$clone_list[] = interface_get_wireless_clone($baseif);
2736
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2737
			foreach ($config['wireless']['clone'] as $clone) {
2738
				if ($clone['if'] == $baseif)
2739
					$clone_list[] = $clone['cloneif'];
2740
			}
2741
		}
2742

    
2743
		/* find which clones are up and bring them down */
2744
		$clones_up = array();
2745
		foreach ($clone_list as $clone_if) {
2746
			$clone_status = pfSense_get_interface_addresses($clone_if);
2747
			if ($clone_status['status'] == 'up') {
2748
				$clones_up[] = $clone_if;
2749
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2750
			}
2751
		}
2752

    
2753
		/* apply the regulatory settings */
2754
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2755

    
2756
		/* bring the clones back up that were previously up */
2757
		foreach ($clones_up as $clone_if) {
2758
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2759

    
2760
			/*
2761
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2762
			 * is in infrastructure mode, and WPA is enabled.
2763
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2764
			 */
2765
			if ($clone_if != $if) {
2766
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2767
				if ( !empty($friendly_if)
2768
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2769
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2770
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2771
				}
2772
			}
2773
		}
2774
	}
2775

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

    
2780
	/* configure wireless */
2781
	$wlcmd_args = implode(" ", $wlcmd);
2782
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2783
	unset($wlcmd_args, $wlcmd);
2784

    
2785

    
2786
	sleep(1);
2787
	/* execute hostapd and wpa_supplicant if required in shell */
2788
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2789

    
2790
	return 0;
2791

    
2792
}
2793

    
2794
function kill_hostapd($interface) {
2795
	global $g;
2796

    
2797
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2798
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2799
}
2800

    
2801
function kill_wpasupplicant($interface) {
2802
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2803
}
2804

    
2805
function find_dhclient_process($interface) {
2806
	if ($interface)
2807
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2808
	else
2809
		$pid = 0;
2810

    
2811
	return intval($pid);
2812
}
2813

    
2814
function find_dhcp6c_process($interface) {
2815
	global $g;
2816

    
2817
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid"))
2818
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2819
	else
2820
		return(false);
2821

    
2822
	return intval($pid);
2823
}
2824

    
2825
function interface_vlan_mtu_configured($realhwif, $mtu) {
2826
	global $config;
2827

    
2828
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
2829
		foreach ($config['vlans']['vlan'] as $vlan) {
2830
			if ($vlan['if'] != $realhwif)
2831
				continue;
2832
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2833
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
2834
				if (intval($config['interfaces'][$assignedport]['mtu'])> $mtu)
2835
					$mtu = $portmtu;
2836
			}
2837
		}
2838
	}
2839

    
2840
	return $mtu;
2841
}
2842

    
2843
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2844
	global $config;
2845

    
2846
	if (!is_array($vlanifs))
2847
		return;
2848

    
2849
	/* All vlans need to use the same mtu value as their parent. */
2850
	foreach ($vlanifs as $vlan) {
2851
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2852
		if (!empty($assignedport)) {
2853
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
2854
				/*
2855
				* XXX: This is really never going to happen just keep the code for safety and readbility.
2856
				* It never happens since interface_vlan_mtu_configured finds the biggest mtu on vlans.
2857
				* Also if it has a lower mtu configured just respect user choice.
2858
				*/
2859
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2860
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2861
			} else {
2862
				if (get_interface_mtu($vlan['vlanif']) != $mtu)
2863
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2864
			}
2865
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2866
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
2867
	}
2868
}
2869

    
2870
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2871
	global $config, $g;
2872
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2873
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2874

    
2875
	$wancfg = $config['interfaces'][$interface];
2876

    
2877
	if (!isset($wancfg['enable']))
2878
		return;
2879

    
2880
	$realif = get_real_interface($interface);
2881
	$realhwif_array = get_parent_interface($interface);
2882
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2883
	$realhwif = $realhwif_array[0];
2884

    
2885
	if (!does_interface_exist($realif)) {
2886
		$matches = array();
2887
		if (preg_match('/^(.*)_vlan([0-9]+)$/', $realif, $matches))
2888
			if (is_array($config['vlans']['vlan']))
2889
				foreach ($config['vlans']['vlan'] as $vlan)
2890
					if ($vlan['if'] == $matches[1] && $vlan['tag'] == $matches[2]) {
2891
						interface_vlan_configure($vlan);
2892
						break;
2893
					}
2894
		unset($matches);
2895
	}
2896

    
2897
	/* Disable Accepting router advertisements unless specifically requested */
2898
	if ($g['debug'])
2899
		log_error("Deny router advertisements for interface {$interface}");
2900
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2901

    
2902
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2903
		/* remove all IPv4 and IPv6 addresses */
2904
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2905
		if (is_array($tmpifaces)) {
2906
			foreach ($tmpifaces as $tmpiface) {
2907
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
2908
					if (!is_linklocal($tmpiface))
2909
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2910
				} else {
2911
					if (is_subnetv4($tmpiface)) {
2912
						$tmpip = explode('/', $tmpiface);
2913
						$tmpip = $tmpip[0];
2914
					} else
2915
						$tmpip = $tmpiface;
2916
					pfSense_interface_deladdress($realif, $tmpip);
2917
				}
2918
			}
2919
		}
2920

    
2921
		/* only bring down the interface when both v4 and v6 are set to NONE */
2922
		if(empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
2923
			interface_bring_down($interface);
2924
		}
2925
	}
2926

    
2927
	/* wireless configuration? */
2928
	if (is_array($wancfg['wireless']))
2929
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2930

    
2931
	$mac = get_interface_mac($realhwif);
2932
	/*
2933
	 * Don't try to reapply the spoofed MAC if it's already applied.
2934
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2935
	 * the interface config again, which attempts to spoof the MAC again,
2936
	 * which cycles the link again...
2937
	 */
2938
	if (!empty($wancfg['spoofmac']) && ($wancfg['spoofmac'] != $mac)) {
2939
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2940
			" link " . escapeshellarg($wancfg['spoofmac']));
2941

    
2942
		/*
2943
		 * All vlans need to spoof their parent mac address, too.  see
2944
		 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2945
		 */
2946
		if (is_array($config['vlans']['vlan'])) {
2947
			foreach ($config['vlans']['vlan'] as $vlan) {
2948
				if ($vlan['if'] == $realhwif)
2949
					mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2950
					" link " . escapeshellarg($wancfg['spoofmac']));
2951
			}
2952
		}
2953
	}  else {
2954

    
2955
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2956
			/*   this is not a valid mac address.  generate a
2957
			 *   temporary mac address so the machine can get online.
2958
			 */
2959
			echo gettext("Generating new MAC address.");
2960
			$random_mac = generate_random_mac_address();
2961
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2962
				" link " . escapeshellarg($random_mac));
2963
			$wancfg['spoofmac'] = $random_mac;
2964
			write_config();
2965
			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");
2966
		}
2967
	}
2968

    
2969
	/* media */
2970
	if (!empty($wancfg['media']) || !empty($wancfg['mediaopt'])) {
2971
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2972
		if ($wancfg['media'])
2973
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2974
		if ($wancfg['mediaopt'])
2975
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2976
		mwexec($cmd);
2977
	}
2978
	$options = pfSense_get_interface_addresses($realhwif);
2979

    
2980
	/* skip vlans for checksumming and polling */
2981
	if (!stristr($realif, "_vlan") && is_array($options)) {
2982
		$flags_on = 0;
2983
		$flags_off = 0;
2984
		if(isset($config['system']['disablechecksumoffloading'])) {
2985
			if (isset($options['encaps']['txcsum']))
2986
				$flags_off |= IFCAP_TXCSUM;
2987
			if (isset($options['encaps']['rxcsum']))
2988
				$flags_off |= IFCAP_RXCSUM;
2989
		} else {
2990
			if (isset($options['caps']['txcsum']))
2991
				$flags_on |= IFCAP_TXCSUM;
2992
			if (isset($options['caps']['rxcsum']))
2993
				$flags_on |= IFCAP_RXCSUM;
2994
		}
2995

    
2996
		if(isset($config['system']['disablesegmentationoffloading']))
2997
			$flags_off |= IFCAP_TSO;
2998
		else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6']))
2999
			$flags_on |= IFCAP_TSO;
3000

    
3001
		if(isset($config['system']['disablelargereceiveoffloading']))
3002
			$flags_off |= IFCAP_LRO;
3003
		else if (isset($options['caps']['lro']))
3004
			$flags_on |= IFCAP_LRO;
3005

    
3006
		/* if the NIC supports polling *AND* it is enabled in the GUI */
3007
		if (!isset($config['system']['polling']))
3008
			$flags_off |= IFCAP_POLLING;
3009
		else if (isset($options['caps']['polling']))
3010
			$flags_on |= IFCAP_POLLING;
3011

    
3012
		pfSense_interface_capabilities($realhwif, -$flags_off);
3013
		pfSense_interface_capabilities($realhwif, $flags_on);
3014
	}
3015

    
3016
	/* invalidate interface/ip/sn cache */
3017
	get_interface_arr(true);
3018
	unset($interface_ip_arr_cache[$realif]);
3019
	unset($interface_sn_arr_cache[$realif]);
3020
	unset($interface_ipv6_arr_cache[$realif]);
3021
	unset($interface_snv6_arr_cache[$realif]);
3022

    
3023
	$tunnelif = substr($realif, 0, 3);
3024
	switch ($wancfg['ipaddr']) {
3025
		case 'dhcp':
3026
			interface_dhcp_configure($interface);
3027
			break;
3028
		case 'pppoe':
3029
		case 'l2tp':
3030
		case 'pptp':
3031
		case 'ppp':
3032
			interface_ppps_configure($interface);
3033
			break;
3034
		default:
3035
			if ($tunnelif == "gre") {
3036
				if (is_array($config['gres']['gre'])) {
3037
					foreach ($config['gres']['gre'] as $gre)
3038
						if ($gre['greif'] == $realif)
3039
							interface_gre_configure($gre);
3040
				}
3041
			} else if ($tunnelif == "gif") {
3042
				if (is_array($config['gifs']['gif'])) {
3043
					foreach ($config['gifs']['gif'] as $gif)
3044
						if($gif['gifif'] == $realif)
3045
							interface_gif_configure($gif);
3046
				}
3047
			} else if (substr($realif, 0, 4) == "ovpn") {
3048
				/* XXX: Should be done anything?! */
3049
			} else if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3050
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3051
			}
3052
			break;
3053
	}
3054

    
3055
	switch ($wancfg['ipaddrv6']) {
3056
		case 'slaac':
3057
		case 'dhcp6':
3058
			interface_dhcpv6_configure($interface, $wancfg);
3059
			break;
3060
		case '6rd':
3061
			interface_6rd_configure($interface, $wancfg);
3062
			break;
3063
		case '6to4':
3064
			interface_6to4_configure($interface, $wancfg);
3065
			break;
3066
		case 'track6':
3067
			interface_track6_configure($interface, $wancfg, $linkupevent);
3068
			break;
3069
		default:
3070
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3071
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3072
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3073
					// FIXME: Add IPv6 Support to the pfSense module
3074
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3075
				}
3076
			}
3077
			break;
3078
	}
3079

    
3080
	if (!empty($wancfg['mtu'])) {
3081
		if (stristr($realif, "_vlan")) {
3082
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3083
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
3084
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3085
			else 
3086
				$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
3087

    
3088
			if ($wancfg['mtu'] > $parentmtu) {
3089
				if (get_interface_mtu($realhwif) != $wancfg['mtu'])
3090
					pfSense_interface_mtu($realhwif, $wancfg['mtu']);
3091

    
3092
				/* All vlans need to use the same mtu value as their parent. */
3093
				interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $wancfg['mtu']);
3094
			} else
3095
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3096
		} else {
3097
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3098
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3099

    
3100
			/* This case is needed when the parent of vlans is being configured */
3101
			interface_vlan_adapt_mtu(link_interface_to_vlans($realif), $wancfg['mtu']);
3102
		}
3103
		/* XXX: What about gre/gif/lagg/.. ? */
3104
	}
3105

    
3106
	if (does_interface_exist($wancfg['if']))
3107
		interfaces_bring_up($wancfg['if']);
3108

    
3109
	interface_netgraph_needed($interface);
3110

    
3111
	if (!$g['booting']) {
3112
		link_interface_to_vips($interface, "update");
3113

    
3114
		unset($gre);
3115
		$gre = link_interface_to_gre($interface);
3116
		if (!empty($gre))
3117
			array_walk($gre, 'interface_gre_configure');
3118

    
3119
		unset($gif);
3120
		$gif = link_interface_to_gif($interface);
3121
		if (!empty($gif))
3122
			array_walk($gif, 'interface_gif_configure');
3123

    
3124
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3125
			unset($bridgetmp);
3126
			$bridgetmp = link_interface_to_bridge($interface);
3127
			if (!empty($bridgetmp))
3128
				interface_bridge_add_member($bridgetmp, $realif);
3129
		}
3130

    
3131
		$grouptmp = link_interface_to_group($interface);
3132
		if (!empty($grouptmp))
3133
			array_walk($grouptmp, 'interface_group_add_member');
3134

    
3135
		if ($interface == "lan")
3136
			/* make new hosts file */
3137
			system_hosts_generate();
3138

    
3139
		if ($reloadall == true) {
3140

    
3141
			/* reconfigure static routes (kernel may have deleted them) */
3142
			system_routing_configure($interface);
3143

    
3144
			/* reload ipsec tunnels */
3145
			vpn_ipsec_configure();
3146

    
3147
			/* restart dnsmasq */
3148
			services_dnsmasq_configure();
3149

    
3150
			/* update dyndns */
3151
			send_event("service reload dyndns {$interface}");
3152

    
3153
			/* reload captive portal */
3154
			captiveportal_init_rules();
3155
		}
3156
	}
3157

    
3158
	interfaces_staticarp_configure($interface);
3159
	return 0;
3160
}
3161

    
3162
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3163
	global $config, $g;
3164

    
3165
	if (!is_array($wancfg))
3166
		return;
3167

    
3168
	if (!isset($wancfg['enable']))
3169
		return;
3170

    
3171
	/* If the interface is not configured via another, exit */
3172
	if (empty($wancfg['track6-interface']))
3173
		return;
3174

    
3175
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3176
	$realif = get_real_interface($interface);
3177
	$linklocal = find_interface_ipv6_ll($realif);
3178
	if (!empty($linklocal))
3179
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3180
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3181
	/* XXX: Probably should remove? */
3182
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3183

    
3184
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3185
	if (!isset($trackcfg['enable'])) {
3186
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3187
		return;
3188
	}
3189

    
3190
	switch($trackcfg['ipaddrv6']) {
3191
	case "6to4":
3192
		if ($g['debug'])
3193
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3194
		interface_track6_6to4_configure($interface, $wancfg);
3195
		break;
3196
	case "6rd":
3197
		if ($g['debug'])
3198
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3199
		interface_track6_6rd_configure($interface, $wancfg);
3200
		break;
3201
	case "dhcp6":
3202
		if ($linkupevent == true) {
3203
			/* 
3204
			 * NOTE: Usually come here from rc.linkup calling so just call directly intead of generating event
3205
			 *      Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3206
			 *
3207
			 * XXX: Probably DHCPv6 client should handle this autmagically itself?
3208
			 */
3209
			$parentrealif = get_real_interface($wancfg['track6-interface']);
3210
			$pidv6 = find_dhcp6c_process($parentrealif);
3211
			if($pidv6)
3212
				posix_kill($pidv6, SIGHUP);
3213
		}
3214
		break;
3215
	}
3216

    
3217
	if (!$g['booting'] && $linkupevent == false) {
3218
		if (!function_exists('services_dhcpd_configure'))
3219
			require_once("services.inc");
3220

    
3221
		services_dhcpd_configure("inet6");
3222
	}
3223

    
3224
	return 0;
3225
}
3226

    
3227
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3228
	global $config, $g;
3229
	global $interface_ipv6_arr_cache;
3230
	global $interface_snv6_arr_cache;
3231

    
3232
	if (!is_array($lancfg))
3233
		return;
3234

    
3235
	/* If the interface is not configured via another, exit */
3236
	if (empty($lancfg['track6-interface']))
3237
		return;
3238

    
3239
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3240
	if (empty($wancfg)) {
3241
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3242
		return;
3243
	}
3244

    
3245
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3246
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3247
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3248
		return;
3249
	}
3250
	$hexwanv4 = return_hex_ipv4($ip4address);
3251

    
3252
	/* create the long prefix notation for math, save the prefix length */
3253
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3254
	$rd6prefixlen = $rd6prefix[1];
3255
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3256

    
3257
	/* binary presentation of the prefix for all 128 bits. */
3258
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3259

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

    
3265
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3266
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3267
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3268
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3269
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3270
	/* fill the rest out with zeros */
3271
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);;
3272

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

    
3276
	$lanif = get_real_interface($interface);
3277
	$oip = find_interface_ipv6($lanif);
3278
	if (is_ipaddrv6($oip))
3279
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3280
	unset($interface_ipv6_arr_cache[$lanif]);
3281
	unset($interface_snv6_arr_cache[$lanif]);
3282
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3283
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3284

    
3285
	return 0;
3286
}
3287

    
3288
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3289
	global $config, $g;
3290
	global $interface_ipv6_arr_cache;
3291
	global $interface_snv6_arr_cache;
3292

    
3293
	if (!is_array($lancfg))
3294
		return;
3295

    
3296
	/* If the interface is not configured via another, exit */
3297
	if (empty($lancfg['track6-interface']))
3298
		return;
3299

    
3300
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3301
	if (empty($wancfg)) {
3302
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3303
		return;
3304
	}
3305

    
3306
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3307
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3308
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3309
		return;
3310
	}
3311
	$hexwanv4 = return_hex_ipv4($ip4address);
3312

    
3313
	/* create the long prefix notation for math, save the prefix length */
3314
	$sixto4prefix = "2002::";
3315
	$sixto4prefixlen = 16;
3316
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3317

    
3318
	/* binary presentation of the prefix for all 128 bits. */
3319
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3320

    
3321
	/* just save the left prefix length bits */
3322
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3323
	/* add the v4 address */
3324
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3325
	/* add the custom prefix id */
3326
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3327
	/* fill the rest out with zeros */
3328
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);;
3329

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

    
3333
	$lanif = get_real_interface($interface);
3334
	$oip = find_interface_ipv6($lanif);
3335
	if (is_ipaddrv6($oip))
3336
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3337
	unset($interface_ipv6_arr_cache[$lanif]);
3338
	unset($interface_snv6_arr_cache[$lanif]);
3339
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3340
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3341

    
3342
	return 0;
3343
}
3344

    
3345
function interface_6rd_configure($interface = "wan", $wancfg) {
3346
	global $config, $g;
3347

    
3348
	/* because this is a tunnel interface we can only function
3349
	 *	with a public IPv4 address on the interface */
3350

    
3351
	if (!is_array($wancfg))
3352
		return;
3353

    
3354
	$wanif = get_real_interface($interface);
3355
	$ip4address = find_interface_ip($wanif);
3356
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3357
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3358
		return false;
3359
	}
3360
	$hexwanv4 = return_hex_ipv4($ip4address);
3361

    
3362
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3363
		$wancfg['prefix-6rd-v4plen'] = 0;
3364

    
3365
	/* create the long prefix notation for math, save the prefix length */
3366
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3367
	$rd6prefixlen = $rd6prefix[1];
3368
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3369

    
3370
	/* binary presentation of the prefix for all 128 bits. */
3371
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3372

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

    
3380
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3381
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3382

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

    
3385
	/* XXX: need to extend to support variable prefix size for v4 */
3386
	if (!is_module_loaded("if_stf"))
3387
		mwexec("/sbin/kldload if_stf.ko");
3388
	$stfiface = "{$interface}_stf";
3389
	if (does_interface_exist($stfiface))
3390
		pfSense_interface_destroy($stfiface);
3391
	$tmpstfiface = pfSense_interface_create("stf");
3392
	pfSense_interface_rename($tmpstfiface, $stfiface);
3393
	pfSense_interface_flags($stfiface, IFF_LINK2);
3394
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3395
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3396
	if ($wancfg['prefix-6rd-v4plen'] > 0 && $wancfg['prefix-6rd-v4plen'] < 32)
3397
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/{$wancfg['prefix-6rd-v4plen']}");
3398
	if ($g['debug'])
3399
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3400

    
3401
	/* write out a default router file */
3402
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3403
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3404

    
3405
	$ip4gateway = get_interface_gateway($interface);
3406
	if (is_ipaddrv4($ip4gateway))
3407
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3408

    
3409
	/* configure dependent interfaces */
3410
	if (!$g['booting'])
3411
		link_interface_to_track6($interface, "update");
3412

    
3413
	return 0;
3414
}
3415

    
3416
function interface_6to4_configure($interface = "wan", $wancfg){
3417
	global $config, $g;
3418

    
3419
	/* because this is a tunnel interface we can only function
3420
	 *	with a public IPv4 address on the interface */
3421

    
3422
	if (!is_array($wancfg))
3423
		return;
3424

    
3425
	$wanif = get_real_interface($interface);
3426
	$ip4address = find_interface_ip($wanif);
3427
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3428
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3429
		return false;
3430
	}
3431

    
3432
	/* create the long prefix notation for math, save the prefix length */
3433
	$stfprefixlen = 16;
3434
	$stfprefix = Net_IPv6::uncompress("2002::");
3435
	$stfarr = explode(":", $stfprefix);
3436
	$v4prefixlen = "0";
3437

    
3438
	/* we need the hex form of the interface IPv4 address */
3439
	$ip4arr = explode(".", $ip4address);
3440
	$hexwanv4 = "";
3441
	foreach($ip4arr as $octet)
3442
		$hexwanv4 .= sprintf("%02x", $octet);
3443

    
3444
	/* we need the hex form of the broker IPv4 address */
3445
	$ip4arr = explode(".", "192.88.99.1");
3446
	$hexbrv4 = "";
3447
	foreach($ip4arr as $octet)
3448
		$hexbrv4 .= sprintf("%02x", $octet);
3449

    
3450
	/* binary presentation of the prefix for all 128 bits. */
3451
	$stfprefixbin = "";
3452
	foreach($stfarr as $element) {
3453
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3454
	}
3455
	/* just save the left prefix length bits */
3456
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3457

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

    
3462
	/* for the local subnet too. */
3463
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3464
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);;
3465

    
3466
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3467
	$stfbrarr = array();
3468
	$stfbrbinarr = array();
3469
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3470
	foreach($stfbrbinarr as $bin)
3471
		$stfbrarr[] = dechex(bindec($bin));
3472
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3473

    
3474
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3475
	$stflanarr = array();
3476
	$stflanbinarr = array();
3477
	$stflanbinarr = str_split($stflanbin, 16);
3478
	foreach($stflanbinarr as $bin)
3479
		$stflanarr[] = dechex(bindec($bin));
3480
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3481
	$stflanarr[7] = 1;
3482
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3483

    
3484
	/* setup the stf interface */
3485
	if (!is_module_loaded("if_stf"))
3486
		mwexec("/sbin/kldload if_stf.ko");
3487
	$stfiface = "{$interface}_stf";
3488
	if (does_interface_exist($stfiface))
3489
		pfSense_interface_destroy($stfiface);
3490
	$tmpstfiface = pfSense_interface_create("stf");
3491
	pfSense_interface_rename($tmpstfiface, $stfiface);
3492
	pfSense_interface_flags($stfiface, IFF_LINK2);
3493
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3494

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

    
3498
	/* write out a default router file */
3499
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3500
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3501

    
3502
	$ip4gateway = get_interface_gateway($interface);
3503
	if (is_ipaddrv4($ip4gateway))
3504
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3505

    
3506
	if (!$g['booting'])
3507
		link_interface_to_track6($interface, "update");
3508

    
3509
	return 0;
3510
}
3511

    
3512
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3513
	global $config, $g;
3514

    
3515
	if (!is_array($wancfg))
3516
		return;
3517

    
3518
	$wanif = get_real_interface($interface, "inet6");
3519
	$dhcp6cconf = "";
3520
	$dhcp6cconf .= "interface {$wanif} {\n";
3521

    
3522
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3523
	if($wancfg['ipaddrv6'] == "slaac") {
3524
		$dhcp6cconf .= "	information-only;\n";
3525
		$dhcp6cconf .= "	request domain-name-servers;\n";
3526
		$dhcp6cconf .= "	request domain-name;\n";
3527
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3528
		$dhcp6cconf .= "};\n";
3529
	} else {
3530
		/* skip address request if this is set */
3531
		if(!isset($wancfg['dhcp6prefixonly']))
3532
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3533
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3534
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3535

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

    
3540
		$dhcp6cconf .= "};\n";
3541

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

    
3545
		if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3546
			/* Setup the prefix delegation */
3547
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3548
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3549
			if (isset($wancfg['dhcp6-ia-pd-send-hint']))
3550
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3551
			$iflist = link_interface_to_track6($interface);
3552
			foreach ($iflist as $friendly => $ifcfg) {
3553
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3554
					if ($g['debug'])
3555
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3556
					$realif = get_real_interface($friendly);
3557
					$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3558
					$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3559
					$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3560
					$dhcp6cconf .= "	};\n";
3561
				}
3562
			}
3563
			unset($preflen, $iflist, $ifcfg);
3564
			$dhcp6cconf .= "};\n";
3565
		}
3566
	}
3567
	/* wide-dhcp6c works for now. */
3568
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3569
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3570
		unset($dhcp6cconf);
3571
		return 1;
3572
	}
3573
	unset($dhcp6cconf);
3574

    
3575
	$dhcp6cscript = "#!/bin/sh\n";
3576
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3577
	$dhcp6cscript .= "/etc/rc.newwanipv6 {$wanif} \n";
3578
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3579
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3580
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3581
		unset($dhcp6cscript);
3582
		return 1;
3583
	}
3584
	unset($dhcp6cscript);
3585
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3586

    
3587
	$rtsoldscript = "#!/bin/sh\n";
3588
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3589
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3590
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3591
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3592
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3593
	$rtsoldscript .= "\t/bin/sleep 1\n";
3594
	$rtsoldscript .= "fi\n";
3595
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3596
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3597
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3598
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3599
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3600
		unset($rtsoldscript);
3601
		return 1;
3602
	}
3603
	unset($rtsoldscript);
3604
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3605

    
3606
	/* accept router advertisements for this interface */
3607
	mwexec("/sbin/sysctl -w net.inet6.ip6.accept_rtadv=1");
3608
	log_error("Accept router advertisements on interface {$wanif} ");
3609
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3610

    
3611
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3612
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3613
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3614
		sleep(2);
3615
	}
3616
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3617

    
3618
	/* NOTE: will be called from rtsold invoked script
3619
	 * link_interface_to_track6($interface, "update");
3620
	 */
3621

    
3622
	return 0;
3623
}
3624

    
3625
function interface_dhcp_configure($interface = "wan") {
3626
	global $config, $g;
3627

    
3628
	$wancfg = $config['interfaces'][$interface];
3629
	$wanif = $wancfg['if'];
3630
	if (empty($wancfg))
3631
		$wancfg = array();
3632

    
3633
	/* generate dhclient_wan.conf */
3634
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3635
	if (!$fd) {
3636
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3637
		return 1;
3638
	}
3639

    
3640
	if ($wancfg['dhcphostname']) {
3641
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3642
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3643
	} else {
3644
		$dhclientconf_hostname = "";
3645
	}
3646

    
3647
	$wanif = get_real_interface($interface);
3648
	if (empty($wanif)) {
3649
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3650
		return 0;
3651
	}
3652
	$dhclientconf = "";
3653

    
3654
	$dhclientconf .= <<<EOD
3655
interface "{$wanif}" {
3656
timeout 60;
3657
retry 15;
3658
select-timeout 0;
3659
initial-interval 1;
3660
	{$dhclientconf_hostname}
3661
	script "/sbin/dhclient-script";
3662
EOD;
3663

    
3664
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3665
	$dhclientconf .= <<<EOD
3666

    
3667
	reject {$wancfg['dhcprejectfrom']};
3668
EOD;
3669
}
3670
	$dhclientconf .= <<<EOD
3671

    
3672
}
3673

    
3674
EOD;
3675

    
3676
if(is_ipaddr($wancfg['alias-address'])) {
3677
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3678
	$dhclientconf .= <<<EOD
3679
alias {
3680
	interface  "{$wanif}";
3681
	fixed-address {$wancfg['alias-address']};
3682
	option subnet-mask {$subnetmask};
3683
}
3684

    
3685
EOD;
3686
}
3687
	fwrite($fd, $dhclientconf);
3688
	fclose($fd);
3689

    
3690
	/* bring wan interface up before starting dhclient */
3691
	if($wanif)
3692
		interfaces_bring_up($wanif);
3693
	else
3694
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3695

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

    
3699
	return 0;
3700
}
3701

    
3702
function interfaces_group_setup() {
3703
	global $config;
3704

    
3705
	if (!is_array($config['ifgroups']['ifgroupentry']))
3706
		return;
3707

    
3708
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3709
		interface_group_setup($groupar);
3710

    
3711
	return;
3712
}
3713

    
3714
function interface_group_setup(&$groupname /* The parameter is an array */) {
3715
	global $config;
3716

    
3717
	if (!is_array($groupname))
3718
		return;
3719
	$members = explode(" ", $groupname['members']);
3720
	foreach($members as $ifs) {
3721
		$realif = get_real_interface($ifs);
3722
		if ($realif)
3723
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3724
	}
3725

    
3726
	return;
3727
}
3728

    
3729
function is_interface_group($if) {
3730
	global $config;
3731

    
3732
	if (is_array($config['ifgroups']['ifgroupentry']))
3733
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
3734
			if ($groupentry['ifname'] === $if)
3735
				return true;
3736
		}
3737

    
3738
	return false;
3739
}
3740

    
3741
function interface_group_add_member($interface, $groupname) {
3742
	$interface = get_real_interface($interface);
3743
	mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
3744
}
3745

    
3746
/* COMPAT Function */
3747
function convert_friendly_interface_to_real_interface_name($interface) {
3748
	return get_real_interface($interface);
3749
}
3750

    
3751
/* COMPAT Function */
3752
function get_real_wan_interface($interface = "wan") {
3753
	return get_real_interface($interface);
3754
}
3755

    
3756
/* COMPAT Function */
3757
function get_current_wan_address($interface = "wan") {
3758
	return get_interface_ip($interface);
3759
}
3760

    
3761
/*
3762
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
3763
 */
3764
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
3765
	global $config;
3766

    
3767
	if (stristr($interface, "_vip")) {
3768
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
3769
			if ($vip['mode'] == "carp")  {
3770
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3771
					return $vip['interface'];
3772
			}
3773
		}
3774
	}
3775

    
3776
	/* XXX: For speed reasons reference directly the interface array */
3777
	$ifdescrs = &$config['interfaces'];
3778
	//$ifdescrs = get_configured_interface_list(false, true);
3779

    
3780
	foreach ($ifdescrs as $if => $ifname) {
3781
		if ($if == $interface || $ifname['if'] == $interface)
3782
			return $if;
3783

    
3784
		if (get_real_interface($if) == $interface)
3785
			return $if;
3786

    
3787
		$int = get_parent_interface($if, true);
3788
		if (is_array($int)) {
3789
			foreach ($int as $iface) {
3790
				if ($iface == $interface)
3791
					return $if;
3792
			}
3793
		}
3794
	}
3795

    
3796
	return NULL;
3797
}
3798

    
3799
/* attempt to resolve interface to friendly descr */
3800
function convert_friendly_interface_to_friendly_descr($interface) {
3801
	global $config;
3802

    
3803
	switch ($interface) {
3804
	case "l2tp":
3805
		$ifdesc = "L2TP";
3806
		break;
3807
	case "pptp":
3808
		$ifdesc = "PPTP";
3809
		break;
3810
	case "pppoe":
3811
		$ifdesc = "PPPoE";
3812
		break;
3813
	case "openvpn":
3814
		$ifdesc = "OpenVPN";
3815
		break;
3816
	case "enc0":
3817
	case "ipsec":
3818
		$ifdesc = "IPsec";
3819
		break;
3820
	default:
3821
		if (isset($config['interfaces'][$interface])) {
3822
			if (empty($config['interfaces'][$interface]['descr']))
3823
				$ifdesc = strtoupper($interface);
3824
			else
3825
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
3826
			break;
3827
		} else if (stristr($interface, "_vip")) {
3828
			if (is_array($config['virtualip']['vip'])) {
3829
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
3830
					if ($vip['mode'] == "carp")  {
3831
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3832
							return "{$vip['subnet']} - {$vip['descr']}";
3833
					}
3834
				}
3835
			}
3836
		} else {
3837
			/* if list */
3838
			$ifdescrs = get_configured_interface_with_descr(false, true);
3839
			foreach ($ifdescrs as $if => $ifname) {
3840
				if ($if == $interface || $ifname == $interface)
3841
					return $ifname;
3842
			}
3843
		}
3844
		break;
3845
	}
3846

    
3847
	return $ifdesc;
3848
}
3849

    
3850
function convert_real_interface_to_friendly_descr($interface) {
3851
	global $config;
3852

    
3853
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
3854

    
3855
	if ($ifdesc) {
3856
		$iflist = get_configured_interface_with_descr(false, true);
3857
		return $iflist[$ifdesc];
3858
	}
3859

    
3860
	return $interface;
3861
}
3862

    
3863
/*
3864
 *  get_parent_interface($interface):
3865
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
3866
 *				or virtual interface (i.e. vlan)
3867
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
3868
 *			-- returns $interface passed in if $interface parent is not found
3869
 *			-- returns empty array if an invalid interface is passed
3870
 *	(Only handles ppps and vlans now.)
3871
 */
3872
function get_parent_interface($interface, $avoidrecurse = false) {
3873
	global $config;
3874

    
3875
	$parents = array();
3876
	//Check that we got a valid interface passed
3877
	$realif = get_real_interface($interface);
3878
	if ($realif == NULL)
3879
		return $parents;
3880

    
3881
	// If we got a real interface, find it's friendly assigned name
3882
	if ($interface == $realif && $avoidrecurse == false)
3883
		$interface = convert_real_interface_to_friendly_interface_name($interface);
3884

    
3885
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
3886
		$ifcfg = $config['interfaces'][$interface];
3887
		switch ($ifcfg['ipaddr']) {
3888
			case "ppp":
3889
			case "pppoe":
3890
			case "pptp":
3891
			case "l2tp":
3892
				if (empty($parents))
3893
					if (is_array($config['ppps']['ppp']))
3894
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
3895
							if ($ifcfg['if'] == $ppp['if']) {
3896
								$ports = explode(',', $ppp['ports']);
3897
								foreach ($ports as $pid => $parent_if)
3898
									$parents[$pid] = get_real_interface($parent_if);
3899
								break;
3900
							}
3901
						}
3902
				break;
3903
			case "dhcp":
3904
			case "static":
3905
			default:
3906
				// Handle _vlans
3907
				if (stristr($realif,"_vlan"))
3908
					if (is_array($config['vlans']['vlan']))
3909
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
3910
							if ($ifcfg['if'] == $vlan['vlanif']){
3911
								$parents[0] = $vlan['if'];
3912
								break;
3913
							}
3914
				break;
3915
		}
3916
	}
3917

    
3918
	if (empty($parents))
3919
		$parents[0] = $realif;
3920

    
3921
	return $parents;
3922
}
3923

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

    
3932
function interface_get_wireless_base($wlif) {
3933
	if(!stristr($wlif, "_wlan")) {
3934
		return $wlif;
3935
	} else {
3936
		return substr($wlif, 0, stripos($wlif, "_wlan"));
3937
	}
3938
}
3939

    
3940
function interface_get_wireless_clone($wlif) {
3941
	if(!stristr($wlif, "_wlan")) {
3942
		return $wlif . "_wlan0";
3943
	} else {
3944
		return $wlif;
3945
	}
3946
}
3947

    
3948
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
3949
	global $config, $g;
3950

    
3951
	$wanif = NULL;
3952

    
3953
	switch ($interface) {
3954
	case "l2tp":
3955
		$wanif = "l2tp";
3956
		break;
3957
	case "pptp":
3958
		$wanif = "pptp";
3959
		break;
3960
	case "pppoe":
3961
		$wanif = "pppoe";
3962
		break;
3963
	case "openvpn":
3964
		$wanif = "openvpn";
3965
		break;
3966
	case "ipsec":
3967
	case "enc0":
3968
		$wanif = "enc0";
3969
		break;
3970
	case "ppp":
3971
		$wanif = "ppp";
3972
		break;
3973
	default:
3974
		// If a real interface was alread passed simply
3975
		// pass the real interface back.  This encourages
3976
		// the usage of this function in more cases so that
3977
		// we can combine logic for more flexibility.
3978
		if(does_interface_exist($interface, $flush)) {
3979
			$wanif = $interface;
3980
			break;
3981
		}
3982

    
3983
		if (empty($config['interfaces'][$interface]))
3984
			break;
3985

    
3986
		$cfg = &$config['interfaces'][$interface];
3987

    
3988
		if ($family == "inet6") {
3989
			switch ($cfg['ipaddrv6']) {
3990
			case "6rd":
3991
			case "6to4":
3992
				$wanif = "{$interface}_stf";
3993
				break;
3994
			case 'pppoe':
3995
			case 'ppp':
3996
			case 'l2tp':
3997
			case 'pptp':
3998
				if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
3999
					$wanif = interface_get_wireless_clone($cfg['if']);
4000
				else
4001
					$wanif = $cfg['if'];
4002
				break;
4003
			default:
4004
				switch ($cfg['ipaddr']) {
4005
				case 'pppoe':
4006
				case 'ppp':
4007
				case 'l2tp':
4008
				case 'pptp':
4009
					if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false)
4010
						$wanif = $cfg['if'];
4011
					else {
4012
						$parents = get_parent_interface($interface);
4013
						if (!empty($parents[0]))
4014
							$wanif = $parents[0];
4015
						else
4016
							$wanif = $cfg['if'];
4017
					}
4018
					break;
4019
				default:
4020
					if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4021
						$wanif = interface_get_wireless_clone($cfg['if']);
4022
					else
4023
						$wanif = $cfg['if'];
4024
					break;
4025
				}
4026
				break;
4027
			}
4028
		} else {
4029
			// Wireless cloned NIC support (FreeBSD 8+)
4030
			// interface name format: $parentnic_wlanparentnic#
4031
			// example: ath0_wlan0
4032
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4033
				$wanif = interface_get_wireless_clone($cfg['if']);
4034
			else
4035
				$wanif = $cfg['if'];
4036
		}
4037
		break;
4038
	}
4039

    
4040
	return $wanif;
4041
}
4042

    
4043
/* Guess the physical interface by providing a IP address */
4044
function guess_interface_from_ip($ipaddress) {
4045
	if(! is_ipaddr($ipaddress)) {
4046
		return false;
4047
	}
4048
	if(is_ipaddrv4($ipaddress)) {
4049
		/* create a route table we can search */
4050
		exec("netstat -rnWf inet", $output, $ret);
4051
		foreach($output as $line) {
4052
			if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
4053
				$fields = preg_split("/[ ]+/", $line);
4054
				if(ip_in_subnet($ipaddress, $fields[0])) {
4055
					return $fields[6];
4056
				}
4057
			}
4058
		}
4059
	}
4060
	/* FIXME: This works from cursory testing, regexp might need fine tuning */
4061
	if(is_ipaddrv6($ipaddress)) {
4062
		/* create a route table we can search */
4063
		exec("netstat -rnWf inet6", $output, $ret);
4064
		foreach($output as $line) {
4065
			if(preg_match("/[0-9a-f]+[:]+[0-9a-f]+[:]+[\/][0-9]+/", $line)) {
4066
				$fields = preg_split("/[ ]+/", $line);
4067
				if(ip_in_subnet($ipaddress, $fields[0])) {
4068
					return $fields[6];
4069
				}
4070
			}
4071
		}
4072
	}
4073
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
4074
	if(empty($ret)) {
4075
		return false;
4076
	}
4077
	return $ret;
4078
}
4079

    
4080
/*
4081
 * find_ip_interface($ip): return the interface where an ip is defined
4082
 *   (or if $bits is specified, where an IP within the subnet is defined)
4083
 */
4084
function find_ip_interface($ip, $bits = null) {
4085
	if (!is_ipaddr($ip))
4086
		return false;
4087

    
4088
	$isv6ip = is_ipaddrv6($ip);
4089

    
4090
	/* if list */
4091
	$ifdescrs = get_configured_interface_list();
4092

    
4093
	foreach ($ifdescrs as $ifdescr => $ifname) {
4094
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4095
		if (is_null($ifip))
4096
			continue;
4097
		if (is_null($bits)) {
4098
			if ($ip == $ifip) {
4099
				$int = get_real_interface($ifname);
4100
				return $int;
4101
			}
4102
		}
4103
		else {
4104
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4105
				$int = get_real_interface($ifname);
4106
				return $int;
4107
			}
4108
		}
4109
	}
4110

    
4111
	return false;
4112
}
4113

    
4114
/*
4115
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4116
 *   (or if $bits is specified, where an IP within the subnet is found)
4117
 */
4118
function find_virtual_ip_alias($ip, $bits = null) {
4119
	global $config;
4120

    
4121
	if (!is_array($config['virtualip']['vip'])) {
4122
		return false;
4123
	}
4124
	if (!is_ipaddr($ip))
4125
		return false;
4126

    
4127
	$isv6ip = is_ipaddrv6($ip);
4128

    
4129
	foreach ($config['virtualip']['vip'] as $vip) {
4130
		if ($vip['mode'] === "ipalias") {
4131
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4132
				continue;
4133
			if (is_null($bits)) {
4134
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4135
					return $vip;
4136
				}
4137
			}
4138
			else {
4139
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4140
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4141
					return $vip;
4142
				}
4143
			}
4144
		}
4145
	}
4146
	return false;
4147
}
4148

    
4149
/*
4150
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4151
 */
4152
function find_number_of_created_carp_interfaces() {
4153
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4154
}
4155

    
4156
function get_all_carp_interfaces() {
4157
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
4158
	$ints = explode(" ", $ints);
4159
	return $ints;
4160
}
4161

    
4162
/*
4163
 * find_carp_interface($ip): return the carp interface where an ip is defined
4164
 */
4165
function find_carp_interface($ip) {
4166
	global $config;
4167
	if (is_array($config['virtualip']['vip'])) {
4168
		foreach ($config['virtualip']['vip'] as $vip) {
4169
			if ($vip['mode'] == "carp") {
4170
				if(is_ipaddrv4($ip)) {
4171
					$carp_ip = get_interface_ip($vip['interface']);
4172
				}
4173
				if(is_ipaddrv6($ip)) {
4174
					$carp_ip = get_interface_ipv6($vip['interface']);
4175
				}
4176
				exec("/sbin/ifconfig", $output, $return);
4177
				foreach($output as $line) {
4178
					$elements = preg_split("/[ ]+/i", $line);
4179
					if(strstr($elements[0], "vip"))
4180
						$curif = str_replace(":", "", $elements[0]);
4181
					if(stristr($line, $ip)) {
4182
						$if = $curif;
4183
						continue;
4184
					}
4185
				}
4186

    
4187
				if ($if)
4188
					return $if;
4189
			}
4190
		}
4191
	}
4192
}
4193

    
4194
function link_carp_interface_to_parent($interface) {
4195
	global $config;
4196

    
4197
	if (empty($interface))
4198
		return;
4199

    
4200
	$carp_ip = get_interface_ip($interface);
4201
	$carp_ipv6 = get_interface_ipv6($interface);
4202

    
4203
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4204
		return;
4205

    
4206
	/* if list */
4207
	$ifdescrs = get_configured_interface_list();
4208
	foreach ($ifdescrs as $ifdescr => $ifname) {
4209
		/* check IPv4 */
4210
		if(is_ipaddrv4($carp_ip)) {
4211
			$interfaceip = get_interface_ip($ifname);
4212
			$subnet_bits = get_interface_subnet($ifname);
4213
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4214
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4215
				return $ifname;
4216
		}
4217
		/* Check IPv6 */
4218
		if(is_ipaddrv6($carp_ipv6)) {
4219
			$interfaceipv6 = get_interface_ipv6($ifname);
4220
			$prefixlen = get_interface_subnetv6($ifname);
4221
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4222
				return $ifname;
4223
		}
4224
	}
4225
	return "";
4226
}
4227

    
4228

    
4229
/****f* interfaces/link_ip_to_carp_interface
4230
 * NAME
4231
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4232
 * INPUTS
4233
 *   $ip
4234
 * RESULT
4235
 *   $carp_ints
4236
 ******/
4237
function link_ip_to_carp_interface($ip) {
4238
	global $config;
4239

    
4240
	if (!is_ipaddr($ip))
4241
		return;
4242

    
4243
	$carp_ints = "";
4244
	if (is_array($config['virtualip']['vip'])) {
4245
		$first = 0;
4246
		$carp_int = array();
4247
		foreach ($config['virtualip']['vip'] as $vip) {
4248
			if ($vip['mode'] == "carp") {
4249
				$carp_ip = $vip['subnet'];
4250
				$carp_sn = $vip['subnet_bits'];
4251
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4252
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4253
					$carp_int[] = "{$vip['interface']}_vip{$vip['vhid']}";
4254
				}
4255
			}
4256
		}
4257
		if (!empty($carp_int))
4258
			$carp_ints = implode(" ", array_unique($carp_int));
4259
	}
4260

    
4261
	return $carp_ints;
4262
}
4263

    
4264
function link_interface_to_track6($int, $action = "") {
4265
	global $config;
4266

    
4267
	if (empty($int))
4268
		return;
4269

    
4270
	if (is_array($config['interfaces'])) {
4271
		$list = array();
4272
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4273
			if (!isset($ifcfg['enable']))
4274
				continue;
4275
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4276
				if ($action == "update")
4277
					interface_track6_configure($ifname, $ifcfg);
4278
				else if ($action == "")
4279
					$list[$ifname] = $ifcfg;
4280
			}
4281
		}
4282
		return $list;
4283
	}
4284
}
4285

    
4286
function link_interface_to_vlans($int, $action = "") {
4287
	global $config;
4288

    
4289
	if (empty($int))
4290
		return;
4291

    
4292
	if (is_array($config['vlans']['vlan'])) {
4293
		$ifaces = array();
4294
		foreach ($config['vlans']['vlan'] as $vlan) {
4295
			if ($int == $vlan['if']) {
4296
				if ($action == "update") {
4297
					interfaces_bring_up($int);
4298
				} else if ($action == "")
4299
					$ifaces[$vlan['tag']] = $vlan;
4300
			}
4301
		}
4302
		if (!empty($ifaces))
4303
			return $ifaces;
4304
	}
4305
}
4306

    
4307
function link_interface_to_vips($int, $action = "") {
4308
	global $config;
4309

    
4310
	if (is_array($config['virtualip']['vip'])) {
4311
		$result = array();
4312
		foreach ($config['virtualip']['vip'] as $vip) {
4313
			if ($int == $vip['interface']) {
4314
				if ($action == "update")
4315
					interfaces_vips_configure($int);
4316
				else
4317
					$result[] = $vip;
4318
			}
4319
		}
4320
		return $result;
4321
	}
4322
}
4323

    
4324
/****f* interfaces/link_interface_to_bridge
4325
 * NAME
4326
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4327
 * INPUTS
4328
 *   $ip
4329
 * RESULT
4330
 *   bridge[0-99]
4331
 ******/
4332
function link_interface_to_bridge($int) {
4333
	global $config;
4334

    
4335
	if (is_array($config['bridges']['bridged'])) {
4336
		foreach ($config['bridges']['bridged'] as $bridge) {
4337
			if (in_array($int, explode(',', $bridge['members'])))
4338
				return "{$bridge['bridgeif']}";
4339
		}
4340
	}
4341
}
4342

    
4343
function link_interface_to_group($int) {
4344
	global $config;
4345

    
4346
	$result = array();
4347

    
4348
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4349
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4350
			if (in_array($int, explode(" ", $group['members'])))
4351
				$result[$group['ifname']] = $int;
4352
		}
4353
	}
4354

    
4355
	return $result;
4356
}
4357

    
4358
function link_interface_to_gre($interface) {
4359
	global $config;
4360

    
4361
	$result = array();
4362

    
4363
	if (is_array($config['gres']['gre'])) {
4364
		foreach ($config['gres']['gre'] as $gre)
4365
			if($gre['if'] == $interface)
4366
				$result[] = $gre;
4367
	}
4368

    
4369
	return $result;
4370
}
4371

    
4372
function link_interface_to_gif($interface) {
4373
	global $config;
4374

    
4375
	$result = array();
4376

    
4377
	if (is_array($config['gifs']['gif'])) {
4378
		foreach ($config['gifs']['gif'] as $gif)
4379
			if($gif['if'] == $interface)
4380
				$result[] = $gif;
4381
	}
4382

    
4383
	return $result;
4384
}
4385

    
4386
/*
4387
 * find_interface_ip($interface): return the interface ip (first found)
4388
 */
4389
function find_interface_ip($interface, $flush = false) {
4390
	global $interface_ip_arr_cache;
4391
	global $interface_sn_arr_cache;
4392

    
4393
	$interface = str_replace("\n", "", $interface);
4394

    
4395
	if (!does_interface_exist($interface))
4396
		return;
4397

    
4398
	/* Setup IP cache */
4399
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4400
		$ifinfo = pfSense_get_interface_addresses($interface);
4401
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4402
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4403
	}
4404

    
4405
	return $interface_ip_arr_cache[$interface];
4406
}
4407

    
4408
/*
4409
 * find_interface_ipv6($interface): return the interface ip (first found)
4410
 */
4411
function find_interface_ipv6($interface, $flush = false) {
4412
	global $interface_ipv6_arr_cache;
4413
	global $interface_snv6_arr_cache;
4414
	global $config;
4415

    
4416
	$interface = trim($interface);
4417
	$interface = get_real_interface($interface);
4418

    
4419
	if (!does_interface_exist($interface))
4420
		return;
4421

    
4422
	/* Setup IP cache */
4423
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4424
		$ifinfo = pfSense_get_interface_addresses($interface);
4425
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4426
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4427
	}
4428

    
4429
	return $interface_ipv6_arr_cache[$interface];
4430
}
4431

    
4432
/*
4433
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4434
 */
4435
function find_interface_ipv6_ll($interface, $flush = false) {
4436
	global $interface_llv6_arr_cache;
4437
	global $config;
4438

    
4439
	$interface = str_replace("\n", "", $interface);
4440

    
4441
	if (!does_interface_exist($interface))
4442
		return;
4443

    
4444
	/* Setup IP cache */
4445
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4446
		$ifinfo = pfSense_getall_interface_addresses($interface);
4447
		foreach($ifinfo as $line) {
4448
			if (strstr($line, ":")) {
4449
				$parts = explode("/", $line);
4450
				if(is_linklocal($parts[0])) {
4451
					$ifinfo['linklocal'] = $parts[0];
4452
				}
4453
			}
4454
		}
4455
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4456
	}
4457
	return $interface_llv6_arr_cache[$interface];
4458
}
4459

    
4460
function find_interface_subnet($interface, $flush = false) {
4461
	global $interface_sn_arr_cache;
4462
	global $interface_ip_arr_cache;
4463

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

    
4468
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4469
		$ifinfo = pfSense_get_interface_addresses($interface);
4470
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4471
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4472
	}
4473

    
4474
	return $interface_sn_arr_cache[$interface];
4475
}
4476

    
4477
function find_interface_subnetv6($interface, $flush = false) {
4478
	global $interface_snv6_arr_cache;
4479
	global $interface_ipv6_arr_cache;
4480

    
4481
	$interface = str_replace("\n", "", $interface);
4482
	if (does_interface_exist($interface) == false)
4483
		return;
4484

    
4485
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4486
		$ifinfo = pfSense_get_interface_addresses($interface);
4487
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4488
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4489
	}
4490

    
4491
	return $interface_snv6_arr_cache[$interface];
4492
}
4493

    
4494
function ip_in_interface_alias_subnet($interface, $ipalias) {
4495
	global $config;
4496

    
4497
	if (empty($interface) || !is_ipaddr($ipalias))
4498
		return false;
4499
	if (is_array($config['virtualip']['vip'])) {
4500
		foreach ($config['virtualip']['vip'] as $vip) {
4501
			switch ($vip['mode']) {
4502
			case "ipalias":
4503
				if ($vip['interface'] <> $interface)
4504
					break;
4505
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4506
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4507
					return true;
4508
				break;
4509
			}
4510
		}
4511
	}
4512

    
4513
	return false;
4514
}
4515

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

    
4527
	$curip = find_interface_ip($realif);
4528
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4529
		return $curip;
4530
	else
4531
		return null;
4532
}
4533

    
4534
function get_interface_ipv6($interface = "wan", $flush = false) {
4535
	global $config;
4536

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

    
4545
	/*
4546
	 * NOTE: On the case when only the prefix is requested,
4547
	 * the communication on WAN will be done over link-local.
4548
	 */
4549
	if (is_array($config['interfaces'][$interface])) {
4550
		switch ($config['interfaces'][$interface]['ipaddr']) {
4551
		case 'pppoe':
4552
		case 'l2tp':
4553
		case 'pptp':
4554
		case 'ppp':
4555
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4556
				$realif = get_real_interface($interface, "inet6", true);
4557
			break;
4558
		}
4559
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4560
			$curip = find_interface_ipv6_ll($realif, $flush);
4561
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4562
				return $curip;
4563
		}
4564
	}
4565

    
4566
	$curip = find_interface_ipv6($realif, $flush);
4567
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4568
		return $curip;
4569
	else
4570
		return null;
4571
}
4572

    
4573
function get_interface_linklocal($interface = "wan") {
4574

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

    
4585
	$curip = find_interface_ipv6_ll($realif);
4586
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4587
		return $curip;
4588
	else
4589
		return null;
4590
}
4591

    
4592
function get_interface_subnet($interface = "wan") {
4593
	$realif = get_real_interface($interface);
4594
	if (!$realif) {
4595
		if (preg_match("/^carp/i", $interface))
4596
			$realif = $interface;
4597
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4598
			$realif = $interface;
4599
		else
4600
			return null;
4601
	}
4602

    
4603
	$cursn = find_interface_subnet($realif);
4604
	if (!empty($cursn))
4605
		return $cursn;
4606

    
4607
	return null;
4608
}
4609

    
4610
function get_interface_subnetv6($interface = "wan") {
4611
	global $config;
4612

    
4613
	$realif = get_real_interface($interface, "inet6");
4614
	if (!$realif) {
4615
		if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4616
			$realif = $interface;
4617
		else
4618
			return null;
4619
	}
4620

    
4621
	$cursn = find_interface_subnetv6($realif);
4622
	if (!empty($cursn))
4623
		return $cursn;
4624

    
4625
	return null;
4626
}
4627

    
4628
/* return outside interfaces with a gateway */
4629
function get_interfaces_with_gateway() {
4630
	global $config;
4631

    
4632
	$ints = array();
4633

    
4634
	/* loop interfaces, check config for outbound */
4635
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4636
		switch ($ifname['ipaddr']) {
4637
			case "dhcp":
4638
			case "ppp";
4639
			case "pppoe":
4640
			case "pptp":
4641
			case "l2tp":
4642
			case "ppp";
4643
				$ints[$ifdescr] = $ifdescr;
4644
			break;
4645
			default:
4646
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
4647
				    !empty($ifname['gateway']))
4648
					$ints[$ifdescr] = $ifdescr;
4649
			break;
4650
		}
4651
	}
4652
	return $ints;
4653
}
4654

    
4655
/* return true if interface has a gateway */
4656
function interface_has_gateway($friendly) {
4657
	global $config;
4658

    
4659
	if (!empty($config['interfaces'][$friendly])) {
4660
		$ifname = &$config['interfaces'][$friendly];
4661
		switch ($ifname['ipaddr']) {
4662
			case "dhcp":
4663
			case "pppoe":
4664
			case "pptp":
4665
			case "l2tp":
4666
			case "ppp";
4667
				return true;
4668
			break;
4669
			default:
4670
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4671
					return true;
4672
				if (!empty($ifname['gateway']))
4673
					return true;
4674
			break;
4675
		}
4676
	}
4677

    
4678
	return false;
4679
}
4680

    
4681
/* return true if interface has a gateway */
4682
function interface_has_gatewayv6($friendly) {
4683
	global $config;
4684

    
4685
	if (!empty($config['interfaces'][$friendly])) {
4686
		$ifname = &$config['interfaces'][$friendly];
4687
		switch ($ifname['ipaddrv6']) {
4688
			case "slaac":
4689
			case "dhcp6":
4690
			case "6to4":
4691
			case "6rd":
4692
				return true;
4693
				break;
4694
			default:
4695
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4696
					return true;
4697
				$tunnelif = substr($ifname['if'], 0, 3);
4698
				if ($tunnelif == "gif" || $tunnelif == "gre")
4699
					return true;
4700
				if (!empty($ifname['gatewayv6']))
4701
					return true;
4702
				break;
4703
		}
4704
	}
4705

    
4706
	return false;
4707
}
4708

    
4709
/****f* interfaces/is_altq_capable
4710
 * NAME
4711
 *   is_altq_capable - Test if interface is capable of using ALTQ
4712
 * INPUTS
4713
 *   $int            - string containing interface name
4714
 * RESULT
4715
 *   boolean         - true or false
4716
 ******/
4717

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

    
4731
	$int_family = remove_ifindex($int);
4732

    
4733
	if (in_array($int_family, $capable))
4734
		return true;
4735
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
4736
		return true;
4737
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
4738
		return true;
4739
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
4740
		return true;
4741
	else
4742
		return false;
4743
}
4744

    
4745
/****f* interfaces/is_interface_wireless
4746
 * NAME
4747
 *   is_interface_wireless - Returns if an interface is wireless
4748
 * RESULT
4749
 *   $tmp       - Returns if an interface is wireless
4750
 ******/
4751
function is_interface_wireless($interface) {
4752
	global $config, $g;
4753

    
4754
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
4755
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
4756
		if (preg_match($g['wireless_regex'], $interface)) {
4757
			if (isset($config['interfaces'][$friendly]))
4758
				$config['interfaces'][$friendly]['wireless'] = array();
4759
			return true;
4760
		}
4761
		return false;
4762
	} else
4763
		return true;
4764
}
4765

    
4766
function get_wireless_modes($interface) {
4767
	/* return wireless modes and channels */
4768
	$wireless_modes = array();
4769

    
4770
	$cloned_interface = get_real_interface($interface);
4771

    
4772
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4773
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
4774
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4775
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
4776

    
4777
		$interface_channels = "";
4778
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4779
		$interface_channel_count = count($interface_channels);
4780

    
4781
		$c = 0;
4782
		while ($c < $interface_channel_count) {
4783
			$channel_line = explode(",", $interface_channels["$c"]);
4784
			$wireless_mode = trim($channel_line[0]);
4785
			$wireless_channel = trim($channel_line[1]);
4786
			if(trim($wireless_mode) != "") {
4787
				/* if we only have 11g also set 11b channels */
4788
				if($wireless_mode == "11g") {
4789
					if(!isset($wireless_modes["11b"]))
4790
						$wireless_modes["11b"] = array();
4791
				} else if($wireless_mode == "11g ht") {
4792
					if(!isset($wireless_modes["11b"]))
4793
						$wireless_modes["11b"] = array();
4794
					if(!isset($wireless_modes["11g"]))
4795
						$wireless_modes["11g"] = array();
4796
					$wireless_mode = "11ng";
4797
				} else if($wireless_mode == "11a ht") {
4798
					if(!isset($wireless_modes["11a"]))
4799
						$wireless_modes["11a"] = array();
4800
					$wireless_mode = "11na";
4801
				}
4802
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
4803
			}
4804
			$c++;
4805
		}
4806
	}
4807
	return($wireless_modes);
4808
}
4809

    
4810
/* return channel numbers, frequency, max txpower, and max regulation txpower */
4811
function get_wireless_channel_info($interface) {
4812
	$wireless_channels = array();
4813

    
4814
	$cloned_interface = get_real_interface($interface);
4815

    
4816
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4817
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
4818
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4819
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
4820

    
4821
		$interface_channels = "";
4822
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4823

    
4824
		foreach ($interface_channels as $channel_line) {
4825
			$channel_line = explode(",", $channel_line);
4826
			if(!isset($wireless_channels[$channel_line[0]]))
4827
				$wireless_channels[$channel_line[0]] = $channel_line;
4828
		}
4829
	}
4830
	return($wireless_channels);
4831
}
4832

    
4833
/****f* interfaces/get_interface_mtu
4834
 * NAME
4835
 *   get_interface_mtu - Return the mtu of an interface
4836
 * RESULT
4837
 *   $tmp       - Returns the mtu of an interface
4838
 ******/
4839
function get_interface_mtu($interface) {
4840
	$mtu = pfSense_get_interface_addresses($interface);
4841
	return $mtu['mtu'];
4842
}
4843

    
4844
function get_interface_mac($interface) {
4845

    
4846
	$macinfo = pfSense_get_interface_addresses($interface);
4847
	return $macinfo["macaddr"];
4848
}
4849

    
4850
/****f* pfsense-utils/generate_random_mac_address
4851
 * NAME
4852
 *   generate_random_mac - generates a random mac address
4853
 * INPUTS
4854
 *   none
4855
 * RESULT
4856
 *   $mac - a random mac address
4857
 ******/
4858
function generate_random_mac_address() {
4859
	$mac = "02";
4860
	for($x=0; $x<5; $x++)
4861
		$mac .= ":" . dechex(rand(16, 255));
4862
	return $mac;
4863
}
4864

    
4865
/****f* interfaces/is_jumbo_capable
4866
 * NAME
4867
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
4868
 * INPUTS
4869
 *   $int             - string containing interface name
4870
 * RESULT
4871
 *   boolean          - true or false
4872
 ******/
4873
function is_jumbo_capable($iface) {
4874
	$iface = trim($iface);
4875
	$capable = pfSense_get_interface_addresses($iface);
4876

    
4877
	if (isset($capable['caps']['vlanmtu']))
4878
		return true;
4879

    
4880
	return false;
4881
}
4882

    
4883
function interface_setup_pppoe_reset_file($pppif, $iface="") {
4884
	global $g;
4885

    
4886
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
4887

    
4888
	if(!empty($iface) && !empty($pppif)){
4889
		$cron_cmd = <<<EOD
4890
#!/bin/sh
4891
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
4892
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
4893

    
4894
EOD;
4895

    
4896
		@file_put_contents($cron_file, $cron_cmd);
4897
		chmod($cron_file, 0755);
4898
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
4899
	} else
4900
		unlink_if_exists($cron_file);
4901
}
4902

    
4903
function get_interface_default_mtu($type = "ethernet") {
4904
	switch ($type) {
4905
	case "gre":
4906
		return 1476;
4907
		break;
4908
	case "gif":
4909
		return 1280;
4910
		break;
4911
	case "tun":
4912
	case "vlan":
4913
	case "tap":
4914
	case "ethernet":
4915
	default:
4916
		return 1500;
4917
		break;
4918
	}
4919

    
4920
	/* Never reached */
4921
	return 1500;
4922
}
4923

    
4924
function get_vip_descr($ipaddress) {
4925
	global $config;
4926

    
4927
	foreach ($config['virtualip']['vip'] as $vip) {
4928
		if ($vip['subnet'] == $ipaddress) {
4929
			return ($vip['descr']);
4930
		}
4931
	}
4932
	return "";
4933
}
4934

    
4935
function interfaces_staticarp_configure($if) {
4936
	global $config, $g;
4937
	if(isset($config['system']['developerspew'])) {
4938
		$mt = microtime();
4939
		echo "interfaces_staticarp_configure($if) being called $mt\n";
4940
	}
4941

    
4942
	$ifcfg = $config['interfaces'][$if];
4943

    
4944
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
4945
		return 0;
4946

    
4947
	/* Enable staticarp, if enabled */
4948
	if(isset($config['dhcpd'][$if]['staticarp'])) {
4949
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
4950
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4951
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
4952

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

    
4956
			}
4957

    
4958
		}
4959
	} else {
4960
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
4961
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4962
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
4963
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
4964
				if (isset($arpent['arp_table_static_entry'])) {
4965
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
4966
				}
4967
			}
4968
		}
4969
	}
4970

    
4971
	return 0;
4972
}
4973

    
4974
function get_failover_interface($interface, $family = "all") {
4975
	global $config;
4976

    
4977
	/* shortcut to get_real_interface if we find it in the config */
4978
	if (is_array($config['interfaces'][$interface])) {
4979
		return get_real_interface($interface, $family);
4980
	}
4981

    
4982
	/* compare against gateway groups */
4983
	$a_groups = return_gateway_groups_array();
4984
	if (is_array($a_groups[$interface])) {
4985
		/* we found a gateway group, fetch the interface or vip */
4986
		if ($a_groups[$interface][0]['vip'] <> "")
4987
			return $a_groups[$interface][0]['vip'];
4988
		else
4989
			return $a_groups[$interface][0]['int'];
4990
	}
4991
	/* fall through to get_real_interface */
4992
	/* XXX: Really needed? */
4993
	return get_real_interface($interface, $family);
4994
}
4995

    
4996
function remove_ifindex($ifname) {
4997
	return preg_replace("/[0-9]+$/", "", $ifname);
4998
}
4999

    
5000
?>
(25-25/66)