Projet

Général

Profil

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

univnautes / etc / inc / interfaces.inc @ 60ef0911

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
	case "ipalias":
102
		/* XXX: Make proper checks? */
103
		$realif = get_real_interface($vip['interface']);
104
		if (!does_interface_exist($realif)) {
105
			return false;
106
		}
107
		break;
108
	case "proxyarp":
109
		/* XXX: Implement this */
110
	default:
111
		return false;
112
	}
113

    
114
	$ifacedata = pfSense_getall_interface_addresses($realif);
115
	foreach ($ifacedata as $vipips) {
116
		if ($vipips == "{$vip['subnet']}/{$vip['subnet_bits']}")
117
			return true;
118
	}
119

    
120
	return false;
121
}
122

    
123
function interface_netgraph_needed($interface = "wan") {
124
	global $config;
125

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

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

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

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

    
202
function interfaces_loopback_configure() {
203
	global $g;
204

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

    
216
function interfaces_vlan_configure($realif = "") {
217
	global $config, $g;
218
	if($g['booting'])
219
		echo gettext("Configuring VLAN interfaces...");
220
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
221
		foreach ($config['vlans']['vlan'] as $vlan) {
222
			if (empty($vlan['vlanif']))
223
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
224
			if (!empty($realif) && $realif != $vlan['vlanif'])
225
				continue;
226

    
227
			/* XXX: Maybe we should report any errors?! */
228
			interface_vlan_configure($vlan);
229
		}
230
	}
231
	if($g['booting'])
232
		echo gettext("done.") . "\n";
233
}
234

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

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

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

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

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

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

    
266
	interfaces_bring_up($vlanif);
267

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

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

    
274
	return $vlanif;
275
}
276

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

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

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

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

    
297
	$vlanif = interface_vlan_configure($vlan);
298

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

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

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

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

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

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

    
350
	return $vlanif;
351
}
352

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

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

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

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

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

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

    
393
	return $vlanif;
394
}
395

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

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

    
402
	$iflist = get_configured_interface_list();
403

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

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

    
423
}
424

    
425
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
426
	global $config;
427

    
428
	$i = 0;
429
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
430
		foreach ($config['bridges']['bridged'] as $bridge) {
431
			if (empty($bridge['bridgeif']))
432
				$bridge['bridgeif'] = "bridge{$i}";
433
			if (!empty($realif) && $realif != $bridge['bridgeif'])
434
				continue;
435

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

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

    
464
	if (!is_array($bridge))
465
		return;
466

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

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

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

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

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

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

    
546
	$checklist = get_configured_interface_list();
547

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

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

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

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

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

    
671
function interface_bridge_add_member($bridgeif, $interface) {
672

    
673
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface))
674
		return;
675

    
676
	$mtu = get_interface_mtu($bridgeif);
677
	$mtum = get_interface_mtu($interface);
678

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

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

    
706
	pfSense_interface_capabilities($interface, -$flags_off);
707
	pfSense_interface_capabilities($interface, $flags_on);
708

    
709
	interfaces_bring_up($interface);
710
	pfSense_bridge_add_member($bridgeif, $interface);
711
}
712

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

    
733
function interface_lagg_configure(&$lagg) {
734
	global $config, $g;
735

    
736
	if (!is_array($lagg))
737
		return -1;
738

    
739
	$members = explode(',', $lagg['members']);
740
	if (!count($members))
741
		return -1;
742

    
743
	if ($g['booting'] || !(empty($lagg['laggif']))) {
744
		pfSense_interface_destroy($lagg['laggif']);
745
		pfSense_interface_create($lagg['laggif']);
746
		$laggif = $lagg['laggif'];
747
	} else
748
		$laggif = pfSense_interface_create("lagg");
749

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

    
771
	/* Just in case anything is not working well */
772
	if ($smallermtu == 0)
773
		$smallermtu = 1500;
774

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

    
798
	$checklist = get_interface_list();
799

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

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

    
813
	interfaces_bring_up($laggif);
814

    
815
	return $laggif;
816
}
817

    
818
function interfaces_gre_configure($checkparent = 0, $realif = "") {
819
	global $config;
820

    
821
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
822
		foreach ($config['gres']['gre'] as $i => $gre) {
823
			if (empty($gre['greif']))
824
				$gre['greif'] = "gre{$i}";
825
			if (!empty($realif) && $realif != $gre['greif'])
826
				continue;
827

    
828
			if ($checkparent == 1) {
829
				if (strstr($gre['if'], "_vip"))
830
					continue;
831
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6")
832
					continue;
833
			}
834
			else if ($checkparent == 2) {
835
				if (strstr($gre['if'], "_vip"))
836
					continue;
837
				if (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")
838
					continue;
839
			}
840
			/* XXX: Maybe we should report any errors?! */
841
			interface_gre_configure($gre);
842
		}
843
	}
844
}
845

    
846
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
847
function interface_gre_configure(&$gre, $grekey = "") {
848
	global $config, $g;
849

    
850
	if (!is_array($gre))
851
		return -1;
852

    
853
	$realif = get_real_interface($gre['if']);
854
	$realifip = get_interface_ip($gre['if']);
855

    
856
	/* make sure the parent interface is up */
857
	interfaces_bring_up($realif);
858

    
859
	if ($g['booting'] || !(empty($gre['greif']))) {
860
		pfSense_interface_destroy($gre['greif']);
861
		pfSense_interface_create($gre['greif']);
862
		$greif = $gre['greif'];
863
	} else
864
		$greif = pfSense_interface_create("gre");
865

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

    
882
	if($greif)
883
		interfaces_bring_up($greif);
884
	else
885
		log_error(gettext("Could not bring greif up -- variable not defined."));
886

    
887
	if (isset($gre['link1']) && $gre['link1'])
888
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
889
	if(is_ipaddrv4($gre['tunnel-remote-addr']))
890
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
891
	if(is_ipaddrv6($gre['tunnel-remote-addr']))
892
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
893

    
894
	interfaces_bring_up($greif);
895

    
896
	return $greif;
897
}
898

    
899
function interfaces_gif_configure($checkparent = 0, $realif = "") {
900
	global $config;
901

    
902
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
903
		foreach ($config['gifs']['gif'] as $i => $gif) {
904
			if (empty($gif['gifif']))
905
				$gre['gifif'] = "gif{$i}";
906
			if (!empty($realif) && $realif != $gif['gifif'])
907
				continue;
908

    
909
			if ($checkparent == 1) {
910
				if (strstr($gif['if'], "_vip"))
911
					continue;
912
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6")
913
					continue;
914
			}
915
			else if ($checkparent == 2) {
916
				if (strstr($gif['if'], "_vip"))
917
					continue;
918
				if (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")
919
					continue;
920
			}
921
			/* XXX: Maybe we should report any errors?! */
922
			interface_gif_configure($gif);
923
		}
924
	}
925
}
926

    
927
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
928
function interface_gif_configure(&$gif, $gifkey = "") {
929
	global $config, $g;
930

    
931
	if (!is_array($gif))
932
		return -1;
933

    
934
	$realif = get_real_interface($gif['if']);
935
	$ipaddr = $gif['ipaddr'];
936

    
937
	if (is_ipaddrv4($gif['remote-addr'])) {
938
		if (is_ipaddrv4($ipaddr))
939
			$realifip = $ipaddr;
940
		else
941
			$realifip = get_interface_ip($gif['if']);
942
		$realifgw = get_interface_gateway($gif['if']);
943
	} else if (is_ipaddrv6($gif['remote-addr'])) {
944
		if (is_ipaddrv6($ipaddr))
945
			$realifip = $ipaddr;
946
		else
947
			$realifip = get_interface_ipv6($gif['if']);
948
		$realifgw = get_interface_gateway_v6($gif['if']);
949
	}
950
	/* make sure the parent interface is up */
951
	if($realif)
952
		interfaces_bring_up($realif);
953
	else
954
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
955

    
956
	if ($g['booting'] || !(empty($gif['gifif']))) {
957
		pfSense_interface_destroy($gif['gifif']);
958
		pfSense_interface_create($gif['gifif']);
959
		$gifif = $gif['gifif'];
960
	} else
961
		$gifif = pfSense_interface_create("gif");
962

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

    
981
	$iflist = get_configured_interface_list();
982
	foreach($iflist as $ifname) {
983
		if($config['interfaces'][$ifname]['if'] == $gifif) {
984
			if(get_interface_gateway($ifname)) {
985
				system_routing_configure($ifname);
986
				break;
987
			}
988
			if(get_interface_gateway_v6($ifname)) {
989
				system_routing_configure($ifname);
990
				break;
991
			}
992
		}
993
	}
994

    
995

    
996
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
997
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
998
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
999
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1000

    
1001
	if (is_ipaddrv4($realifgw)) {
1002
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1003
	}
1004
	if (is_ipaddrv6($realifgw)) {
1005
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1006
	}
1007

    
1008
	interfaces_bring_up($gifif);
1009

    
1010
	return $gifif;
1011
}
1012

    
1013
function interfaces_configure() {
1014
	global $config, $g;
1015

    
1016
	if ($g['platform'] == 'jail')
1017
		return;
1018

    
1019
	/* Set up our loopback interface */
1020
	interfaces_loopback_configure();
1021

    
1022
	/* create the unconfigured wireless clones */
1023
	interfaces_create_wireless_clones();
1024

    
1025
	/* set up LAGG virtual interfaces */
1026
	interfaces_lagg_configure();
1027

    
1028
	/* set up VLAN virtual interfaces */
1029
	interfaces_vlan_configure();
1030

    
1031
	interfaces_qinq_configure();
1032

    
1033
	$iflist = get_configured_interface_with_descr();
1034
	$delayed_list = array();
1035
	$bridge_list = array();
1036
	$track6_list = array();
1037

    
1038
	/* This is needed to speedup interfaces on bootup. */
1039
	$reload = false;
1040
	if (!$g['booting'])
1041
		$reload = true;
1042

    
1043
	foreach($iflist as $if => $ifname) {
1044
		$realif = $config['interfaces'][$if]['if'];
1045
		if (strstr($realif, "bridge"))
1046
			$bridge_list[$if] = $ifname;
1047
		else if (strstr($realif, "gre"))
1048
			$delayed_list[$if] = $ifname;
1049
		else if (strstr($realif, "gif"))
1050
			$delayed_list[$if] = $ifname;
1051
		else if (strstr($realif, "ovpn")) {
1052
			//echo "Delaying OpenVPN interface configuration...done.\n";
1053
			continue;
1054
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1055
			$track6_list[$if] = $ifname;
1056
		} else {
1057
			if ($g['booting'])
1058
				printf(gettext("Configuring %s interface..."), $ifname);
1059

    
1060
			if($g['debug'])
1061
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1062
			interface_configure($if, $reload);
1063
			if ($g['booting'])
1064
				echo gettext( "done.") . "\n";
1065
		}
1066
	}
1067

    
1068
	/*
1069
	 * NOTE: The following function parameter consists of
1070
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1071
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1072
	 */
1073

    
1074
	/* set up GRE virtual interfaces */
1075
	interfaces_gre_configure(1);
1076

    
1077
	/* set up GIF virtual interfaces */
1078
	interfaces_gif_configure(1);
1079

    
1080
	/* set up BRIDGe virtual interfaces */
1081
	interfaces_bridge_configure(1);
1082

    
1083
	foreach ($track6_list as $if => $ifname) {
1084
		if ($g['booting'])
1085
			printf(gettext("Configuring %s interface..."), $ifname);
1086
		if ($g['debug'])
1087
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1088

    
1089
		interface_configure($if, $reload);
1090

    
1091
		if ($g['booting'])
1092
			echo gettext("done.") . "\n";
1093
	}
1094

    
1095
	/* bring up vip interfaces */
1096
	interfaces_vips_configure();
1097

    
1098
	/* set up GRE virtual interfaces */
1099
	interfaces_gre_configure(2);
1100

    
1101
	/* set up GIF virtual interfaces */
1102
	interfaces_gif_configure(2);
1103

    
1104
	foreach ($delayed_list as $if => $ifname) {
1105
		if ($g['booting'])
1106
			printf(gettext("Configuring %s interface..."), $ifname);
1107
		if ($g['debug'])
1108
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1109

    
1110
		interface_configure($if, $reload);
1111

    
1112
		if ($g['booting'])
1113
			echo gettext("done.") . "\n";
1114
	}
1115

    
1116
	/* set up BRIDGe virtual interfaces */
1117
	interfaces_bridge_configure(2);
1118

    
1119
	foreach ($bridge_list as $if => $ifname) {
1120
		if ($g['booting'])
1121
			printf(gettext("Configuring %s interface..."), $ifname);
1122
		if($g['debug'])
1123
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1124

    
1125
		interface_configure($if, $reload);
1126

    
1127
		if ($g['booting'])
1128
			echo gettext("done.") . "\n";
1129
	}
1130

    
1131
	/* configure interface groups */
1132
	interfaces_group_setup();
1133

    
1134
	if (!$g['booting']) {
1135
		/* reconfigure static routes (kernel may have deleted them) */
1136
		system_routing_configure();
1137

    
1138
		/* reload IPsec tunnels */
1139
		vpn_ipsec_configure();
1140

    
1141
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1142
		services_dhcpd_configure();
1143

    
1144
		/* restart dnsmasq or unbound */
1145
		if (isset($config['dnsmasq']['enable']))
1146
			services_dnsmasq_configure();
1147
		elseif (isset($config['unbound']['enable']))
1148
			services_unbound_configure();
1149
	}
1150

    
1151
	return 0;
1152
}
1153

    
1154
function interface_reconfigure($interface = "wan", $reloadall = false) {
1155
	interface_bring_down($interface);
1156
	interface_configure($interface, $reloadall);
1157
}
1158

    
1159
function interface_vip_bring_down($vip) {
1160
	global $g;
1161

    
1162
	$vipif = get_real_interface($vip['interface']);
1163
	switch ($vip['mode']) {
1164
	case "proxyarp":
1165
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1166
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1167
		break;
1168
	case "ipalias":
1169
		if (does_interface_exist($vipif)) {
1170
			if (is_ipaddrv6($vip['subnet']))
1171
				mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1172
			else
1173
				pfSense_interface_deladdress($vipif, $vip['subnet']);
1174
		}
1175
		break;
1176
	case "carp":
1177
		/* XXX: Is enough to delete ip address? */
1178
		if (does_interface_exist($vipif))
1179
			pfSense_interface_deladdress($vipif, $vip['subnet']);
1180
		break;
1181
	}
1182
}
1183

    
1184
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1185
	global $config, $g;
1186

    
1187
	if (!isset($config['interfaces'][$interface]))
1188
		return;
1189

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

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

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

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

    
1352
	return;
1353
}
1354

    
1355
function interfaces_carp_set_maintenancemode($carp_maintenancemode){
1356
	global $config;
1357
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1358
		unset($config["virtualip_carp_maintenancemode"]);
1359
		write_config("Leave CARP maintenance mode");
1360
	} else
