Project

General

Profile

Download (158 KB) Statistics
| Branch: | Tag: | Revision:
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($laggif);
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_gatewayv6($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($laggif);
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 */
1145
		services_dnsmasq_configure();
1146
	}
1147

    
1148
	return 0;
1149
}
1150

    
1151
function interface_reconfigure($interface = "wan", $reloadall = false) {
1152
	interface_bring_down($interface);
1153
	interface_configure($interface, $reloadall);
1154
}
1155

    
1156
function interface_vip_bring_down($vip) {
1157
	global $g;
1158

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

    
1181
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1182
	global $config, $g;
1183

    
1184
	if (!isset($config['interfaces'][$interface]))
1185
		return;
1186

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

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

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

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

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

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

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

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

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

    
1346
	return;
1347
}
1348

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

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

    
1357
	return false;
1358
}
1359

    
1360
function interfaces_ptpid_next() {
1361

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

    
1366
	return $ptpid;
1367
}
1368

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

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

    
1380
	return NULL;
1381
}
1382

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

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

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

    
1392
	$itemhash = getMPDCRONSettings($pppif);
1393

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

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

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

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

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

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

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

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

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

    
1542
				if(!is_ipaddr($localips[$pid])){
1543
					log_error("Could not get a Local IP address for PPTP/L2TP link on {$port} in interfaces_ppps_configure. Using 0.0.0.0 ip!");
1544
					$localips[$pid] = "0.0.0.0";
1545
				}
1546
				if(!is_ipaddr($gateways[$pid])){
1547
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $dhcp_gateway, $gway));
1548
					return 0;
1549
				}
1550
				pfSense_ngctl_attach(".", $port);
1551
				break;
1552
			case "ppp":
1553
				if (!file_exists("{$port}")) {
1554
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1555
					return 0;
1556
				}
1557
				break;
1558
			default:
1559
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1560
				break;
1561
		}
1562
	}
1563

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1652
EOD;
1653

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

    
1658
EOD;
1659

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

    
1667
EOD;
1668

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

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

    
1679
EOD;
1680

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

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

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

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

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

    
1707
EOD;
1708

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

    
1713
EOD;
1714

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

    
1719
EOD;
1720

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

    
1726
EOD;
1727

    
1728

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

    
1733
EOD;
1734

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

    
1740
EOD;
1741

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

    
1746
EOD;
1747

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

    
1752
EOD;
1753

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

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

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

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

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

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

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

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

    
1811
EOD;
1812

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

    
1818
EOD;
1819
		}
1820

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

    
1824

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

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

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

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

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

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

    
1900
	return 1;
1901
}
1902

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

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

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

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

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

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

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

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

    
1949
		sleep(1);
1950

    
1951
		/* XXX: Handle an issue with pfsync(4) and carp(4). In a cluster carp will come up before pfsync(4) has updated and so will cause issues
1952
		 * for existing sessions.
1953
		 */
1954
		log_error("waiting for pfsync...");
1955
		$i = 0;
1956
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1957
			$i++;
1958
			sleep(1);
1959
		}
1960
		log_error("pfsync done in $i seconds.");
1961
		log_error("Configuring CARP settings finalize...");
1962
	} else {
1963
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
1964
	}
1965

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2100
function interface_ipalias_configure(&$vip) {
2101
	if ($vip['mode'] == "ipalias") {
2102
		$if = get_real_interface($vip['interface']);
2103
		$af = "inet";
2104
		if(is_ipaddrv6($vip['subnet']))
2105
			$af = "inet6";
2106
		mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
2107
	}
2108
}
2109

    
2110
function interface_reload_carps($cif) {
2111
	global $config;
2112

    
2113
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2114
	if (empty($carpifs))
2115
		return;
2116

    
2117
	$carps = explode(" ", $carpifs);
2118
	if(is_array($config['virtualip']['vip'])) {
2119
		$viparr = &$config['virtualip']['vip'];
2120
		foreach ($viparr as $vip) {
2121
			if (in_array($vip['carpif'], $carps)) {
2122
				switch ($vip['mode']) {
2123
				case "carp":
2124
					interface_vip_bring_down($vip);
2125
					sleep(1);
2126
					interface_carp_configure($vip);
2127
					break;
2128
				case "ipalias":
2129
					interface_vip_bring_down($vip);
2130
					sleep(1);
2131
					interface_ipalias_configure($vip);
2132
					break;
2133
				}
2134
			}
2135
		}
2136
	}
2137
}
2138

    
2139
function interface_carp_configure(&$vip) {
2140
	global $config, $g;
2141
	if(isset($config['system']['developerspew'])) {
2142
		$mt = microtime();
2143
		echo "interface_carp_configure() being called $mt\n";
2144
	}
2145

    
2146
	if ($vip['mode'] != "carp")
2147
		return;
2148

    
2149
	/* NOTE: Maybe its useless nowdays */
2150
	$realif = get_real_interface($vip['interface']);
2151
	if (!does_interface_exist($realif)) {
2152
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2153
		return;
2154
	}
2155

    
2156
	if (is_ipaddrv4($vip['subnet'])) {
2157
		/* Ensure CARP IP really exists prior to loading up. */
2158
		$ww_subnet_ip = find_interface_ip($realif);
2159
		$ww_subnet_bits = find_interface_subnet($realif);
2160
		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'])) {
2161
			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", "");
2162
			return;
2163
		}
2164
	} else if (is_ipaddrv6($vip['subnet'])) {
2165
		/* Ensure CARP IP really exists prior to loading up. */
2166
		$ww_subnet_ip = find_interface_ipv6($realif);
2167
		$ww_subnet_bits = find_interface_subnetv6($realif);
2168
		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'])) {
2169
			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", "");
2170
			return;
2171
		}
2172
	}
2173

    
2174
	$vip_password = $vip['password'];
2175
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2176
	if ($vip['password'] != "")
2177
		$password = " pass {$vip_password}";
2178

    
2179
	$advbase = "";
2180
	if (!empty($vip['advbase']))
2181
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2182

    
2183
	if (is_ipaddrv4($vip['subnet']))
2184
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias");
2185
	else if (is_ipaddrv6($vip['subnet']))
2186
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']));
2187

    
2188
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) . " advskew " . escapeshellarg($vip['advskew']) . " {$advbase} {$password}");
2189

    
2190
	return $realif;
2191
}
2192

    
2193
function interface_wireless_clone($realif, $wlcfg) {
2194
	global $config, $g;
2195
	/*   Check to see if interface has been cloned as of yet.
2196
	 *   If it has not been cloned then go ahead and clone it.
2197
	 */
2198
	$needs_clone = false;
2199
	if(is_array($wlcfg['wireless']))
2200
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2201
	else
2202
		$wlcfg_mode = $wlcfg['mode'];
2203
	switch($wlcfg_mode) {
2204
	case "hostap":
2205
		$mode = "wlanmode hostap";
2206
		break;
2207
	case "adhoc":
2208
		$mode = "wlanmode adhoc";
2209
		break;
2210
	default:
2211
		$mode = "";
2212
		break;
2213
	}
2214
	$baseif = interface_get_wireless_base($wlcfg['if']);
2215
	if(does_interface_exist($realif)) {
2216
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2217
		$ifconfig_str = implode($output);
2218
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
2219
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2220
			$needs_clone = true;
2221
		}
2222
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
2223
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2224
			$needs_clone = true;
2225
		}
2226
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2227
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2228
			$needs_clone = true;
2229
		}
2230
	} else {
2231
		$needs_clone = true;
2232
	}
2233

    
2234
	if($needs_clone == true) {
2235
		/* remove previous instance if it exists */
2236
		if(does_interface_exist($realif))
2237
			pfSense_interface_destroy($realif);
2238

    
2239
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2240
		// Create the new wlan interface. FreeBSD returns the new interface name.
2241
		// example:  wlan2
2242
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2243
		if($ret <> 0) {
2244
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2245
			return false;
2246
		}
2247
		$newif = trim($out[0]);
2248
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2249
		pfSense_interface_rename($newif, $realif);
2250
		// FIXME: not sure what ngctl is for. Doesn't work.
2251
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
2252
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2253
	}
2254
	return true;
2255
}
2256

    
2257
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2258
	global $config, $g;
2259

    
2260
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2261
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2262
				 'regdomain', 'regcountry', 'reglocation');
2263

    
2264
	if(!is_interface_wireless($ifcfg['if']))
2265
		return;
2266

    
2267
	$baseif = interface_get_wireless_base($ifcfg['if']);
2268

    
2269
	// Sync shared settings for assigned clones
2270
	$iflist = get_configured_interface_list(false, true);
2271
	foreach ($iflist as $if) {
2272
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2273
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2274
				foreach ($shared_settings as $setting) {
2275
					if ($sync_changes) {
2276
						if (isset($ifcfg['wireless'][$setting]))
2277
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2278
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2279
							unset($config['interfaces'][$if]['wireless'][$setting]);
2280
					} else {
2281
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2282
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2283
						else if (isset($ifcfg['wireless'][$setting]))
2284
							unset($ifcfg['wireless'][$setting]);
2285
					}
2286
				}
2287
				if (!$sync_changes)
2288
					break;
2289
			}
2290
		}
2291
	}
2292

    
2293
	// Read or write settings at shared area
2294
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2295
		foreach ($shared_settings as $setting) {
2296
			if ($sync_changes) {
2297
				if (isset($ifcfg['wireless'][$setting]))
2298
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2299
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2300
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2301
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2302
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2303
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2304
				else if (isset($ifcfg['wireless'][$setting]))
2305
					unset($ifcfg['wireless'][$setting]);
2306
			}
2307
		}
2308
	}
2309

    
2310
	// Sync the mode on the clone creation page with the configured mode on the interface
2311
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2312
		foreach ($config['wireless']['clone'] as &$clone) {
2313
			if ($clone['cloneif'] == $ifcfg['if']) {
2314
				if ($sync_changes) {
2315
					$clone['mode'] = $ifcfg['wireless']['mode'];
2316
				} else {
2317
					$ifcfg['wireless']['mode'] = $clone['mode'];
2318
				}
2319
				break;
2320
			}
2321
		}
2322
		unset($clone);
2323
	}
2324
}
2325

    
2326
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2327
	global $config, $g;
2328

    
2329
	/*    open up a shell script that will be used to output the commands.
2330
	 *    since wireless is changing a lot, these series of commands are fragile
2331
	 *    and will sometimes need to be verified by a operator by executing the command
2332
	 *    and returning the output of the command to the developers for inspection.  please
2333
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2334
	 */
2335

    
2336
	// Remove script file
2337
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2338

    
2339
	// Clone wireless nic if needed.
2340
	interface_wireless_clone($if, $wl);
2341

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

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

    
2349
	/* set values for /path/program */
2350
	$hostapd = "/usr/sbin/hostapd";
2351
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2352
	$ifconfig = "/sbin/ifconfig";
2353
	$sysctl = "/sbin/sysctl";
2354
	$killall = "/usr/bin/killall";
2355

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

    
2358
	$wlcmd = array();
2359
	$wl_sysctl = array();
2360
	/* Make sure it's up */
2361
	$wlcmd[] = "up";
2362
	/* Set a/b/g standard */
2363
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2364
	$wlcmd[] = "mode " . escapeshellarg($standard);
2365

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

    
2371
	/* Set ssid */
2372
	if($wlcfg['ssid'])
2373
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2374

    
2375
	/* Set 802.11g protection mode */
2376
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2377

    
2378
	/* set wireless channel value */
2379
	if(isset($wlcfg['channel'])) {
2380
		if($wlcfg['channel'] == "0") {
2381
			$wlcmd[] = "channel any";
2382
		} else {
2383
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2384
		}
2385
	}
2386

    
2387
	/* Set antenna diversity value */
