Projet

Général

Profil

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

univnautes / etc / inc / interfaces.inc @ d9d1bd20

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
	/* fire up dhclient */
3913
	mwexec("/sbin/dhclient -c {$g['varetc_path']}/dhclient_{$interface}.conf {$wanif} > {$g['tmp_path']}/{$wanif}_output 2> {$g['tmp_path']}/{$wanif}_error_output");
3914

    
3915
	return 0;
3916
}
3917

    
3918
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3919

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

    
3925
	/* DHCP Protocol Timings */
3926
	$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");
3927
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
3928
		$pt_variable = "{$Protocol_Timing}";
3929
		${$pt_variable} = "";
3930
		if ($wancfg[$Protocol_Timing] != "") {
3931
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
3932
		}
3933
	}
3934

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

    
3943
	$request_options = "";
3944
	if ($wancfg['adv_dhcp_request_options'] != '') {
3945
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
3946
	}
3947

    
3948
	$required_options = "";
3949
	if ($wancfg['adv_dhcp_required_options'] != '') {
3950
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
3951
	}
3952

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

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

    
3981
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3982

    
3983
	return $dhclientconf;
3984
}
3985

    
3986

    
3987
function DHCP_Config_File_Override($wancfg, $wanif) {
3988

    
3989
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
3990
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3991

    
3992
	return $dhclientconf;
3993
}
3994

    
3995

    
3996
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
3997

    
3998
	/* Apply Interface Substitutions */
3999
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4000

    
4001
	/* Apply Hostname Substitutions */
4002
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4003

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

    
4010
	/* Apply MAC Address Substitutions */
4011
	foreach ($various_mac_types as $various_mac_type) {
4012
		foreach ($various_mac_cases as $various_mac_case) {
4013
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4014

    
4015
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4016
				if ($res !== false) {
4017

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

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

    
4034
					/* MAC Address Delimiter Substitutions */
4035
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4036

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

    
4044
	return $dhclientconf;
4045
}
4046

    
4047
function interfaces_group_setup() {
4048
	global $config;
4049

    
4050
	if (!is_array($config['ifgroups']['ifgroupentry']))
4051
		return;
4052

    
4053
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
4054
		interface_group_setup($groupar);
4055

    
4056
	return;
4057
}
4058

    
4059
function interface_group_setup(&$groupname /* The parameter is an array */) {
4060
	global $config;
4061

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

    
4071
	return;
4072
}
4073

    
4074
function is_interface_group($if) {
4075
	global $config;
4076

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

    
4083
	return false;
4084
}
4085

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

    
4091
/* COMPAT Function */
4092
function convert_friendly_interface_to_real_interface_name($interface) {
4093
	return get_real_interface($interface);
4094
}
4095

    
4096
/* COMPAT Function */
4097
function get_real_wan_interface($interface = "wan") {
4098
	return get_real_interface($interface);
4099
}
4100

    
4101
/* COMPAT Function */
4102
function get_current_wan_address($interface = "wan") {
4103
	return get_interface_ip($interface);
4104
}
4105

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

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

    
4116
	foreach ($ifdescrs as $if => $ifname) {
4117
		if ($if == $interface || $ifname['if'] == $interface)
4118
			return $if;
4119

    
4120
		if (get_real_interface($if) == $interface)
4121
			return $if;
4122

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

    
4132
	if ($interface == "enc0")
4133
		return 'IPsec';
4134

    
4135
	return NULL;
4136
}
4137

    
4138
/* attempt to resolve interface to friendly descr */
4139
function convert_friendly_interface_to_friendly_descr($interface) {
4140
	global $config;
4141

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

    
4187
	return $ifdesc;
4188
}
4189

    
4190
function convert_real_interface_to_friendly_descr($interface) {
4191

    
4192
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4193

    
4194
	if (!empty($ifdesc))
4195
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4196

    
4197
	return $interface;
4198
}
4199

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

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

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

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

    
4255
	if (empty($parents))
4256
		$parents[0] = $realif;
4257

    
4258
	return $parents;
4259
}
4260

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

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

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

    
4285
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4286
	global $config, $g;
4287

    
4288
	$wanif = NULL;
4289

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

    
4320
		if (empty($config['interfaces'][$interface]))
4321
			break;
4322

    
4323
		$cfg = &$config['interfaces'][$interface];
4324

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

    
4377
	return $wanif;
4378
}
4379

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

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

    
4425
	$isv6ip = is_ipaddrv6($ip);