1361
	if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1362
		$config["virtualip_carp_maintenancemode"] = true;
1363
		write_config("Enter CARP maintenance mode");
1364
	}
1365

    
1366
	$viparr = &$config['virtualip']['vip'];
1367
	foreach ($viparr as $vip) {
1368
		if ($vip['mode'] == "carp") {
1369
			interface_carp_configure($vip);
1370
		}
1371
	}
1372
}
1373

    
1374
function interfaces_ptpid_used($ptpid) {
1375
	global $config;
1376

    
1377
	if (is_array($config['ppps']['ppp']))
1378
		foreach ($config['ppps']['ppp'] as & $settings)
1379
			if ($ptpid == $settings['ptpid'])
1380
				return true;
1381

    
1382
	return false;
1383
}
1384

    
1385
function interfaces_ptpid_next() {
1386

    
1387
	$ptpid = 0;
1388
	while(interfaces_ptpid_used($ptpid))
1389
		$ptpid++;
1390

    
1391
	return $ptpid;
1392
}
1393

    
1394
function getMPDCRONSettings($pppif) {
1395
	global $config;
1396

    
1397
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1398
	if (is_array($config['cron']['item'])) {
1399
		foreach ($config['cron']['item'] as $i => $item) {
1400
			if (stripos($item['command'], $cron_cmd_file) !== false)
1401
				return array("ID" => $i, "ITEM" => $item);
1402
		}
1403
	}
1404

    
1405
	return NULL;
1406
}
1407

    
1408
function handle_pppoe_reset($post_array) {
1409
	global $config, $g;
1410

    
1411
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1412
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1413

    
1414
	if (!is_array($config['cron']['item']))
1415
		$config['cron']['item'] = array();
1416

    
1417
	$itemhash = getMPDCRONSettings($pppif);
1418

    
1419
	// reset cron items if necessary and return
1420
	if (empty($post_array['pppoe-reset-type'])) {
1421
		if (isset($itemhash))
1422
			unset($config['cron']['item'][$itemhash['ID']]);
1423
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1424
		return;
1425
	}
1426

    
1427
	if (empty($itemhash))
1428
		$itemhash = array();
1429
	$item = array();
1430
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1431
		$item['minute'] = $post_array['pppoe_resetminute'];
1432
		$item['hour'] = $post_array['pppoe_resethour'];
1433
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1434
			$date = explode("/", $post_array['pppoe_resetdate']);
1435
			$item['mday'] = $date[1];
1436
			$item['month'] = $date[0];
1437
		} else {
1438
			$item['mday'] = "*";
1439
			$item['month'] = "*";
1440
		}
1441
		$item['wday'] = "*";
1442
		$item['who'] = "root";
1443
		$item['command'] = $cron_cmd_file;
1444
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1445
		switch ($post_array['pppoe_pr_preset_val']) {
1446
		case "monthly":
1447
			$item['minute'] = "0";
1448
			$item['hour'] = "0";
1449
			$item['mday'] = "1";
1450
			$item['month'] = "*";
1451
			$item['wday'] = "*";
1452
			break;
1453
		case "weekly":
1454
			$item['minute'] = "0";
1455
			$item['hour'] = "0";
1456
			$item['mday'] = "*";
1457
			$item['month'] = "*";
1458
			$item['wday'] = "0";
1459
			break;
1460
		case "daily":
1461
			$item['minute'] = "0";
1462
			$item['hour'] = "0";
1463
			$item['mday'] = "*";
1464
			$item['month'] = "*";
1465
			$item['wday'] = "*";
1466
			break;
1467
		case "hourly":
1468
			$item['minute'] = "0";
1469
			$item['hour'] = "*";
1470
			$item['mday'] = "*";
1471
			$item['month'] = "*";
1472
			$item['wday'] = "*";
1473
			break;
1474
		} // end switch
1475
		$item['who'] = "root";
1476
		$item['command'] = $cron_cmd_file;
1477
	}
1478
	if (empty($item))
1479
		return;
1480
	if (isset($itemhash['ID']))
1481
		$config['cron']['item'][$itemhash['ID']] = $item;
1482
	else
1483
		$config['cron']['item'][] = $item;
1484
}
1485

    
1486
/*
1487
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1488
 * It writes the mpd config file to /var/etc every time the link is opened.
1489
 */
1490
function interface_ppps_configure($interface) {
1491
	global $config, $g;
1492

    
1493
	/* Return for unassigned interfaces. This is a minimum requirement. */
1494
	if (empty($config['interfaces'][$interface]))
1495
		return 0;
1496
	$ifcfg = $config['interfaces'][$interface];
1497
	if (!isset($ifcfg['enable']))
1498
		return 0;
1499

    
1500
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1501
	if(!is_dir("/var/spool/lock")) {
1502
		mkdir("/var/spool/lock", 0777, true);
1503
	}
1504
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1505
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1506
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1507

    
1508
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1509
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1510
			if ($ifcfg['if'] == $ppp['if'])
1511
				break;
1512
		}
1513
	}
1514
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1515
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1516
		return 0;
1517
	}
1518
	$pppif = $ifcfg['if'];
1519
	if ($ppp['type'] == "ppp")
1520
		$type = "modem";
1521
	else
1522
		$type = $ppp['type'];
1523
	$upper_type = strtoupper($ppp['type']);
1524

    
1525
	if($g['booting']) {
1526
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1527
		echo "starting {$pppif} link...";
1528
		// Do not re-configure the interface if we are booting and it's already been started
1529
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1530
			return 0;
1531
	}
1532

    
1533
	$ports = explode(',',$ppp['ports']);
1534
	if ($type != "modem") {
1535
		foreach ($ports as $pid => $port) {
1536
			$ports[$pid] = get_real_interface($port);
1537
			if (empty($ports[$pid]))
1538
				return 0;
1539
		}
1540
	}
1541
	$localips = explode(',',$ppp['localip']);
1542
	$gateways = explode(',',$ppp['gateway']);
1543
	$subnets = explode(',',$ppp['subnet']);
1544

    
1545
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1546
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1547
	 */
1548
	foreach($ports as $pid => $port){
1549
		switch ($ppp['type']) {
1550
			case "pppoe":
1551
				/* Bring the parent interface up */
1552
				interfaces_bring_up($port);
1553
				pfSense_ngctl_attach(".", $port);
1554
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1555
				mwexec("ngctl msg {$port}: setautosrc 1");
1556
				break;
1557
			case "pptp":
1558
			case "l2tp":
1559
				/* configure interface */
1560
				if(is_ipaddr($localips[$pid])){
1561
					// Manually configure interface IP/subnet
1562
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1563
					interfaces_bring_up($port);
1564
				} else if (empty($localips[$pid]))
1565
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1566

    
1567
				if(!is_ipaddr($localips[$pid])){
1568
					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!");
1569
					$localips[$pid] = "0.0.0.0";
1570
				}
1571
				if(!is_ipaddr($gateways[$pid])){
1572
					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));
1573
					return 0;
1574
				}
1575
				pfSense_ngctl_attach(".", $port);
1576
				break;
1577
			case "ppp":
1578
				if (!file_exists("{$port}")) {
1579
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1580
					return 0;
1581
				}
1582
				break;
1583
			default:
1584
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1585
				break;
1586
		}
1587
	}
1588

    
1589
	if (is_array($ports) && count($ports) > 1)
1590
		$multilink = "enable";
1591
	else
1592
		$multilink = "disable";
1593

    
1594
	if ($type == "modem"){
1595
		if (is_ipaddr($ppp['localip']))
1596
			$localip = $ppp['localip'];
1597
		else
1598
			$localip = '0.0.0.0';
1599

    
1600
		if (is_ipaddr($ppp['gateway']))
1601
			$gateway = $ppp['gateway'];
1602
		else
1603
			$gateway = "10.64.64.{$pppid}";
1604
		$ranges = "{$localip}/0 {$gateway}/0";
1605

    
1606
		if (empty($ppp['apnum']))
1607
			$ppp['apnum'] = 1;
1608
	} else
1609
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1610

    
1611
	if (isset($ppp['ondemand']))
1612
		$ondemand = "enable";
1613
	else
1614
		$ondemand = "disable";
1615
	if (!isset($ppp['idletimeout']))
1616
		$ppp['idletimeout'] = 0;
1617

    
1618
	if (empty($ppp['username']) && $type == "modem"){
1619
		$ppp['username'] = "user";
1620
		$ppp['password'] = "none";
1621
	}
1622
	if (empty($ppp['password']) && $type == "modem")
1623
		$passwd = "none";
1624
	else
1625
		$passwd = base64_decode($ppp['password']);
1626

    
1627
	$bandwidths = explode(',',$ppp['bandwidth']);
1628
	$defaultmtu = "1492";
1629
	if (!empty($ifcfg['mtu']))
1630
		$defaultmtu = intval($ifcfg['mtu']);
1631
	$mtus = explode(',',$ppp['mtu']);
1632
	$mrus = explode(',',$ppp['mru']);
1633

    
1634
	if (isset($ppp['mrru']))
1635
		$mrrus = explode(',',$ppp['mrru']);
1636

    
1637
	// Construct the mpd.conf file
1638
	$mpdconf = <<<EOD
1639
startup:
1640
	# configure the console
1641
	set console close
1642
	# configure the web server
1643
	set web close
1644

    
1645
default:
1646
{$ppp['type']}client:
1647
	create bundle static {$interface}
1648
	set bundle enable ipv6cp
1649
	set iface name {$pppif}
1650

    
1651
EOD;
1652
	$setdefaultgw = false;
1653
	$founddefaultgw = false;
1654
	if (is_array($config['gateways']['gateway_item'])) {
1655
		foreach($config['gateways']['gateway_item'] as $gateway) {
1656
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1657
				$setdefaultgw = true;
1658
				break;
1659
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1660
				$founddefaultgw = true;
1661
				break;
1662
			}
1663
		}
1664
	}
1665

    
1666
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1667
		$setdefaultgw = true;
1668
		$mpdconf .= <<<EOD
1669
	set iface route default
1670

    
1671
EOD;
1672
	}
1673
	$mpdconf .= <<<EOD
1674
	set iface {$ondemand} on-demand
1675
	set iface idle {$ppp['idletimeout']}
1676

    
1677
EOD;
1678

    
1679
	if (isset($ppp['ondemand']))
1680
		$mpdconf .= <<<EOD
1681
	set iface addrs 10.10.1.1 10.10.1.2
1682

    
1683
EOD;
1684

    
1685
	if (isset($ppp['tcpmssfix']))
1686
		$tcpmss = "disable";
1687
	else
1688
		$tcpmss = "enable";
1689
		$mpdconf .= <<<EOD
1690
	set iface {$tcpmss} tcpmssfix
1691

    
1692
EOD;
1693

    
1694
	$mpdconf .= <<<EOD
1695
	set iface up-script /usr/local/sbin/ppp-linkup
1696
	set iface down-script /usr/local/sbin/ppp-linkdown
1697
	set ipcp ranges {$ranges}
1698

    
1699
EOD;
1700
	if (isset($ppp['vjcomp']))
1701
		$mpdconf .= <<<EOD
1702
	set ipcp no vjcomp
1703

    
1704
EOD;
1705

    
1706
	if (isset($config['system']['dnsallowoverride']))
1707
		$mpdconf .= <<<EOD
1708
	set ipcp enable req-pri-dns
1709
	set ipcp enable req-sec-dns
1710

    
1711
EOD;
1712
	if (!isset($ppp['verbose_log']))
1713
		$mpdconf .= <<<EOD
1714
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1715

    
1716
EOD;
1717
	foreach($ports as $pid => $port){
1718
		$port = get_real_interface($port);
1719
		$mpdconf .= <<<EOD
1720

    
1721
	create link static {$interface}_link{$pid} {$type}
1722
	set link action bundle {$interface}
1723
	set link {$multilink} multilink
1724
	set link keep-alive 10 60
1725
	set link max-redial 0
1726

    
1727
EOD;
1728
		if (isset($ppp['shortseq']))
1729
			$mpdconf .= <<<EOD
1730
	set link no shortseq
1731

    
1732
EOD;
1733

    
1734
		if (isset($ppp['acfcomp']))
1735
			$mpdconf .= <<<EOD
1736
	set link no acfcomp
1737

    
1738
EOD;
1739

    
1740
		if (isset($ppp['protocomp']))
1741
			$mpdconf .= <<<EOD
1742
	set link no protocomp
1743

    
1744
EOD;
1745

    
1746
		$mpdconf .= <<<EOD
1747
	set link disable chap pap
1748
	set link accept chap pap eap
1749
	set link disable incoming
1750

    
1751
EOD;
1752

    
1753

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

    
1758
EOD;
1759

    
1760
		if (empty($mtus[$pid]))
1761
			$mtus[$pid] = $defaultmtu;
1762
			$mpdconf .= <<<EOD
1763
	set link mtu {$mtus[$pid]}
1764

    
1765
EOD;
1766

    
1767
		if (!empty($mrus[$pid]))
1768
			$mpdconf .= <<<EOD
1769
	set link mru {$mrus[$pid]}
1770

    
1771
EOD;
1772

    
1773
		if (!empty($mrrus[$pid]))
1774
			$mpdconf .= <<<EOD
1775
	set link mrru {$mrrus[$pid]}
1776

    
1777
EOD;
1778

    
1779
		$mpdconf .= <<<EOD
1780
	set auth authname "{$ppp['username']}"
1781
	set auth password {$passwd}
1782

    
1783
EOD;
1784
		if ($type == "modem") {
1785
			$mpdconf .= <<<EOD
1786
	set modem device {$ppp['ports']}
1787
	set modem script DialPeer
1788
	set modem idle-script Ringback
1789
	set modem watch -cd
1790
	set modem var \$DialPrefix "DT"
1791
	set modem var \$Telephone "{$ppp['phone']}"
1792

    
1793
EOD;
1794
		}
1795
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1796
			$mpdconf .= <<<EOD
1797
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1798

    
1799
EOD;
1800
		}
1801
		if (isset($ppp['initstr']) && $type == "modem") {
1802
			$initstr = base64_decode($ppp['initstr']);
1803
			$mpdconf .= <<<EOD
1804
	set modem var \$InitString "{$initstr}"
1805

    
1806
EOD;
1807
		}
1808
		if (isset($ppp['simpin']) && $type == "modem") {
1809
			if($ppp['pin-wait'] == "")
1810
				$ppp['pin-wait'] = 0;
1811
			$mpdconf .= <<<EOD
1812
	set modem var \$SimPin "{$ppp['simpin']}"
1813
	set modem var \$PinWait "{$ppp['pin-wait']}"
1814

    
1815
EOD;
1816
		}
1817
		if (isset($ppp['apn']) && $type == "modem") {
1818
			$mpdconf .= <<<EOD
1819
	set modem var \$APN "{$ppp['apn']}"
1820
	set modem var \$APNum "{$ppp['apnum']}"
1821

    
1822
EOD;
1823
		}