2388
	if(isset($wlcfg['diversity']))
2389
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2390

    
2391
	/* Set txantenna value */
2392
	if(isset($wlcfg['txantenna']))
2393
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2394

    
2395
	/* Set rxantenna value */
2396
	if(isset($wlcfg['rxantenna']))
2397
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2398

    
2399
	/* set Distance value */
2400
	if($wlcfg['distance'])
2401
		$distance = escapeshellarg($wlcfg['distance']);
2402

    
2403
	/* Set wireless hostap mode */
2404
	if ($wlcfg['mode'] == "hostap") {
2405
		$wlcmd[] = "mediaopt hostap";
2406
	} else {
2407
		$wlcmd[] = "-mediaopt hostap";
2408
	}
2409

    
2410
	/* Set wireless adhoc mode */
2411
	if ($wlcfg['mode'] == "adhoc") {
2412
		$wlcmd[] = "mediaopt adhoc";
2413
	} else {
2414
		$wlcmd[] = "-mediaopt adhoc";
2415
	}
2416

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

    
2419
	/* handle hide ssid option */
2420
	if(isset($wlcfg['hidessid']['enable'])) {
2421
		$wlcmd[] = "hidessid";
2422
	} else {
2423
		$wlcmd[] = "-hidessid";
2424
	}
2425

    
2426
	/* handle pureg (802.11g) only option */
2427
	if(isset($wlcfg['pureg']['enable'])) {
2428
		$wlcmd[] = "mode 11g pureg";
2429
	} else {
2430
		$wlcmd[] = "-pureg";
2431
	}
2432

    
2433
	/* handle puren (802.11n) only option */
2434
	if(isset($wlcfg['puren']['enable'])) {
2435
		$wlcmd[] = "puren";
2436
	} else {
2437
		$wlcmd[] = "-puren";
2438
	}
2439

    
2440
	/* enable apbridge option */
2441
	if(isset($wlcfg['apbridge']['enable'])) {
2442
		$wlcmd[] = "apbridge";
2443
	} else {
2444
		$wlcmd[] = "-apbridge";
2445
	}
2446

    
2447
	/* handle turbo option */
2448
	if(isset($wlcfg['turbo']['enable'])) {
2449
		$wlcmd[] = "mediaopt turbo";
2450
	} else {
2451
		$wlcmd[] = "-mediaopt turbo";
2452
	}
2453

    
2454
	/* handle txpower setting */
2455
	/* if($wlcfg['txpower'] <> "")
2456
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2457
	*/
2458
	/* handle wme option */
2459
	if(isset($wlcfg['wme']['enable'])) {
2460
		$wlcmd[] = "wme";
2461
	} else {
2462
		$wlcmd[] = "-wme";
2463
	}
2464

    
2465
	/* set up wep if enabled */
2466
	$wepset = "";
2467
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2468
		switch($wlcfg['wpa']['auth_algs']) {
2469
			case "1":
2470
				$wepset .= "authmode open wepmode on ";
2471
				break;
2472
			case "2":
2473
				$wepset .= "authmode shared wepmode on ";
2474
				break;
2475
			case "3":
2476
				$wepset .= "authmode mixed wepmode on ";
2477
		}
2478
		$i = 1;
2479
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2480
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2481
			if (isset($wepkey['txkey'])) {
2482
				$wlcmd[] = "weptxkey {$i} ";
2483
			}
2484
			$i++;
2485
		}
2486
		$wlcmd[] = $wepset;
2487
	} else {
2488
		$wlcmd[] = "authmode open wepmode off ";
2489
	}
2490

    
2491
	kill_hostapd($if);
2492
	mwexec(kill_wpasupplicant("{$if}"));
2493

    
2494
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2495
	conf_mount_rw();
2496

    
2497
	switch ($wlcfg['mode']) {
2498
	case 'bss':
2499
		if (isset($wlcfg['wpa']['enable'])) {
2500
			$wpa .= <<<EOD
2501
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2502
ctrl_interface_group=0
2503
ap_scan=1
2504
#fast_reauth=1
2505
network={
2506
ssid="{$wlcfg['ssid']}"
2507
scan_ssid=1
2508
priority=5
2509
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2510
psk="{$wlcfg['wpa']['passphrase']}"
2511
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2512
group={$wlcfg['wpa']['wpa_pairwise']}
2513
}
2514
EOD;
2515

    
2516
			@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2517
			unset($wpa);
2518
		}
2519
		break;
2520
	case 'hostap':
2521
		if (!empty($wlcfg['wpa']['passphrase']))
2522
			$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2523
		else
2524
			$wpa_passphrase = "";
2525
		if (isset($wlcfg['wpa']['enable'])) {
2526
			$wpa .= <<<EOD
2527
interface={$if}
2528
driver=bsd
2529
logger_syslog=-1
2530
logger_syslog_level=0
2531
logger_stdout=-1
2532
logger_stdout_level=0
2533
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2534
ctrl_interface={$g['varrun_path']}/hostapd
2535
ctrl_interface_group=wheel
2536
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2537
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2538
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2539
ssid={$wlcfg['ssid']}
2540
debug={$wlcfg['wpa']['debug_mode']}
2541
auth_algs={$wlcfg['wpa']['auth_algs']}
2542
wpa={$wlcfg['wpa']['wpa_mode']}
2543
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2544
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2545
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2546
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2547
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2548
{$wpa_passphrase}
2549

    
2550
EOD;
2551

    
2552
			if (isset($wlcfg['wpa']['rsn_preauth'])) {
2553
				$wpa .= <<<EOD
2554
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2555
rsn_preauth=1
2556
rsn_preauth_interfaces={$if}
2557

    
2558
EOD;
2559
			}
2560
			if (isset($wlcfg['wpa']['ieee8021x'])) {
2561
				$wpa .= "ieee8021x=1\n";
2562

    
2563
			if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2564
				$auth_server_port = "1812";
2565
				if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port']))
2566
					$auth_server_port = intval($wlcfg['auth_server_port']);
2567
				$wpa .= <<<EOD
2568

    
2569
auth_server_addr={$wlcfg['auth_server_addr']}
2570
auth_server_port={$auth_server_port}
2571
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2572

    
2573
EOD;
2574
				if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2575
					$auth_server_port2 = "1812";
2576
					if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2']))
2577
						$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2578

    
2579
					$wpa .= <<<EOD
2580
auth_server_addr={$wlcfg['auth_server_addr2']}
2581
auth_server_port={$auth_server_port2}
2582
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2583

    
2584
EOD;
2585
					}
2586
				}
2587
			}
2588

    
2589
			@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2590
			unset($wpa);
2591
		}
2592
		break;
2593
	}
2594

    
2595
	/*
2596
	 *    all variables are set, lets start up everything
2597
	 */
2598

    
2599
	$baseif = interface_get_wireless_base($if);
2600
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2601
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2602

    
2603
	/* set sysctls for the wireless interface */
2604
	if (!empty($wl_sysctl)) {
2605
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2606
		foreach ($wl_sysctl as $wl_sysctl_line) {
2607
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2608
		}
2609
	}
2610

    
2611
	/* set ack timers according to users preference (if he/she has any) */
2612
	if($distance) {
2613
		fwrite($fd_set, "# Enable ATH distance settings\n");
2614
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2615
	}
2616

    
2617
	if (isset($wlcfg['wpa']['enable'])) {
2618
		if ($wlcfg['mode'] == "bss") {
2619
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2620
		}
2621
		if ($wlcfg['mode'] == "hostap") {
2622
			/* add line to script to restore old mac to make hostapd happy */
2623
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2624
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2625
				if (is_macaddr($if_oldmac))
2626
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2627
						" link " . escapeshellarg($if_oldmac) . "\n");
2628
			}
2629

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

    
2632
			/* add line to script to restore spoofed mac after running hostapd */
2633
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2634
				if ($wl['spoofmac'])
2635
					$if_curmac = $wl['spoofmac'];
2636
				else
2637
					$if_curmac = get_interface_mac($if);
2638
				if (is_macaddr($if_curmac))
2639
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2640
						" link " . escapeshellarg($if_curmac) . "\n");
2641
			}
2642
		}
2643
	}
2644

    
2645
	fclose($fd_set);
2646
	conf_mount_ro();
2647

    
2648
	/* Making sure regulatory settings have actually changed
2649
	 * before applying, because changing them requires bringing
2650
	 * down all wireless networks on the interface. */
2651
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2652
	$ifconfig_str = implode($output);
2653
	unset($output);
2654
	$reg_changing = false;
2655

    
2656
	/* special case for the debug country code */
2657
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2658
		$reg_changing = true;
2659
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2660
		$reg_changing = true;
2661
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2662
		$reg_changing = true;
2663
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2664
		$reg_changing = true;
2665
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2666
		$reg_changing = true;
2667

    
2668
	if ($reg_changing) {
2669
		/* set regulatory domain */
2670
		if($wlcfg['regdomain'])
2671
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2672

    
2673
		/* set country */
2674
		if($wlcfg['regcountry'])
2675
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2676

    
2677
		/* set location */
2678
		if($wlcfg['reglocation'])
2679
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2680

    
2681
		$wlregcmd_args = implode(" ", $wlregcmd);
2682

    
2683
		/* build a complete list of the wireless clones for this interface */
2684
		$clone_list = array();
2685
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2686
			$clone_list[] = interface_get_wireless_clone($baseif);
2687
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2688
			foreach ($config['wireless']['clone'] as $clone) {
2689
				if ($clone['if'] == $baseif)
2690
					$clone_list[] = $clone['cloneif'];
2691
			}
2692
		}
2693

    
2694
		/* find which clones are up and bring them down */
2695
		$clones_up = array();
2696
		foreach ($clone_list as $clone_if) {
2697
			$clone_status = pfSense_get_interface_addresses($clone_if);
2698
			if ($clone_status['status'] == 'up') {
2699
				$clones_up[] = $clone_if;
2700
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2701
			}
2702
		}
2703

    
2704
		/* apply the regulatory settings */
2705
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2706

    
2707
		/* bring the clones back up that were previously up */
2708
		foreach ($clones_up as $clone_if) {
2709
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2710

    
2711
			/*
2712
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2713
			 * is in infrastructure mode, and WPA is enabled.
2714
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2715
			 */
2716
			if ($clone_if != $if) {
2717
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2718
				if ( !empty($friendly_if)
2719
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2720
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2721
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2722
				}
2723
			}
2724
		}
2725
	}
2726

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

    
2731
	/* configure wireless */
2732
	$wlcmd_args = implode(" ", $wlcmd);
2733
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2734
	unset($wlcmd_args, $wlcmd);
2735

    
2736

    
2737
	sleep(1);
2738
	/* execute hostapd and wpa_supplicant if required in shell */
2739
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2740

    
2741
	return 0;
2742

    
2743
}
2744

    
2745
function kill_hostapd($interface) {
2746
	global $g;
2747

    
2748
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2749
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2750
}
2751

    
2752
function kill_wpasupplicant($interface) {
2753
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2754
}
2755

    
2756
function find_dhclient_process($interface) {
2757
	if ($interface)
2758
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2759
	else
2760
		$pid = 0;
2761

    
2762
	return intval($pid);
2763
}
2764

    
2765
function find_dhcp6c_process($interface) {
2766
	global $g;
2767

    
2768
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid"))
2769
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2770
	else
2771
		return(false);
2772

    
2773
	return intval($pid);
2774
}
2775

    
2776
function interface_vlan_mtu_configured($realhwif, $mtu) {
2777
	global $config;
2778

    
2779
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
2780
		foreach ($config['vlans']['vlan'] as $vlan) {
2781
			if ($vlan['if'] != $realhwif)
2782
				continue;
2783
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2784
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
2785
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2786
					$mtu = $portmtu;
2787
			}
2788
		}