4426

    
4427
	/* if list */
4428
	$ifdescrs = get_configured_interface_list();
4429

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

    
4448
	return false;
4449
}
4450

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

    
4458
	if (!is_array($config['virtualip']['vip'])) {
4459
		return false;
4460
	}
4461
	if (!is_ipaddr($ip))
4462
		return false;
4463

    
4464
	$isv6ip = is_ipaddrv6($ip);
4465

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

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

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

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

    
4524
				if ($if)
4525
					return $if;
4526
			}
4527
		}
4528
	}
4529
}
4530

    
4531
function link_carp_interface_to_parent($interface) {
4532
	global $config;
4533

    
4534
	if (empty($interface))
4535
		return;
4536

    
4537
	$carp_ip = get_interface_ip($interface);
4538
	$carp_ipv6 = get_interface_ipv6($interface);
4539

    
4540
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4541
		return;
4542

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

    
4565

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

    
4577
	if (!is_ipaddr($ip))
4578
		return;
4579

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

    
4598
	return $carp_ints;
4599
}
4600

    
4601
function link_interface_to_track6($int, $action = "") {
4602
	global $config;
4603

    
4604
	if (empty($int))
4605
		return;
4606

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

    
4623
function link_interface_to_vlans($int, $action = "") {
4624
	global $config;
4625

    
4626
	if (empty($int))
4627
		return;
4628

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

    
4644
function link_interface_to_vips($int, $action = "") {
4645
	global $config;
4646

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

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

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

    
4680
function link_interface_to_group($int) {
4681
	global $config;
4682

    
4683
	$result = array();
4684

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

    
4692
	return $result;
4693
}
4694

    
4695
function link_interface_to_gre($interface) {
4696
	global $config;
4697

    
4698
	$result = array();
4699

    
4700
	if (is_array($config['gres']['gre'])) {
4701
		foreach ($config['gres']['gre'] as $gre)
4702
			if($gre['if'] == $interface)
4703
				$result[] = $gre;
4704
	}
4705

    
4706
	return $result;
4707
}
4708

    
4709
function link_interface_to_gif($interface) {
4710
	global $config;
4711

    
4712
	$result = array();
4713

    
4714
	if (is_array($config['gifs']['gif'])) {
4715
		foreach ($config['gifs']['gif'] as $gif)
4716
			if($gif['if'] == $interface)
4717
				$result[] = $gif;
4718
	}
4719

    
4720
	return $result;
4721
}
4722

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

    
4730
	$interface = str_replace("\n", "", $interface);
4731

    
4732
	if (!does_interface_exist($interface))
4733
		return;
4734

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

    
4742
	return $interface_ip_arr_cache[$interface];
4743
}
4744

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

    
4753
	$interface = trim($interface);
4754
	$interface = get_real_interface($interface);
4755

    
4756
	if (!does_interface_exist($interface))
4757
		return;
4758

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

    
4766
	return $interface_ipv6_arr_cache[$interface];
4767
}
4768

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

    
4776
	$interface = str_replace("\n", "", $interface);
4777

    
4778
	if (!does_interface_exist($interface))
4779
		return;
4780

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

    
4797
function find_interface_subnet($interface, $flush = false) {
4798
	global $interface_sn_arr_cache;
4799
	global $interface_ip_arr_cache;
4800

    
4801
	$interface = str_replace("\n", "", $interface);
4802
	if (does_interface_exist($interface) == false)
4803
		return;
4804

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

    
4811
	return $interface_sn_arr_cache[$interface];
4812
}
4813

    
4814
function find_interface_subnetv6($interface, $flush = false) {
4815
	global $interface_snv6_arr_cache;
4816
	global $interface_ipv6_arr_cache;
4817

    
4818
	$interface = str_replace("\n", "", $interface);
4819
	if (does_interface_exist($interface) == false)
4820
		return;
4821

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

    
4828
	return $interface_snv6_arr_cache[$interface];
4829
}
4830

    
4831
function ip_in_interface_alias_subnet($interface, $ipalias) {
4832
	global $config;
4833

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

    
4850
	return false;
4851
}
4852

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

    
4862
	$curip = find_interface_ip($realif);
4863
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4864
		return $curip;
4865
	else
4866
		return null;
4867
}
4868

    
4869
function get_interface_ipv6($interface = "wan", $flush = false) {
4870
	global $config;
4871

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

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

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

    
4908
function get_interface_linklocal($interface = "wan") {
4909

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

    
4919
	$curip = find_interface_ipv6_ll($realif);
4920
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4921
		return $curip;
4922
	else
4923
		return null;
4924
}
4925

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

    
4936
	$cursn = find_interface_subnet($realif);
4937
	if (!empty($cursn))
4938
		return $cursn;
4939

    
4940
	return null;
4941
}
4942

    
4943
function get_interface_subnetv6($interface = "wan") {
4944
	global $config;
4945

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

    
4955
	$cursn = find_interface_subnetv6($realif);
4956
	if (!empty($cursn))
4957
		return $cursn;
4958

    
4959
	return null;
4960
}
4961

    
4962
/* return outside interfaces with a gateway */
4963
function get_interfaces_with_gateway() {
4964
	global $config;
4965

    
4966
	$ints = array();
4967

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

    
4989
/* return true if interface has a gateway */
4990
function interface_has_gateway($friendly) {
4991
	global $config;
4992

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

    
5015
	return false;
5016
}
5017

    
5018
/* return true if interface has a gateway */
5019
function interface_has_gatewayv6($friendly) {
5020
	global $config;
5021

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

    
5043
	return false;
5044
}
5045

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

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

    
5068
	$int_family = remove_ifindex($int);
5069

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

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

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

    
5103
function get_wireless_modes($interface) {
5104
	/* return wireless modes and channels */
5105
	$wireless_modes = array();
5106

    
5107
	$cloned_interface = get_real_interface($interface);
5108

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

    
5114
		$interface_channels = "";
5115
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5116
		$interface_channel_count = count($interface_channels);
5117

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

    
5147
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5148
function get_wireless_channel_info($interface) {
5149
	$wireless_channels = array();
5150

    
5151
	$cloned_interface = get_real_interface($interface);
5152

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

    
5158
		$interface_channels = "";
5159
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5160

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

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

    
5181
function get_interface_mac($interface) {
5182

    
5183
	$macinfo = pfSense_get_interface_addresses($interface);
5184
	return $macinfo["macaddr"];
5185
}
5186

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

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

    
5214
	if (isset($capable['caps']['vlanmtu']))
5215
		return true;
5216

    
5217
	return false;
5218
}
5219

    
5220
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5221
	global $g;
5222

    
5223
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5224

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

    
5231
EOD;
5232

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

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

    
5257
	/* Never reached */
5258
	return 1500;
5259
}
5260

    
5261
function get_vip_descr($ipaddress) {
5262
	global $config;
5263

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

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

    
5279
	$ifcfg = $config['interfaces'][$if];
5280

    
5281
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5282
		return 0;
5283

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

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

    
5293
			}
5294

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

    
5308
	return 0;
5309
}
5310

    
5311
function get_failover_interface($interface, $family = "all") {
5312
	global $config;
5313

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

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

    
5333
function remove_ifindex($ifname) {
5334
	return preg_replace("/[0-9]+$/", "", $ifname);
5335
}
5336

    
5337
?>
(26-26/68)