1824
		if ($type == "pppoe") {
1825
			// Send a null service name if none is set.
1826
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1827
			$mpdconf .= <<<EOD
1828
	set pppoe service "{$provider}"
1829

    
1830
EOD;
1831
		}
1832
		if ($type == "pppoe")
1833
			$mpdconf .= <<<EOD
1834
	set pppoe iface {$port}
1835

    
1836
EOD;
1837

    
1838
		if ($type == "pptp" || $type == "l2tp") {
1839
			$mpdconf .= <<<EOD
1840
	set {$type} self {$localips[$pid]}
1841
	set {$type} peer {$gateways[$pid]}
1842

    
1843
EOD;
1844
		}
1845

    
1846
		$mpdconf .= "\topen\n";
1847
	} //end foreach($port)
1848

    
1849

    
1850
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1851
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1852
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1853
	else {
1854
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1855
		if (!$fd) {
1856
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1857
			return 0;
1858
		}
1859
		// Write out mpd_ppp.conf
1860
		fwrite($fd, $mpdconf);
1861
		fclose($fd);
1862
		unset($mpdconf);
1863
	}
1864

    
1865
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1866
	if (isset($ppp['uptime'])) {
1867
		if (!file_exists("/conf/{$pppif}.log")) {
1868
			conf_mount_rw();
1869
			file_put_contents("/conf/{$pppif}.log", '');
1870
			conf_mount_ro();
1871
		}
1872
	} else {
1873
		if (file_exists("/conf/{$pppif}.log")) {
1874
			conf_mount_rw();
1875
			@unlink("/conf/{$pppif}.log");
1876
			conf_mount_ro();
1877
		}
1878
	}
1879

    
1880
	/* clean up old lock files */
1881
	foreach($ports as $port) {
1882
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1883
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1884
	}
1885

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

    
1890
	// Check for PPPoE periodic reset request
1891
	if ($type == "pppoe") {
1892
		if (!empty($ppp['pppoe-reset-type']))
1893
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1894
		else
1895
			interface_setup_pppoe_reset_file($ppp['if']);
1896
	}
1897
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1898
	$i = 0;
1899
	while($i < 10) {
1900
		exec("/sbin/ifconfig " . escapeshellarg($ppp['if']) . " 2>&1", $out, $ret);
1901
		if($ret == 0)
1902
			break;
1903
		sleep(1);
1904
		$i++;
1905
	}
1906

    
1907
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
1908
	/* We should be able to launch the right version for each modem */
1909
	/* We can also guess the mondev from the manufacturer */
1910
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
1911
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
1912
	foreach($ports as $port) {
1913
		if(preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1914
			$mondev  = substr(basename($port), 0, -1);
1915
			$devlist = glob("/dev/{$mondev}?");
1916
			$mondev = basename(end($devlist));
1917
		}
1918
		if(preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1919
			$mondev  = substr(basename($port), 0, -1) . "1";
1920
		}
1921
		log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
1922
		mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
1923
	}
1924

    
1925
	return 1;
1926
}
1927

    
1928
function interfaces_carp_setup() {
1929
	global $g, $config;
1930

    
1931
	if (isset($config['system']['developerspew'])) {
1932
		$mt = microtime();
1933
		echo "interfaces_carp_setup() being called $mt\n";
1934
	}
1935

    
1936
	if ($g['booting']) {
1937
		echo gettext("Configuring CARP settings...");
1938
		mute_kernel_msgs();
1939
	}
1940

    
1941
	/* suck in configuration items */
1942
	if ($config['hasync']) {
1943
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1944
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1945
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1946
	} else {
1947
		unset($pfsyncinterface);
1948
		unset($pfsyncenabled);
1949
	}
1950

    
1951
	set_sysctl(array(
1952
		"net.inet.carp.preempt" => "1",
1953
		"net.inet.carp.log" => "1")
1954
	);
1955

    
1956
	if (!empty($pfsyncinterface))
1957
		$carp_sync_int = get_real_interface($pfsyncinterface);
1958
	else
1959
		unset($carp_sync_int);
1960

    
1961
	/* setup pfsync interface */
1962
	if ($carp_sync_int and $pfsyncenabled) {
1963
		if (is_ipaddr($pfsyncpeerip))
1964
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1965
		else
1966
			$syncpeer = "-syncpeer";
1967

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

    
1970
		sleep(1);
1971

    
1972
		/* 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
1973
		 * for existing sessions.
1974
		 */
1975
		log_error("waiting for pfsync...");
1976
		$i = 0;
1977
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1978
			$i++;
1979
			sleep(1);
1980
		}
1981
		log_error("pfsync done in $i seconds.");
1982
		log_error("Configuring CARP settings finalize...");
1983
	} else {
1984
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
1985
	}
1986

    
1987
	if($config['virtualip']['vip'])
1988
		set_single_sysctl("net.inet.carp.allow", "1");
1989
	else
1990
		set_single_sysctl("net.inet.carp.allow", "0");
1991

    
1992
	if ($g['booting']) {
1993
		unmute_kernel_msgs();
1994
		echo gettext("done.") . "\n";
1995
	}
1996
}
1997

    
1998
function interface_proxyarp_configure($interface = "") {
1999
	global $config, $g;
2000
	if(isset($config['system']['developerspew'])) {
2001
		$mt = microtime();
2002
		echo "interface_proxyarp_configure() being called $mt\n";
2003
	}
2004

    
2005
	/* kill any running choparp */
2006
	if (empty($interface))
2007
		killbyname("choparp");
2008
	else {
2009
		$vipif = get_real_interface($interface);
2010
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
2011
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2012
	}
2013

    
2014
	$paa = array();
2015
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2016

    
2017
		/* group by interface */
2018
		foreach ($config['virtualip']['vip'] as $vipent) {
2019
			if ($vipent['mode'] === "proxyarp") {
2020
				if ($vipent['interface'])
2021
					$proxyif = $vipent['interface'];
2022
				else
2023
					$proxyif = "wan";
2024

    
2025
				if (!empty($interface) && $interface != $proxyif)
2026
					continue;
2027

    
2028
				if (!is_array($paa[$proxyif]))
2029
					$paa[$proxyif] = array();
2030

    
2031
				$paa[$proxyif][] = $vipent;
2032
			}
2033
		}
2034
	}
2035

    
2036
	if (!empty($interface)) {
2037
		if (is_array($paa[$interface])) {
2038
			$paaifip = get_interface_ip($interface);
2039
			if (!is_ipaddr($paaifip))
2040
				return;
2041
			$args = get_real_interface($interface) . " auto";
2042
			foreach ($paa[$interface] as $paent) {
2043
				if (isset($paent['subnet']))
2044
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2045
				else if (isset($paent['range']))
2046
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2047
			}
2048
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2049
		}
2050
	} else if (count($paa) > 0) {
2051
		foreach ($paa as $paif => $paents)  {
2052
			$paaifip = get_interface_ip($paif);
2053
			if (!is_ipaddr($paaifip))
2054
				continue;
2055
			$args = get_real_interface($paif) . " auto";
2056
			foreach ($paents as $paent) {
2057
				if (isset($paent['subnet']))
2058
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2059
				else if (isset($paent['range']))
2060
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2061
			}
2062
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2063
		}
2064
	}
2065
}
2066

    
2067
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2068
	global $g, $config;
2069

    
2070
	if (is_array($config['virtualip']['vip'])) {
2071
		foreach ($config['virtualip']['vip'] as $vip) {
2072
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2073
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2074
					interface_vip_bring_down($vip);
2075
				else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2076
					interface_vip_bring_down($vip);
2077
			}
2078
		}
2079
	}
2080
}
2081

    
2082
function interfaces_vips_configure($interface = "") {
2083
	global $g, $config;
2084
	if(isset($config['system']['developerspew'])) {
2085
		$mt = microtime();
2086
		echo "interfaces_vips_configure() being called $mt\n";
2087
	}
2088
	$paa = array();
2089
	if(is_array($config['virtualip']['vip'])) {
2090
		$carp_setuped = false;
2091
		$anyproxyarp = false;
2092
		foreach ($config['virtualip']['vip'] as $vip) {
2093
			switch ($vip['mode']) {
2094
			case "proxyarp":
2095
				/* nothing it is handled on interface_proxyarp_configure() */
2096
				if ($interface <> "" && $vip['interface'] <> $interface)
2097
					continue;
2098
				$anyproxyarp = true;
2099
				break;
2100
			case "ipalias":
2101
				if ($interface <> "" && $vip['interface'] <> $interface)
2102
					continue;
2103
				interface_ipalias_configure($vip);
2104
				break;
2105
			case "carp":
2106
				if ($interface <> "" && $vip['interface'] <> $interface)
2107
					continue;
2108
				if ($carp_setuped == false)
2109
					$carp_setuped = true;
2110
				interface_carp_configure($vip);
2111
				break;
2112
			}
2113
		}
2114
		if ($carp_setuped == true)
2115
			interfaces_carp_setup();
2116
		if ($anyproxyarp == true)
2117
			interface_proxyarp_configure();
2118
	}
2119
}
2120

    
2121
function interface_ipalias_configure(&$vip) {
2122
	global $config;
2123

    
2124
	if ($vip['mode'] != "ipalias")
2125
		return;
2126

    
2127
	if ($vip['interface'] != 'lo0' && !isset($config['interfaces'][$vip['interface']]))
2128
		return;
2129

    
2130
	if ($vip['interface'] != 'lo0' && !isset($config['interfaces'][$vip['interface']]['enable']))
2131
		return;
2132

    
2133
	$if = get_real_interface($vip['interface']);
2134
	$af = "inet";
2135
	if(is_ipaddrv6($vip['subnet']))
2136
		$af = "inet6";
2137
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
2138
}
2139

    
2140
function interface_reload_carps($cif) {
2141
	global $config;
2142

    
2143
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2144
	if (empty($carpifs))
2145
		return;
2146

    
2147
	$carps = explode(" ", $carpifs);
2148
	if(is_array($config['virtualip']['vip'])) {
2149
		$viparr = &$config['virtualip']['vip'];
2150
		foreach ($viparr as $vip) {
2151
			if (in_array($vip['carpif'], $carps)) {
2152
				switch ($vip['mode']) {
2153
				case "carp":
2154
					interface_vip_bring_down($vip);
2155
					sleep(1);
2156
					interface_carp_configure($vip);
2157
					break;
2158
				case "ipalias":
2159
					interface_vip_bring_down($vip);
2160
					sleep(1);
2161
					interface_ipalias_configure($vip);
2162
					break;
2163
				}
2164
			}
2165
		}
2166
	}
2167
}
2168

    
2169
function interface_carp_configure(&$vip) {
2170
	global $config, $g;
2171
	if(isset($config['system']['developerspew'])) {
2172
		$mt = microtime();
2173
		echo "interface_carp_configure() being called $mt\n";
2174
	}
2175

    
2176
	if ($vip['mode'] != "carp")
2177
		return;
2178

    
2179
	/* NOTE: Maybe its useless nowdays */
2180
	$realif = get_real_interface($vip['interface']);
2181
	if (!does_interface_exist($realif)) {
2182
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2183
		return;
2184
	}
2185

    
2186
	if (is_ipaddrv4($vip['subnet'])) {
2187
		/* Ensure CARP IP really exists prior to loading up. */
2188
		$ww_subnet_ip = find_interface_ip($realif);
2189
		$ww_subnet_bits = find_interface_subnet($realif);
2190
		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'])) {
2191
			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", "");
2192
			return;
2193
		}
2194
	} else if (is_ipaddrv6($vip['subnet'])) {
2195
		/* Ensure CARP IP really exists prior to loading up. */
2196
		$ww_subnet_ip = find_interface_ipv6($realif);
2197
		$ww_subnet_bits = find_interface_subnetv6($realif);
2198
		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'])) {
2199
			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", "");
2200
			return;
2201
		}
2202
	}
2203

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

    
2209
	$advbase = "";
2210
	if (!empty($vip['advbase']))
2211
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2212

    
2213
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2214
	if ($carp_maintenancemode)
2215
		$advskew = "advskew 254";
2216
	else
2217
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2218
	
2219
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) . " {$advskew} {$advbase} {$password}");
2220

    
2221
	if (is_ipaddrv4($vip['subnet']))
2222
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2223
	else if (is_ipaddrv6($vip['subnet']))
2224
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " vhid " . escapeshellarg($vip['vhid']));
2225

    
2226
	return $realif;
2227
}
2228

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

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

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

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

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

    
2300
	if(!is_interface_wireless($ifcfg['if']))
2301
		return;
2302

    
2303
	$baseif = interface_get_wireless_base($ifcfg['if']);
2304

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

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

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

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

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

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

    
2375
	// Clone wireless nic if needed.
2376
	interface_wireless_clone($if, $wl);
2377

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2527
	kill_hostapd($if);
2528
	mwexec(kill_wpasupplicant("{$if}"));
2529

    
2530
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2531
	conf_mount_rw();
2532

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

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

    
2586
EOD;
2587

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

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

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

    
2605
auth_server_addr={$wlcfg['auth_server_addr']}
2606
auth_server_port={$auth_server_port}
2607
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2608

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

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

    
2620
EOD;
2621
					}
2622
				}
2623
			}
2624

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

    
2631
	/*
2632
	 *    all variables are set, lets start up everything
2633
	 */
2634

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

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

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

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

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

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

    
2681
	fclose($fd_set);
2682
	conf_mount_ro();
2683

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

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

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

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

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

    
2717
		$wlregcmd_args = implode(" ", $wlregcmd);
2718

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

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

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

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

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

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

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

    
2772

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

    
2777
	return 0;
2778

    
2779
}
2780

    
2781
function kill_hostapd($interface) {
2782
	global $g;
2783

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

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

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

    
2798
	return intval($pid);
2799
}
2800

    
2801
function kill_dhclient_process($interface) {
2802
	if (empty($interface) || !does_interface_exist($interface))
2803
		return;
2804

    
2805
	$i = 0;
2806
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2807
		/* 3rd time make it die for sure */
2808
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2809
		posix_kill($pid, $sig);
2810
		sleep(1);
2811
		$i++;
2812
	}
2813
	unset($i);