2789
	}
2790

    
2791
	return $mtu;
2792
}
2793

    
2794
function interface_virtual_create($interface) {
2795
	global $config;
2796

    
2797
	if (strstr($interface, "_vlan")) {
2798
		interfaces_vlan_configure($vlan);
2799
	} else if (substr($interface, 0, 3) == "gre") {
2800
		interfaces_gre_configure(0, $interface);
2801
	} else if (substr($interface, 0, 3) == "gif") {
2802
		interfaces_gif_configure(0, $interface);
2803
	} else if (substr($interface, 0, 5) == "ovpns") {
2804
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
2805
			foreach ($config['openvpn']['openvpn-server'] as $server) {
2806
				if ($interface == "ovpns{$server['vpnid']}") {
2807
					if (!function_exists('openvpn_resync'))
2808
						require_once('openvpn.inc');
2809
					log_error("OpenVPN: Resync server {$server['description']}");
2810
					openvpn_resync('server', $server);
2811
				}
2812
			}
2813
			unset($server);
2814
		}
2815
	} else if (substr($interface, 0, 5) == "ovpnc") {
2816
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
2817
			foreach ($config['openvpn']['openvpn-client'] as $client) {
2818
				if ($interface == "ovpnc{$client['vpnid']}") {
2819
					if (!function_exists('openvpn_resync'))
2820
						require_once('openvpn.inc');
2821
					log_error("OpenVPN: Resync server {$client['description']}");
2822
					openvpn_resync('client', $client);
2823
				}
2824
			}
2825
			unset($client);
2826
		}
2827
	} else if (substr($interface, 0, 4) == "lagg") {
2828
		interfaces_lagg_configure($interface);
2829
	} else if (substr($interface, 0, 6) == "bridge") {
2830
		interfaces_bridge_configure(0, $interface);
2831
	}
2832
}
2833

    
2834
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2835
	global $config;
2836

    
2837
	if (!is_array($vlanifs))
2838
		return;
2839

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

    
2861
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2862
	global $config, $g;
2863
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2864
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2865

    
2866
	$wancfg = $config['interfaces'][$interface];
2867

    
2868
	if (!isset($wancfg['enable']))
2869
		return;
2870

    
2871
	$realif = get_real_interface($interface);
2872
	$realhwif_array = get_parent_interface($interface);
2873
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2874
	$realhwif = $realhwif_array[0];
2875

    
2876
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2877
		/* remove all IPv4 and IPv6 addresses */
2878
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2879
		if (is_array($tmpifaces)) {
2880
			foreach ($tmpifaces as $tmpiface) {
2881
				if (strstr($tmpiface, ":"))
2882
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2883
				else
2884
					pfSense_interface_deladdress($realif, $tmpiface);
2885
			}
2886
		}
2887

    
2888
		/* only bring down the interface when both v4 and v6 are set to NONE */
2889
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6']))
2890
			interface_bring_down($interface);
2891
	}
2892

    
2893
	$interface_to_check = $realif;
2894
	switch ($wancfg['ipaddr']) {
2895
	case 'pppoe':
2896
	case 'l2tp':
2897
	case 'pptp':
2898
	case 'ppp':
2899
		$interface_to_check = $realhwif;
2900
		break;
2901
	}
2902

    
2903
	/* Need to check that the interface exists or not in the case where its coming back from disabled state see #3270 */
2904
	if (!does_interface_exist($interface_to_check))
2905
		interface_virtual_create($interface_to_check);
2906

    
2907
	/* Disable Accepting router advertisements unless specifically requested */
2908
	if ($g['debug'])
2909
		log_error("Deny router advertisements for interface {$interface}");
2910
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2911

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

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

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

    
2940
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2941
			/*   this is not a valid mac address.  generate a
2942
			 *   temporary mac address so the machine can get online.
2943
			 */
2944
			echo gettext("Generating new MAC address.");
2945
			$random_mac = generate_random_mac_address();
2946
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2947
				" link " . escapeshellarg($random_mac));
2948
			$wancfg['spoofmac'] = $random_mac;
2949
			write_config();
2950
			file_notice("MAC Address altered", sprintf(gettext('The INVALID MAC address (ff:ff:ff:ff:ff:ff) on interface %1$s has been automatically replaced with %2$s'), $realif, $random_mac), "Interfaces");
2951
		}
2952
	}
2953

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

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

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

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

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

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

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

    
3008
	$tunnelif = substr($realif, 0, 3);
3009
	switch ($wancfg['ipaddr']) {
3010
	case 'dhcp':
3011
		interface_dhcp_configure($interface);
3012
		break;
3013
	case 'pppoe':
3014
	case 'l2tp':
3015
	case 'pptp':
3016
	case 'ppp':
3017
		interface_ppps_configure($interface);
3018
		break;
3019
	default:
3020
		/* XXX: Kludge for now related to #3280 */
3021
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3022
			if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "")
3023
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3024
		}
3025
		break;
3026
	}
3027

    
3028
	switch ($wancfg['ipaddrv6']) {
3029
	case 'slaac':
3030
	case 'dhcp6':
3031
		interface_dhcpv6_configure($interface, $wancfg);
3032
		break;
3033
	case '6rd':
3034
		interface_6rd_configure($interface, $wancfg);
3035
		break;
3036
	case '6to4':
3037
		interface_6to4_configure($interface, $wancfg);
3038
		break;
3039
	case 'track6':
3040
		interface_track6_configure($interface, $wancfg);
3041
		break;
3042
	default:
3043
		/* XXX: Kludge for now related to #3280 */
3044
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3045
			if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3046
				//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3047
				// FIXME: Add IPv6 Support to the pfSense module
3048
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3049
			}
3050
		}
3051
		break;
3052
	}
3053

    
3054
	if (!empty($wancfg['mtu'])) {
3055
		if (stristr($realif, "_vlan")) {
3056
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3057
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
3058
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3059
			else
3060
				$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
3061

    
3062
			if ($wancfg['mtu'] > $parentmtu) {
3063
				if (get_interface_mtu($realhwif) != $wancfg['mtu'])
3064
					pfSense_interface_mtu($realhwif, $wancfg['mtu']);
3065

    
3066
				/* All vlans need to use the same mtu value as their parent. */
3067
				interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $wancfg['mtu']);
3068
			} else
3069
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3070
		} else {
3071
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3072
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3073

    
3074
			/* This case is needed when the parent of vlans is being configured */
3075
			interface_vlan_adapt_mtu(link_interface_to_vlans($realif), $wancfg['mtu']);
3076
		}
3077
		/* XXX: What about gre/gif/lagg/.. ? */
3078
	}
3079

    
3080
	if (does_interface_exist($wancfg['if']))
3081
		interfaces_bring_up($wancfg['if']);
3082

    
3083
	interface_netgraph_needed($interface);
3084

    
3085
	if (!$g['booting']) {
3086
		link_interface_to_vips($interface, "update");
3087

    
3088
		unset($gre);
3089
		$gre = link_interface_to_gre($interface);
3090
		if (!empty($gre))
3091
			array_walk($gre, 'interface_gre_configure');
3092

    
3093
		unset($gif);
3094
		$gif = link_interface_to_gif($interface);
3095
		if (!empty($gif))
3096
			array_walk($gif, 'interface_gif_configure');
3097

    
3098
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3099
			unset($bridgetmp);
3100
			$bridgetmp = link_interface_to_bridge($interface);
3101
			if (!empty($bridgetmp))
3102
				interface_bridge_add_member($bridgetmp, $realif);
3103
		}
3104

    
3105
		$grouptmp = link_interface_to_group($interface);
3106
		if (!empty($grouptmp))
3107
			array_walk($grouptmp, 'interface_group_add_member');
3108

    
3109
		if ($interface == "lan")
3110
			/* make new hosts file */
3111
			system_hosts_generate();
3112

    
3113
		if ($reloadall == true) {
3114

    
3115
			/* reconfigure static routes (kernel may have deleted them) */
3116
			system_routing_configure($interface);
3117

    
3118
			/* reload ipsec tunnels */
3119
			vpn_ipsec_configure();
3120

    
3121
			/* restart dnsmasq */
3122
			services_dnsmasq_configure();
3123

    
3124
			/* update dyndns */
3125
			send_event("service reload dyndns {$interface}");
3126

    
3127
			/* XXX: which CPZONE? Needed? */
3128
			/* reload captive portal */
3129
			captiveportal_init_rules();
3130
		}
3131
	}
3132

    
3133
	interfaces_staticarp_configure($interface);
3134
	return 0;
3135
}
3136

    
3137
function interface_track6_configure($interface = "lan", $wancfg) {
3138
	global $config, $g;
3139

    
3140
	if (!is_array($wancfg))
3141
		return;
3142

    
3143
	if (!isset($wancfg['enable']))
3144
		return;
3145

    
3146
	/* If the interface is not configured via another, exit */
3147
	if (empty($wancfg['track6-interface']))
3148
		return;
3149

    
3150
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3151
	$realif = get_real_interface($interface);
3152
	$linklocal = find_interface_ipv6_ll($realif);
3153
	if (!empty($linklocal))
3154
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3155
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3156
	/* XXX: Probably should remove? */
3157
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3158

    
3159
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3160
	if (!isset($trackcfg['enable'])) {
3161
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3162
		return;
3163
	}
3164

    
3165
	switch($trackcfg['ipaddrv6']) {
3166
	case "6to4":
3167
		if ($g['debug'])
3168
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3169
		interface_track6_6to4_configure($interface, $wancfg);
3170
		break;
3171
	case "6rd":
3172
		if ($g['debug'])
3173
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3174
		interface_track6_6rd_configure($interface, $wancfg);
3175
		break;
3176
	}
3177

    
3178
	if (!$g['booting']) {
3179
		if (!function_exists('services_dhcpd_configure'))
3180
			require_once("services.inc");
3181

    
3182
		services_dhcpd_configure("inet6");
3183
	}
3184

    
3185
	return 0;
3186
}
3187

    
3188
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3189
	global $config, $g;
3190
	global $interface_ipv6_arr_cache;
3191
	global $interface_snv6_arr_cache;
3192

    
3193
	if (!is_array($lancfg))
3194
		return;
3195

    
3196
	/* If the interface is not configured via another, exit */
3197
	if (empty($lancfg['track6-interface']))
3198
		return;
3199

    
3200
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3201
	if (empty($wancfg)) {
3202
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3203
		return;
3204
	}
3205

    
3206
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3207
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3208
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3209
		return;
3210
	}
3211
	$hexwanv4 = return_hex_ipv4($ip4address);
3212

    
3213
	/* create the long prefix notation for math, save the prefix length */
3214
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3215
	$rd6prefixlen = $rd6prefix[1];
3216
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3217

    
3218
	/* binary presentation of the prefix for all 128 bits. */
3219
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3220

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

    
3226
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3227
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3228
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3229
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3230
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3231
	/* fill the rest out with zeros */
3232
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);;
3233

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

    
3237
	$lanif = get_real_interface($interface);
3238
	$oip = find_interface_ipv6($lanif);
3239
	if (is_ipaddrv6($oip))
3240
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3241
	unset($interface_ipv6_arr_cache[$lanif]);
3242
	unset($interface_snv6_arr_cache[$lanif]);
3243
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3244
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3245

    
3246
	return 0;
3247
}
3248

    
3249
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3250
	global $config, $g;
3251
	global $interface_ipv6_arr_cache;
3252
	global $interface_snv6_arr_cache;
3253

    
3254
	if (!is_array($lancfg))
3255
		return;
3256

    
3257
	/* If the interface is not configured via another, exit */
3258
	if (empty($lancfg['track6-interface']))
3259
		return;
3260

    
3261
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3262
	if (empty($wancfg)) {
3263
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3264
		return;
3265
	}
3266

    
3267
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3268
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3269
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3270
		return;
3271
	}
3272
	$hexwanv4 = return_hex_ipv4($ip4address);
3273

    
3274
	/* create the long prefix notation for math, save the prefix length */
3275
	$sixto4prefix = "2002::";
3276
	$sixto4prefixlen = 16;
3277
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3278

    
3279
	/* binary presentation of the prefix for all 128 bits. */
3280
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3281

    
3282
	/* just save the left prefix length bits */
3283
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3284
	/* add the v4 address */
3285
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3286
	/* add the custom prefix id */
3287
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3288
	/* fill the rest out with zeros */
3289
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);;
3290

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

    
3294
	$lanif = get_real_interface($interface);
3295
	$oip = find_interface_ipv6($lanif);
3296
	if (is_ipaddrv6($oip))
3297
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3298
	unset($interface_ipv6_arr_cache[$lanif]);
3299
	unset($interface_snv6_arr_cache[$lanif]);
3300
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3301
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3302

    
3303
	return 0;
3304
}
3305

    
3306
function interface_6rd_configure($interface = "wan", $wancfg) {
3307
	global $config, $g;
3308

    
3309
	/* because this is a tunnel interface we can only function
3310
	 *	with a public IPv4 address on the interface */
3311

    
3312
	if (!is_array($wancfg))
3313
		return;
3314

    
3315
	$wanif = get_real_interface($interface);
3316
	$ip4address = find_interface_ip($wanif);
3317
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3318
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3319
		return false;
3320
	}
3321
	$hexwanv4 = return_hex_ipv4($ip4address);
3322

    
3323
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3324
		$wancfg['prefix-6rd-v4plen'] = 0;
3325

    
3326
	/* create the long prefix notation for math, save the prefix length */
3327
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3328
	$rd6prefixlen = $rd6prefix[1];
3329
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3330

    
3331
	/* binary presentation of the prefix for all 128 bits. */
3332
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3333

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

    
3341
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3342
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3343

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

    
3346
	/* XXX: need to extend to support variable prefix size for v4 */
3347
	if (!is_module_loaded("if_stf"))
3348
		mwexec("/sbin/kldload if_stf.ko");
3349
	$stfiface = "{$interface}_stf";
3350
	if (does_interface_exist($stfiface))
3351
		pfSense_interface_destroy($stfiface);
3352
	$tmpstfiface = pfSense_interface_create("stf");
3353
	pfSense_interface_rename($tmpstfiface, $stfiface);
3354
	pfSense_interface_flags($stfiface, IFF_LINK2);
3355
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3356
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3357
	if ($wancfg['prefix-6rd-v4plen'] > 0 && $wancfg['prefix-6rd-v4plen'] < 32)
3358
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/{$wancfg['prefix-6rd-v4plen']}");
3359
	if ($g['debug'])
3360
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3361

    
3362
	/* write out a default router file */
3363
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3364
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3365

    
3366
	$ip4gateway = get_interface_gateway($interface);
3367
	if (is_ipaddrv4($ip4gateway))
3368
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3369

    
3370
	/* configure dependent interfaces */
3371
	if (!$g['booting'])
3372
		link_interface_to_track6($interface, "update");
3373

    
3374
	return 0;
3375
}
3376

    
3377
function interface_6to4_configure($interface = "wan", $wancfg){
3378
	global $config, $g;
3379

    
3380
	/* because this is a tunnel interface we can only function
3381
	 *	with a public IPv4 address on the interface */
3382

    
3383
	if (!is_array($wancfg))
3384
		return;
3385

    
3386
	$wanif = get_real_interface($interface);
3387
	$ip4address = find_interface_ip($wanif);
3388
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3389
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3390
		return false;
3391
	}
3392

    
3393
	/* create the long prefix notation for math, save the prefix length */
3394
	$stfprefixlen = 16;
3395
	$stfprefix = Net_IPv6::uncompress("2002::");
3396
	$stfarr = explode(":", $stfprefix);
3397
	$v4prefixlen = "0";
3398

    
3399
	/* we need the hex form of the interface IPv4 address */
3400
	$ip4arr = explode(".", $ip4address);
3401
	$hexwanv4 = "";
3402
	foreach($ip4arr as $octet)
3403
		$hexwanv4 .= sprintf("%02x", $octet);
3404

    
3405
	/* we need the hex form of the broker IPv4 address */
3406
	$ip4arr = explode(".", "192.88.99.1");
3407
	$hexbrv4 = "";
3408
	foreach($ip4arr as $octet)
3409
		$hexbrv4 .= sprintf("%02x", $octet);
3410

    
3411
	/* binary presentation of the prefix for all 128 bits. */
3412
	$stfprefixbin = "";
3413
	foreach($stfarr as $element) {
3414
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3415
	}
3416
	/* just save the left prefix length bits */
3417
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3418

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

    
3423
	/* for the local subnet too. */
3424
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3425
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);;
3426

    
3427
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3428
	$stfbrarr = array();
3429
	$stfbrbinarr = array();
3430
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3431
	foreach($stfbrbinarr as $bin)
3432
		$stfbrarr[] = dechex(bindec($bin));
3433
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3434

    
3435
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3436
	$stflanarr = array();
3437
	$stflanbinarr = array();
3438
	$stflanbinarr = str_split($stflanbin, 16);
3439
	foreach($stflanbinarr as $bin)
3440
		$stflanarr[] = dechex(bindec($bin));
3441
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3442
	$stflanarr[7] = 1;
3443
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3444

    
3445
	/* setup the stf interface */
3446
	if (!is_module_loaded("if_stf"))
3447
		mwexec("/sbin/kldload if_stf.ko");
3448
	$stfiface = "{$interface}_stf";
3449
	if (does_interface_exist($stfiface))
3450
		pfSense_interface_destroy($stfiface);
3451
	$tmpstfiface = pfSense_interface_create("stf");
3452
	pfSense_interface_rename($tmpstfiface, $stfiface);
3453
	pfSense_interface_flags($stfiface, IFF_LINK2);
3454
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3455

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

    
3459
	/* write out a default router file */
3460
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3461
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3462

    
3463
	$ip4gateway = get_interface_gateway($interface);
3464
	if (is_ipaddrv4($ip4gateway))
3465
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3466

    
3467
	if (!$g['booting'])
3468
		link_interface_to_track6($interface, "update");
3469

    
3470
	return 0;
3471
}
3472

    
3473
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3474
	global $config, $g;
3475

    
3476
	if (!is_array($wancfg))
3477
		return;
3478

    
3479
	$wanif = get_real_interface($interface, "inet6");
3480
	$dhcp6cconf = "";
3481
	$dhcp6cconf .= "interface {$wanif} {\n";
3482

    
3483
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3484
	if($wancfg['ipaddrv6'] == "slaac") {
3485
		$dhcp6cconf .= "	information-only;\n";
3486
		$dhcp6cconf .= "	request domain-name-servers;\n";
3487
		$dhcp6cconf .= "	request domain-name;\n";
3488
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3489
		$dhcp6cconf .= "};\n";
3490
	} else {
3491
		/* skip address request if this is set */
3492
		if(!isset($wancfg['dhcp6prefixonly']))
3493
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3494
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3495
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3496

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

    
3501
		$dhcp6cconf .= "};\n";
3502

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

    
3506
		if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3507
			/* Setup the prefix delegation */
3508
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3509
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3510
			if (isset($wancfg['dhcp6-ia-pd-send-hint']))
3511
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3512
			$iflist = link_interface_to_track6($interface);
3513
			foreach ($iflist as $friendly => $ifcfg) {
3514
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3515
					if ($g['debug'])
3516
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3517
					$realif = get_real_interface($friendly);
3518
					$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3519
					$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3520
					$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3521
					$dhcp6cconf .= "	};\n";
3522
				}
3523
			}
3524
			unset($preflen, $iflist, $ifcfg);
3525
			$dhcp6cconf .= "};\n";
3526
		}
3527
	}
3528

    
3529
	// DHCP6 Config File Advanced
3530
	if ($wancfg['adv_dhcp6_config_advanced']) { $dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif); }
3531

    
3532
	// DHCP6 Config File Override
3533
	if ($wancfg['adv_dhcp6_config_file_override']) { $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif); }
3534

    
3535
	/* wide-dhcp6c works for now. */
3536
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3537
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3538
		unset($dhcp6cconf);
3539
		return 1;
3540
	}
3541
	unset($dhcp6cconf);
3542

    
3543
	$dhcp6cscript = "#!/bin/sh\n";
3544
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3545
	$dhcp6cscript .= "\$dmips = \${new_domain_name_servers}\n";
3546
	$dhcp6cscript .= "\$dmnames = \${new_domain_name}\n";
3547
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\$dmnames&dmips=\$dmips\"\n";
3548
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3549
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3550
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3551
		unset($dhcp6cscript);
3552
		return 1;
3553
	}
3554
	unset($dhcp6cscript);
3555
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3556

    
3557
	$rtsoldscript = "#!/bin/sh\n";
3558
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3559
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3560
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3561
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3562
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3563
	$rtsoldscript .= "\t/bin/sleep 1\n";
3564
	$rtsoldscript .= "fi\n";
3565
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3566
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3567
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3568
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3569
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3570
		unset($rtsoldscript);
3571
		return 1;
3572
	}
3573
	unset($rtsoldscript);
3574
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3575

    
3576
	/* accept router advertisements for this interface */
3577
	mwexec("/sbin/sysctl -w net.inet6.ip6.accept_rtadv=1");
3578
	log_error("Accept router advertisements on interface {$wanif} ");
3579
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3580

    
3581
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3582
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3583
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3584
		sleep(2);
3585
	}
3586
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3587

    
3588
	/* NOTE: will be called from rtsold invoked script
3589
	 * link_interface_to_track6($interface, "update");
3590
	 */
3591

    
3592
	return 0;
3593
}
3594

    
3595
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3596
	global $g;
3597

    
3598
	$send_options = "";
3599
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3600
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_send_options']);
3601
		foreach ($options as $option) {
3602
			$send_options .= "\tsend " . trim($option) . ";\n";
3603
		}
3604
	}
3605

    
3606
	$request_options = "";
3607
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3608
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_request_options']);
3609
		foreach ($options as $option) {
3610
			$request_options .= "\trequest " . trim($option) . ";\n";
3611
		}
3612
	}
3613

    
3614
	$information_only = "";
3615
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') 
3616
		$information_only = "\tinformation-only;\n";
3617

    
3618
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3619
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '')
3620
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3621

    
3622
	$interface_statement  = "interface";
3623
	$interface_statement .= " {$wanif}";
3624
	$interface_statement .= " {\n";
3625
	$interface_statement .= "$send_options";
3626
	$interface_statement .= "$request_options";
3627
	$interface_statement .= "$information_only";
3628
	$interface_statement .= "$script";
3629
	$interface_statement .= "};\n";
3630

    
3631
	$id_assoc_statement_address = "";
3632
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3633
		$id_assoc_statement_address .= "id-assoc";
3634
		$id_assoc_statement_address .= " na";
3635
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) 
3636
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3637
		$id_assoc_statement_address .= " { ";
3638

    
3639
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') && 
3640
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) || 
3641
			 ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity')) ) {
3642
			$id_assoc_statement_address .= "\n\taddress";
3643
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3644
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3645
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) || 
3646
							($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity') ) 
3647
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3648
			$id_assoc_statement_address .= ";\n";
3649
		}
3650

    
3651
		$id_assoc_statement_address  .= "};\n";
3652
	}
3653

    
3654
	$id_assoc_statement_prefix = "";
3655
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3656
		$id_assoc_statement_prefix .= "id-assoc";
3657
		$id_assoc_statement_prefix .= " pd";