2814
}
2815

    
2816
function find_dhcp6c_process($interface) {
2817
	global $g;
2818

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

    
2824
	return intval($pid);
2825
}
2826

    
2827
function interface_vlan_mtu_configured($realhwif, $mtu) {
2828
	global $config;
2829

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

    
2842
	return $mtu;
2843
}
2844

    
2845
function interface_virtual_create($interface) {
2846
	global $config;
2847

    
2848
	if (strstr($interface, "_vlan")) {
2849
		interfaces_vlan_configure($vlan);
2850
	} else if (substr($interface, 0, 3) == "gre") {
2851
		interfaces_gre_configure(0, $interface);
2852
	} else if (substr($interface, 0, 3) == "gif") {
2853
		interfaces_gif_configure(0, $interface);
2854
	} else if (substr($interface, 0, 5) == "ovpns") {
2855
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
2856
			foreach ($config['openvpn']['openvpn-server'] as $server) {
2857
				if ($interface == "ovpns{$server['vpnid']}") {
2858
					if (!function_exists('openvpn_resync'))
2859
						require_once('openvpn.inc');
2860
					log_error("OpenVPN: Resync server {$server['description']}");
2861
					openvpn_resync('server', $server);
2862
				}
2863
			}
2864
			unset($server);
2865
		}
2866
	} else if (substr($interface, 0, 5) == "ovpnc") {
2867
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
2868
			foreach ($config['openvpn']['openvpn-client'] as $client) {
2869
				if ($interface == "ovpnc{$client['vpnid']}") {
2870
					if (!function_exists('openvpn_resync'))
2871
						require_once('openvpn.inc');
2872
					log_error("OpenVPN: Resync server {$client['description']}");
2873
					openvpn_resync('client', $client);
2874
				}
2875
			}
2876
			unset($client);
2877
		}
2878
	} else if (substr($interface, 0, 4) == "lagg") {
2879
		interfaces_lagg_configure($interface);
2880
	} else if (substr($interface, 0, 6) == "bridge") {
2881
		interfaces_bridge_configure(0, $interface);
2882
	}
2883
}
2884

    
2885
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2886
	global $config;
2887

    
2888
	if (!is_array($vlanifs))
2889
		return;
2890

    
2891
	/* All vlans need to use the same mtu value as their parent. */
2892
	foreach ($vlanifs as $vlan) {
2893
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2894
		if (!empty($assignedport)) {
2895
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
2896
				/*
2897
				* XXX: This is really never going to happen just keep the code for safety and readbility.
2898
				* It never happens since interface_vlan_mtu_configured finds the biggest mtu on vlans.
2899
				* Also if it has a lower mtu configured just respect user choice.
2900
				*/
2901
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2902
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2903
			} else {
2904
				if (get_interface_mtu($vlan['vlanif']) != $mtu)
2905
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2906
			}
2907
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2908
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
2909
	}
2910
}
2911

    
2912
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2913
	global $config, $g;
2914
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2915
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2916

    
2917
	$wancfg = $config['interfaces'][$interface];
2918

    
2919
	if (!isset($wancfg['enable']))
2920
		return;
2921

    
2922
	$realif = get_real_interface($interface);
2923
	$realhwif_array = get_parent_interface($interface);
2924
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2925
	$realhwif = $realhwif_array[0];
2926

    
2927
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2928
		/* remove all IPv4 and IPv6 addresses */
2929
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2930
		if (is_array($tmpifaces)) {
2931
			foreach ($tmpifaces as $tmpiface) {
2932
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
2933
					if (!is_linklocal($tmpiface))
2934
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2935
				} else {
2936
					if (is_subnetv4($tmpiface)) {
2937
						$tmpip = explode('/', $tmpiface);
2938
						$tmpip = $tmpip[0];
2939
					} else
2940
						$tmpip = $tmpiface;
2941
					pfSense_interface_deladdress($realif, $tmpip);
2942
				}
2943
			}
2944
		}
2945

    
2946
		/* only bring down the interface when both v4 and v6 are set to NONE */
2947
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6']))
2948
			interface_bring_down($interface);
2949
	}
2950

    
2951
	$interface_to_check = $realif;
2952
	switch ($wancfg['ipaddr']) {
2953
	case 'pppoe':
2954
	case 'l2tp':
2955
	case 'pptp':
2956
	case 'ppp':
2957
		$interface_to_check = $realhwif;
2958
		break;
2959
	}
2960

    
2961
	/* Need to check that the interface exists or not in the case where its coming back from disabled state see #3270 */
2962
	if (in_array(substr($realif, 0, 3), array("gre", "gif")) || !does_interface_exist($interface_to_check))
2963
		interface_virtual_create($interface_to_check);
2964

    
2965
	/* Disable Accepting router advertisements unless specifically requested */
2966
	if ($g['debug'])
2967
		log_error("Deny router advertisements for interface {$interface}");
2968
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2969

    
2970
	/* wireless configuration? */
2971
	if (is_array($wancfg['wireless']))
2972
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2973

    
2974
	$mac = get_interface_mac($realhwif);
2975
	/*
2976
	 * Don't try to reapply the spoofed MAC if it's already applied.
2977
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2978
	 * the interface config again, which attempts to spoof the MAC again,
2979
	 * which cycles the link again...
2980
	 */
2981
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
2982
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2983
			" link " . escapeshellarg($wancfg['spoofmac']));
2984

    
2985
		/*
2986
		 * All vlans need to spoof their parent mac address, too.  see
2987
		 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2988
		 */
2989
		if (is_array($config['vlans']['vlan'])) {
2990
			foreach ($config['vlans']['vlan'] as $vlan) {
2991
				if ($vlan['if'] == $realhwif)
2992
					mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2993
					" link " . escapeshellarg($wancfg['spoofmac']));
2994
			}
2995
		}
2996
	}  else {
2997

    
2998
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2999
			/*   this is not a valid mac address.  generate a
3000
			 *   temporary mac address so the machine can get online.
3001
			 */
3002
			echo gettext("Generating new MAC address.");
3003
			$random_mac = generate_random_mac_address();
3004
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3005
				" link " . escapeshellarg($random_mac));
3006
			$wancfg['spoofmac'] = $random_mac;
3007
			write_config();
3008
			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");
3009
		}
3010
	}
3011

    
3012
	/* media */
3013
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3014
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3015
		if ($wancfg['media'])
3016
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3017
		if ($wancfg['mediaopt'])
3018
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3019
		mwexec($cmd);
3020
	}
3021
	$options = pfSense_get_interface_addresses($realhwif);
3022

    
3023
	/* skip vlans for checksumming and polling */
3024
	if (!stristr($realif, "_vlan") && is_array($options)) {
3025
		$flags_on = 0;
3026
		$flags_off = 0;
3027
		if(isset($config['system']['disablechecksumoffloading'])) {
3028
			if (isset($options['encaps']['txcsum']))
3029
				$flags_off |= IFCAP_TXCSUM;
3030
			if (isset($options['encaps']['rxcsum']))
3031
				$flags_off |= IFCAP_RXCSUM;
3032
		} else {
3033
			if (isset($options['caps']['txcsum']))
3034
				$flags_on |= IFCAP_TXCSUM;
3035
			if (isset($options['caps']['rxcsum']))
3036
				$flags_on |= IFCAP_RXCSUM;
3037
		}
3038

    
3039
		if(isset($config['system']['disablesegmentationoffloading']))
3040
			$flags_off |= IFCAP_TSO;
3041
		else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6']))
3042
			$flags_on |= IFCAP_TSO;
3043

    
3044
		if(isset($config['system']['disablelargereceiveoffloading']))
3045
			$flags_off |= IFCAP_LRO;
3046
		else if (isset($options['caps']['lro']))
3047
			$flags_on |= IFCAP_LRO;
3048

    
3049
		/* if the NIC supports polling *AND* it is enabled in the GUI */
3050
		if (!isset($config['system']['polling']))
3051
			$flags_off |= IFCAP_POLLING;
3052
		else if (isset($options['caps']['polling']))
3053
			$flags_on |= IFCAP_POLLING;
3054

    
3055
		pfSense_interface_capabilities($realhwif, -$flags_off);
3056
		pfSense_interface_capabilities($realhwif, $flags_on);
3057
	}
3058

    
3059
	/* invalidate interface/ip/sn cache */
3060
	get_interface_arr(true);
3061
	unset($interface_ip_arr_cache[$realif]);
3062
	unset($interface_sn_arr_cache[$realif]);
3063
	unset($interface_ipv6_arr_cache[$realif]);
3064
	unset($interface_snv6_arr_cache[$realif]);
3065

    
3066
	$tunnelif = substr($realif, 0, 3);
3067
	switch ($wancfg['ipaddr']) {
3068
	case 'dhcp':
3069
		interface_dhcp_configure($interface);
3070
		break;
3071
	case 'pppoe':
3072
	case 'l2tp':
3073
	case 'pptp':
3074
	case 'ppp':
3075
		interface_ppps_configure($interface);
3076
		break;
3077
	default:
3078
		/* XXX: Kludge for now related to #3280 */
3079
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3080
			if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "")
3081
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3082
		}
3083
		break;
3084
	}
3085

    
3086
	switch ($wancfg['ipaddrv6']) {
3087
	case 'slaac':
3088
	case 'dhcp6':
3089
		interface_dhcpv6_configure($interface, $wancfg);
3090
		break;
3091
	case '6rd':
3092
		interface_6rd_configure($interface, $wancfg);
3093
		break;
3094
	case '6to4':
3095
		interface_6to4_configure($interface, $wancfg);
3096
		break;
3097
	case 'track6':
3098
		interface_track6_configure($interface, $wancfg, $linkupevent);
3099
		break;
3100
	default:
3101
		/* XXX: Kludge for now related to #3280 */
3102
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3103
			if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3104
				//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3105
				// FIXME: Add IPv6 Support to the pfSense module
3106
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3107
			}
3108
		}
3109
		break;
3110
	}
3111

    
3112
	if (!empty($wancfg['mtu'])) {
3113
		if (stristr($realif, "_vlan")) {
3114
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3115
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
3116
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3117
			else
3118
				$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
3119

    
3120
			if ($wancfg['mtu'] > $parentmtu) {
3121
				if (get_interface_mtu($realhwif) != $wancfg['mtu'])
3122
					pfSense_interface_mtu($realhwif, $wancfg['mtu']);
3123

    
3124
				/* All vlans need to use the same mtu value as their parent. */
3125
				interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $wancfg['mtu']);
3126
			} else
3127
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3128
		} else {
3129
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3130
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3131

    
3132
			/* This case is needed when the parent of vlans is being configured */
3133
			interface_vlan_adapt_mtu(link_interface_to_vlans($realif), $wancfg['mtu']);
3134
		}
3135
		/* XXX: What about gre/gif/lagg/.. ? */
3136
	}
3137

    
3138
	if (does_interface_exist($wancfg['if']))
3139
		interfaces_bring_up($wancfg['if']);
3140

    
3141
	interface_netgraph_needed($interface);
3142

    
3143
	if (!$g['booting']) {
3144
		link_interface_to_vips($interface, "update");
3145

    
3146
		unset($gre);
3147
		$gre = link_interface_to_gre($interface);
3148
		if (!empty($gre))
3149
			array_walk($gre, 'interface_gre_configure');
3150

    
3151
		unset($gif);
3152
		$gif = link_interface_to_gif($interface);
3153
		if (!empty($gif))
3154
			array_walk($gif, 'interface_gif_configure');
3155

    
3156
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3157
			unset($bridgetmp);
3158
			$bridgetmp = link_interface_to_bridge($interface);
3159
			if (!empty($bridgetmp))
3160
				interface_bridge_add_member($bridgetmp, $realif);
3161
		}
3162

    
3163
		$grouptmp = link_interface_to_group($interface);
3164
		if (!empty($grouptmp))
3165
			array_walk($grouptmp, 'interface_group_add_member');
3166

    
3167
		if ($interface == "lan")
3168
			/* make new hosts file */
3169
			system_hosts_generate();
3170

    
3171
		if ($reloadall == true) {
3172

    
3173
			/* reconfigure static routes (kernel may have deleted them) */
3174
			system_routing_configure($interface);
3175

    
3176
			/* reload ipsec tunnels */
3177
			vpn_ipsec_configure();
3178

    
3179
			/* restart dnsmasq or unbound */
3180
			if (isset($config['dnsmasq']['enable']))
3181
				services_dnsmasq_configure();
3182
			elseif (isset($config['unbound']['enable']))
3183
				services_unbound_configure();
3184

    
3185
			/* update dyndns */
3186
			send_event("service reload dyndns {$interface}");
3187

    
3188
			/* XXX: which CPZONE? Needed? */
3189
			/* reload captive portal */
3190
			captiveportal_init_rules();
3191
		}
3192
	}
3193

    
3194
	interfaces_staticarp_configure($interface);
3195
	return 0;
3196
}
3197

    
3198
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3199
	global $config, $g;
3200

    
3201
	if (!is_array($wancfg))
3202
		return;
3203

    
3204
	if (!isset($wancfg['enable']))
3205
		return;
3206

    
3207
	/* If the interface is not configured via another, exit */
3208
	if (empty($wancfg['track6-interface']))
3209
		return;
3210

    
3211
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3212
	$realif = get_real_interface($interface);
3213
	$linklocal = find_interface_ipv6_ll($realif);
3214
	if (!empty($linklocal))
3215
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3216
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3217
	/* XXX: Probably should remove? */
3218
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3219

    
3220
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3221
	if (!isset($trackcfg['enable'])) {
3222
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3223
		return;
3224
	}
3225

    
3226
	switch($trackcfg['ipaddrv6']) {
3227
	case "6to4":
3228
		if ($g['debug'])
3229
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3230
		interface_track6_6to4_configure($interface, $wancfg);
3231
		break;
3232
	case "6rd":
3233
		if ($g['debug'])
3234
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3235
		interface_track6_6rd_configure($interface, $wancfg);
3236
		break;
3237
	case "dhcp6":
3238
		if ($linkupevent == true) {
3239
			/* 
3240
			 * NOTE: Usually come here from rc.linkup calling so just call directly intead of generating event
3241
			 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3242
			 *
3243
			 * XXX: Probably DHCPv6 client should handle this autmagically itself?
3244
			 */
3245
			$parentrealif = get_real_interface($wancfg['track6-interface']);
3246
			$pidv6 = find_dhcp6c_process($parentrealif);
3247
			if($pidv6)
3248
				posix_kill($pidv6, SIGHUP);
3249
		}
3250
		break;
3251
	}
3252

    
3253
	if (!$g['booting'] && $linkupevent == false) {
3254
		if (!function_exists('services_dhcpd_configure'))
3255
			require_once("services.inc");
3256

    
3257
		services_dhcpd_configure("inet6");
3258
	}
3259

    
3260
	return 0;
3261
}
3262

    
3263
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3264
	global $config, $g;
3265
	global $interface_ipv6_arr_cache;
3266
	global $interface_snv6_arr_cache;
3267

    
3268
	if (!is_array($lancfg))
3269
		return;
3270

    
3271
	/* If the interface is not configured via another, exit */
3272
	if (empty($lancfg['track6-interface']))
3273
		return;
3274

    
3275
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3276
	if (empty($wancfg)) {
3277
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3278
		return;
3279
	}
3280

    
3281
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3282
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3283
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3284
		return;
3285
	}
3286
	$hexwanv4 = return_hex_ipv4($ip4address);
3287

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

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

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

    
3301
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3302
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3303
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3304
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3305
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3306
	/* fill the rest out with zeros */
3307
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3308

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

    
3312
	$lanif = get_real_interface($interface);