3658
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) 
3659
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3660
		$id_assoc_statement_prefix .= " { ";
3661

    
3662
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') && 
3663
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) || 
3664
			 ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity')) ) {
3665
			$id_assoc_statement_prefix .= "\n\tprefix";
3666
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3667
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3668
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) || 
3669
						  ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity') ) 
3670
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3671
			$id_assoc_statement_prefix .= ";";
3672
		}
3673

    
3674
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3675
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3676
			$id_assoc_statement_prefix .= " {$wanif}";
3677
			$id_assoc_statement_prefix .= " {\n";
3678
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3679
			if ( ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) && 
3680
				 ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128) ) 
3681
				 $id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3682
			$id_assoc_statement_prefix .= "\t};";
3683
		}
3684

    
3685
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') || 
3686
			 (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) ) { 
3687
			$id_assoc_statement_prefix .= "\n";
3688
		}
3689

    
3690
		$id_assoc_statement_prefix  .= "};\n";
3691
	}
3692

    
3693
	$authentication_statement = "";
3694
	if ( ($wancfg['adv_dhcp6_authentication_statement_authname'] != '') && 
3695
		 ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed') ) {
3696
		$authentication_statement .= "authentication";
3697
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
3698
		$authentication_statement .= " {\n";
3699
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
3700
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) 
3701
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
3702
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') 
3703
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
3704
		$authentication_statement .= "};\n";
3705
	}
3706

    
3707
	$key_info_statement = "";
3708
	if ( ($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') && 
3709
		 ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') && 
3710
		 (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) && 
3711
		 ($wancfg['adv_dhcp6_key_info_statement_secret'] != '') ) {
3712
		$key_info_statement .= "keyinfo";
3713
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
3714
		$key_info_statement .= " {\n";
3715
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
3716
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
3717
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
3718
		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'])) 
3719
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
3720
		$key_info_statement .= "};\n";
3721
	}
3722

    
3723
	$dhcp6cconf  = $interface_statement;
3724
	$dhcp6cconf .= $id_assoc_statement_address;
3725
	$dhcp6cconf .= $id_assoc_statement_prefix;
3726
	$dhcp6cconf .= $authentication_statement;
3727
	$dhcp6cconf .= $key_info_statement;
3728

    
3729
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3730

    
3731
	return $dhcp6cconf;
3732
}
3733

    
3734

    
3735
function DHCP6_Config_File_Override($wancfg, $wanif) {
3736

    
3737
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
3738
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3739

    
3740
	return $dhcp6cconf;
3741
}
3742

    
3743

    
3744
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
3745

    
3746
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3747

    
3748
	return $dhcp6cconf;
3749
}
3750

    
3751

    
3752
function interface_dhcp_configure($interface = "wan") {
3753
	global $config, $g;
3754

    
3755
	$wancfg = $config['interfaces'][$interface];
3756
	$wanif = $wancfg['if'];
3757
	if (empty($wancfg))
3758
		$wancfg = array();
3759

    
3760
	/* generate dhclient_wan.conf */
3761
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3762
	if (!$fd) {
3763
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3764
		return 1;
3765
	}
3766

    
3767
	if ($wancfg['dhcphostname']) {
3768
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3769
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3770
	} else {
3771
		$dhclientconf_hostname = "";
3772
	}
3773

    
3774
	$wanif = get_real_interface($interface);
3775
	if (empty($wanif)) {
3776
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3777
		return 0;
3778
	}
3779
	$dhclientconf = "";
3780

    
3781
	$dhclientconf .= <<<EOD
3782
interface "{$wanif}" {
3783
timeout 60;
3784
retry 15;
3785
select-timeout 0;
3786
initial-interval 1;
3787
	{$dhclientconf_hostname}
3788
	script "/sbin/dhclient-script";
3789
EOD;
3790

    
3791
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3792
	$dhclientconf .= <<<EOD
3793

    
3794
	reject {$wancfg['dhcprejectfrom']};
3795
EOD;
3796
}
3797
	$dhclientconf .= <<<EOD
3798

    
3799
}
3800

    
3801
EOD;
3802

    
3803
	// DHCP Config File Advanced
3804
	if ($wancfg['adv_dhcp_config_advanced']) { $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif); }
3805

    
3806
if(is_ipaddr($wancfg['alias-address'])) {
3807
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3808
	$dhclientconf .= <<<EOD
3809
alias {
3810
	interface  "{$wanif}";
3811
	fixed-address {$wancfg['alias-address']};
3812
	option subnet-mask {$subnetmask};
3813
}
3814

    
3815
EOD;
3816
}
3817

    
3818
	// DHCP Config File Override
3819
	if ($wancfg['adv_dhcp_config_file_override']) { $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif); }
3820

    
3821
	fwrite($fd, $dhclientconf);
3822
	fclose($fd);
3823

    
3824
	/* bring wan interface up before starting dhclient */
3825
	if($wanif)
3826
		interfaces_bring_up($wanif);
3827
	else
3828
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3829

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

    
3833
	return 0;
3834
}
3835

    
3836
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3837

    
3838
	$hostname = "";
3839
	if ($wancfg['dhcphostname'] != '') {
3840
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3841
	}
3842

    
3843
	/* DHCP Protocol Timings */
3844
	$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");
3845
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
3846
		$pt_variable = "{$Protocol_Timing}";
3847
		${$pt_variable} = "";
3848
		if ($wancfg[$Protocol_Timing] != "") {
3849
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
3850
		}
3851
	}
3852

    
3853
	$send_options = "";
3854
	if ($wancfg['adv_dhcp_send_options'] != '') {
3855
		$options = split(",", $wancfg['adv_dhcp_send_options']);
3856
		foreach ($options as $option) {
3857
			$send_options .= "\tsend " . trim($option) . ";\n";
3858
		}
3859
	}
3860

    
3861
	$request_options = "";
3862
	if ($wancfg['adv_dhcp_request_options'] != '') {
3863
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
3864
	}
3865

    
3866
	$required_options = "";
3867
	if ($wancfg['adv_dhcp_required_options'] != '') {
3868
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
3869
	}
3870

    
3871
	$option_modifiers = "";
3872
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
3873
		$modifiers = split(",", $wancfg['adv_dhcp_option_modifiers']);
3874
		foreach ($modifiers as $modifier) {
3875
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
3876
		}
3877
	}
3878

    
3879
 	$dhclientconf  = "interface \"{$wanif}\" {\n";
3880
 	$dhclientconf .= "\n";
3881
 	$dhclientconf .= "# DHCP Protocol Timing Values\n";
3882
 	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
3883
 	$dhclientconf .= "{$adv_dhcp_pt_retry}";
3884
 	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
3885
 	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
3886
 	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
3887
 	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
3888
 	$dhclientconf .= "\n";
3889
 	$dhclientconf .= "# DHCP Protocol Options\n";
3890
 	$dhclientconf .= "{$hostname}";
3891
 	$dhclientconf .= "{$send_options}";
3892
 	$dhclientconf .= "{$request_options}";
3893
 	$dhclientconf .= "{$required_options}";
3894
 	$dhclientconf .= "{$option_modifiers}";
3895
 	$dhclientconf .= "\n";
3896
 	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
3897
 	$dhclientconf .= "}\n";
3898

    
3899
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3900

    
3901
	return $dhclientconf;
3902
}
3903

    
3904

    
3905
function DHCP_Config_File_Override($wancfg, $wanif) {
3906

    
3907
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
3908
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3909

    
3910
	return $dhclientconf;
3911
}
3912

    
3913

    
3914
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
3915

    
3916
	/* Apply Interface Substitutions */
3917
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
3918

    
3919
	/* Apply Hostname Substitutions */
3920
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
3921

    
3922
	/* Arrays of MAC Address Types, Cases, Delimiters */
3923
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
3924
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
3925
	$various_mac_cases      = array("U", "L");
3926
	$various_mac_delimiters = array("", " ", ":", "-", ".");
3927

    
3928
	/* Apply MAC Address Substitutions */
3929
	foreach ($various_mac_types as $various_mac_type) {
3930
		foreach ($various_mac_cases as $various_mac_case) {
3931
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
3932

    
3933
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
3934
				if ($res !== false) {
3935

    
3936
					/* Get MAC Address as ASCII String With Colon (:) Celimiters */
3937
					if ("$various_mac_case" == "U") $dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
3938
					if ("$various_mac_case" == "L") $dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
3939

    
3940
					if ("$various_mac_type" == "mac_addr_hex") {
3941
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
3942
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
3943
						$dhcpclientconf_mac_hex = "";
3944
						$delimiter = "";
3945
						for($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
3946
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
3947
							$delimiter = ":";
3948
						}
3949
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
3950
					}
3951

    
3952
					/* MAC Address Delimiter Substitutions */
3953
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
3954

    
3955
					/* Apply MAC Address Substitutions */
3956
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
3957
				}
3958
			}
3959
		}
3960
	}
3961

    
3962
	return $dhclientconf;
3963
}
3964

    
3965
function interfaces_group_setup() {
3966
	global $config;
3967

    
3968
	if (!is_array($config['ifgroups']['ifgroupentry']))
3969
		return;
3970

    
3971
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3972
		interface_group_setup($groupar);
3973

    
3974
	return;
3975
}
3976

    
3977
function interface_group_setup(&$groupname /* The parameter is an array */) {
3978
	global $config;
3979

    
3980
	if (!is_array($groupname))
3981
		return;
3982
	$members = explode(" ", $groupname['members']);
3983
	foreach($members as $ifs) {
3984
		$realif = get_real_interface($ifs);
3985
		if ($realif)
3986
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3987
	}
3988

    
3989
	return;
3990
}
3991

    
3992
function is_interface_group($if) {
3993
	global $config;
3994

    
3995
	if (is_array($config['ifgroups']['ifgroupentry']))
3996
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
3997
			if ($groupentry['ifname'] === $if)
3998
				return true;
3999
		}
4000

    
4001
	return false;
4002
}
4003

    
4004
function interface_group_add_member($interface, $groupname) {
4005
	$interface = get_real_interface($interface);
4006
	mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4007
}
4008

    
4009
/* COMPAT Function */
4010
function convert_friendly_interface_to_real_interface_name($interface) {
4011
	return get_real_interface($interface);
4012
}
4013

    
4014
/* COMPAT Function */
4015
function get_real_wan_interface($interface = "wan") {
4016
	return get_real_interface($interface);
4017
}
4018

    
4019
/* COMPAT Function */
4020
function get_current_wan_address($interface = "wan") {
4021
	return get_interface_ip($interface);
4022
}
4023

    
4024
/*
4025
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4026
 */
4027
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
4028
	global $config;
4029

    
4030
	/* XXX: For speed reasons reference directly the interface array */
4031
	$ifdescrs = &$config['interfaces'];
4032
	//$ifdescrs = get_configured_interface_list(false, true);
4033

    
4034
	foreach ($ifdescrs as $if => $ifname) {
4035
		if ($if == $interface || $ifname['if'] == $interface)
4036
			return $if;
4037

    
4038
		if (get_real_interface($if) == $interface)
4039
			return $if;
4040

    
4041
		$int = get_parent_interface($if, true);
4042
		if (is_array($int)) {
4043
			foreach ($int as $iface) {
4044
				if ($iface == $interface)
4045
					return $if;
4046
			}
4047
		}
4048
	}
4049

    
4050
	return NULL;
4051
}
4052

    
4053
/* attempt to resolve interface to friendly descr */
4054
function convert_friendly_interface_to_friendly_descr($interface) {
4055
	global $config;
4056

    
4057
	switch ($interface) {
4058
	case "l2tp":
4059
		$ifdesc = "L2TP";
4060
		break;
4061
	case "pptp":
4062
		$ifdesc = "PPTP";
4063
		break;
4064
	case "pppoe":
4065
		$ifdesc = "PPPoE";
4066
		break;
4067
	case "openvpn":
4068
		$ifdesc = "OpenVPN";
4069
		break;
4070
	case "enc0":
4071
	case "ipsec":
4072
		$ifdesc = "IPsec";
4073
		break;
4074
	default:
4075
		if (isset($config['interfaces'][$interface])) {
4076
			if (empty($config['interfaces'][$interface]['descr']))
4077
				$ifdesc = strtoupper($interface);
4078
			else
4079
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4080
			break;
4081
		} else if (stristr($interface, "_vip")) {
4082
			if (is_array($config['virtualip']['vip'])) {
4083
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
4084
					if ($vip['mode'] == "carp")  {
4085
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4086
							return "{$vip['subnet']} - {$vip['descr']}";
4087
					}
4088
				}
4089
			}
4090
		} else {
4091
			/* if list */
4092
			$ifdescrs = get_configured_interface_with_descr(false, true);
4093
			foreach ($ifdescrs as $if => $ifname) {
4094
				if ($if == $interface || $ifname == $interface)
4095
					return $ifname;
4096
			}
4097
		}
4098
		break;
4099
	}
4100

    
4101
	return $ifdesc;
4102
}
4103

    
4104
function convert_real_interface_to_friendly_descr($interface) {
4105
	global $config;
4106

    
4107
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4108

    
4109
	if ($ifdesc) {
4110
		$iflist = get_configured_interface_with_descr(false, true);
4111
		return $iflist[$ifdesc];
4112
	}
4113

    
4114
	return $interface;
4115
}
4116

    
4117
/*
4118
 *  get_parent_interface($interface):
4119
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4120
 *				or virtual interface (i.e. vlan)
4121
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4122
 *			-- returns $interface passed in if $interface parent is not found
4123
 *			-- returns empty array if an invalid interface is passed
4124
 *	(Only handles ppps and vlans now.)
4125
 */
4126
function get_parent_interface($interface, $avoidrecurse = false) {
4127
	global $config;
4128

    
4129
	$parents = array();
4130
	//Check that we got a valid interface passed
4131
	$realif = get_real_interface($interface);
4132
	if ($realif == NULL)
4133
		return $parents;
4134

    
4135
	// If we got a real interface, find it's friendly assigned name
4136
	if ($interface == $realif && $avoidrecurse == false)
4137
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4138

    
4139
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4140
		$ifcfg = $config['interfaces'][$interface];
4141
		switch ($ifcfg['ipaddr']) {
4142
			case "ppp":
4143
			case "pppoe":
4144
			case "pptp":
4145
			case "l2tp":
4146
				if (empty($parents))
4147
					if (is_array($config['ppps']['ppp']))
4148
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4149
							if ($ifcfg['if'] == $ppp['if']) {
4150
								$ports = explode(',', $ppp['ports']);
4151
								foreach ($ports as $pid => $parent_if)
4152
									$parents[$pid] = get_real_interface($parent_if);
4153
								break;
4154
							}
4155
						}
4156
				break;
4157
			case "dhcp":
4158
			case "static":
4159
			default:
4160
				// Handle _vlans
4161
				if (stristr($realif,"_vlan"))
4162
					if (is_array($config['vlans']['vlan']))
4163
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
4164
							if ($ifcfg['if'] == $vlan['vlanif']){
4165
								$parents[0] = $vlan['if'];
4166
								break;
4167
							}
4168
				break;
4169
		}
4170
	}
4171

    
4172
	if (empty($parents))
4173
		$parents[0] = $realif;
4174

    
4175
	return $parents;
4176
}
4177

    
4178
function interface_is_wireless_clone($wlif) {
4179
	if(!stristr($wlif, "_wlan")) {
4180
		return false;
4181
	} else {
4182
		return true;
4183
	}
4184
}
4185

    
4186
function interface_get_wireless_base($wlif) {
4187
	if(!stristr($wlif, "_wlan")) {
4188
		return $wlif;
4189
	} else {
4190
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4191
	}
4192
}
4193

    
4194
function interface_get_wireless_clone($wlif) {
4195
	if(!stristr($wlif, "_wlan")) {
4196
		return $wlif . "_wlan0";
4197
	} else {
4198
		return $wlif;
4199
	}
4200
}
4201

    
4202
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4203
	global $config, $g;
4204

    
4205
	$wanif = NULL;
4206

    
4207
	switch ($interface) {
4208
	case "l2tp":
4209
		$wanif = "l2tp";
4210
		break;
4211
	case "pptp":
4212
		$wanif = "pptp";
4213
		break;
4214
	case "pppoe":
4215
		$wanif = "pppoe";
4216
		break;
4217
	case "openvpn":
4218
		$wanif = "openvpn";
4219
		break;
4220
	case "ipsec":
4221
	case "enc0":
4222
		$wanif = "enc0";
4223
		break;
4224
	case "ppp":
4225
		$wanif = "ppp";
4226
		break;
4227
	default:
4228
		// If a real interface was alread passed simply
4229
		// pass the real interface back.  This encourages
4230
		// the usage of this function in more cases so that
4231
		// we can combine logic for more flexibility.
4232
		if(does_interface_exist($interface, $flush)) {
4233
			$wanif = $interface;
4234
			break;
4235
		}
4236

    
4237
		if (empty($config['interfaces'][$interface]))
4238
			break;
4239

    
4240
		$cfg = &$config['interfaces'][$interface];
4241

    
4242
		if ($family == "inet6") {
4243
			switch ($cfg['ipaddrv6']) {
4244
			case "6rd":
4245
			case "6to4":
4246
				$wanif = "{$interface}_stf";
4247
				break;
4248
			case 'pppoe':
4249
			case 'ppp':
4250
			case 'l2tp':
4251
			case 'pptp':
4252
				if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4253
					$wanif = interface_get_wireless_clone($cfg['if']);
4254
				else
4255
					$wanif = $cfg['if'];
4256
				break;
4257
			default:
4258
				switch ($cfg['ipaddr']) {
4259
				case 'pppoe':
4260
				case 'ppp':
4261
				case 'l2tp':
4262
				case 'pptp':
4263
					if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false)
4264
						$wanif = $cfg['if'];
4265
					else {
4266
						$parents = get_parent_interface($interface);
4267
						if (!empty($parents[0]))
4268
							$wanif = $parents[0];
4269
						else
4270
							$wanif = $cfg['if'];
4271
					}
4272
					break;
4273
				default:
4274
					if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4275
						$wanif = interface_get_wireless_clone($cfg['if']);
4276
					else
4277
						$wanif = $cfg['if'];
4278
					break;
4279
				}
4280
				break;
4281
			}
4282
		} else {
4283
			// Wireless cloned NIC support (FreeBSD 8+)
4284
			// interface name format: $parentnic_wlanparentnic#
4285
			// example: ath0_wlan0
4286
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4287
				$wanif = interface_get_wireless_clone($cfg['if']);
4288
			else
4289
				$wanif = $cfg['if'];
4290
		}
4291
		break;
4292
	}
4293

    
4294
	return $wanif;
4295
}
4296

    
4297
/* Guess the physical interface by providing a IP address */
4298
function guess_interface_from_ip($ipaddress) {
4299
	if(! is_ipaddr($ipaddress)) {
4300
		return false;
4301
	}
4302
	if(is_ipaddrv4($ipaddress)) {
4303
		/* create a route table we can search */
4304
		exec("netstat -rnWf inet", $output, $ret);
4305
		foreach($output as $line) {
4306
			if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
4307
				$fields = preg_split("/[ ]+/", $line);
4308
				if(ip_in_subnet($ipaddress, $fields[0])) {
4309
					return $fields[6];
4310
				}
4311
			}
4312
		}
4313
	}
4314
	/* FIXME: This works from cursory testing, regexp might need fine tuning */
4315
	if(is_ipaddrv6($ipaddress)) {
4316
		/* create a route table we can search */
4317
		exec("netstat -rnWf inet6", $output, $ret);
4318
		foreach($output as $line) {
4319
			if(preg_match("/[0-9a-f]+[:]+[0-9a-f]+[:]+[\/][0-9]+/", $line)) {
4320
				$fields = preg_split("/[ ]+/", $line);
4321
				if(ip_in_subnet($ipaddress, $fields[0])) {
4322
					return $fields[6];
4323
				}
4324
			}
4325
		}
4326
	}
4327
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
4328
	if(empty($ret)) {
4329
		return false;
4330
	}
4331
	return $ret;
4332
}
4333

    
4334
/*
4335
 * find_ip_interface($ip): return the interface where an ip is defined
4336
 *   (or if $bits is specified, where an IP within the subnet is defined)
4337
 */
4338
function find_ip_interface($ip, $bits = null) {
4339
	if (!is_ipaddr($ip))
4340
		return false;
4341

    
4342
	$isv6ip = is_ipaddrv6($ip);
4343

    
4344
	/* if list */
4345
	$ifdescrs = get_configured_interface_list();
4346

    
4347
	foreach ($ifdescrs as $ifdescr => $ifname) {
4348
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4349
		if (is_null($ifip))
4350
			continue;
4351
		if (is_null($bits)) {
4352
			if ($ip == $ifip) {
4353
				$int = get_real_interface($ifname);
4354
				return $int;
4355
			}
4356
		}
4357
		else {
4358
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4359
				$int = get_real_interface($ifname);
4360
				return $int;
4361
			}
4362
		}
4363
	}
4364

    
4365
	return false;
4366
}
4367

    
4368
/*
4369
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4370
 *   (or if $bits is specified, where an IP within the subnet is found)
4371
 */
4372
function find_virtual_ip_alias($ip, $bits = null) {
4373
	global $config;
4374

    
4375
	if (!is_array($config['virtualip']['vip'])) {
4376
		return false;
4377
	}
4378
	if (!is_ipaddr($ip))
4379
		return false;
4380

    
4381
	$isv6ip = is_ipaddrv6($ip);
4382

    
4383
	foreach ($config['virtualip']['vip'] as $vip) {
4384
		if ($vip['mode'] === "ipalias") {
4385
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4386
				continue;
4387
			if (is_null($bits)) {
4388
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4389
					return $vip;
4390
				}
4391
			}
4392
			else {
4393
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4394
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4395
					return $vip;
4396
				}
4397
			}
4398
		}
4399
	}
4400
	return false;
4401
}
4402

    
4403
/*
4404
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4405
 */
4406
function find_number_of_created_carp_interfaces() {
4407
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4408
}
4409

    
4410
function get_all_carp_interfaces() {
4411
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
4412
	$ints = explode(" ", $ints);
4413
	return $ints;
4414
}
4415

    
4416
/*
4417
 * find_carp_interface($ip): return the carp interface where an ip is defined
4418
 */