3313
	$oip = find_interface_ipv6($lanif);
3314
	if (is_ipaddrv6($oip))
3315
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3316
	unset($interface_ipv6_arr_cache[$lanif]);
3317
	unset($interface_snv6_arr_cache[$lanif]);
3318
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3319
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3320

    
3321
	return 0;
3322
}
3323

    
3324
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3325
	global $config, $g;
3326
	global $interface_ipv6_arr_cache;
3327
	global $interface_snv6_arr_cache;
3328

    
3329
	if (!is_array($lancfg))
3330
		return;
3331

    
3332
	/* If the interface is not configured via another, exit */
3333
	if (empty($lancfg['track6-interface']))
3334
		return;
3335

    
3336
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3337
	if (empty($wancfg)) {
3338
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3339
		return;
3340
	}
3341

    
3342
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3343
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3344
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3345
		return;
3346
	}
3347
	$hexwanv4 = return_hex_ipv4($ip4address);
3348

    
3349
	/* create the long prefix notation for math, save the prefix length */
3350
	$sixto4prefix = "2002::";
3351
	$sixto4prefixlen = 16;
3352
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3353

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

    
3357
	/* just save the left prefix length bits */
3358
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3359
	/* add the v4 address */
3360
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3361
	/* add the custom prefix id */
3362
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3363
	/* fill the rest out with zeros */
3364
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3365

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

    
3369
	$lanif = get_real_interface($interface);
3370
	$oip = find_interface_ipv6($lanif);
3371
	if (is_ipaddrv6($oip))
3372
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3373
	unset($interface_ipv6_arr_cache[$lanif]);
3374
	unset($interface_snv6_arr_cache[$lanif]);
3375
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3376
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3377

    
3378
	return 0;
3379
}
3380

    
3381
function interface_6rd_configure($interface = "wan", $wancfg) {
3382
	global $config, $g;
3383

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

    
3387
	if (!is_array($wancfg))
3388
		return;
3389

    
3390
	if (!is_module_loaded('if_stf.ko'))
3391
		mwexec('/sbin/kldload if_stf.ko');
3392

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

    
3401
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3402
		$wancfg['prefix-6rd-v4plen'] = 0;
3403

    
3404
	/* create the long prefix notation for math, save the prefix length */
3405
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3406
	$rd6prefixlen = $rd6prefix[1];
3407
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3408

    
3409
	/* binary presentation of the prefix for all 128 bits. */
3410
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3411

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

    
3419
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3420
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3421

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

    
3424
	/* XXX: need to extend to support variable prefix size for v4 */
3425
	if (!is_module_loaded("if_stf"))
3426
		mwexec("/sbin/kldload if_stf.ko");
3427
	$stfiface = "{$interface}_stf";
3428
	if (does_interface_exist($stfiface))
3429
		pfSense_interface_destroy($stfiface);
3430
	$tmpstfiface = pfSense_interface_create("stf");
3431
	pfSense_interface_rename($tmpstfiface, $stfiface);
3432
	pfSense_interface_flags($stfiface, IFF_LINK2);
3433
	if ($wancfg['prefix-6rd-v4plen'] > 0)
3434
		$rd6prefixlen += intval($wancfg['prefix-6rd-v4plen']);
3435
	else
3436
		$rd6prefixlen += 32;
3437
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3438
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3439
	if ($wancfg['prefix-6rd-v4plen'] > 0 && $wancfg['prefix-6rd-v4plen'] < 32)
3440
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/{$wancfg['prefix-6rd-v4plen']}");
3441
	if ($g['debug'])
3442
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3443

    
3444
	/* write out a default router file */
3445
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3446
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3447

    
3448
	$ip4gateway = get_interface_gateway($interface);
3449
	if (is_ipaddrv4($ip4gateway))
3450
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3451

    
3452
	/* configure dependent interfaces */
3453
	if (!$g['booting'])
3454
		link_interface_to_track6($interface, "update");
3455

    
3456
	return 0;
3457
}
3458

    
3459
function interface_6to4_configure($interface = "wan", $wancfg){
3460
	global $config, $g;
3461

    
3462
	/* because this is a tunnel interface we can only function
3463
	 *	with a public IPv4 address on the interface */
3464

    
3465
	if (!is_array($wancfg))
3466
		return;
3467

    
3468
	$wanif = get_real_interface($interface);
3469
	$ip4address = find_interface_ip($wanif);
3470
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3471
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3472
		return false;
3473
	}
3474

    
3475
	/* create the long prefix notation for math, save the prefix length */
3476
	$stfprefixlen = 16;
3477
	$stfprefix = Net_IPv6::uncompress("2002::");
3478
	$stfarr = explode(":", $stfprefix);
3479
	$v4prefixlen = "0";
3480

    
3481
	/* we need the hex form of the interface IPv4 address */
3482
	$ip4arr = explode(".", $ip4address);
3483
	$hexwanv4 = "";
3484
	foreach($ip4arr as $octet)
3485
		$hexwanv4 .= sprintf("%02x", $octet);
3486

    
3487
	/* we need the hex form of the broker IPv4 address */
3488
	$ip4arr = explode(".", "192.88.99.1");
3489
	$hexbrv4 = "";
3490
	foreach($ip4arr as $octet)
3491
		$hexbrv4 .= sprintf("%02x", $octet);
3492

    
3493
	/* binary presentation of the prefix for all 128 bits. */
3494
	$stfprefixbin = "";
3495
	foreach($stfarr as $element) {
3496
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3497
	}
3498
	/* just save the left prefix length bits */
3499
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3500

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

    
3505
	/* for the local subnet too. */
3506
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3507
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3508

    
3509
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3510
	$stfbrarr = array();
3511
	$stfbrbinarr = array();
3512
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3513
	foreach($stfbrbinarr as $bin)
3514
		$stfbrarr[] = dechex(bindec($bin));
3515
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3516

    
3517
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3518
	$stflanarr = array();
3519
	$stflanbinarr = array();
3520
	$stflanbinarr = str_split($stflanbin, 16);
3521
	foreach($stflanbinarr as $bin)
3522
		$stflanarr[] = dechex(bindec($bin));
3523
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3524
	$stflanarr[7] = 1;
3525
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3526

    
3527
	/* setup the stf interface */
3528
	if (!is_module_loaded("if_stf"))
3529
		mwexec("/sbin/kldload if_stf.ko");
3530
	$stfiface = "{$interface}_stf";
3531
	if (does_interface_exist($stfiface))
3532
		pfSense_interface_destroy($stfiface);
3533
	$tmpstfiface = pfSense_interface_create("stf");
3534
	pfSense_interface_rename($tmpstfiface, $stfiface);
3535
	pfSense_interface_flags($stfiface, IFF_LINK2);
3536
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3537

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

    
3541
	/* write out a default router file */
3542
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3543
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3544

    
3545
	$ip4gateway = get_interface_gateway($interface);
3546
	if (is_ipaddrv4($ip4gateway))
3547
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3548

    
3549
	if (!$g['booting'])
3550
		link_interface_to_track6($interface, "update");
3551

    
3552
	return 0;
3553
}
3554

    
3555
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3556
	global $config, $g;
3557

    
3558
	if (!is_array($wancfg))
3559
		return;
3560

    
3561
	$wanif = get_real_interface($interface, "inet6");
3562
	$dhcp6cconf = "";
3563
	$dhcp6cconf .= "interface {$wanif} {\n";
3564

    
3565
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3566
	if($wancfg['ipaddrv6'] == "slaac") {
3567
		$dhcp6cconf .= "	information-only;\n";
3568
		$dhcp6cconf .= "	request domain-name-servers;\n";
3569
		$dhcp6cconf .= "	request domain-name;\n";
3570
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3571
		$dhcp6cconf .= "};\n";
3572
	} else {
3573
		/* skip address request if this is set */
3574
		if(!isset($wancfg['dhcp6prefixonly']))
3575
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3576
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3577
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3578

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

    
3583
		$dhcp6cconf .= "};\n";
3584

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

    
3588
		if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3589
			/* Setup the prefix delegation */
3590
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3591
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3592
			if (isset($wancfg['dhcp6-ia-pd-send-hint']))
3593
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3594
			$iflist = link_interface_to_track6($interface);
3595
			foreach ($iflist as $friendly => $ifcfg) {
3596
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3597
					if ($g['debug'])
3598
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3599
					$realif = get_real_interface($friendly);
3600
					$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3601
					$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3602
					$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3603
					$dhcp6cconf .= "	};\n";
3604
				}
3605
			}
3606
			unset($preflen, $iflist, $ifcfg);
3607
			$dhcp6cconf .= "};\n";
3608
		}
3609
	}
3610

    
3611
	// DHCP6 Config File Advanced
3612
	if ($wancfg['adv_dhcp6_config_advanced']) { $dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif); }
3613

    
3614
	// DHCP6 Config File Override
3615
	if ($wancfg['adv_dhcp6_config_file_override']) { $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif); }
3616

    
3617
	/* wide-dhcp6c works for now. */
3618
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3619
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3620
		unset($dhcp6cconf);
3621
		return 1;
3622
	}
3623
	unset($dhcp6cconf);
3624

    
3625
	$dhcp6cscript = "#!/bin/sh\n";
3626
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3627
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3628
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3629
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3630
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3631
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3632
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3633
		unset($dhcp6cscript);
3634
		return 1;
3635
	}
3636
	unset($dhcp6cscript);
3637
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3638

    
3639
	$rtsoldscript = "#!/bin/sh\n";
3640
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3641
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3642
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3643
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3644
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3645
	$rtsoldscript .= "\t/bin/sleep 1\n";
3646
	$rtsoldscript .= "fi\n";
3647
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3648
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3649
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3650
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3651
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3652
		unset($rtsoldscript);
3653
		return 1;
3654
	}
3655
	unset($rtsoldscript);
3656
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3657

    
3658
	/* accept router advertisements for this interface */
3659
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3660
	log_error("Accept router advertisements on interface {$wanif} ");
3661
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3662

    
3663
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3664
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3665
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3666
		sleep(2);
3667
	}
3668
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3669

    
3670
	/* NOTE: will be called from rtsold invoked script
3671
	 * link_interface_to_track6($interface, "update");
3672
	 */
3673

    
3674
	return 0;
3675
}
3676

    
3677
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3678
	global $g;
3679

    
3680
	$send_options = "";
3681
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3682
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_send_options']);
3683
		foreach ($options as $option) {
3684
			$send_options .= "\tsend " . trim($option) . ";\n";
3685
		}
3686
	}
3687

    
3688
	$request_options = "";
3689
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3690
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_request_options']);
3691
		foreach ($options as $option) {
3692
			$request_options .= "\trequest " . trim($option) . ";\n";
3693
		}
3694
	}
3695

    
3696
	$information_only = "";
3697
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') 
3698
		$information_only = "\tinformation-only;\n";
3699

    
3700
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3701
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '')
3702
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3703

    
3704
	$interface_statement  = "interface";
3705
	$interface_statement .= " {$wanif}";
3706
	$interface_statement .= " {\n";
3707
	$interface_statement .= "$send_options";
3708
	$interface_statement .= "$request_options";
3709
	$interface_statement .= "$information_only";
3710
	$interface_statement .= "$script";
3711
	$interface_statement .= "};\n";
3712

    
3713
	$id_assoc_statement_address = "";
3714
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3715
		$id_assoc_statement_address .= "id-assoc";
3716
		$id_assoc_statement_address .= " na";
3717
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) 
3718
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3719
		$id_assoc_statement_address .= " { ";
3720

    
3721
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') && 
3722
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) || 
3723
			 ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity')) ) {
3724
			$id_assoc_statement_address .= "\n\taddress";
3725
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3726
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3727
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) || 
3728
							($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity') ) 
3729
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3730
			$id_assoc_statement_address .= ";\n";
3731
		}
3732

    
3733
		$id_assoc_statement_address  .= "};\n";
3734
	}
3735

    
3736
	$id_assoc_statement_prefix = "";
3737
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3738
		$id_assoc_statement_prefix .= "id-assoc";
3739
		$id_assoc_statement_prefix .= " pd";
3740
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) 
3741
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3742
		$id_assoc_statement_prefix .= " { ";
3743

    
3744
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') && 
3745
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) || 
3746
			 ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity')) ) {
3747
			$id_assoc_statement_prefix .= "\n\tprefix";
3748
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3749
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3750
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) || 
3751
						  ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity') ) 
3752
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3753
			$id_assoc_statement_prefix .= ";";
3754
		}
3755

    
3756
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3757
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3758
			$id_assoc_statement_prefix .= " {$wanif}";
3759
			$id_assoc_statement_prefix .= " {\n";
3760
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3761
			if ( ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) && 
3762
				 ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128) ) 
3763
				 $id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3764
			$id_assoc_statement_prefix .= "\t};";
3765
		}
3766

    
3767
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') || 
3768
			 (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) ) { 
3769
			$id_assoc_statement_prefix .= "\n";
3770
		}
3771

    
3772
		$id_assoc_statement_prefix  .= "};\n";
3773
	}
3774

    
3775
	$authentication_statement = "";
3776
	if ( ($wancfg['adv_dhcp6_authentication_statement_authname'] != '') && 
3777
		 ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed') ) {
3778
		$authentication_statement .= "authentication";
3779
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
3780
		$authentication_statement .= " {\n";
3781
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
3782
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) 
3783
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
3784
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') 
3785
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
3786
		$authentication_statement .= "};\n";
3787
	}
3788

    
3789
	$key_info_statement = "";
3790
	if ( ($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') && 
3791
		 ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') && 
3792
		 (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) && 
3793
		 ($wancfg['adv_dhcp6_key_info_statement_secret'] != '') ) {
3794
		$key_info_statement .= "keyinfo";
3795
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
3796
		$key_info_statement .= " {\n";
3797
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
3798
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
3799
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
3800
		if (preg_match("/((([0-9]{4}-)?[0-9]{2}[0-9]{2} )?[0-9]{2}:[0-9]{2})||(foreever)/", $wancfg['adv_dhcp6_key_info_statement_expire'])) 
3801
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
3802
		$key_info_statement .= "};\n";
3803
	}
3804

    
3805
	$dhcp6cconf  = $interface_statement;
3806
	$dhcp6cconf .= $id_assoc_statement_address;
3807
	$dhcp6cconf .= $id_assoc_statement_prefix;
3808
	$dhcp6cconf .= $authentication_statement;
3809
	$dhcp6cconf .= $key_info_statement;
3810

    
3811
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3812

    
3813
	return $dhcp6cconf;
3814
}
3815

    
3816

    
3817
function DHCP6_Config_File_Override($wancfg, $wanif) {
3818

    
3819
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
3820
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3821

    
3822
	return $dhcp6cconf;
3823
}
3824

    
3825

    
3826
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
3827

    
3828
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3829

    
3830
	return $dhcp6cconf;