4419
function find_carp_interface($ip) {
4420
	global $config;
4421
	if (is_array($config['virtualip']['vip'])) {
4422
		foreach ($config['virtualip']['vip'] as $vip) {
4423
			if ($vip['mode'] == "carp") {
4424
				if(is_ipaddrv4($ip)) {
4425
					$carp_ip = get_interface_ip($vip['interface']);
4426
				}
4427
				if(is_ipaddrv6($ip)) {
4428
					$carp_ip = get_interface_ipv6($vip['interface']);
4429
				}
4430
				exec("/sbin/ifconfig", $output, $return);
4431
				foreach($output as $line) {
4432
					$elements = preg_split("/[ ]+/i", $line);
4433
					if(strstr($elements[0], "vip"))
4434
						$curif = str_replace(":", "", $elements[0]);
4435
					if(stristr($line, $ip)) {
4436
						$if = $curif;
4437
						continue;
4438
					}
4439
				}
4440

    
4441
				if ($if)
4442
					return $if;
4443
			}
4444
		}
4445
	}
4446
}
4447

    
4448
function link_carp_interface_to_parent($interface) {
4449
	global $config;
4450

    
4451
	if (empty($interface))
4452
		return;
4453

    
4454
	$carp_ip = get_interface_ip($interface);
4455
	$carp_ipv6 = get_interface_ipv6($interface);
4456

    
4457
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4458
		return;
4459

    
4460
	/* if list */
4461
	$ifdescrs = get_configured_interface_list();
4462
	foreach ($ifdescrs as $ifdescr => $ifname) {
4463
		/* check IPv4 */
4464
		if(is_ipaddrv4($carp_ip)) {
4465
			$interfaceip = get_interface_ip($ifname);
4466
			$subnet_bits = get_interface_subnet($ifname);
4467
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4468
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4469
				return $ifname;
4470
		}
4471
		/* Check IPv6 */
4472
		if(is_ipaddrv6($carp_ipv6)) {
4473
			$interfaceipv6 = get_interface_ipv6($ifname);
4474
			$prefixlen = get_interface_subnetv6($ifname);
4475
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4476
				return $ifname;
4477
		}
4478
	}
4479
	return "";
4480
}
4481

    
4482

    
4483
/****f* interfaces/link_ip_to_carp_interface
4484
 * NAME
4485
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4486
 * INPUTS
4487
 *   $ip
4488
 * RESULT
4489
 *   $carp_ints
4490
 ******/
4491
function link_ip_to_carp_interface($ip) {
4492
	global $config;
4493

    
4494
	if (!is_ipaddr($ip))
4495
		return;
4496

    
4497
	$carp_ints = "";
4498
	if (is_array($config['virtualip']['vip'])) {
4499
		$first = 0;
4500
		$carp_int = array();
4501
		foreach ($config['virtualip']['vip'] as $vip) {
4502
			if ($vip['mode'] == "carp") {
4503
				$carp_ip = $vip['subnet'];
4504
				$carp_sn = $vip['subnet_bits'];
4505
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4506
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4507
					$carp_int[] = get_real_interface($vip['interface']);
4508
				}
4509
			}
4510
		}
4511
		if (!empty($carp_int))
4512
			$carp_ints = implode(" ", array_unique($carp_int));
4513
	}
4514

    
4515
	return $carp_ints;
4516
}
4517

    
4518
function link_interface_to_track6($int, $action = "") {
4519
	global $config;
4520

    
4521
	if (empty($int))
4522
		return;
4523

    
4524
	if (is_array($config['interfaces'])) {
4525
		$list = array();
4526
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4527
			if (!isset($ifcfg['enable']))
4528
				continue;
4529
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4530
				if ($action == "update")
4531
					interface_track6_configure($ifname, $ifcfg);
4532
				else if ($action == "")
4533
					$list[$ifname] = $ifcfg;
4534
			}
4535
		}
4536
		return $list;
4537
	}
4538
}
4539

    
4540
function link_interface_to_vlans($int, $action = "") {
4541
	global $config;
4542

    
4543
	if (empty($int))
4544
		return;
4545

    
4546
	if (is_array($config['vlans']['vlan'])) {
4547
		$ifaces = array();
4548
		foreach ($config['vlans']['vlan'] as $vlan) {
4549
			if ($int == $vlan['if']) {
4550
				if ($action == "update") {
4551
					interfaces_bring_up($int);
4552
				} else if ($action == "")
4553
					$ifaces[$vlan['tag']] = $vlan;
4554
			}
4555
		}
4556
		if (!empty($ifaces))
4557
			return $ifaces;
4558
	}
4559
}
4560

    
4561
function link_interface_to_vips($int, $action = "") {
4562
	global $config;
4563

    
4564
	if (is_array($config['virtualip']['vip'])) {
4565
		$result = array();
4566
		foreach ($config['virtualip']['vip'] as $vip) {
4567
			if ($int == $vip['interface']) {
4568
				if ($action == "update")
4569
					interfaces_vips_configure($int);
4570
				else
4571
					$result[] = $vip;
4572
			}
4573
		}
4574
		return $result;
4575
	}
4576
}
4577

    
4578
/****f* interfaces/link_interface_to_bridge
4579
 * NAME
4580
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4581
 * INPUTS
4582
 *   $ip
4583
 * RESULT
4584
 *   bridge[0-99]
4585
 ******/
4586
function link_interface_to_bridge($int) {
4587
	global $config;
4588

    
4589
	if (is_array($config['bridges']['bridged'])) {
4590
		foreach ($config['bridges']['bridged'] as $bridge) {
4591
			if (in_array($int, explode(',', $bridge['members'])))
4592
				return "{$bridge['bridgeif']}";
4593
		}
4594
	}
4595
}
4596

    
4597
function link_interface_to_group($int) {
4598
	global $config;
4599

    
4600
	$result = array();
4601

    
4602
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4603
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4604
			if (in_array($int, explode(" ", $group['members'])))
4605
				$result[$group['ifname']] = $int;
4606
		}
4607
	}
4608

    
4609
	return $result;
4610
}
4611

    
4612
function link_interface_to_gre($interface) {
4613
	global $config;
4614

    
4615
	$result = array();
4616

    
4617
	if (is_array($config['gres']['gre'])) {
4618
		foreach ($config['gres']['gre'] as $gre)
4619
			if($gre['if'] == $interface)
4620
				$result[] = $gre;
4621
	}
4622

    
4623
	return $result;
4624
}
4625

    
4626
function link_interface_to_gif($interface) {
4627
	global $config;
4628

    
4629
	$result = array();
4630

    
4631
	if (is_array($config['gifs']['gif'])) {
4632
		foreach ($config['gifs']['gif'] as $gif)
4633
			if($gif['if'] == $interface)
4634
				$result[] = $gif;
4635
	}
4636

    
4637
	return $result;
4638
}
4639

    
4640
/*
4641
 * find_interface_ip($interface): return the interface ip (first found)
4642
 */
4643
function find_interface_ip($interface, $flush = false) {
4644
	global $interface_ip_arr_cache;
4645
	global $interface_sn_arr_cache;
4646

    
4647
	$interface = str_replace("\n", "", $interface);
4648

    
4649
	if (!does_interface_exist($interface))
4650
		return;
4651

    
4652
	/* Setup IP cache */
4653
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4654
		$ifinfo = pfSense_get_interface_addresses($interface);
4655
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4656
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4657
	}
4658

    
4659
	return $interface_ip_arr_cache[$interface];
4660
}
4661

    
4662
/*
4663
 * find_interface_ipv6($interface): return the interface ip (first found)
4664
 */
4665
function find_interface_ipv6($interface, $flush = false) {
4666
	global $interface_ipv6_arr_cache;
4667
	global $interface_snv6_arr_cache;
4668
	global $config;
4669

    
4670
	$interface = trim($interface);
4671
	$interface = get_real_interface($interface);
4672

    
4673
	if (!does_interface_exist($interface))
4674
		return;
4675

    
4676
	/* Setup IP cache */
4677
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4678
		$ifinfo = pfSense_get_interface_addresses($interface);
4679
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4680
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4681
	}
4682

    
4683
	return $interface_ipv6_arr_cache[$interface];
4684
}
4685

    
4686
/*
4687
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4688
 */
4689
function find_interface_ipv6_ll($interface, $flush = false) {
4690
	global $interface_llv6_arr_cache;
4691
	global $config;
4692

    
4693
	$interface = str_replace("\n", "", $interface);
4694

    
4695
	if (!does_interface_exist($interface))
4696
		return;
4697

    
4698
	/* Setup IP cache */
4699
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4700
		$ifinfo = pfSense_getall_interface_addresses($interface);
4701
		foreach($ifinfo as $line) {
4702
			if (strstr($line, ":")) {
4703
				$parts = explode("/", $line);
4704
				if(is_linklocal($parts[0])) {
4705
					$ifinfo['linklocal'] = $parts[0];
4706
				}
4707
			}
4708
		}
4709
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4710
	}
4711
	return $interface_llv6_arr_cache[$interface];
4712
}
4713

    
4714
function find_interface_subnet($interface, $flush = false) {
4715
	global $interface_sn_arr_cache;
4716
	global $interface_ip_arr_cache;
4717

    
4718
	$interface = str_replace("\n", "", $interface);
4719
	if (does_interface_exist($interface) == false)
4720
		return;
4721

    
4722
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4723
		$ifinfo = pfSense_get_interface_addresses($interface);
4724
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4725
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4726
	}
4727

    
4728
	return $interface_sn_arr_cache[$interface];
4729
}
4730

    
4731
function find_interface_subnetv6($interface, $flush = false) {
4732
	global $interface_snv6_arr_cache;
4733
	global $interface_ipv6_arr_cache;
4734

    
4735
	$interface = str_replace("\n", "", $interface);
4736
	if (does_interface_exist($interface) == false)
4737
		return;
4738

    
4739
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4740
		$ifinfo = pfSense_get_interface_addresses($interface);
4741
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4742
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4743
	}
4744

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

    
4748
function ip_in_interface_alias_subnet($interface, $ipalias) {
4749
	global $config;
4750

    
4751
	if (empty($interface) || !is_ipaddr($ipalias))
4752
		return false;
4753
	if (is_array($config['virtualip']['vip'])) {
4754
		foreach ($config['virtualip']['vip'] as $vip) {
4755
			switch ($vip['mode']) {
4756
			case "ipalias":
4757
				if ($vip['interface'] <> $interface)
4758
					break;
4759
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4760
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4761
					return true;
4762
				break;
4763
			}
4764
		}
4765
	}
4766

    
4767
	return false;
4768
}
4769

    
4770
function get_interface_ip($interface = "wan") {
4771
	$realif = get_failover_interface($interface);
4772
	if (!$realif) {
4773
		if (strstr($interface, "_vip"))
4774
			return get_configured_carp_interface_list($interface);
4775
		else
4776
			return null;
4777
	}
4778

    
4779
	$curip = find_interface_ip($realif);
4780
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4781
		return $curip;
4782
	else
4783
		return null;
4784
}
4785

    
4786
function get_interface_ipv6($interface = "wan", $flush = false) {
4787
	global $config;
4788

    
4789
	$realif = get_failover_interface($interface, "inet6");
4790
	if (!$realif) {
4791
		if (strstr($interface, "_vip"))
4792
			return get_configured_carp_interface_list($interface, "inet6");
4793
		else
4794
			return null;
4795
	}
4796

    
4797
	/*
4798
	 * NOTE: On the case when only the prefix is requested,
4799
	 * the communication on WAN will be done over link-local.
4800
	 */
4801
	if (is_array($config['interfaces'][$interface])) {
4802
		switch ($config['interfaces'][$interface]['ipaddr']) {
4803
		case 'pppoe':
4804
		case 'l2tp':
4805
		case 'pptp':
4806
		case 'ppp':
4807
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4808
				$realif = get_real_interface($interface, "inet6", true);
4809
			break;
4810
		}
4811
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4812
			$curip = find_interface_ipv6_ll($realif, $flush);
4813
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4814
				return $curip;
4815
		}
4816
	}
4817

    
4818
	$curip = find_interface_ipv6($realif, $flush);
4819
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4820
		return $curip;
4821
	else
4822
		return null;