3831
}
3832

    
3833

    
3834
function interface_dhcp_configure($interface = "wan") {
3835
	global $config, $g;
3836

    
3837
	$wancfg = $config['interfaces'][$interface];
3838
	$wanif = $wancfg['if'];
3839
	if (empty($wancfg))
3840
		$wancfg = array();
3841

    
3842
	/* generate dhclient_wan.conf */
3843
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3844
	if (!$fd) {
3845
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3846
		return 1;
3847
	}
3848

    
3849
	if ($wancfg['dhcphostname']) {
3850
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3851
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3852
	} else {
3853
		$dhclientconf_hostname = "";
3854
	}
3855

    
3856
	$wanif = get_real_interface($interface);
3857
	if (empty($wanif)) {
3858
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3859
		return 0;
3860
	}
3861
	$dhclientconf = "";
3862

    
3863
	$dhclientconf .= <<<EOD
3864
interface "{$wanif}" {
3865
timeout 60;
3866
retry 15;
3867
select-timeout 0;
3868
initial-interval 1;
3869
	{$dhclientconf_hostname}
3870
	script "/sbin/dhclient-script";
3871
EOD;
3872

    
3873
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3874
	$dhclientconf .= <<<EOD
3875

    
3876
	reject {$wancfg['dhcprejectfrom']};
3877
EOD;
3878
}
3879
	$dhclientconf .= <<<EOD
3880

    
3881
}
3882

    
3883
EOD;
3884

    
3885
	// DHCP Config File Advanced
3886
	if ($wancfg['adv_dhcp_config_advanced']) { $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif); }
3887

    
3888
if(is_ipaddr($wancfg['alias-address'])) {
3889
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3890
	$dhclientconf .= <<<EOD
3891
alias {
3892
	interface  "{$wanif}";
3893
	fixed-address {$wancfg['alias-address']};
3894
	option subnet-mask {$subnetmask};
3895
}
3896

    
3897
EOD;
3898
}
3899

    
3900
	// DHCP Config File Override
3901
	if ($wancfg['adv_dhcp_config_file_override']) { $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif); }
3902

    
3903
	fwrite($fd, $dhclientconf);
3904
	fclose($fd);
3905

    
3906
	/* bring wan interface up before starting dhclient */
3907
	if($wanif)
3908
		interfaces_bring_up($wanif);
3909
	else
3910
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3911

    
3912
	/* Make sure dhclient is not running */
3913
	kill_dhclient_process($wanif);
3914

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

    
3918
	return 0;
3919
}
3920

    
3921
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3922

    
3923
	$hostname = "";
3924
	if ($wancfg['dhcphostname'] != '') {
3925
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3926
	}
3927

    
3928
	/* DHCP Protocol Timings */
3929
	$protocol_timings = array ('adv_dhcp_pt_timeout' => "timeout", 'adv_dhcp_pt_retry' => "retry", 'adv_dhcp_pt_select_timeout' => "select-timeout", 'adv_dhcp_pt_reboot' => "reboot", 'adv_dhcp_pt_backoff_cutoff' => "backoff-cutoff", 'adv_dhcp_pt_initial_interval' => "initial-interval");
3930
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
3931
		$pt_variable = "{$Protocol_Timing}";
3932
		${$pt_variable} = "";
3933
		if ($wancfg[$Protocol_Timing] != "") {
3934
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
3935
		}
3936
	}
3937

    
3938
	$send_options = "";
3939
	if ($wancfg['adv_dhcp_send_options'] != '') {
3940
		$options = split(",", $wancfg['adv_dhcp_send_options']);
3941
		foreach ($options as $option) {
3942
			$send_options .= "\tsend " . trim($option) . ";\n";
3943
		}
3944
	}
3945

    
3946
	$request_options = "";
3947
	if ($wancfg['adv_dhcp_request_options'] != '') {
3948
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
3949
	}
3950

    
3951
	$required_options = "";
3952
	if ($wancfg['adv_dhcp_required_options'] != '') {
3953
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
3954
	}
3955

    
3956
	$option_modifiers = "";
3957
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
3958
		$modifiers = split(",", $wancfg['adv_dhcp_option_modifiers']);
3959
		foreach ($modifiers as $modifier) {
3960
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
3961
		}
3962
	}
3963

    
3964
 	$dhclientconf  = "interface \"{$wanif}\" {\n";
3965
 	$dhclientconf .= "\n";
3966
 	$dhclientconf .= "# DHCP Protocol Timing Values\n";
3967
 	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
3968
 	$dhclientconf .= "{$adv_dhcp_pt_retry}";
3969
 	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
3970
 	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
3971
 	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
3972
 	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
3973
 	$dhclientconf .= "\n";
3974
 	$dhclientconf .= "# DHCP Protocol Options\n";
3975
 	$dhclientconf .= "{$hostname}";
3976
 	$dhclientconf .= "{$send_options}";
3977
 	$dhclientconf .= "{$request_options}";
3978
 	$dhclientconf .= "{$required_options}";
3979
 	$dhclientconf .= "{$option_modifiers}";
3980
 	$dhclientconf .= "\n";
3981
 	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
3982
 	$dhclientconf .= "}\n";
3983

    
3984
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3985

    
3986
	return $dhclientconf;
3987
}
3988

    
3989

    
3990
function DHCP_Config_File_Override($wancfg, $wanif) {
3991

    
3992
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
3993
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3994

    
3995
	return $dhclientconf;
3996
}
3997

    
3998

    
3999
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4000

    
4001
	/* Apply Interface Substitutions */
4002
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4003

    
4004
	/* Apply Hostname Substitutions */
4005
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4006

    
4007
	/* Arrays of MAC Address Types, Cases, Delimiters */
4008
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4009
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4010
	$various_mac_cases      = array("U", "L");
4011
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4012

    
4013
	/* Apply MAC Address Substitutions */
4014
	foreach ($various_mac_types as $various_mac_type) {
4015
		foreach ($various_mac_cases as $various_mac_case) {
4016
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4017

    
4018
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4019
				if ($res !== false) {
4020

    
4021
					/* Get MAC Address as ASCII String With Colon (:) Celimiters */
4022
					if ("$various_mac_case" == "U") $dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4023
					if ("$various_mac_case" == "L") $dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4024

    
4025
					if ("$various_mac_type" == "mac_addr_hex") {
4026
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4027
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4028
						$dhcpclientconf_mac_hex = "";
4029
						$delimiter = "";
4030
						for($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4031
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4032
							$delimiter = ":";
4033
						}
4034
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4035
					}
4036

    
4037
					/* MAC Address Delimiter Substitutions */
4038
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4039

    
4040
					/* Apply MAC Address Substitutions */
4041
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4042
				}
4043
			}
4044
		}
4045
	}
4046

    
4047
	return $dhclientconf;
4048
}
4049

    
4050
function interfaces_group_setup() {
4051
	global $config;
4052

    
4053
	if (!is_array($config['ifgroups']['ifgroupentry']))
4054
		return;
4055

    
4056
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
4057
		interface_group_setup($groupar);
4058

    
4059
	return;
4060
}
4061

    
4062
function interface_group_setup(&$groupname /* The parameter is an array */) {
4063
	global $config;
4064

    
4065
	if (!is_array($groupname))
4066
		return;
4067
	$members = explode(" ", $groupname['members']);
4068
	foreach($members as $ifs) {
4069
		$realif = get_real_interface($ifs);
4070
		if ($realif)
4071
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4072
	}
4073

    
4074
	return;
4075
}
4076

    
4077
function is_interface_group($if) {
4078
	global $config;
4079

    
4080
	if (is_array($config['ifgroups']['ifgroupentry']))
4081
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4082
			if ($groupentry['ifname'] === $if)
4083
				return true;
4084
		}
4085

    
4086
	return false;
4087
}
4088

    
4089
function interface_group_add_member($interface, $groupname) {
4090
	$interface = get_real_interface($interface);
4091
	mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4092
}
4093

    
4094
/* COMPAT Function */
4095
function convert_friendly_interface_to_real_interface_name($interface) {
4096
	return get_real_interface($interface);
4097
}
4098

    
4099
/* COMPAT Function */
4100
function get_real_wan_interface($interface = "wan") {
4101
	return get_real_interface($interface);
4102
}
4103

    
4104
/* COMPAT Function */
4105
function get_current_wan_address($interface = "wan") {
4106
	return get_interface_ip($interface);
4107
}
4108

    
4109
/*
4110
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4111
 */
4112
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
4113
	global $config;
4114

    
4115
	/* XXX: For speed reasons reference directly the interface array */
4116
	$ifdescrs = &$config['interfaces'];
4117
	//$ifdescrs = get_configured_interface_list(false, true);
4118

    
4119
	foreach ($ifdescrs as $if => $ifname) {
4120
		if ($if == $interface || $ifname['if'] == $interface)
4121
			return $if;
4122

    
4123
		if (get_real_interface($if) == $interface)
4124
			return $if;
4125

    
4126
		$int = get_parent_interface($if, true);
4127
		if (is_array($int)) {
4128
			foreach ($int as $iface) {
4129
				if ($iface == $interface)
4130
					return $if;
4131
			}
4132
		}
4133
	}
4134

    
4135
	if ($interface == "enc0")
4136
		return 'IPsec';
4137

    
4138
	return NULL;
4139
}
4140

    
4141
/* attempt to resolve interface to friendly descr */
4142
function convert_friendly_interface_to_friendly_descr($interface) {
4143
	global $config;
4144

    
4145
	switch ($interface) {
4146
	case "l2tp":
4147
		$ifdesc = "L2TP";
4148
		break;
4149
	case "pptp":
4150
		$ifdesc = "PPTP";
4151
		break;
4152
	case "pppoe":
4153
		$ifdesc = "PPPoE";
4154
		break;
4155
	case "openvpn":
4156
		$ifdesc = "OpenVPN";
4157
		break;
4158
	case "enc0":
4159
	case "ipsec":
4160
	case "IPsec":
4161
		$ifdesc = "IPsec";
4162
		break;
4163
	default:
4164
		if (isset($config['interfaces'][$interface])) {
4165
			if (empty($config['interfaces'][$interface]['descr']))
4166
				$ifdesc = strtoupper($interface);
4167
			else
4168
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4169
			break;
4170
		} else if (stristr($interface, "_vip")) {
4171
			if (is_array($config['virtualip']['vip'])) {
4172
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
4173
					if ($vip['mode'] == "carp")  {
4174
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4175
							return "{$vip['subnet']} - {$vip['descr']}";
4176
					}
4177
				}
4178
			}
4179
		} else {
4180
			/* if list */
4181
			$ifdescrs = get_configured_interface_with_descr(false, true);
4182
			foreach ($ifdescrs as $if => $ifname) {
4183
				if ($if == $interface || $ifname == $interface)
4184
					return $ifname;
4185
			}
4186
		}
4187
		break;
4188
	}
4189

    
4190
	return $ifdesc;
4191
}
4192

    
4193
function convert_real_interface_to_friendly_descr($interface) {
4194

    
4195
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4196

    
4197
	if (!empty($ifdesc))
4198
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4199

    
4200
	return $interface;
4201
}
4202

    
4203
/*
4204
 *  get_parent_interface($interface):
4205
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4206
 *				or virtual interface (i.e. vlan)
4207
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4208
 *			-- returns $interface passed in if $interface parent is not found
4209
 *			-- returns empty array if an invalid interface is passed
4210
 *	(Only handles ppps and vlans now.)
4211
 */
4212
function get_parent_interface($interface, $avoidrecurse = false) {
4213
	global $config;
4214

    
4215
	$parents = array();
4216
	//Check that we got a valid interface passed
4217
	$realif = get_real_interface($interface);
4218
	if ($realif == NULL)
4219
		return $parents;
4220

    
4221
	// If we got a real interface, find it's friendly assigned name
4222
	if ($interface == $realif && $avoidrecurse == false)
4223
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4224

    
4225
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4226
		$ifcfg = $config['interfaces'][$interface];
4227
		switch ($ifcfg['ipaddr']) {
4228
			case "ppp":
4229
			case "pppoe":
4230
			case "pptp":
4231
			case "l2tp":
4232
				if (empty($parents))
4233
					if (is_array($config['ppps']['ppp']))
4234
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4235
							if ($ifcfg['if'] == $ppp['if']) {
4236
								$ports = explode(',', $ppp['ports']);
4237
								foreach ($ports as $pid => $parent_if)
4238
									$parents[$pid] = get_real_interface($parent_if);
4239
								break;
4240
							}
4241
						}
4242
				break;
4243
			case "dhcp":
4244
			case "static":
4245
			default:
4246
				// Handle _vlans
4247
				if (stristr($realif,"_vlan"))
4248
					if (is_array($config['vlans']['vlan']))
4249
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
4250
							if ($ifcfg['if'] == $vlan['vlanif']){
4251
								$parents[0] = $vlan['if'];
4252
								break;
4253
							}
4254
				break;
4255
		}
4256
	}
4257

    
4258
	if (empty($parents))
4259
		$parents[0] = $realif;
4260

    
4261
	return $parents;
4262
}
4263

    
4264
function interface_is_wireless_clone($wlif) {
4265
	if(!stristr($wlif, "_wlan")) {
4266
		return false;
4267
	} else {
4268
		return true;
4269
	}
4270
}
4271

    
4272
function interface_get_wireless_base($wlif) {
4273
	if(!stristr($wlif, "_wlan")) {
4274
		return $wlif;
4275
	} else {
4276
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4277
	}
4278
}
4279

    
4280
function interface_get_wireless_clone($wlif) {
4281
	if(!stristr($wlif, "_wlan")) {
4282
		return $wlif . "_wlan0";
4283
	} else {
4284
		return $wlif;
4285
	}
4286
}
4287

    
4288
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4289
	global $config, $g;
4290

    
4291
	$wanif = NULL;
4292

    
4293
	switch ($interface) {
4294
	case "l2tp":
4295
		$wanif = "l2tp";
4296
		break;
4297
	case "pptp":
4298
		$wanif = "pptp";
4299
		break;
4300
	case "pppoe":
4301
		$wanif = "pppoe";
4302
		break;
4303
	case "openvpn":
4304
		$wanif = "openvpn";
4305
		break;
4306
	case "ipsec":
4307
	case "enc0":
4308
		$wanif = "enc0";
4309
		break;
4310
	case "ppp":
4311
		$wanif = "ppp";
4312
		break;
4313
	default:
4314
		// If a real interface was alread passed simply
4315
		// pass the real interface back.  This encourages
4316
		// the usage of this function in more cases so that
4317
		// we can combine logic for more flexibility.
4318
		if(does_interface_exist($interface, $flush)) {
4319
			$wanif = $interface;
4320
			break;
4321
		}
4322

    
4323
		if (empty($config['interfaces'][$interface]))
4324
			break;
4325

    
4326
		$cfg = &$config['interfaces'][$interface];
4327

    
4328
		if ($family == "inet6") {
4329
			switch ($cfg['ipaddrv6']) {
4330
			case "6rd":
4331
			case "6to4":
4332
				$wanif = "{$interface}_stf";
4333
				break;
4334
			case 'pppoe':
4335
			case 'ppp':
4336
			case 'l2tp':
4337
			case 'pptp':
4338
				if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4339
					$wanif = interface_get_wireless_clone($cfg['if']);
4340
				else
4341
					$wanif = $cfg['if'];
4342
				break;
4343
			default:
4344
				switch ($cfg['ipaddr']) {
4345
				case 'pppoe':
4346
				case 'ppp':
4347
				case 'l2tp':
4348
				case 'pptp':
4349
					if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false)
4350
						$wanif = $cfg['if'];
4351
					else {
4352
						$parents = get_parent_interface($interface);
4353
						if (!empty($parents[0]))
4354
							$wanif = $parents[0];
4355
						else
4356
							$wanif = $cfg['if'];
4357
					}
4358
					break;
4359
				default:
4360
					if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4361
						$wanif = interface_get_wireless_clone($cfg['if']);
4362
					else
4363
						$wanif = $cfg['if'];
4364
					break;
4365
				}
4366
				break;
4367
			}
4368
		} else {
4369
			// Wireless cloned NIC support (FreeBSD 8+)
4370
			// interface name format: $parentnic_wlanparentnic#
4371
			// example: ath0_wlan0
4372
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4373
				$wanif = interface_get_wireless_clone($cfg['if']);
4374
			else
4375
				$wanif = $cfg['if'];
4376
		}
4377
		break;
4378
	}
4379

    
4380
	return $wanif;
4381
}
4382

    
4383
/* Guess the physical interface by providing a IP address */
4384
function guess_interface_from_ip($ipaddress) {
4385
	if(! is_ipaddr($ipaddress)) {
4386
		return false;
4387
	}
4388
	if(is_ipaddrv4($ipaddress)) {
4389
		/* create a route table we can search */
4390
		exec("/usr/bin/netstat -rnWf inet", $output, $ret);
4391
		foreach($output as $line) {
4392
			if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
4393
				$fields = preg_split("/[ ]+/", $line);
4394
				if(ip_in_subnet($ipaddress, $fields[0])) {
4395
					return $fields[5];
4396
				}
4397
			}
4398
		}
4399
	}
4400
	/* FIXME: This works from cursory testing, regexp might need fine tuning */
4401
	if(is_ipaddrv6($ipaddress)) {
4402
		/* create a route table we can search */
4403
		exec("/usr/bin/netstat -rnWf inet6", $output, $ret);
4404
		foreach($output as $line) {
4405
			if(preg_match("/[0-9a-f]+[:]+[0-9a-f]+[:]+[\/][0-9]+/", $line)) {
4406
				$fields = preg_split("/[ ]+/", $line);
4407
				if(ip_in_subnet($ipaddress, $fields[0])) {
4408
					return $fields[5];
4409
				}
4410
			}
4411
		}
4412
	}
4413
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
4414
	if(empty($ret)) {
4415
		return false;
4416
	}
4417
	return $ret;
4418
}
4419

    
4420
/*
4421
 * find_ip_interface($ip): return the interface where an ip is defined
4422
 *   (or if $bits is specified, where an IP within the subnet is defined)
4423
 */
4424
function find_ip_interface($ip, $bits = null) {
4425
	if (!is_ipaddr($ip))
4426
		return false;
4427

    
4428
	$isv6ip = is_ipaddrv6($ip);
4429

    
4430
	/* if list */
4431
	$ifdescrs = get_configured_interface_list();
4432

    
4433
	foreach ($ifdescrs as $ifdescr => $ifname) {
4434
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4435
		if (is_null($ifip))
4436
			continue;
4437
		if (is_null($bits)) {
4438
			if ($ip == $ifip) {
4439
				$int = get_real_interface($ifname);
4440
				return $int;
4441
			}
4442
		}
4443
		else {
4444
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4445
				$int = get_real_interface($ifname);
4446
				return $int;
4447
			}
4448
		}
4449
	}
4450

    
4451
	return false;
4452
}
4453

    
4454
/*
4455
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4456
 *   (or if $bits is specified, where an IP within the subnet is found)
4457
 */
4458
function find_virtual_ip_alias($ip, $bits = null) {
4459
	global $config;
4460

    
4461
	if (!is_array($config['virtualip']['vip'])) {
4462
		return false;
4463
	}
4464
	if (!is_ipaddr($ip))
4465
		return false;
4466

    
4467
	$isv6ip = is_ipaddrv6($ip);
4468

    
4469
	foreach ($config['virtualip']['vip'] as $vip) {
4470
		if ($vip['mode'] === "ipalias") {
4471
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4472
				continue;
4473
			if (is_null($bits)) {
4474
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4475
					return $vip;
4476
				}
4477
			}
4478
			else {
4479
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4480
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4481
					return $vip;
4482
				}
4483
			}
4484
		}
4485
	}
4486
	return false;
4487
}
4488

    
4489
/*
4490
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4491
 */
4492
function find_number_of_created_carp_interfaces() {
4493
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4494
}
4495

    
4496
function get_all_carp_interfaces() {
4497
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
4498
	$ints = explode(" ", $ints);
4499
	return $ints;
4500
}
4501

    
4502
/*
4503
 * find_carp_interface($ip): return the carp interface where an ip is defined
4504
 */
4505
function find_carp_interface($ip) {
4506
	global $config;
4507
	if (is_array($config['virtualip']['vip'])) {
4508
		foreach ($config['virtualip']['vip'] as $vip) {
4509
			if ($vip['mode'] == "carp") {
4510
				if(is_ipaddrv4($ip)) {
4511
					$carp_ip = get_interface_ip($vip['interface']);
4512
				}
4513
				if(is_ipaddrv6($ip)) {
4514
					$carp_ip = get_interface_ipv6($vip['interface']);
4515
				}
4516
				exec("/sbin/ifconfig", $output, $return);
4517
				foreach($output as $line) {
4518
					$elements = preg_split("/[ ]+/i", $line);
4519
					if(strstr($elements[0], "vip"))
4520
						$curif = str_replace(":", "", $elements[0]);
4521
					if(stristr($line, $ip)) {
4522
						$if = $curif;
4523
						continue;
4524
					}
4525
				}
4526

    
4527
				if ($if)
4528
					return $if;
4529
			}
4530
		}
4531
	}
4532
}
4533

    
4534
function link_carp_interface_to_parent($interface) {
4535
	global $config;
4536

    
4537
	if (empty($interface))
4538
		return;
4539

    
4540
	$carp_ip = get_interface_ip($interface);
4541
	$carp_ipv6 = get_interface_ipv6($interface);
4542

    
4543
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4544
		return;
4545

    
4546
	/* if list */
4547
	$ifdescrs = get_configured_interface_list();
4548
	foreach ($ifdescrs as $ifdescr => $ifname) {
4549
		/* check IPv4 */
4550
		if(is_ipaddrv4($carp_ip)) {
4551
			$interfaceip = get_interface_ip($ifname);
4552
			$subnet_bits = get_interface_subnet($ifname);
4553
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4554
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4555
				return $ifname;
4556
		}
4557
		/* Check IPv6 */
4558
		if(is_ipaddrv6($carp_ipv6)) {
4559
			$interfaceipv6 = get_interface_ipv6($ifname);
4560
			$prefixlen = get_interface_subnetv6($ifname);
4561
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4562
				return $ifname;
4563
		}
4564
	}
4565
	return "";
4566
}
4567

    
4568

    
4569
/****f* interfaces/link_ip_to_carp_interface
4570
 * NAME
4571
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4572
 * INPUTS
4573
 *   $ip
4574
 * RESULT
4575
 *   $carp_ints
4576
 ******/
4577
function link_ip_to_carp_interface($ip) {
4578
	global $config;
4579

    
4580
	if (!is_ipaddr($ip))
4581
		return;
4582

    
4583
	$carp_ints = "";
4584
	if (is_array($config['virtualip']['vip'])) {
4585
		$first = 0;
4586
		$carp_int = array();
4587
		foreach ($config['virtualip']['vip'] as $vip) {
4588
			if ($vip['mode'] == "carp") {
4589
				$carp_ip = $vip['subnet'];
4590
				$carp_sn = $vip['subnet_bits'];
4591
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4592
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4593
					$carp_int[] = get_real_interface($vip['interface']);
4594
				}
4595
			}
4596
		}
4597
		if (!empty($carp_int))
4598
			$carp_ints = implode(" ", array_unique($carp_int));
4599
	}
4600

    
4601
	return $carp_ints;
4602
}
4603

    
4604
function link_interface_to_track6($int, $action = "") {
4605
	global $config;
4606

    
4607
	if (empty($int))
4608
		return;
4609

    
4610
	if (is_array($config['interfaces'])) {
4611
		$list = array();
4612
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4613
			if (!isset($ifcfg['enable']))
4614
				continue;
4615
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4616
				if ($action == "update")
4617
					interface_track6_configure($ifname, $ifcfg);
4618
				else if ($action == "")
4619
					$list[$ifname] = $ifcfg;
4620
			}
4621
		}
4622
		return $list;
4623
	}
4624
}
4625

    
4626
function link_interface_to_vlans($int, $action = "") {
4627
	global $config;
4628

    
4629
	if (empty($int))
4630
		return;
4631

    
4632
	if (is_array($config['vlans']['vlan'])) {
4633
		$ifaces = array();
4634
		foreach ($config['vlans']['vlan'] as $vlan) {
4635
			if ($int == $vlan['if']) {
4636
				if ($action == "update") {
4637
					interfaces_bring_up($int);
4638
				} else if ($action == "")
4639
					$ifaces[$vlan['tag']] = $vlan;
4640
			}
4641
		}
4642
		if (!empty($ifaces))
4643
			return $ifaces;
4644
	}
4645
}
4646

    
4647
function link_interface_to_vips($int, $action = "") {
4648
	global $config;
4649

    
4650
	if (is_array($config['virtualip']['vip'])) {
4651
		$result = array();
4652
		foreach ($config['virtualip']['vip'] as $vip) {
4653
			if ($int == $vip['interface']) {
4654
				if ($action == "update")
4655
					interfaces_vips_configure($int);
4656
				else
4657
					$result[] = $vip;
4658
			}
4659
		}
4660
		return $result;
4661
	}
4662
}
4663

    
4664
/****f* interfaces/link_interface_to_bridge
4665
 * NAME
4666
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4667
 * INPUTS
4668
 *   $ip
4669
 * RESULT
4670
 *   bridge[0-99]
4671
 ******/
4672
function link_interface_to_bridge($int) {
4673
	global $config;
4674

    
4675
	if (is_array($config['bridges']['bridged'])) {
4676
		foreach ($config['bridges']['bridged'] as $bridge) {
4677
			if (in_array($int, explode(',', $bridge['members'])))
4678
				return "{$bridge['bridgeif']}";
4679
		}
4680
	}
4681
}
4682

    
4683
function link_interface_to_group($int) {
4684
	global $config;
4685

    
4686
	$result = array();
4687

    
4688
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4689
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4690
			if (in_array($int, explode(" ", $group['members'])))
4691
				$result[$group['ifname']] = $int;
4692
		}
4693
	}
4694

    
4695
	return $result;
4696
}
4697

    
4698
function link_interface_to_gre($interface) {
4699
	global $config;
4700

    
4701
	$result = array();
4702

    
4703
	if (is_array($config['gres']['gre'])) {
4704
		foreach ($config['gres']['gre'] as $gre)
4705
			if($gre['if'] == $interface)
4706
				$result[] = $gre;
4707
	}
4708

    
4709
	return $result;
4710
}
4711

    
4712
function link_interface_to_gif($interface) {
4713
	global $config;
4714

    
4715
	$result = array();
4716

    
4717
	if (is_array($config['gifs']['gif'])) {
4718
		foreach ($config['gifs']['gif'] as $gif)
4719
			if($gif['if'] == $interface)
4720
				$result[] = $gif;
4721
	}
4722

    
4723
	return $result;
4724
}
4725

    
4726
/*
4727
 * find_interface_ip($interface): return the interface ip (first found)
4728
 */
4729
function find_interface_ip($interface, $flush = false) {
4730
	global $interface_ip_arr_cache;
4731
	global $interface_sn_arr_cache;
4732

    
4733
	$interface = str_replace("\n", "", $interface);
4734

    
4735
	if (!does_interface_exist($interface))
4736
		return;
4737

    
4738
	/* Setup IP cache */
4739
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4740
		$ifinfo = pfSense_get_interface_addresses($interface);
4741
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4742
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4743
	}
4744

    
4745
	return $interface_ip_arr_cache[$interface];
4746
}
4747

    
4748
/*
4749
 * find_interface_ipv6($interface): return the interface ip (first found)
4750
 */
4751
function find_interface_ipv6($interface, $flush = false) {
4752
	global $interface_ipv6_arr_cache;
4753
	global $interface_snv6_arr_cache;
4754
	global $config;
4755

    
4756
	$interface = trim($interface);
4757
	$interface = get_real_interface($interface);
4758

    
4759
	if (!does_interface_exist($interface))
4760
		return;
4761

    
4762
	/* Setup IP cache */
4763
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4764
		$ifinfo = pfSense_get_interface_addresses($interface);
4765
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4766
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4767
	}
4768

    
4769
	return $interface_ipv6_arr_cache[$interface];
4770
}
4771

    
4772
/*
4773
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4774
 */
4775
function find_interface_ipv6_ll($interface, $flush = false) {
4776
	global $interface_llv6_arr_cache;
4777
	global $config;
4778

    
4779
	$interface = str_replace("\n", "", $interface);
4780

    
4781
	if (!does_interface_exist($interface))
4782
		return;
4783

    
4784
	/* Setup IP cache */
4785
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4786
		$ifinfo = pfSense_getall_interface_addresses($interface);
4787
		foreach($ifinfo as $line) {
4788
			if (strstr($line, ":")) {
4789
				$parts = explode("/", $line);
4790
				if(is_linklocal($parts[0])) {
4791
					$ifinfo['linklocal'] = $parts[0];
4792
				}
4793
			}
4794
		}
4795
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4796
	}
4797
	return $interface_llv6_arr_cache[$interface];
4798
}
4799

    
4800
function find_interface_subnet($interface, $flush = false) {
4801
	global $interface_sn_arr_cache;
4802
	global $interface_ip_arr_cache;
4803

    
4804
	$interface = str_replace("\n", "", $interface);
4805
	if (does_interface_exist($interface) == false)
4806
		return;
4807

    
4808
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4809
		$ifinfo = pfSense_get_interface_addresses($interface);
4810
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4811
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4812
	}
4813

    
4814
	return $interface_sn_arr_cache[$interface];