4823
}
4824

    
4825
function get_interface_linklocal($interface = "wan") {
4826

    
4827
	$realif = get_failover_interface($interface, "inet6");
4828
	if (!$realif) {
4829
		if (strstr($interface, "_vip")) {
4830
			list($interface, $vhid) = explode("_vip", $interface);
4831
			$realif = get_real_interface($interface);
4832
		} else
4833
			return null;
4834
	}
4835

    
4836
	$curip = find_interface_ipv6_ll($realif);
4837
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4838
		return $curip;
4839
	else
4840
		return null;
4841
}
4842

    
4843
function get_interface_subnet($interface = "wan") {
4844
	$realif = get_real_interface($interface);
4845
	if (!$realif) {
4846
		if (strstr($interface, "_vip")) {
4847
			list($interface, $vhid) = explode("_vip", $interface);
4848
			$realif = get_real_interface($interface);
4849
		} else
4850
			return null;
4851
	}
4852

    
4853
	$cursn = find_interface_subnet($realif);
4854
	if (!empty($cursn))
4855
		return $cursn;
4856

    
4857
	return null;
4858
}
4859

    
4860
function get_interface_subnetv6($interface = "wan") {
4861
	global $config;
4862

    
4863
	$realif = get_real_interface($interface, "inet6");
4864
	if (!$realif) {
4865
		if (strstr($interface, "_vip")) {
4866
			list($interface, $vhid) = explode("_vip", $interface);
4867
			$realif = get_real_interface($interface);
4868
		} else
4869
			return null;
4870
	}
4871

    
4872
	$cursn = find_interface_subnetv6($realif);
4873
	if (!empty($cursn))
4874
		return $cursn;
4875

    
4876
	return null;
4877
}
4878

    
4879
/* return outside interfaces with a gateway */
4880
function get_interfaces_with_gateway() {
4881
	global $config;
4882

    
4883
	$ints = array();
4884

    
4885
	/* loop interfaces, check config for outbound */
4886
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4887
		switch ($ifname['ipaddr']) {
4888
			case "dhcp":
4889
			case "ppp";
4890
			case "pppoe":
4891
			case "pptp":
4892
			case "l2tp":
4893
			case "ppp";
4894
				$ints[$ifdescr] = $ifdescr;
4895
			break;
4896
			default:
4897
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
4898
				    !empty($ifname['gateway']))
4899
					$ints[$ifdescr] = $ifdescr;
4900
			break;
4901
		}
4902
	}
4903
	return $ints;
4904
}
4905

    
4906
/* return true if interface has a gateway */
4907
function interface_has_gateway($friendly) {
4908
	global $config;
4909

    
4910
	if (!empty($config['interfaces'][$friendly])) {
4911
		$ifname = &$config['interfaces'][$friendly];
4912
		switch ($ifname['ipaddr']) {
4913
			case "dhcp":
4914
			case "pppoe":
4915
			case "pptp":
4916
			case "l2tp":
4917
			case "ppp";
4918
				return true;
4919
			break;
4920
			default:
4921
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4922
					return true;
4923
				if (!empty($ifname['gateway']))
4924
					return true;
4925
			break;
4926
		}
4927
	}
4928

    
4929
	return false;
4930
}
4931

    
4932
/* return true if interface has a gateway */
4933
function interface_has_gatewayv6($friendly) {
4934
	global $config;
4935

    
4936
	if (!empty($config['interfaces'][$friendly])) {
4937
		$ifname = &$config['interfaces'][$friendly];
4938
		switch ($ifname['ipaddrv6']) {
4939
			case "slaac":
4940
			case "dhcp6":
4941
			case "6to4":
4942
			case "6rd":
4943
				return true;
4944
				break;
4945
			default:
4946
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4947
					return true;
4948
				$tunnelif = substr($ifname['if'], 0, 3);
4949
				if ($tunnelif == "gif" || $tunnelif == "gre")
4950
					return true;
4951
				if (!empty($ifname['gatewayv6']))
4952
					return true;
4953
				break;
4954
		}
4955
	}
4956

    
4957
	return false;
4958
}
4959

    
4960
/****f* interfaces/is_altq_capable
4961
 * NAME
4962
 *   is_altq_capable - Test if interface is capable of using ALTQ
4963
 * INPUTS
4964
 *   $int            - string containing interface name
4965
 * RESULT
4966
 *   boolean         - true or false
4967
 ******/
4968

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

    
4982
	$int_family = remove_ifindex($int);
4983

    
4984
	if (in_array($int_family, $capable))
4985
		return true;
4986
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
4987
		return true;
4988
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
4989
		return true;
4990
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
4991
		return true;
4992
	else
4993
		return false;
4994
}
4995

    
4996
/****f* interfaces/is_interface_wireless
4997
 * NAME
4998
 *   is_interface_wireless - Returns if an interface is wireless
4999
 * RESULT
5000
 *   $tmp       - Returns if an interface is wireless
5001
 ******/
5002
function is_interface_wireless($interface) {
5003
	global $config, $g;
5004

    
5005
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5006
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
5007
		if (preg_match($g['wireless_regex'], $interface)) {
5008
			if (isset($config['interfaces'][$friendly]))
5009
				$config['interfaces'][$friendly]['wireless'] = array();
5010
			return true;
5011
		}
5012
		return false;
5013
	} else
5014
		return true;
5015
}
5016

    
5017
function get_wireless_modes($interface) {
5018
	/* return wireless modes and channels */
5019
	$wireless_modes = array();
5020

    
5021
	$cloned_interface = get_real_interface($interface);
5022

    
5023
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5024
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5025
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5026
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5027

    
5028
		$interface_channels = "";
5029
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5030
		$interface_channel_count = count($interface_channels);
5031

    
5032
		$c = 0;
5033
		while ($c < $interface_channel_count) {
5034
			$channel_line = explode(",", $interface_channels["$c"]);
5035
			$wireless_mode = trim($channel_line[0]);
5036
			$wireless_channel = trim($channel_line[1]);
5037
			if(trim($wireless_mode) != "") {
5038
				/* if we only have 11g also set 11b channels */
5039
				if($wireless_mode == "11g") {
5040
					if(!isset($wireless_modes["11b"]))
5041
						$wireless_modes["11b"] = array();
5042
				} else if($wireless_mode == "11g ht") {
5043
					if(!isset($wireless_modes["11b"]))
5044
						$wireless_modes["11b"] = array();
5045
					if(!isset($wireless_modes["11g"]))
5046
						$wireless_modes["11g"] = array();
5047
					$wireless_mode = "11ng";
5048
				} else if($wireless_mode == "11a ht") {
5049
					if(!isset($wireless_modes["11a"]))
5050
						$wireless_modes["11a"] = array();
5051
					$wireless_mode = "11na";
5052
				}
5053
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5054
			}
5055
			$c++;
5056
		}
5057
	}
5058
	return($wireless_modes);
5059
}
5060

    
5061
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5062
function get_wireless_channel_info($interface) {
5063
	$wireless_channels = array();
5064

    
5065
	$cloned_interface = get_real_interface($interface);
5066

    
5067
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5068
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5069
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5070
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5071

    
5072
		$interface_channels = "";
5073
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5074

    
5075
		foreach ($interface_channels as $channel_line) {
5076
			$channel_line = explode(",", $channel_line);
5077
			if(!isset($wireless_channels[$channel_line[0]]))
5078
				$wireless_channels[$channel_line[0]] = $channel_line;
5079
		}
5080
	}
5081
	return($wireless_channels);
5082
}
5083

    
5084
/****f* interfaces/get_interface_mtu
5085
 * NAME
5086
 *   get_interface_mtu - Return the mtu of an interface
5087
 * RESULT
5088
 *   $tmp       - Returns the mtu of an interface
5089
 ******/
5090
function get_interface_mtu($interface) {
5091
	$mtu = pfSense_get_interface_addresses($interface);
5092
	return $mtu['mtu'];
5093
}
5094

    
5095
function get_interface_mac($interface) {
5096

    
5097
	$macinfo = pfSense_get_interface_addresses($interface);
5098
	return $macinfo["macaddr"];
5099
}
5100

    
5101
/****f* pfsense-utils/generate_random_mac_address
5102
 * NAME
5103
 *   generate_random_mac - generates a random mac address
5104
 * INPUTS
5105
 *   none
5106
 * RESULT
5107
 *   $mac - a random mac address
5108
 ******/
5109
function generate_random_mac_address() {
5110
	$mac = "02";
5111
	for($x=0; $x<5; $x++)
5112
		$mac .= ":" . dechex(rand(16, 255));
5113
	return $mac;
5114
}
5115

    
5116
/****f* interfaces/is_jumbo_capable
5117
 * NAME
5118
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5119
 * INPUTS
5120
 *   $int             - string containing interface name
5121
 * RESULT
5122
 *   boolean          - true or false
5123
 ******/
5124
function is_jumbo_capable($iface) {
5125
	$iface = trim($iface);
5126
	$capable = pfSense_get_interface_addresses($iface);
5127

    
5128
	if (isset($capable['caps']['vlanmtu']))
5129
		return true;
5130

    
5131
	return false;
5132
}
5133

    
5134
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5135
	global $g;
5136

    
5137
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5138

    
5139
	if(!empty($iface) && !empty($pppif)){
5140
		$cron_cmd = <<<EOD
5141
#!/bin/sh
5142
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5143
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5144

    
5145
EOD;
5146

    
5147
		@file_put_contents($cron_file, $cron_cmd);
5148
		chmod($cron_file, 0755);
5149
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5150
	} else
5151
		unlink_if_exists($cron_file);
5152
}
5153

    
5154
function get_interface_default_mtu($type = "ethernet") {
5155
	switch ($type) {
5156
	case "gre":
5157
		return 1476;
5158
		break;
5159
	case "gif":
5160
		return 1280;
5161
		break;
5162
	case "tun":
5163
	case "vlan":
5164
	case "tap":
5165
	case "ethernet":
5166
	default:
5167
		return 1500;
5168
		break;
5169
	}
5170

    
5171
	/* Never reached */
5172
	return 1500;
5173
}
5174

    
5175
function get_vip_descr($ipaddress) {
5176
	global $config;
5177

    
5178
	foreach ($config['virtualip']['vip'] as $vip) {
5179
		if ($vip['subnet'] == $ipaddress) {
5180
			return ($vip['descr']);
5181
		}
5182
	}
5183
	return "";
5184
}
5185

    
5186
function interfaces_staticarp_configure($if) {
5187
	global $config, $g;
5188
	if(isset($config['system']['developerspew'])) {
5189
		$mt = microtime();
5190
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5191
	}
5192

    
5193
	$ifcfg = $config['interfaces'][$if];
5194

    
5195
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5196
		return 0;
5197

    
5198
	/* Enable staticarp, if enabled */
5199
	if(isset($config['dhcpd'][$if]['staticarp'])) {
5200
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
5201
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5202
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5203

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

    
5207
			}
5208

    
5209
		}
5210
	} else {
5211
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
5212
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5213
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5214
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5215
				if (isset($arpent['arp_table_static_entry'])) {
5216
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5217
				}
5218
			}
5219
		}
5220
	}
5221

    
5222
	return 0;
5223
}
5224

    
5225
function get_failover_interface($interface, $family = "all") {
5226
	global $config;
5227

    
5228
	/* shortcut to get_real_interface if we find it in the config */
5229
	if (is_array($config['interfaces'][$interface])) {
5230
		return get_real_interface($interface, $family);
5231
	}
5232

    
5233
	/* compare against gateway groups */
5234
	$a_groups = return_gateway_groups_array();
5235
	if (is_array($a_groups[$interface])) {
5236
		/* we found a gateway group, fetch the interface or vip */
5237
		if ($a_groups[$interface][0]['vip'] <> "")
5238
			return $a_groups[$interface][0]['vip'];
5239
		else
5240
			return $a_groups[$interface][0]['int'];
5241
	}
5242
	/* fall through to get_real_interface */
5243
	/* XXX: Really needed? */
5244
	return get_real_interface($interface, $family);
5245
}
5246

    
5247
function remove_ifindex($ifname) {
5248
	return preg_replace("/[0-9]+$/", "", $ifname);
5249
}
5250

    
5251
?>
(25-25/67)