4815
}
4816

    
4817
function find_interface_subnetv6($interface, $flush = false) {
4818
	global $interface_snv6_arr_cache;
4819
	global $interface_ipv6_arr_cache;
4820

    
4821
	$interface = str_replace("\n", "", $interface);
4822
	if (does_interface_exist($interface) == false)
4823
		return;
4824

    
4825
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4826
		$ifinfo = pfSense_get_interface_addresses($interface);
4827
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4828
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4829
	}
4830

    
4831
	return $interface_snv6_arr_cache[$interface];
4832
}
4833

    
4834
function ip_in_interface_alias_subnet($interface, $ipalias) {
4835
	global $config;
4836

    
4837
	if (empty($interface) || !is_ipaddr($ipalias))
4838
		return false;
4839
	if (is_array($config['virtualip']['vip'])) {
4840
		foreach ($config['virtualip']['vip'] as $vip) {
4841
			switch ($vip['mode']) {
4842
			case "ipalias":
4843
				if ($vip['interface'] <> $interface)
4844
					break;
4845
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4846
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4847
					return true;
4848
				break;
4849
			}
4850
		}
4851
	}
4852

    
4853
	return false;
4854
}
4855

    
4856
function get_interface_ip($interface = "wan") {
4857
	$realif = get_failover_interface($interface);
4858
	if (!$realif) {
4859
		if (strstr($interface, "_vip"))
4860
			return get_configured_carp_interface_list($interface);
4861
		else
4862
			return null;
4863
	}
4864

    
4865
	$curip = find_interface_ip($realif);
4866
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4867
		return $curip;
4868
	else
4869
		return null;
4870
}
4871

    
4872
function get_interface_ipv6($interface = "wan", $flush = false) {
4873
	global $config;
4874

    
4875
	$realif = get_failover_interface($interface, "inet6");
4876
	if (!$realif) {
4877
		if (strstr($interface, "_vip"))
4878
			return get_configured_carp_interface_list($interface, "inet6");
4879
		else
4880
			return null;
4881
	}
4882

    
4883
	/*
4884
	 * NOTE: On the case when only the prefix is requested,
4885
	 * the communication on WAN will be done over link-local.
4886
	 */
4887
	if (is_array($config['interfaces'][$interface])) {
4888
		switch ($config['interfaces'][$interface]['ipaddr']) {
4889
		case 'pppoe':
4890
		case 'l2tp':
4891
		case 'pptp':
4892
		case 'ppp':
4893
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4894
				$realif = get_real_interface($interface, "inet6", true);
4895
			break;
4896
		}
4897
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4898
			$curip = find_interface_ipv6_ll($realif, $flush);
4899
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4900
				return $curip;
4901
		}
4902
	}
4903

    
4904
	$curip = find_interface_ipv6($realif, $flush);
4905
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4906
		return $curip;
4907
	else
4908
		return null;
4909
}
4910

    
4911
function get_interface_linklocal($interface = "wan") {
4912

    
4913
	$realif = get_failover_interface($interface, "inet6");
4914
	if (!$realif) {
4915
		if (strstr($interface, "_vip")) {
4916
			list($interface, $vhid) = explode("_vip", $interface);
4917
			$realif = get_real_interface($interface);
4918
		} else
4919
			return null;
4920
	}
4921

    
4922
	$curip = find_interface_ipv6_ll($realif);
4923
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4924
		return $curip;
4925
	else
4926
		return null;
4927
}
4928

    
4929
function get_interface_subnet($interface = "wan") {
4930
	$realif = get_real_interface($interface);
4931
	if (!$realif) {
4932
		if (strstr($interface, "_vip")) {
4933
			list($interface, $vhid) = explode("_vip", $interface);
4934
			$realif = get_real_interface($interface);
4935
		} else
4936
			return null;
4937
	}
4938

    
4939
	$cursn = find_interface_subnet($realif);
4940
	if (!empty($cursn))
4941
		return $cursn;
4942

    
4943
	return null;
4944
}
4945

    
4946
function get_interface_subnetv6($interface = "wan") {
4947
	global $config;
4948

    
4949
	$realif = get_real_interface($interface, "inet6");
4950
	if (!$realif) {
4951
		if (strstr($interface, "_vip")) {
4952
			list($interface, $vhid) = explode("_vip", $interface);
4953
			$realif = get_real_interface($interface);
4954
		} else
4955
			return null;
4956
	}
4957

    
4958
	$cursn = find_interface_subnetv6($realif);
4959
	if (!empty($cursn))
4960
		return $cursn;
4961

    
4962
	return null;
4963
}
4964

    
4965
/* return outside interfaces with a gateway */
4966
function get_interfaces_with_gateway() {
4967
	global $config;
4968

    
4969
	$ints = array();
4970

    
4971
	/* loop interfaces, check config for outbound */
4972
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4973
		switch ($ifname['ipaddr']) {
4974
			case "dhcp":
4975
			case "ppp";
4976
			case "pppoe":
4977
			case "pptp":
4978
			case "l2tp":
4979
			case "ppp";
4980
				$ints[$ifdescr] = $ifdescr;
4981
			break;
4982
			default:
4983
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
4984
				    !empty($ifname['gateway']))
4985
					$ints[$ifdescr] = $ifdescr;
4986
			break;
4987
		}
4988
	}
4989
	return $ints;
4990
}
4991

    
4992
/* return true if interface has a gateway */
4993
function interface_has_gateway($friendly) {
4994
	global $config;
4995

    
4996
	if (!empty($config['interfaces'][$friendly])) {
4997
		$ifname = &$config['interfaces'][$friendly];
4998
		switch ($ifname['ipaddr']) {
4999
			case "dhcp":
5000
			case "pppoe":
5001
			case "pptp":
5002
			case "l2tp":
5003
			case "ppp";
5004
				return true;
5005
			break;
5006
			default:
5007
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
5008
					return true;
5009
				$tunnelif = substr($ifname['if'], 0, 3);
5010
				if ($tunnelif == "gif" || $tunnelif == "gre")
5011
					return true;
5012
				if (!empty($ifname['gateway']))
5013
					return true;
5014
			break;
5015
		}
5016
	}
5017

    
5018
	return false;
5019
}
5020

    
5021
/* return true if interface has a gateway */
5022
function interface_has_gatewayv6($friendly) {
5023
	global $config;
5024

    
5025
	if (!empty($config['interfaces'][$friendly])) {
5026
		$ifname = &$config['interfaces'][$friendly];
5027
		switch ($ifname['ipaddrv6']) {
5028
			case "slaac":
5029
			case "dhcp6":
5030
			case "6to4":
5031
			case "6rd":
5032
				return true;
5033
				break;
5034
			default:
5035
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
5036
					return true;
5037
				$tunnelif = substr($ifname['if'], 0, 3);
5038
				if ($tunnelif == "gif" || $tunnelif == "gre")
5039
					return true;
5040
				if (!empty($ifname['gatewayv6']))
5041
					return true;
5042
				break;
5043
		}
5044
	}
5045

    
5046
	return false;
5047
}
5048

    
5049
/****f* interfaces/is_altq_capable
5050
 * NAME
5051
 *   is_altq_capable - Test if interface is capable of using ALTQ
5052
 * INPUTS
5053
 *   $int            - string containing interface name
5054
 * RESULT
5055
 *   boolean         - true or false
5056
 ******/
5057

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

    
5071
	$int_family = remove_ifindex($int);
5072

    
5073
	if (in_array($int_family, $capable))
5074
		return true;
5075
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
5076
		return true;
5077
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
5078
		return true;
5079
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
5080
		return true;
5081
	else
5082
		return false;
5083
}
5084

    
5085
/****f* interfaces/is_interface_wireless
5086
 * NAME
5087
 *   is_interface_wireless - Returns if an interface is wireless
5088
 * RESULT
5089
 *   $tmp       - Returns if an interface is wireless
5090
 ******/
5091
function is_interface_wireless($interface) {
5092
	global $config, $g;
5093

    
5094
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5095
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
5096
		if (preg_match($g['wireless_regex'], $interface)) {
5097
			if (isset($config['interfaces'][$friendly]))
5098
				$config['interfaces'][$friendly]['wireless'] = array();
5099
			return true;
5100
		}
5101
		return false;
5102
	} else
5103
		return true;
5104
}
5105

    
5106
function get_wireless_modes($interface) {
5107
	/* return wireless modes and channels */
5108
	$wireless_modes = array();
5109

    
5110
	$cloned_interface = get_real_interface($interface);
5111

    
5112
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5113
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5114
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5115
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5116

    
5117
		$interface_channels = "";
5118
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5119
		$interface_channel_count = count($interface_channels);
5120

    
5121
		$c = 0;
5122
		while ($c < $interface_channel_count) {
5123
			$channel_line = explode(",", $interface_channels["$c"]);
5124
			$wireless_mode = trim($channel_line[0]);
5125
			$wireless_channel = trim($channel_line[1]);
5126
			if(trim($wireless_mode) != "") {
5127
				/* if we only have 11g also set 11b channels */
5128
				if($wireless_mode == "11g") {
5129
					if(!isset($wireless_modes["11b"]))
5130
						$wireless_modes["11b"] = array();
5131
				} else if($wireless_mode == "11g ht") {
5132
					if(!isset($wireless_modes["11b"]))
5133
						$wireless_modes["11b"] = array();
5134
					if(!isset($wireless_modes["11g"]))
5135
						$wireless_modes["11g"] = array();
5136
					$wireless_mode = "11ng";
5137
				} else if($wireless_mode == "11a ht") {
5138
					if(!isset($wireless_modes["11a"]))
5139
						$wireless_modes["11a"] = array();
5140
					$wireless_mode = "11na";
5141
				}
5142
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5143
			}
5144
			$c++;
5145
		}
5146
	}
5147
	return($wireless_modes);
5148
}
5149

    
5150
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5151
function get_wireless_channel_info($interface) {
5152
	$wireless_channels = array();
5153

    
5154
	$cloned_interface = get_real_interface($interface);
5155

    
5156
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5157
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5158
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5159
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5160

    
5161
		$interface_channels = "";
5162
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5163

    
5164
		foreach ($interface_channels as $channel_line) {
5165
			$channel_line = explode(",", $channel_line);
5166
			if(!isset($wireless_channels[$channel_line[0]]))
5167
				$wireless_channels[$channel_line[0]] = $channel_line;
5168
		}
5169
	}
5170
	return($wireless_channels);
5171
}
5172

    
5173
/****f* interfaces/get_interface_mtu
5174
 * NAME
5175
 *   get_interface_mtu - Return the mtu of an interface
5176
 * RESULT
5177
 *   $tmp       - Returns the mtu of an interface
5178
 ******/
5179
function get_interface_mtu($interface) {
5180
	$mtu = pfSense_get_interface_addresses($interface);
5181
	return $mtu['mtu'];
5182
}
5183

    
5184
function get_interface_mac($interface) {
5185

    
5186
	$macinfo = pfSense_get_interface_addresses($interface);
5187
	return $macinfo["macaddr"];
5188
}
5189

    
5190
/****f* pfsense-utils/generate_random_mac_address
5191
 * NAME
5192
 *   generate_random_mac - generates a random mac address
5193
 * INPUTS
5194
 *   none
5195
 * RESULT
5196
 *   $mac - a random mac address
5197
 ******/
5198
function generate_random_mac_address() {
5199
	$mac = "02";
5200
	for($x=0; $x<5; $x++)
5201
		$mac .= ":" . dechex(rand(16, 255));
5202
	return $mac;
5203
}
5204

    
5205
/****f* interfaces/is_jumbo_capable
5206
 * NAME
5207
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5208
 * INPUTS
5209
 *   $int             - string containing interface name
5210
 * RESULT
5211
 *   boolean          - true or false
5212
 ******/
5213
function is_jumbo_capable($iface) {
5214
	$iface = trim($iface);
5215
	$capable = pfSense_get_interface_addresses($iface);
5216

    
5217
	if (isset($capable['caps']['vlanmtu']))
5218
		return true;
5219

    
5220
	return false;
5221
}
5222

    
5223
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5224
	global $g;
5225

    
5226
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5227

    
5228
	if(!empty($iface) && !empty($pppif)){
5229
		$cron_cmd = <<<EOD
5230
#!/bin/sh
5231
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5232
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5233

    
5234
EOD;
5235

    
5236
		@file_put_contents($cron_file, $cron_cmd);
5237
		chmod($cron_file, 0755);
5238
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5239
	} else
5240
		unlink_if_exists($cron_file);
5241
}
5242

    
5243
function get_interface_default_mtu($type = "ethernet") {
5244
	switch ($type) {
5245
	case "gre":
5246
		return 1476;
5247
		break;
5248
	case "gif":
5249
		return 1280;
5250
		break;
5251
	case "tun":
5252
	case "vlan":
5253
	case "tap":
5254
	case "ethernet":
5255
	default:
5256
		return 1500;
5257
		break;
5258
	}
5259

    
5260
	/* Never reached */
5261
	return 1500;
5262
}
5263

    
5264
function get_vip_descr($ipaddress) {
5265
	global $config;
5266

    
5267
	foreach ($config['virtualip']['vip'] as $vip) {
5268
		if ($vip['subnet'] == $ipaddress) {
5269
			return ($vip['descr']);
5270
		}
5271
	}
5272
	return "";
5273
}
5274

    
5275
function interfaces_staticarp_configure($if) {
5276
	global $config, $g;
5277
	if(isset($config['system']['developerspew'])) {
5278
		$mt = microtime();
5279
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5280
	}
5281

    
5282
	$ifcfg = $config['interfaces'][$if];
5283

    
5284
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5285
		return 0;
5286

    
5287
	/* Enable staticarp, if enabled */
5288
	if(isset($config['dhcpd'][$if]['staticarp'])) {
5289
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
5290
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5291
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5292

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

    
5296
			}
5297

    
5298
		}
5299
	} else {
5300
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
5301
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5302
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5303
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5304
				if (isset($arpent['arp_table_static_entry'])) {
5305
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5306
				}
5307
			}
5308
		}
5309
	}
5310

    
5311
	return 0;
5312
}
5313

    
5314
function get_failover_interface($interface, $family = "all") {
5315
	global $config;
5316

    
5317
	/* shortcut to get_real_interface if we find it in the config */
5318
	if (is_array($config['interfaces'][$interface])) {
5319
		return get_real_interface($interface, $family);
5320
	}
5321

    
5322
	/* compare against gateway groups */
5323
	$a_groups = return_gateway_groups_array();
5324
	if (is_array($a_groups[$interface])) {
5325
		/* we found a gateway group, fetch the interface or vip */
5326
		if ($a_groups[$interface][0]['vip'] <> "")
5327
			return $a_groups[$interface][0]['vip'];
5328
		else
5329
			return $a_groups[$interface][0]['int'];
5330
	}
5331
	/* fall through to get_real_interface */
5332
	/* XXX: Really needed? */
5333
	return get_real_interface($interface, $family);
5334
}
5335

    
5336
function remove_ifindex($ifname) {
5337
	return preg_replace("/[0-9]+$/", "", $ifname);
5338
}
5339

    
5340
?>
(26-26/68)