Project

General

Profile

Download (156 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
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
870
	} else {
871
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
872
	}
873
	if (isset($gre['link0']))
874
		pfSense_interface_flags($greif, IFF_LINK0);
875
	if (isset($gre['link1']))
876
		pfSense_interface_flags($greif, IFF_LINK1);
877
	if (isset($gre['link2']))
878
		pfSense_interface_flags($greif, IFF_LINK2);
879

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

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

    
892
	interfaces_bring_up($laggif);
893

    
894
	return $greif;
895
}
896

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

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

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

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

    
929
	if (!is_array($gif))
930
		return -1;
931

    
932
	$realif = get_real_interface($gif['if']);
933
	$ipaddr = $gif['ipaddr'];
934

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

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

    
961
	/* Do not change the order here for more see gif(4) NOTES section. */
962
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
963
	if((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
964
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
965
	} else {
966
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
967
	}
968
	if (isset($gif['link0']))
969
		pfSense_interface_flags($gifif, IFF_LINK0);
970
	if (isset($gif['link1']))
971
		pfSense_interface_flags($gifif, IFF_LINK1);
972
	if($gifif)
973
		interfaces_bring_up($gifif);
974
	else
975
		log_error(gettext("could not bring gifif up -- variable not defined"));
976

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

    
991

    
992
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
993
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
994
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
995
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
996

    
997
	if (is_ipaddrv4($realifgw)) {
998
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
999
	}
1000
	if (is_ipaddrv6($realifgw)) {
1001
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1002
	}
1003

    
1004
	interfaces_bring_up($laggif);
1005

    
1006
	return $gifif;
1007
}
1008

    
1009
function interfaces_configure() {
1010
	global $config, $g;
1011

    
1012
	if ($g['platform'] == 'jail')
1013
		return;
1014

    
1015
	/* Set up our loopback interface */
1016
	interfaces_loopback_configure();
1017

    
1018
	/* create the unconfigured wireless clones */
1019
	interfaces_create_wireless_clones();
1020

    
1021
	/* set up LAGG virtual interfaces */
1022
	interfaces_lagg_configure();
1023

    
1024
	/* set up VLAN virtual interfaces */
1025
	interfaces_vlan_configure();
1026

    
1027
	interfaces_qinq_configure();
1028

    
1029
	$iflist = get_configured_interface_with_descr();
1030
	$delayed_list = array();
1031
	$bridge_list = array();
1032
	$track6_list = array();
1033

    
1034
	/* This is needed to speedup interfaces on bootup. */
1035
	$reload = false;
1036
	if (!$g['booting'])
1037
		$reload = true;
1038

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

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

    
1064
	/*
1065
	 * NOTE: The following function parameter consists of
1066
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1067
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1068
	 */
1069

    
1070
	/* set up GRE virtual interfaces */
1071
	interfaces_gre_configure(1);
1072

    
1073
	/* set up GIF virtual interfaces */
1074
	interfaces_gif_configure(1);
1075

    
1076
	/* set up BRIDGe virtual interfaces */
1077
	interfaces_bridge_configure(1);
1078

    
1079
	foreach ($track6_list as $if => $ifname) {
1080
		if ($g['booting'])
1081
			printf(gettext("Configuring %s interface..."), $ifname);
1082
		if ($g['debug'])
1083
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1084

    
1085
		interface_configure($if, $reload);
1086

    
1087
		if ($g['booting'])
1088
			echo gettext("done.") . "\n";
1089
	}
1090

    
1091
	/* bring up vip interfaces */
1092
	interfaces_vips_configure();
1093

    
1094
	/* set up GRE virtual interfaces */
1095
	interfaces_gre_configure(2);
1096

    
1097
	/* set up GIF virtual interfaces */
1098
	interfaces_gif_configure(2);
1099

    
1100
	foreach ($delayed_list as $if => $ifname) {
1101
		if ($g['booting'])
1102
			printf(gettext("Configuring %s interface..."), $ifname);
1103
		if ($g['debug'])
1104
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1105

    
1106
		interface_configure($if, $reload);
1107

    
1108
		if ($g['booting'])
1109
			echo gettext("done.") . "\n";
1110
	}
1111

    
1112
	/* set up BRIDGe virtual interfaces */
1113
	interfaces_bridge_configure(2);
1114

    
1115
	foreach ($bridge_list as $if => $ifname) {
1116
		if ($g['booting'])
1117
			printf(gettext("Configuring %s interface..."), $ifname);
1118
		if($g['debug'])
1119
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1120

    
1121
		interface_configure($if, $reload);
1122

    
1123
		if ($g['booting'])
1124
			echo gettext("done.") . "\n";
1125
	}
1126

    
1127
	/* configure interface groups */
1128
	interfaces_group_setup();
1129

    
1130
	if (!$g['booting']) {
1131
		/* reconfigure static routes (kernel may have deleted them) */
1132
		system_routing_configure();
1133

    
1134
		/* reload IPsec tunnels */
1135
		vpn_ipsec_configure();
1136

    
1137
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1138
		services_dhcpd_configure();
1139

    
1140
		/* restart dnsmasq */
1141
		services_dnsmasq_configure();
1142
	}
1143

    
1144
	return 0;
1145
}
1146

    
1147
function interface_reconfigure($interface = "wan", $reloadall = false) {
1148
	interface_bring_down($interface);
1149
	interface_configure($interface, $reloadall);
1150
}
1151

    
1152
function interface_vip_bring_down($vip) {
1153
	global $g;
1154

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

    
1177
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1178
	global $config, $g;
1179

    
1180
	if (!isset($config['interfaces'][$interface]))
1181
		return;
1182

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

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

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

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

    
1302
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1303
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1304
//	log_error("Checking for old router states: {$g['tmp_path']}/{$realif}_router = {$old_router}");
1305
	if (!empty($old_router)) {
1306
		log_error("Clearing states to old gateway {$old_router}.");
1307
		mwexec("/sbin/pfctl -i " . escapeshellarg($realif) . " -Fs -G {$old_router}");
1308
	}
1309

    
1310
	/* remove interface up file if it exists */
1311
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1312
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1313
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1314
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1315
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1316
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1317
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1318

    
1319
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1320
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1321
	if (is_array($ifcfg['wireless'])) {
1322
		kill_hostapd($realif);
1323
		mwexec(kill_wpasupplicant($realif));
1324
	}
1325

    
1326
	if ($destroy == true) {
1327
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif))
1328
			pfSense_interface_destroy($realif);
1329
	}
1330

    
1331
	return;
1332
}
1333

    
1334
function interfaces_ptpid_used($ptpid) {
1335
	global $config;
1336

    
1337
	if (is_array($config['ppps']['ppp']))
1338
		foreach ($config['ppps']['ppp'] as & $settings)
1339
			if ($ptpid == $settings['ptpid'])
1340
				return true;
1341

    
1342
	return false;
1343
}
1344

    
1345
function interfaces_ptpid_next() {
1346

    
1347
	$ptpid = 0;
1348
	while(interfaces_ptpid_used($ptpid))
1349
		$ptpid++;
1350

    
1351
	return $ptpid;
1352
}
1353

    
1354
function getMPDCRONSettings($pppif) {
1355
	global $config;
1356

    
1357
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1358
	if (is_array($config['cron']['item'])) {
1359
		foreach ($config['cron']['item'] as $i => $item) {
1360
			if (stripos($item['command'], $cron_cmd_file) !== false)
1361
				return array("ID" => $i, "ITEM" => $item);
1362
		}
1363
	}
1364

    
1365
	return NULL;
1366
}
1367

    
1368
function handle_pppoe_reset($post_array) {
1369
	global $config, $g;
1370

    
1371
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1372
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1373

    
1374
	if (!is_array($config['cron']['item']))
1375
		$config['cron']['item'] = array();
1376

    
1377
	$itemhash = getMPDCRONSettings($pppif);
1378

    
1379
	// reset cron items if necessary and return
1380
	if (empty($post_array['pppoe-reset-type'])) {
1381
		if (isset($itemhash))
1382
			unset($config['cron']['item'][$itemhash['ID']]);
1383
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1384
		return;
1385
	}
1386

    
1387
	if (empty($itemhash))
1388
		$itemhash = array();
1389
	$item = array();
1390
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1391
		$item['minute'] = $post_array['pppoe_resetminute'];
1392
		$item['hour'] = $post_array['pppoe_resethour'];
1393
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1394
			$date = explode("/", $post_array['pppoe_resetdate']);
1395
			$item['mday'] = $date[1];
1396
			$item['month'] = $date[0];
1397
		} else {
1398
			$item['mday'] = "*";
1399
			$item['month'] = "*";
1400
		}
1401
		$item['wday'] = "*";
1402
		$item['who'] = "root";
1403
		$item['command'] = $cron_cmd_file;
1404
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1405
		switch ($post_array['pppoe_pr_preset_val']) {
1406
		case "monthly":
1407
			$item['minute'] = "0";
1408
			$item['hour'] = "0";
1409
			$item['mday'] = "1";
1410
			$item['month'] = "*";
1411
			$item['wday'] = "*";
1412
			break;
1413
		case "weekly":
1414
			$item['minute'] = "0";
1415
			$item['hour'] = "0";
1416
			$item['mday'] = "*";
1417
			$item['month'] = "*";
1418
			$item['wday'] = "0";
1419
			break;
1420
		case "daily":
1421
			$item['minute'] = "0";
1422
			$item['hour'] = "0";
1423
			$item['mday'] = "*";
1424
			$item['month'] = "*";
1425
			$item['wday'] = "*";
1426
			break;
1427
		case "hourly":
1428
			$item['minute'] = "0";
1429
			$item['hour'] = "*";
1430
			$item['mday'] = "*";
1431
			$item['month'] = "*";
1432
			$item['wday'] = "*";
1433
			break;
1434
		} // end switch
1435
		$item['who'] = "root";
1436
		$item['command'] = $cron_cmd_file;
1437
	}
1438
	if (empty($item))
1439
		return;
1440
	if (isset($itemhash['ID']))
1441
		$config['cron']['item'][$itemhash['ID']] = $item;
1442
	else
1443
		$config['cron']['item'][] = $item;
1444
}
1445

    
1446
/*
1447
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1448
 * It writes the mpd config file to /var/etc every time the link is opened.
1449
 */
1450
function interface_ppps_configure($interface) {
1451
	global $config, $g;
1452

    
1453
	/* Return for unassigned interfaces. This is a minimum requirement. */
1454
	if (empty($config['interfaces'][$interface]))
1455
		return 0;
1456
	$ifcfg = $config['interfaces'][$interface];
1457
	if (!isset($ifcfg['enable']))
1458
		return 0;
1459

    
1460
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1461
	if(!is_dir("/var/spool/lock")) {
1462
		mkdir("/var/spool/lock", 0777, true);
1463
	}
1464
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1465
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1466
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1467

    
1468
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1469
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1470
			if ($ifcfg['if'] == $ppp['if'])
1471
				break;
1472
		}
1473
	}
1474
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1475
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1476
		return 0;
1477
	}
1478
	$pppif = $ifcfg['if'];
1479
	if ($ppp['type'] == "ppp")
1480
		$type = "modem";
1481
	else
1482
		$type = $ppp['type'];
1483
	$upper_type = strtoupper($ppp['type']);
1484

    
1485
	if($g['booting']) {
1486
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1487
		echo "starting {$pppif} link...";
1488
		// Do not re-configure the interface if we are booting and it's already been started
1489
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1490
			return 0;
1491
	}
1492

    
1493
	$ports = explode(',',$ppp['ports']);
1494
	if ($type != "modem") {
1495
		foreach ($ports as $pid => $port) {
1496
			$ports[$pid] = get_real_interface($port);
1497
			if (empty($ports[$pid]))
1498
				return 0;
1499
		}
1500
	}
1501
	$localips = explode(',',$ppp['localip']);
1502
	$gateways = explode(',',$ppp['gateway']);
1503
	$subnets = explode(',',$ppp['subnet']);
1504

    
1505
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1506
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1507
	 */
1508
	foreach($ports as $pid => $port){
1509
		switch ($ppp['type']) {
1510
			case "pppoe":
1511
				/* Bring the parent interface up */
1512
				interfaces_bring_up($port);
1513
				pfSense_ngctl_attach(".", $port);
1514
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1515
				mwexec("ngctl msg {$port}: setautosrc 1");
1516
				break;
1517
			case "pptp":
1518
			case "l2tp":
1519
				/* configure interface */
1520
				if(is_ipaddr($localips[$pid])){
1521
					// Manually configure interface IP/subnet
1522
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1523
					interfaces_bring_up($port);
1524
				} else if (empty($localips[$pid]))
1525
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1526

    
1527
				if(!is_ipaddr($localips[$pid])){
1528
					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!");
1529
					$localips[$pid] = "0.0.0.0";
1530
				}
1531
				if(!is_ipaddr($gateways[$pid])){
1532
					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));
1533
					return 0;
1534
				}
1535
				pfSense_ngctl_attach(".", $port);
1536
				break;
1537
			case "ppp":
1538
				if (!file_exists("{$port}")) {
1539
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1540
					return 0;
1541
				}
1542
				break;
1543
			default:
1544
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1545
				break;
1546
		}
1547
	}
1548

    
1549
	if (is_array($ports) && count($ports) > 1)
1550
		$multilink = "enable";
1551
	else
1552
		$multilink = "disable";
1553

    
1554
	if ($type == "modem"){
1555
		if (is_ipaddr($ppp['localip']))
1556
			$localip = $ppp['localip'];
1557
		else
1558
			$localip = '0.0.0.0';
1559

    
1560
		if (is_ipaddr($ppp['gateway']))
1561
			$gateway = $ppp['gateway'];
1562
		else
1563
			$gateway = "10.64.64.{$pppid}";
1564
		$ranges = "{$localip}/0 {$gateway}/0";
1565

    
1566
		if (empty($ppp['apnum']))
1567
			$ppp['apnum'] = 1;
1568
	} else
1569
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1570

    
1571
	if (isset($ppp['ondemand']))
1572
		$ondemand = "enable";
1573
	else
1574
		$ondemand = "disable";
1575
	if (!isset($ppp['idletimeout']))
1576
		$ppp['idletimeout'] = 0;
1577

    
1578
	if (empty($ppp['username']) && $type == "modem"){
1579
		$ppp['username'] = "user";
1580
		$ppp['password'] = "none";
1581
	}
1582
	if (empty($ppp['password']) && $type == "modem")
1583
		$passwd = "none";
1584
	else
1585
		$passwd = base64_decode($ppp['password']);
1586

    
1587
	$bandwidths = explode(',',$ppp['bandwidth']);
1588
	$defaultmtu = "1492";
1589
	if (!empty($ifcfg['mtu']))
1590
		$defaultmtu = intval($ifcfg['mtu']);
1591
	$mtus = explode(',',$ppp['mtu']);
1592
	$mrus = explode(',',$ppp['mru']);
1593

    
1594
	if (isset($ppp['mrru']))
1595
		$mrrus = explode(',',$ppp['mrru']);
1596

    
1597
	// Construct the mpd.conf file
1598
	$mpdconf = <<<EOD
1599
startup:
1600
	# configure the console
1601
	set console close
1602
	# configure the web server
1603
	set web close
1604

    
1605
default:
1606
{$ppp['type']}client:
1607
	create bundle static {$interface}
1608
	set bundle enable ipv6cp
1609
	set iface name {$pppif}
1610

    
1611
EOD;
1612
	$setdefaultgw = false;
1613
	$founddefaultgw = false;
1614
	if (is_array($config['gateways']['gateway_item'])) {
1615
		foreach($config['gateways']['gateway_item'] as $gateway) {
1616
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1617
				$setdefaultgw = true;
1618
				break;
1619
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1620
				$founddefaultgw = true;
1621
				break;
1622
			}
1623
		}
1624
	}
1625

    
1626
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1627
		$setdefaultgw = true;
1628
		$mpdconf .= <<<EOD
1629
	set iface route default
1630

    
1631
EOD;
1632
	}
1633
	$mpdconf .= <<<EOD
1634
	set iface {$ondemand} on-demand
1635
	set iface idle {$ppp['idletimeout']}
1636

    
1637
EOD;
1638

    
1639
	if (isset($ppp['ondemand']))
1640
		$mpdconf .= <<<EOD
1641
	set iface addrs 10.10.1.1 10.10.1.2
1642

    
1643
EOD;
1644

    
1645
	if (isset($ppp['tcpmssfix']))
1646
		$tcpmss = "disable";
1647
	else
1648
		$tcpmss = "enable";
1649
		$mpdconf .= <<<EOD
1650
	set iface {$tcpmss} tcpmssfix
1651

    
1652
EOD;
1653

    
1654
	$mpdconf .= <<<EOD
1655
	set iface up-script /usr/local/sbin/ppp-linkup
1656
	set iface down-script /usr/local/sbin/ppp-linkdown
1657
	set ipcp ranges {$ranges}
1658

    
1659
EOD;
1660
	if (isset($ppp['vjcomp']))
1661
		$mpdconf .= <<<EOD
1662
	set ipcp no vjcomp
1663

    
1664
EOD;
1665

    
1666
	if (isset($config['system']['dnsallowoverride']))
1667
		$mpdconf .= <<<EOD
1668
	set ipcp enable req-pri-dns
1669
	set ipcp enable req-sec-dns
1670

    
1671
EOD;
1672
	if (!isset($ppp['verbose_log']))
1673
		$mpdconf .= <<<EOD
1674
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1675

    
1676
EOD;
1677
	foreach($ports as $pid => $port){
1678
		$port = get_real_interface($port);
1679
		$mpdconf .= <<<EOD
1680

    
1681
	create link static {$interface}_link{$pid} {$type}
1682
	set link action bundle {$interface}
1683
	set link {$multilink} multilink
1684
	set link keep-alive 10 60
1685
	set link max-redial 0
1686

    
1687
EOD;
1688
		if (isset($ppp['shortseq']))
1689
			$mpdconf .= <<<EOD
1690
	set link no shortseq
1691

    
1692
EOD;
1693

    
1694
		if (isset($ppp['acfcomp']))
1695
			$mpdconf .= <<<EOD
1696
	set link no acfcomp
1697

    
1698
EOD;
1699

    
1700
		if (isset($ppp['protocomp']))
1701
			$mpdconf .= <<<EOD
1702
	set link no protocomp
1703

    
1704
EOD;
1705

    
1706
		$mpdconf .= <<<EOD
1707
	set link disable chap pap
1708
	set link accept chap pap eap
1709
	set link disable incoming
1710

    
1711
EOD;
1712

    
1713

    
1714
		if (!empty($bandwidths[$pid]))
1715
			$mpdconf .= <<<EOD
1716
	set link bandwidth {$bandwidths[$pid]}
1717

    
1718
EOD;
1719

    
1720
		if (empty($mtus[$pid]))
1721
			$mtus[$pid] = $defaultmtu;
1722
			$mpdconf .= <<<EOD
1723
	set link mtu {$mtus[$pid]}
1724

    
1725
EOD;
1726

    
1727
		if (!empty($mrus[$pid]))
1728
			$mpdconf .= <<<EOD
1729
	set link mru {$mrus[$pid]}
1730

    
1731
EOD;
1732

    
1733
		if (!empty($mrrus[$pid]))
1734
			$mpdconf .= <<<EOD
1735
	set link mrru {$mrrus[$pid]}
1736

    
1737
EOD;
1738

    
1739
		$mpdconf .= <<<EOD
1740
	set auth authname "{$ppp['username']}"
1741
	set auth password {$passwd}
1742

    
1743
EOD;
1744
		if ($type == "modem") {
1745
			$mpdconf .= <<<EOD
1746
	set modem device {$ppp['ports']}
1747
	set modem script DialPeer
1748
	set modem idle-script Ringback
1749
	set modem watch -cd
1750
	set modem var \$DialPrefix "DT"
1751
	set modem var \$Telephone "{$ppp['phone']}"
1752

    
1753
EOD;
1754
		}
1755
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1756
			$mpdconf .= <<<EOD
1757
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1758

    
1759
EOD;
1760
		}
1761
		if (isset($ppp['initstr']) && $type == "modem") {
1762
			$initstr = base64_decode($ppp['initstr']);
1763
			$mpdconf .= <<<EOD
1764
	set modem var \$InitString "{$initstr}"
1765

    
1766
EOD;
1767
		}
1768
		if (isset($ppp['simpin']) && $type == "modem") {
1769
			if($ppp['pin-wait'] == "")
1770
				$ppp['pin-wait'] = 0;
1771
			$mpdconf .= <<<EOD
1772
	set modem var \$SimPin "{$ppp['simpin']}"
1773
	set modem var \$PinWait "{$ppp['pin-wait']}"
1774

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

    
1782
EOD;
1783
		}
1784
		if ($type == "pppoe") {
1785
			// Send a null service name if none is set.
1786
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1787
			$mpdconf .= <<<EOD
1788
	set pppoe service "{$provider}"
1789

    
1790
EOD;
1791
		}
1792
		if ($type == "pppoe")
1793
			$mpdconf .= <<<EOD
1794
	set pppoe iface {$port}
1795

    
1796
EOD;
1797

    
1798
		if ($type == "pptp" || $type == "l2tp") {
1799
			$mpdconf .= <<<EOD
1800
	set {$type} self {$localips[$pid]}
1801
	set {$type} peer {$gateways[$pid]}
1802

    
1803
EOD;
1804
		}
1805

    
1806
		$mpdconf .= "\topen\n";
1807
	} //end foreach($port)
1808

    
1809

    
1810
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1811
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1812
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1813
	else {
1814
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1815
		if (!$fd) {
1816
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1817
			return 0;
1818
		}
1819
		// Write out mpd_ppp.conf
1820
		fwrite($fd, $mpdconf);
1821
		fclose($fd);
1822
		unset($mpdconf);
1823
	}
1824

    
1825
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1826
	if (isset($ppp['uptime'])) {
1827
		if (!file_exists("/conf/{$pppif}.log")) {
1828
			conf_mount_rw();
1829
			file_put_contents("/conf/{$pppif}.log", '');
1830
			conf_mount_ro();
1831
		}
1832
	} else {
1833
		if (file_exists("/conf/{$pppif}.log")) {
1834
			conf_mount_rw();
1835
			@unlink("/conf/{$pppif}.log");
1836
			conf_mount_ro();
1837
		}
1838
	}
1839

    
1840
	/* clean up old lock files */
1841
	foreach($ports as $port) {
1842
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1843
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1844
	}
1845

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

    
1850
	// Check for PPPoE periodic reset request
1851
	if ($type == "pppoe") {
1852
		if (!empty($ppp['pppoe-reset-type']))
1853
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1854
		else
1855
			interface_setup_pppoe_reset_file($ppp['if']);
1856
	}
1857
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1858
	$i = 0;
1859
	while($i < 10) {
1860
		exec("/sbin/ifconfig " . escapeshellarg($ppp['if']) . " 2>&1", $out, $ret);
1861
		if($ret == 0)
1862
			break;
1863
		sleep(1);
1864
		$i++;
1865
	}
1866

    
1867
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
1868
	/* We should be able to launch the right version for each modem */
1869
	/* We can also guess the mondev from the manufacturer */
1870
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
1871
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
1872
	foreach($ports as $port) {
1873
		if(preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1874
			$mondev  = substr(basename($port), 0, -1);
1875
			$devlist = glob("/dev/{$mondev}?");
1876
			$mondev = basename(end($devlist));
1877
		}
1878
		if(preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1879
			$mondev  = substr(basename($port), 0, -1) . "1";
1880
		}
1881
		log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
1882
		mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
1883
	}
1884

    
1885
	return 1;
1886
}
1887

    
1888
function interfaces_carp_setup() {
1889
	global $g, $config;
1890

    
1891
	if (isset($config['system']['developerspew'])) {
1892
		$mt = microtime();
1893
		echo "interfaces_carp_setup() being called $mt\n";
1894
	}
1895

    
1896
	if ($g['booting']) {
1897
		echo gettext("Configuring CARP settings...");
1898
		mute_kernel_msgs();
1899
	}
1900

    
1901
	/* suck in configuration items */
1902
	if ($config['hasync']) {
1903
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1904
		$balancing = $config['hasync']['balancing'];
1905
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1906
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1907
	} else {
1908
		unset($pfsyncinterface);
1909
		unset($balancing);
1910
		unset($pfsyncenabled);
1911
	}
1912

    
1913
	if ($balancing) {
1914
		mwexec("/sbin/sysctl net.inet.carp.arpbalance=1", true);
1915
		mwexec("/sbin/sysctl net.inet.carp.preempt=0", true);
1916
	} else
1917
		mwexec("/sbin/sysctl net.inet.carp.preempt=1", true);
1918

    
1919
	mwexec("sbin/sysctl net.inet.carp.log=1", true);
1920
	if (!empty($pfsyncinterface))
1921
		$carp_sync_int = get_real_interface($pfsyncinterface);
1922
	else
1923
		unset($carp_sync_int);
1924

    
1925
	/* setup pfsync interface */
1926
	if ($carp_sync_int and $pfsyncenabled) {
1927
		if (is_ipaddr($pfsyncpeerip))
1928
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1929
		else
1930
			$syncpeer = "-syncpeer";
1931

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

    
1934
		sleep(1);
1935

    
1936
		/* 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
1937
		 * for existing sessions.
1938
		 */
1939
		log_error("waiting for pfsync...");
1940
		$i = 0;
1941
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1942
			$i++;
1943
			sleep(1);
1944
		}
1945
		log_error("pfsync done in $i seconds.");
1946
		log_error("Configuring CARP settings finalize...");
1947
	} else {
1948
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
1949
	}
1950

    
1951
	if($config['virtualip']['vip'])
1952
		mwexec("/sbin/sysctl net.inet.carp.allow=1", true);
1953
	else
1954
		mwexec("/sbin/sysctl net.inet.carp.allow=0", true);
1955

    
1956
	if ($g['booting']) {
1957
		unmute_kernel_msgs();
1958
		echo gettext("done.") . "\n";
1959
	}
1960
}
1961

    
1962
function interface_proxyarp_configure($interface = "") {
1963
	global $config, $g;
1964
	if(isset($config['system']['developerspew'])) {
1965
		$mt = microtime();
1966
		echo "interface_proxyarp_configure() being called $mt\n";
1967
	}
1968

    
1969
	/* kill any running choparp */
1970
	if (empty($interface))
1971
		killbyname("choparp");
1972
	else {
1973
		$vipif = get_real_interface($interface);
1974
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1975
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1976
	}
1977

    
1978
	$paa = array();
1979
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1980

    
1981
		/* group by interface */
1982
		foreach ($config['virtualip']['vip'] as $vipent) {
1983
			if ($vipent['mode'] === "proxyarp") {
1984
				if ($vipent['interface'])
1985
					$proxyif = $vipent['interface'];
1986
				else
1987
					$proxyif = "wan";
1988

    
1989
				if (!empty($interface) && $interface != $proxyif)
1990
					continue;
1991

    
1992
				if (!is_array($paa[$proxyif]))
1993
					$paa[$proxyif] = array();
1994

    
1995
				$paa[$proxyif][] = $vipent;
1996
			}
1997
		}
1998
	}
1999

    
2000
	if (!empty($interface)) {
2001
		if (is_array($paa[$interface])) {
2002
			$paaifip = get_interface_ip($interface);
2003
			if (!is_ipaddr($paaifip))
2004
				return;
2005
			$args = get_real_interface($interface) . " auto";
2006
			foreach ($paa[$interface] as $paent) {
2007
				if (isset($paent['subnet']))
2008
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2009
				else if (isset($paent['range']))
2010
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2011
			}
2012
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2013
		}
2014
	} else if (count($paa) > 0) {
2015
		foreach ($paa as $paif => $paents)  {
2016
			$paaifip = get_interface_ip($paif);
2017
			if (!is_ipaddr($paaifip))
2018
				continue;
2019
			$args = get_real_interface($paif) . " auto";
2020
			foreach ($paents as $paent) {
2021
				if (isset($paent['subnet']))
2022
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2023
				else if (isset($paent['range']))
2024
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2025
			}
2026
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2027
		}
2028
	}
2029
}
2030

    
2031
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2032
	global $g, $config;
2033

    
2034
	if (is_array($config['virtualip']['vip'])) {
2035
		foreach ($config['virtualip']['vip'] as $vip) {
2036
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2037
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2038
					interface_vip_bring_down($vip);
2039
				else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2040
					interface_vip_bring_down($vip);
2041
			}
2042
		}
2043
	}
2044
}
2045

    
2046
function interfaces_vips_configure($interface = "") {
2047
	global $g, $config;
2048
	if(isset($config['system']['developerspew'])) {
2049
		$mt = microtime();
2050
		echo "interfaces_vips_configure() being called $mt\n";
2051
	}
2052
	$paa = array();
2053
	if(is_array($config['virtualip']['vip'])) {
2054
		$carp_setuped = false;
2055
		$anyproxyarp = false;
2056
		foreach ($config['virtualip']['vip'] as $vip) {
2057
			switch ($vip['mode']) {
2058
			case "proxyarp":
2059
				/* nothing it is handled on interface_proxyarp_configure() */
2060
				if ($interface <> "" && $vip['interface'] <> $interface)
2061
					continue;
2062
				$anyproxyarp = true;
2063
				break;
2064
			case "ipalias":
2065
				if ($interface <> "" && $vip['interface'] <> $interface)
2066
					continue;
2067
				interface_ipalias_configure($vip);
2068
				break;
2069
			case "carp":
2070
				if ($interface <> "" && $vip['interface'] <> $interface)
2071
					continue;
2072
				if ($carp_setuped == false)
2073
					$carp_setuped = true;
2074
				interface_carp_configure($vip);
2075
				break;
2076
			}
2077
		}
2078
		if ($carp_setuped == true)
2079
			interfaces_carp_setup();
2080
		if ($anyproxyarp == true)
2081
			interface_proxyarp_configure();
2082
	}
2083
}
2084

    
2085
function interface_ipalias_configure(&$vip) {
2086
	if ($vip['mode'] == "ipalias") {
2087
		$if = get_real_interface($vip['interface']);
2088
		$af = "inet";
2089
		if(is_ipaddrv6($vip['subnet']))
2090
			$af = "inet6";
2091
		mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
2092
	}
2093
}
2094

    
2095
function interface_reload_carps($cif) {
2096
	global $config;
2097

    
2098
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2099
	if (empty($carpifs))
2100
		return;
2101

    
2102
	$carps = explode(" ", $carpifs);
2103
	if(is_array($config['virtualip']['vip'])) {
2104
		$viparr = &$config['virtualip']['vip'];
2105
		foreach ($viparr as $vip) {
2106
			if (in_array($vip['carpif'], $carps)) {
2107
				switch ($vip['mode']) {
2108
				case "carp":
2109
					interface_vip_bring_down($vip);
2110
					sleep(1);
2111
					interface_carp_configure($vip);
2112
					break;
2113
				case "ipalias":
2114
					interface_vip_bring_down($vip);
2115
					sleep(1);
2116
					interface_ipalias_configure($vip);
2117
					break;
2118
				}
2119
			}
2120
		}
2121
	}
2122
}
2123

    
2124
function interface_carp_configure(&$vip) {
2125
	global $config, $g;
2126
	if(isset($config['system']['developerspew'])) {
2127
		$mt = microtime();
2128
		echo "interface_carp_configure() being called $mt\n";
2129
	}
2130

    
2131
	if ($vip['mode'] != "carp")
2132
		return;
2133

    
2134
	/* NOTE: Maybe its useless nowdays */
2135
	$realif = get_real_interface($vip['interface']);
2136
	if (!does_interface_exist($realif)) {
2137
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2138
		return;
2139
	}
2140

    
2141
	if (is_ipaddrv4($vip['subnet'])) {
2142
		/* Ensure CARP IP really exists prior to loading up. */
2143
		$ww_subnet_ip = find_interface_ip($realif);
2144
		$ww_subnet_bits = find_interface_subnet($realif);
2145
		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'])) {
2146
			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", "");
2147
			return;
2148
		}
2149
	} else if (is_ipaddrv6($vip['subnet'])) {
2150
		/* Ensure CARP IP really exists prior to loading up. */
2151
		$ww_subnet_ip = find_interface_ipv6($realif);
2152
		$ww_subnet_bits = find_interface_subnetv6($realif);
2153
		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'])) {
2154
			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", "");
2155
			return;
2156
		}
2157
	}
2158

    
2159
	$vip_password = $vip['password'];
2160
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2161
	if ($vip['password'] != "")
2162
		$password = " pass {$vip_password}";
2163

    
2164
	$advbase = "";
2165
	if (!empty($vip['advbase']))
2166
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2167

    
2168
	if (is_ipaddrv4($vip['subnet']))
2169
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias");
2170
	else if (is_ipaddrv6($vip['subnet']))
2171
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']));
2172

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

    
2175
	return $realif;
2176
}
2177

    
2178
function interface_wireless_clone($realif, $wlcfg) {
2179
	global $config, $g;
2180
	/*   Check to see if interface has been cloned as of yet.
2181
	 *   If it has not been cloned then go ahead and clone it.
2182
	 */
2183
	$needs_clone = false;
2184
	if(is_array($wlcfg['wireless']))
2185
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2186
	else
2187
		$wlcfg_mode = $wlcfg['mode'];
2188
	switch($wlcfg_mode) {
2189
	case "hostap":
2190
		$mode = "wlanmode hostap";
2191
		break;
2192
	case "adhoc":
2193
		$mode = "wlanmode adhoc";
2194
		break;
2195
	default:
2196
		$mode = "";
2197
		break;
2198
	}
2199
	$baseif = interface_get_wireless_base($wlcfg['if']);
2200
	if(does_interface_exist($realif)) {
2201
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2202
		$ifconfig_str = implode($output);
2203
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
2204
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2205
			$needs_clone = true;
2206
		}
2207
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
2208
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2209
			$needs_clone = true;
2210
		}
2211
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2212
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2213
			$needs_clone = true;
2214
		}
2215
	} else {
2216
		$needs_clone = true;
2217
	}
2218

    
2219
	if($needs_clone == true) {
2220
		/* remove previous instance if it exists */
2221
		if(does_interface_exist($realif))
2222
			pfSense_interface_destroy($realif);
2223

    
2224
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2225
		// Create the new wlan interface. FreeBSD returns the new interface name.
2226
		// example:  wlan2
2227
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2228
		if($ret <> 0) {
2229
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2230
			return false;
2231
		}
2232
		$newif = trim($out[0]);
2233
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2234
		pfSense_interface_rename($newif, $realif);
2235
		// FIXME: not sure what ngctl is for. Doesn't work.
2236
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
2237
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2238
	}
2239
	return true;
2240
}
2241

    
2242
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2243
	global $config, $g;
2244

    
2245
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2246
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2247
				 'regdomain', 'regcountry', 'reglocation');
2248

    
2249
	if(!is_interface_wireless($ifcfg['if']))
2250
		return;
2251

    
2252
	$baseif = interface_get_wireless_base($ifcfg['if']);
2253

    
2254
	// Sync shared settings for assigned clones
2255
	$iflist = get_configured_interface_list(false, true);
2256
	foreach ($iflist as $if) {
2257
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2258
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2259
				foreach ($shared_settings as $setting) {
2260
					if ($sync_changes) {
2261
						if (isset($ifcfg['wireless'][$setting]))
2262
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2263
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2264
							unset($config['interfaces'][$if]['wireless'][$setting]);
2265
					} else {
2266
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2267
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2268
						else if (isset($ifcfg['wireless'][$setting]))
2269
							unset($ifcfg['wireless'][$setting]);
2270
					}
2271
				}
2272
				if (!$sync_changes)
2273
					break;
2274
			}
2275
		}
2276
	}
2277

    
2278
	// Read or write settings at shared area
2279
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2280
		foreach ($shared_settings as $setting) {
2281
			if ($sync_changes) {
2282
				if (isset($ifcfg['wireless'][$setting]))
2283
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2284
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2285
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2286
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2287
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2288
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2289
				else if (isset($ifcfg['wireless'][$setting]))
2290
					unset($ifcfg['wireless'][$setting]);
2291
			}
2292
		}
2293
	}
2294

    
2295
	// Sync the mode on the clone creation page with the configured mode on the interface
2296
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2297
		foreach ($config['wireless']['clone'] as &$clone) {
2298
			if ($clone['cloneif'] == $ifcfg['if']) {
2299
				if ($sync_changes) {
2300
					$clone['mode'] = $ifcfg['wireless']['mode'];
2301
				} else {
2302
					$ifcfg['wireless']['mode'] = $clone['mode'];
2303
				}
2304
				break;
2305
			}
2306
		}
2307
		unset($clone);
2308
	}
2309
}
2310

    
2311
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2312
	global $config, $g;
2313

    
2314
	/*    open up a shell script that will be used to output the commands.
2315
	 *    since wireless is changing a lot, these series of commands are fragile
2316
	 *    and will sometimes need to be verified by a operator by executing the command
2317
	 *    and returning the output of the command to the developers for inspection.  please
2318
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2319
	 */
2320

    
2321
	// Remove script file
2322
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2323

    
2324
	// Clone wireless nic if needed.
2325
	interface_wireless_clone($if, $wl);
2326

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

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

    
2334
	/* set values for /path/program */
2335
	$hostapd = "/usr/sbin/hostapd";
2336
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2337
	$ifconfig = "/sbin/ifconfig";
2338
	$sysctl = "/sbin/sysctl";
2339
	$killall = "/usr/bin/killall";
2340

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

    
2343
	$wlcmd = array();
2344
	$wl_sysctl = array();
2345
	/* Make sure it's up */
2346
	$wlcmd[] = "up";
2347
	/* Set a/b/g standard */
2348
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2349
	$wlcmd[] = "mode " . escapeshellarg($standard);
2350

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

    
2356
	/* Set ssid */
2357
	if($wlcfg['ssid'])
2358
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2359

    
2360
	/* Set 802.11g protection mode */
2361
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2362

    
2363
	/* set wireless channel value */
2364
	if(isset($wlcfg['channel'])) {
2365
		if($wlcfg['channel'] == "0") {
2366
			$wlcmd[] = "channel any";
2367
		} else {
2368
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2369
		}
2370
	}
2371

    
2372
	/* Set antenna diversity value */
2373
	if(isset($wlcfg['diversity']))
2374
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2375

    
2376
	/* Set txantenna value */
2377
	if(isset($wlcfg['txantenna']))
2378
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2379

    
2380
	/* Set rxantenna value */
2381
	if(isset($wlcfg['rxantenna']))
2382
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2383

    
2384
	/* set Distance value */
2385
	if($wlcfg['distance'])
2386
		$distance = escapeshellarg($wlcfg['distance']);
2387

    
2388
	/* Set wireless hostap mode */
2389
	if ($wlcfg['mode'] == "hostap") {
2390
		$wlcmd[] = "mediaopt hostap";
2391
	} else {
2392
		$wlcmd[] = "-mediaopt hostap";
2393
	}
2394

    
2395
	/* Set wireless adhoc mode */
2396
	if ($wlcfg['mode'] == "adhoc") {
2397
		$wlcmd[] = "mediaopt adhoc";
2398
	} else {
2399
		$wlcmd[] = "-mediaopt adhoc";
2400
	}
2401

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

    
2404
	/* handle hide ssid option */
2405
	if(isset($wlcfg['hidessid']['enable'])) {
2406
		$wlcmd[] = "hidessid";
2407
	} else {
2408
		$wlcmd[] = "-hidessid";
2409
	}
2410

    
2411
	/* handle pureg (802.11g) only option */
2412
	if(isset($wlcfg['pureg']['enable'])) {
2413
		$wlcmd[] = "mode 11g pureg";
2414
	} else {
2415
		$wlcmd[] = "-pureg";
2416
	}
2417

    
2418
	/* handle puren (802.11n) only option */
2419
	if(isset($wlcfg['puren']['enable'])) {
2420
		$wlcmd[] = "puren";
2421
	} else {
2422
		$wlcmd[] = "-puren";
2423
	}
2424

    
2425
	/* enable apbridge option */
2426
	if(isset($wlcfg['apbridge']['enable'])) {
2427
		$wlcmd[] = "apbridge";
2428
	} else {
2429
		$wlcmd[] = "-apbridge";
2430
	}
2431

    
2432
	/* handle turbo option */
2433
	if(isset($wlcfg['turbo']['enable'])) {
2434
		$wlcmd[] = "mediaopt turbo";
2435
	} else {
2436
		$wlcmd[] = "-mediaopt turbo";
2437
	}
2438

    
2439
	/* handle txpower setting */
2440
	/* if($wlcfg['txpower'] <> "")
2441
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2442
	*/
2443
	/* handle wme option */
2444
	if(isset($wlcfg['wme']['enable'])) {
2445
		$wlcmd[] = "wme";
2446
	} else {
2447
		$wlcmd[] = "-wme";
2448
	}
2449

    
2450
	/* set up wep if enabled */
2451
	$wepset = "";
2452
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2453
		switch($wlcfg['wpa']['auth_algs']) {
2454
			case "1":
2455
				$wepset .= "authmode open wepmode on ";
2456
				break;
2457
			case "2":
2458
				$wepset .= "authmode shared wepmode on ";
2459
				break;
2460
			case "3":
2461
				$wepset .= "authmode mixed wepmode on ";
2462
		}
2463
		$i = 1;
2464
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2465
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2466
			if (isset($wepkey['txkey'])) {
2467
				$wlcmd[] = "weptxkey {$i} ";
2468
			}
2469
			$i++;
2470
		}
2471
		$wlcmd[] = $wepset;
2472
	} else {
2473
		$wlcmd[] = "authmode open wepmode off ";
2474
	}
2475

    
2476
	kill_hostapd($if);
2477
	mwexec(kill_wpasupplicant("{$if}"));
2478

    
2479
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2480
	conf_mount_rw();
2481

    
2482
	switch ($wlcfg['mode']) {
2483
		case 'bss':
2484
			if (isset($wlcfg['wpa']['enable'])) {
2485
				$wpa .= <<<EOD
2486
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2487
ctrl_interface_group=0
2488
ap_scan=1
2489
#fast_reauth=1
2490
network={
2491
ssid="{$wlcfg['ssid']}"
2492
scan_ssid=1
2493
priority=5
2494
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2495
psk="{$wlcfg['wpa']['passphrase']}"
2496
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2497
group={$wlcfg['wpa']['wpa_pairwise']}
2498
}
2499
EOD;
2500

    
2501
				$fd = fopen("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", "w");
2502
				fwrite($fd, "{$wpa}");
2503
				fclose($fd);
2504
			}
2505
			break;
2506
		case 'hostap':
2507
			if($wlcfg['wpa']['passphrase'])
2508
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2509
			else
2510
				$wpa_passphrase = "";
2511
			if (isset($wlcfg['wpa']['enable'])) {
2512
				$wpa .= <<<EOD
2513
interface={$if}
2514
driver=bsd
2515
logger_syslog=-1
2516
logger_syslog_level=0
2517
logger_stdout=-1
2518
logger_stdout_level=0
2519
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2520
ctrl_interface={$g['varrun_path']}/hostapd
2521
ctrl_interface_group=wheel
2522
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2523
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2524
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2525
ssid={$wlcfg['ssid']}
2526
debug={$wlcfg['wpa']['debug_mode']}
2527
auth_algs={$wlcfg['wpa']['auth_algs']}
2528
wpa={$wlcfg['wpa']['wpa_mode']}
2529
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2530
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2531
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2532
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2533
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2534
{$wpa_passphrase}
2535

    
2536
EOD;
2537

    
2538
if (isset($wlcfg['wpa']['rsn_preauth'])) {
2539
	$wpa .= <<<EOD
2540
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2541
rsn_preauth=1
2542
rsn_preauth_interfaces={$if}
2543

    
2544
EOD;
2545

    
2546
}
2547
				if($wlcfg['auth_server_addr'] && $wlcfg['auth_server_shared_secret']) {
2548
					$auth_server_port = "1812";
2549
					if($wlcfg['auth_server_port'])
2550
						$auth_server_port = $wlcfg['auth_server_port'];
2551
					$auth_server_port2 = "1812";
2552
					if($wlcfg['auth_server_port2'])
2553
						$auth_server_port2 = $wlcfg['auth_server_port2'];
2554
					$wpa .= <<<EOD
2555

    
2556
ieee8021x=1
2557
auth_server_addr={$wlcfg['auth_server_addr']}
2558
auth_server_port={$auth_server_port}
2559
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2560
auth_server_addr={$wlcfg['auth_server_addr2']}
2561
auth_server_port={$auth_server_port2}
2562
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2563

    
2564
EOD;
2565
				} else if (isset($wlcfg['wpa']['ieee8021x'])) {
2566
					$wpa .= "ieee8021x=1\n";
2567
				}
2568

    
2569
				$fd = fopen("{$g['varetc_path']}/hostapd_{$if}.conf", "w");
2570
				fwrite($fd, "{$wpa}");
2571
				fclose($fd);
2572

    
2573
			}
2574
			break;
2575
	}
2576

    
2577
	/*
2578
	 *    all variables are set, lets start up everything
2579
	 */
2580

    
2581
	$baseif = interface_get_wireless_base($if);
2582
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2583
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2584

    
2585
	/* set sysctls for the wireless interface */
2586
	if (!empty($wl_sysctl)) {
2587
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2588
		foreach ($wl_sysctl as $wl_sysctl_line) {
2589
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2590
		}
2591
	}
2592

    
2593
	/* set ack timers according to users preference (if he/she has any) */
2594
	if($distance) {
2595
		fwrite($fd_set, "# Enable ATH distance settings\n");
2596
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2597
	}
2598

    
2599
	if (isset($wlcfg['wpa']['enable'])) {
2600
		if ($wlcfg['mode'] == "bss") {
2601
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2602
		}
2603
		if ($wlcfg['mode'] == "hostap") {
2604
			/* add line to script to restore old mac to make hostapd happy */
2605
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2606
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2607
				if (is_macaddr($if_oldmac))
2608
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2609
						" link " . escapeshellarg($if_oldmac) . "\n");
2610
			}
2611

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

    
2614
			/* add line to script to restore spoofed mac after running hostapd */
2615
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2616
				if ($wl['spoofmac'])
2617
					$if_curmac = $wl['spoofmac'];
2618
				else
2619
					$if_curmac = get_interface_mac($if);
2620
				if (is_macaddr($if_curmac))
2621
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2622
						" link " . escapeshellarg($if_curmac) . "\n");
2623
			}
2624
		}
2625
	}
2626

    
2627
	fclose($fd_set);
2628
	conf_mount_ro();
2629

    
2630
	/* Making sure regulatory settings have actually changed
2631
	 * before applying, because changing them requires bringing
2632
	 * down all wireless networks on the interface. */
2633
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2634
	$ifconfig_str = implode($output);
2635
	unset($output);
2636
	$reg_changing = false;
2637

    
2638
	/* special case for the debug country code */
2639
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2640
		$reg_changing = true;
2641
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2642
		$reg_changing = true;
2643
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2644
		$reg_changing = true;
2645
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2646
		$reg_changing = true;
2647
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2648
		$reg_changing = true;
2649

    
2650
	if ($reg_changing) {
2651
		/* set regulatory domain */
2652
		if($wlcfg['regdomain'])
2653
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2654

    
2655
		/* set country */
2656
		if($wlcfg['regcountry'])
2657
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2658

    
2659
		/* set location */
2660
		if($wlcfg['reglocation'])
2661
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2662

    
2663
		$wlregcmd_args = implode(" ", $wlregcmd);
2664

    
2665
		/* build a complete list of the wireless clones for this interface */
2666
		$clone_list = array();
2667
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2668
			$clone_list[] = interface_get_wireless_clone($baseif);
2669
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2670
			foreach ($config['wireless']['clone'] as $clone) {
2671
				if ($clone['if'] == $baseif)
2672
					$clone_list[] = $clone['cloneif'];
2673
			}
2674
		}
2675

    
2676
		/* find which clones are up and bring them down */
2677
		$clones_up = array();
2678
		foreach ($clone_list as $clone_if) {
2679
			$clone_status = pfSense_get_interface_addresses($clone_if);
2680
			if ($clone_status['status'] == 'up') {
2681
				$clones_up[] = $clone_if;
2682
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2683
			}
2684
		}
2685

    
2686
		/* apply the regulatory settings */
2687
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2688

    
2689
		/* bring the clones back up that were previously up */
2690
		foreach ($clones_up as $clone_if) {
2691
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2692

    
2693
			/*
2694
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2695
			 * is in infrastructure mode, and WPA is enabled.
2696
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2697
			 */
2698
			if ($clone_if != $if) {
2699
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2700
				if ( !empty($friendly_if)
2701
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2702
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2703
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2704
				}
2705
			}
2706
		}
2707
	}
2708

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

    
2713
	/* configure wireless */
2714
	$wlcmd_args = implode(" ", $wlcmd);
2715
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2716

    
2717

    
2718
	sleep(1);
2719
	/* execute hostapd and wpa_supplicant if required in shell */
2720
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2721

    
2722
	return 0;
2723

    
2724
}
2725

    
2726
function kill_hostapd($interface) {
2727
	global $g;
2728

    
2729
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2730
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2731
}
2732

    
2733
function kill_wpasupplicant($interface) {
2734
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2735
}
2736

    
2737
function find_dhclient_process($interface) {
2738
	if ($interface)
2739
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2740
	else
2741
		$pid = 0;
2742

    
2743
	return intval($pid);
2744
}
2745

    
2746
function find_dhcp6c_process($interface) {
2747
	global $g;
2748

    
2749
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid"))
2750
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2751
	else
2752
		return(false);
2753

    
2754
	return intval($pid);
2755
}
2756

    
2757
function interface_vlan_mtu_configured($realhwif, $mtu) {
2758
	global $config;
2759

    
2760
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
2761
		foreach ($config['vlans']['vlan'] as $vlan) {
2762
			if ($vlan['if'] != $realhwif)
2763
				continue;
2764
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2765
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
2766
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2767
					$mtu = $portmtu;
2768
			}
2769
		}
2770
	}
2771

    
2772
	return $mtu;
2773
}
2774

    
2775
function interface_virtual_create($interface) {
2776
	global $config;
2777

    
2778
	if (strstr($interface, "_vlan")) {
2779
		interfaces_vlan_configure($vlan);
2780
	} else if (substr($interface, 0, 3) == "gre") {
2781
		interfaces_gre_configure(0, $interface);
2782
	} else if (substr($interface, 0, 3) == "gif") {
2783
		interfaces_gif_configure(0, $interface);
2784
	} else if (substr($interface, 0, 5) == "ovpns") {
2785
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
2786
			foreach ($config['openvpn']['openvpn-server'] as $server) {
2787
				if ($interface == "ovpns{$server['vpnid']}") {
2788
					if (!function_exists('openvpn_resync'))
2789
						require_once('openvpn.inc');
2790
					log_error("OpenVPN: Resync server {$server['description']}");
2791
					openvpn_resync('server', $server);
2792
				}
2793
			}
2794
			unset($server);
2795
		}
2796
	} else if (substr($interface, 0, 5) == "ovpnc") {
2797
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
2798
			foreach ($config['openvpn']['openvpn-client'] as $client) {
2799
				if ($interface == "ovpnc{$client['vpnid']}") {
2800
					if (!function_exists('openvpn_resync'))
2801
						require_once('openvpn.inc');
2802
					log_error("OpenVPN: Resync server {$client['description']}");
2803
					openvpn_resync('client', $client);
2804
				}
2805
			}
2806
			unset($client);
2807
		}
2808
	} else if (substr($interface, 0, 4) == "lagg") {
2809
		interfaces_lagg_configure($interface);
2810
	} else if (substr($interface, 0, 6) == "bridge") {
2811
		interfaces_bridge_configure(0, $interface);
2812
	}
2813
}
2814

    
2815
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2816
	global $config;
2817

    
2818
	if (!is_array($vlanifs))
2819
		return;
2820

    
2821
	/* All vlans need to use the same mtu value as their parent. */
2822
	foreach ($vlanifs as $vlan) {
2823
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2824
		if (!empty($assignedport)) {
2825
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
2826
				/*
2827
				* XXX: This is really never going to happen just keep the code for safety and readbility.
2828
				* It never happens since interface_vlan_mtu_configured finds the biggest mtu on vlans.
2829
				* Also if it has a lower mtu configured just respect user choice.
2830
				*/
2831
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2832
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2833
			} else {
2834
				if (get_interface_mtu($vlan['vlanif']) != $mtu)
2835
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2836
			}
2837
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2838
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
2839
	}
2840
}
2841

    
2842
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2843
	global $config, $g;
2844
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2845
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2846

    
2847
	$wancfg = $config['interfaces'][$interface];
2848

    
2849
	if (!isset($wancfg['enable']))
2850
		return;
2851

    
2852
	$realif = get_real_interface($interface);
2853
	$realhwif_array = get_parent_interface($interface);
2854
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2855
	$realhwif = $realhwif_array[0];
2856

    
2857
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2858
		/* remove all IPv4 and IPv6 addresses */
2859
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2860
		if (is_array($tmpifaces)) {
2861
			foreach ($tmpifaces as $tmpiface) {
2862
				if (strstr($tmpiface, ":"))
2863
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2864
				else
2865
					pfSense_interface_deladdress($realif, $tmpiface);
2866
			}
2867
		}
2868

    
2869
		/* only bring down the interface when both v4 and v6 are set to NONE */
2870
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6']))
2871
			interface_bring_down($interface);
2872
	}
2873

    
2874
	$interface_to_check = $realif;
2875
	switch ($wancfg['ipaddr']) {
2876
	case 'pppoe':
2877
	case 'l2tp':
2878
	case 'pptp':
2879
	case 'ppp':
2880
		$interface_to_check = $realhwif;
2881
		break;
2882
	}
2883

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

    
2888
	/* Disable Accepting router advertisements unless specifically requested */
2889
	if ($g['debug'])
2890
		log_error("Deny router advertisements for interface {$interface}");
2891
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2892

    
2893
	/* wireless configuration? */
2894
	if (is_array($wancfg['wireless']))
2895
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2896

    
2897
	$mac = get_interface_mac($realhwif);
2898
	/*
2899
	 * Don't try to reapply the spoofed MAC if it's already applied.
2900
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2901
	 * the interface config again, which attempts to spoof the MAC again,
2902
	 * which cycles the link again...
2903
	 */
2904
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
2905
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2906
			" link " . escapeshellarg($wancfg['spoofmac']));
2907

    
2908
		/*
2909
		 * All vlans need to spoof their parent mac address, too.  see
2910
		 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2911
		 */
2912
		if (is_array($config['vlans']['vlan'])) {
2913
			foreach ($config['vlans']['vlan'] as $vlan) {
2914
				if ($vlan['if'] == $realhwif)
2915
					mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2916
					" link " . escapeshellarg($wancfg['spoofmac']));
2917
			}
2918
		}
2919
	}  else {
2920

    
2921
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2922
			/*   this is not a valid mac address.  generate a
2923
			 *   temporary mac address so the machine can get online.
2924
			 */
2925
			echo gettext("Generating new MAC address.");
2926
			$random_mac = generate_random_mac_address();
2927
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2928
				" link " . escapeshellarg($random_mac));
2929
			$wancfg['spoofmac'] = $random_mac;
2930
			write_config();
2931
			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");
2932
		}
2933
	}
2934

    
2935
	/* media */
2936
	if ($wancfg['media'] || $wancfg['mediaopt']) {
2937
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2938
		if ($wancfg['media'])
2939
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2940
		if ($wancfg['mediaopt'])
2941
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2942
		mwexec($cmd);
2943
	}
2944
	$options = pfSense_get_interface_addresses($realhwif);
2945

    
2946
	/* skip vlans for checksumming and polling */
2947
	if (!stristr($realif, "_vlan") && is_array($options)) {
2948
		$flags_on = 0;
2949
		$flags_off = 0;
2950
		if(isset($config['system']['disablechecksumoffloading'])) {
2951
			if (isset($options['encaps']['txcsum']))
2952
				$flags_off |= IFCAP_TXCSUM;
2953
			if (isset($options['encaps']['rxcsum']))
2954
				$flags_off |= IFCAP_RXCSUM;
2955
		} else {
2956
			if (isset($options['caps']['txcsum']))
2957
				$flags_on |= IFCAP_TXCSUM;
2958
			if (isset($options['caps']['rxcsum']))
2959
				$flags_on |= IFCAP_RXCSUM;
2960
		}
2961

    
2962
		if(isset($config['system']['disablesegmentationoffloading']))
2963
			$flags_off |= IFCAP_TSO;
2964
		else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6']))
2965
			$flags_on |= IFCAP_TSO;
2966

    
2967
		if(isset($config['system']['disablelargereceiveoffloading']))
2968
			$flags_off |= IFCAP_LRO;
2969
		else if (isset($options['caps']['lro']))
2970
			$flags_on |= IFCAP_LRO;
2971

    
2972
		/* if the NIC supports polling *AND* it is enabled in the GUI */
2973
		if (!isset($config['system']['polling']))
2974
			$flags_off |= IFCAP_POLLING;
2975
		else if (isset($options['caps']['polling']))
2976
			$flags_on |= IFCAP_POLLING;
2977

    
2978
		pfSense_interface_capabilities($realhwif, -$flags_off);
2979
		pfSense_interface_capabilities($realhwif, $flags_on);
2980
	}
2981

    
2982
	/* invalidate interface/ip/sn cache */
2983
	get_interface_arr(true);
2984
	unset($interface_ip_arr_cache[$realif]);
2985
	unset($interface_sn_arr_cache[$realif]);
2986
	unset($interface_ipv6_arr_cache[$realif]);
2987
	unset($interface_snv6_arr_cache[$realif]);
2988

    
2989
	$tunnelif = substr($realif, 0, 3);
2990
	switch ($wancfg['ipaddr']) {
2991
	case 'dhcp':
2992
		interface_dhcp_configure($interface);
2993
		break;
2994
	case 'pppoe':
2995
	case 'l2tp':
2996
	case 'pptp':
2997
	case 'ppp':
2998
		interface_ppps_configure($interface);
2999
		break;
3000
	default:
3001
		/* XXX: Kludge for now related to #3280 */
3002
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3003
			if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "")
3004
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3005
		}
3006
		break;
3007
	}
3008

    
3009
	switch ($wancfg['ipaddrv6']) {
3010
	case 'slaac':
3011
	case 'dhcp6':
3012
		interface_dhcpv6_configure($interface, $wancfg);
3013
		break;
3014
	case '6rd':
3015
		interface_6rd_configure($interface, $wancfg);
3016
		break;
3017
	case '6to4':
3018
		interface_6to4_configure($interface, $wancfg);
3019
		break;
3020
	case 'track6':
3021
		interface_track6_configure($interface, $wancfg);
3022
		break;
3023
	default:
3024
		/* XXX: Kludge for now related to #3280 */
3025
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3026
			if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3027
				//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3028
				// FIXME: Add IPv6 Support to the pfSense module
3029
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3030
			}
3031
		}
3032
		break;
3033
	}
3034

    
3035
	if (!empty($wancfg['mtu'])) {
3036
		if (stristr($realif, "_vlan")) {
3037
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3038
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
3039
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3040
			else
3041
				$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
3042

    
3043
			if ($wancfg['mtu'] > $parentmtu) {
3044
				if (get_interface_mtu($realhwif) != $wancfg['mtu'])
3045
					pfSense_interface_mtu($realhwif, $wancfg['mtu']);
3046

    
3047
				/* All vlans need to use the same mtu value as their parent. */
3048
				interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $wancfg['mtu']);
3049
			} else
3050
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3051
		} else {
3052
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3053
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3054

    
3055
			/* This case is needed when the parent of vlans is being configured */
3056
			interface_vlan_adapt_mtu(link_interface_to_vlans($realif), $wancfg['mtu']);
3057
		}
3058
		/* XXX: What about gre/gif/lagg/.. ? */
3059
	}
3060

    
3061
	if (does_interface_exist($wancfg['if']))
3062
		interfaces_bring_up($wancfg['if']);
3063

    
3064
	interface_netgraph_needed($interface);
3065

    
3066
	if (!$g['booting']) {
3067
		link_interface_to_vips($interface, "update");
3068

    
3069
		unset($gre);
3070
		$gre = link_interface_to_gre($interface);
3071
		if (!empty($gre))
3072
			array_walk($gre, 'interface_gre_configure');
3073

    
3074
		unset($gif);
3075
		$gif = link_interface_to_gif($interface);
3076
		if (!empty($gif))
3077
			array_walk($gif, 'interface_gif_configure');
3078

    
3079
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3080
			unset($bridgetmp);
3081
			$bridgetmp = link_interface_to_bridge($interface);
3082
			if (!empty($bridgetmp))
3083
				interface_bridge_add_member($bridgetmp, $realif);
3084
		}
3085

    
3086
		$grouptmp = link_interface_to_group($interface);
3087
		if (!empty($grouptmp))
3088
			array_walk($grouptmp, 'interface_group_add_member');
3089

    
3090
		if ($interface == "lan")
3091
			/* make new hosts file */
3092
			system_hosts_generate();
3093

    
3094
		if ($reloadall == true) {
3095

    
3096
			/* reconfigure static routes (kernel may have deleted them) */
3097
			system_routing_configure($interface);
3098

    
3099
			/* reload ipsec tunnels */
3100
			vpn_ipsec_configure();
3101

    
3102
			/* restart dnsmasq */
3103
			services_dnsmasq_configure();
3104

    
3105
			/* update dyndns */
3106
			send_event("service reload dyndns {$interface}");
3107

    
3108
			/* XXX: which CPZONE? Needed? */
3109
			/* reload captive portal */
3110
			captiveportal_init_rules();
3111
		}
3112
	}
3113

    
3114
	interfaces_staticarp_configure($interface);
3115
	return 0;
3116
}
3117

    
3118
function interface_track6_configure($interface = "lan", $wancfg) {
3119
	global $config, $g;
3120

    
3121
	if (!is_array($wancfg))
3122
		return;
3123

    
3124
	if (!isset($wancfg['enable']))
3125
		return;
3126

    
3127
	/* If the interface is not configured via another, exit */
3128
	if (empty($wancfg['track6-interface']))
3129
		return;
3130

    
3131
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3132
	$realif = get_real_interface($interface);
3133
	$linklocal = find_interface_ipv6_ll($realif);
3134
	if (!empty($linklocal))
3135
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3136
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3137
	/* XXX: Probably should remove? */
3138
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3139

    
3140
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3141
	if (!isset($trackcfg['enable'])) {
3142
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3143
		return;
3144
	}
3145

    
3146
	switch($trackcfg['ipaddrv6']) {
3147
	case "6to4":
3148
		if ($g['debug'])
3149
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3150
		interface_track6_6to4_configure($interface, $wancfg);
3151
		break;
3152
	case "6rd":
3153
		if ($g['debug'])
3154
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3155
		interface_track6_6rd_configure($interface, $wancfg);
3156
		break;
3157
	}
3158

    
3159
	if (!$g['booting']) {
3160
		if (!function_exists('services_dhcpd_configure'))
3161
			require_once("services.inc");
3162

    
3163
		services_dhcpd_configure("inet6");
3164
	}
3165

    
3166
	return 0;
3167
}
3168

    
3169
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3170
	global $config, $g;
3171
	global $interface_ipv6_arr_cache;
3172
	global $interface_snv6_arr_cache;
3173

    
3174
	if (!is_array($lancfg))
3175
		return;
3176

    
3177
	/* If the interface is not configured via another, exit */
3178
	if (empty($lancfg['track6-interface']))
3179
		return;
3180

    
3181
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3182
	if (empty($wancfg)) {
3183
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3184
		return;
3185
	}
3186

    
3187
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3188
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3189
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3190
		return;
3191
	}
3192
	$hexwanv4 = return_hex_ipv4($ip4address);
3193

    
3194
	/* create the long prefix notation for math, save the prefix length */
3195
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3196
	$rd6prefixlen = $rd6prefix[1];
3197
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3198

    
3199
	/* binary presentation of the prefix for all 128 bits. */
3200
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3201

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

    
3207
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3208
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3209
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3210
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3211
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3212
	/* fill the rest out with zeros */
3213
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);;
3214

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

    
3218
	$lanif = get_real_interface($interface);
3219
	$oip = find_interface_ipv6($lanif);
3220
	if (is_ipaddrv6($oip))
3221
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3222
	unset($interface_ipv6_arr_cache[$lanif]);
3223
	unset($interface_snv6_arr_cache[$lanif]);
3224
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3225
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3226

    
3227
	return 0;
3228
}
3229

    
3230
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3231
	global $config, $g;
3232
	global $interface_ipv6_arr_cache;
3233
	global $interface_snv6_arr_cache;
3234

    
3235
	if (!is_array($lancfg))
3236
		return;
3237

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

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

    
3248
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3249
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3250
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3251
		return;
3252
	}
3253
	$hexwanv4 = return_hex_ipv4($ip4address);
3254

    
3255
	/* create the long prefix notation for math, save the prefix length */
3256
	$sixto4prefix = "2002::";
3257
	$sixto4prefixlen = 16;
3258
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3259

    
3260
	/* binary presentation of the prefix for all 128 bits. */
3261
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3262

    
3263
	/* just save the left prefix length bits */
3264
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3265
	/* add the v4 address */
3266
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3267
	/* add the custom prefix id */
3268
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3269
	/* fill the rest out with zeros */
3270
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);;
3271

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

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

    
3284
	return 0;
3285
}
3286

    
3287
function interface_6rd_configure($interface = "wan", $wancfg) {
3288
	global $config, $g;
3289

    
3290
	/* because this is a tunnel interface we can only function
3291
	 *	with a public IPv4 address on the interface */
3292

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

    
3296
	$wanif = get_real_interface($interface);
3297
	$ip4address = find_interface_ip($wanif);
3298
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3299
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3300
		return false;
3301
	}
3302
	$hexwanv4 = return_hex_ipv4($ip4address);
3303

    
3304
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3305
		$wancfg['prefix-6rd-v4plen'] = 0;
3306

    
3307
	/* create the long prefix notation for math, save the prefix length */
3308
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3309
	$rd6prefixlen = $rd6prefix[1];
3310
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3311

    
3312
	/* binary presentation of the prefix for all 128 bits. */
3313
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3314

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

    
3322
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3323
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3324

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

    
3327
	/* XXX: need to extend to support variable prefix size for v4 */
3328
	if (!is_module_loaded("if_stf"))
3329
		mwexec("/sbin/kldload if_stf.ko");
3330
	$stfiface = "{$interface}_stf";
3331
	if (does_interface_exist($stfiface))
3332
		pfSense_interface_destroy($stfiface);
3333
	$tmpstfiface = pfSense_interface_create("stf");
3334
	pfSense_interface_rename($tmpstfiface, $stfiface);
3335
	pfSense_interface_flags($stfiface, IFF_LINK2);
3336
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3337
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3338
	if ($wancfg['prefix-6rd-v4plen'] > 0 && $wancfg['prefix-6rd-v4plen'] < 32)
3339
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/{$wancfg['prefix-6rd-v4plen']}");
3340
	if ($g['debug'])
3341
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3342

    
3343
	/* write out a default router file */
3344
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3345
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3346

    
3347
	$ip4gateway = get_interface_gateway($interface);
3348
	if (is_ipaddrv4($ip4gateway))
3349
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3350

    
3351
	/* configure dependent interfaces */
3352
	if (!$g['booting'])
3353
		link_interface_to_track6($interface, "update");
3354

    
3355
	return 0;
3356
}
3357

    
3358
function interface_6to4_configure($interface = "wan", $wancfg){
3359
	global $config, $g;
3360

    
3361
	/* because this is a tunnel interface we can only function
3362
	 *	with a public IPv4 address on the interface */
3363

    
3364
	if (!is_array($wancfg))
3365
		return;
3366

    
3367
	$wanif = get_real_interface($interface);
3368
	$ip4address = find_interface_ip($wanif);
3369
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3370
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3371
		return false;
3372
	}
3373

    
3374
	/* create the long prefix notation for math, save the prefix length */
3375
	$stfprefixlen = 16;
3376
	$stfprefix = Net_IPv6::uncompress("2002::");
3377
	$stfarr = explode(":", $stfprefix);
3378
	$v4prefixlen = "0";
3379

    
3380
	/* we need the hex form of the interface IPv4 address */
3381
	$ip4arr = explode(".", $ip4address);
3382
	$hexwanv4 = "";
3383
	foreach($ip4arr as $octet)
3384
		$hexwanv4 .= sprintf("%02x", $octet);
3385

    
3386
	/* we need the hex form of the broker IPv4 address */
3387
	$ip4arr = explode(".", "192.88.99.1");
3388
	$hexbrv4 = "";
3389
	foreach($ip4arr as $octet)
3390
		$hexbrv4 .= sprintf("%02x", $octet);
3391

    
3392
	/* binary presentation of the prefix for all 128 bits. */
3393
	$stfprefixbin = "";
3394
	foreach($stfarr as $element) {
3395
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3396
	}
3397
	/* just save the left prefix length bits */
3398
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3399

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

    
3404
	/* for the local subnet too. */
3405
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3406
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);;
3407

    
3408
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3409
	$stfbrarr = array();
3410
	$stfbrbinarr = array();
3411
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3412
	foreach($stfbrbinarr as $bin)
3413
		$stfbrarr[] = dechex(bindec($bin));
3414
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3415

    
3416
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3417
	$stflanarr = array();
3418
	$stflanbinarr = array();
3419
	$stflanbinarr = str_split($stflanbin, 16);
3420
	foreach($stflanbinarr as $bin)
3421
		$stflanarr[] = dechex(bindec($bin));
3422
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3423
	$stflanarr[7] = 1;
3424
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3425

    
3426
	/* setup the stf interface */
3427
	if (!is_module_loaded("if_stf"))
3428
		mwexec("/sbin/kldload if_stf.ko");
3429
	$stfiface = "{$interface}_stf";
3430
	if (does_interface_exist($stfiface))
3431
		pfSense_interface_destroy($stfiface);
3432
	$tmpstfiface = pfSense_interface_create("stf");
3433
	pfSense_interface_rename($tmpstfiface, $stfiface);
3434
	pfSense_interface_flags($stfiface, IFF_LINK2);
3435
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3436

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

    
3440
	/* write out a default router file */
3441
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3442
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3443

    
3444
	$ip4gateway = get_interface_gateway($interface);
3445
	if (is_ipaddrv4($ip4gateway))
3446
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3447

    
3448
	if (!$g['booting'])
3449
		link_interface_to_track6($interface, "update");
3450

    
3451
	return 0;
3452
}
3453

    
3454
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3455
	global $config, $g;
3456

    
3457
	if (!is_array($wancfg))
3458
		return;
3459

    
3460
	$wanif = get_real_interface($interface, "inet6");
3461
	$dhcp6cconf = "";
3462
	$dhcp6cconf .= "interface {$wanif} {\n";
3463

    
3464
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3465
	if($wancfg['ipaddrv6'] == "slaac") {
3466
		$dhcp6cconf .= "	information-only;\n";
3467
		$dhcp6cconf .= "	request domain-name-servers;\n";
3468
		$dhcp6cconf .= "	request domain-name;\n";
3469
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3470
		$dhcp6cconf .= "};\n";
3471
	} else {
3472
		/* skip address request if this is set */
3473
		if(!isset($wancfg['dhcp6prefixonly']))
3474
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3475
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3476
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3477

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

    
3482
		$dhcp6cconf .= "};\n";
3483

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

    
3487
		if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3488
			/* Setup the prefix delegation */
3489
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3490
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3491
			if (isset($wancfg['dhcp6-ia-pd-send-hint']))
3492
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3493
			$iflist = link_interface_to_track6($interface);
3494
			foreach ($iflist as $friendly => $ifcfg) {
3495
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3496
					if ($g['debug'])
3497
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3498
					$realif = get_real_interface($friendly);
3499
					$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3500
					$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3501
					$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3502
					$dhcp6cconf .= "	};\n";
3503
				}
3504
			}
3505
			unset($preflen, $iflist, $ifcfg);
3506
			$dhcp6cconf .= "};\n";
3507
		}
3508
	}
3509

    
3510
	// DHCP6 Config File Advanced
3511
	if ($wancfg['adv_dhcp6_config_advanced']) { $dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif); }
3512

    
3513
	// DHCP6 Config File Override
3514
	if ($wancfg['adv_dhcp6_config_file_override']) { $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif); }
3515

    
3516
	/* wide-dhcp6c works for now. */
3517
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3518
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3519
		unset($dhcp6cconf);
3520
		return 1;
3521
	}
3522
	unset($dhcp6cconf);
3523

    
3524
	$dhcp6cscript = "#!/bin/sh\n";
3525
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3526
	$dhcp6cscript .= "\$dmips = \${new_domain_name_servers}\n";
3527
	$dhcp6cscript .= "\$dmnames = \${new_domain_name}\n";
3528
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\$dmnames&dmips=\$dmips\"\n";
3529
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3530
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3531
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3532
		unset($dhcp6cscript);
3533
		return 1;
3534
	}
3535
	unset($dhcp6cscript);
3536
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3537

    
3538
	$rtsoldscript = "#!/bin/sh\n";
3539
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3540
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3541
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3542
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3543
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3544
	$rtsoldscript .= "\t/bin/sleep 1\n";
3545
	$rtsoldscript .= "fi\n";
3546
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3547
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\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']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3550
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3551
		unset($rtsoldscript);
3552
		return 1;
3553
	}
3554
	unset($rtsoldscript);
3555
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3556

    
3557
	/* accept router advertisements for this interface */
3558
	mwexec("/sbin/sysctl -w net.inet6.ip6.accept_rtadv=1");
3559
	log_error("Accept router advertisements on interface {$wanif} ");
3560
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3561

    
3562
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3563
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3564
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3565
		sleep(2);
3566
	}
3567
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3568

    
3569
	/* NOTE: will be called from rtsold invoked script
3570
	 * link_interface_to_track6($interface, "update");
3571
	 */
3572

    
3573
	return 0;
3574
}
3575

    
3576
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3577
	global $g;
3578

    
3579
	$send_options = "";
3580
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3581
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_send_options']);
3582
		foreach ($options as $option) {
3583
			$send_options .= "\tsend " . trim($option) . ";\n";
3584
		}
3585
	}
3586

    
3587
	$request_options = "";
3588
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3589
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_request_options']);
3590
		foreach ($options as $option) {
3591
			$request_options .= "\trequest " . trim($option) . ";\n";
3592
		}
3593
	}
3594

    
3595
	$information_only = "";
3596
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') 
3597
		$information_only = "\tinformation-only;\n";
3598

    
3599
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3600
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '')
3601
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3602

    
3603
	$interface_statement  = "interface";
3604
	$interface_statement .= " {$wanif}";
3605
	$interface_statement .= " {\n";
3606
	$interface_statement .= "$send_options";
3607
	$interface_statement .= "$request_options";
3608
	$interface_statement .= "$information_only";
3609
	$interface_statement .= "$script";
3610
	$interface_statement .= "};\n";
3611

    
3612
	$id_assoc_statement_address = "";
3613
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3614
		$id_assoc_statement_address .= "id-assoc";
3615
		$id_assoc_statement_address .= " na";
3616
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) 
3617
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3618
		$id_assoc_statement_address .= " { ";
3619

    
3620
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') && 
3621
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) || 
3622
			 ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity')) ) {
3623
			$id_assoc_statement_address .= "\n\taddress";
3624
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3625
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3626
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) || 
3627
							($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity') ) 
3628
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3629
			$id_assoc_statement_address .= ";\n";
3630
		}
3631

    
3632
		$id_assoc_statement_address  .= "};\n";
3633
	}
3634

    
3635
	$id_assoc_statement_prefix = "";
3636
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3637
		$id_assoc_statement_prefix .= "id-assoc";
3638
		$id_assoc_statement_prefix .= " pd";
3639
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) 
3640
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3641
		$id_assoc_statement_prefix .= " { ";
3642

    
3643
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') && 
3644
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) || 
3645
			 ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity')) ) {
3646
			$id_assoc_statement_prefix .= "\n\tprefix";
3647
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3648
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3649
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) || 
3650
						  ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity') ) 
3651
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3652
			$id_assoc_statement_prefix .= ";";
3653
		}
3654

    
3655
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3656
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3657
			$id_assoc_statement_prefix .= " {$wanif}";
3658
			$id_assoc_statement_prefix .= " {\n";
3659
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3660
			if ( ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) && 
3661
				 ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128) ) 
3662
				 $id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3663
			$id_assoc_statement_prefix .= "\t};";
3664
		}
3665

    
3666
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') || 
3667
			 (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) ) { 
3668
			$id_assoc_statement_prefix .= "\n";
3669
		}
3670

    
3671
		$id_assoc_statement_prefix  .= "};\n";
3672
	}
3673

    
3674
	$authentication_statement = "";
3675
	if ( ($wancfg['adv_dhcp6_authentication_statement_authname'] != '') && 
3676
		 ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed') ) {
3677
		$authentication_statement .= "authentication";
3678
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
3679
		$authentication_statement .= " {\n";
3680
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
3681
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) 
3682
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
3683
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') 
3684
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
3685
		$authentication_statement .= "};\n";
3686
	}
3687

    
3688
	$key_info_statement = "";
3689
	if ( ($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') && 
3690
		 ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') && 
3691
		 (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) && 
3692
		 ($wancfg['adv_dhcp6_key_info_statement_secret'] != '') ) {
3693
		$key_info_statement .= "keyinfo";
3694
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
3695
		$key_info_statement .= " {\n";
3696
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
3697
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
3698
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
3699
		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'])) 
3700
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
3701
		$key_info_statement .= "};\n";
3702
	}
3703

    
3704
	$dhcp6cconf  = $interface_statement;
3705
	$dhcp6cconf .= $id_assoc_statement_address;
3706
	$dhcp6cconf .= $id_assoc_statement_prefix;
3707
	$dhcp6cconf .= $authentication_statement;
3708
	$dhcp6cconf .= $key_info_statement;
3709

    
3710
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3711

    
3712
	return $dhcp6cconf;
3713
}
3714

    
3715

    
3716
function DHCP6_Config_File_Override($wancfg, $wanif) {
3717

    
3718
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
3719
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3720

    
3721
	return $dhcp6cconf;
3722
}
3723

    
3724

    
3725
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
3726

    
3727
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3728

    
3729
	return $dhcp6cconf;
3730
}
3731

    
3732

    
3733
function interface_dhcp_configure($interface = "wan") {
3734
	global $config, $g;
3735

    
3736
	$wancfg = $config['interfaces'][$interface];
3737
	$wanif = $wancfg['if'];
3738
	if (empty($wancfg))
3739
		$wancfg = array();
3740

    
3741
	/* generate dhclient_wan.conf */
3742
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3743
	if (!$fd) {
3744
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3745
		return 1;
3746
	}
3747

    
3748
	if ($wancfg['dhcphostname']) {
3749
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3750
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3751
	} else {
3752
		$dhclientconf_hostname = "";
3753
	}
3754

    
3755
	$wanif = get_real_interface($interface);
3756
	if (empty($wanif)) {
3757
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3758
		return 0;
3759
	}
3760
	$dhclientconf = "";
3761

    
3762
	$dhclientconf .= <<<EOD
3763
interface "{$wanif}" {
3764
timeout 60;
3765
retry 15;
3766
select-timeout 0;
3767
initial-interval 1;
3768
	{$dhclientconf_hostname}
3769
	script "/sbin/dhclient-script";
3770
EOD;
3771

    
3772
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3773
	$dhclientconf .= <<<EOD
3774

    
3775
	reject {$wancfg['dhcprejectfrom']};
3776
EOD;
3777
}
3778
	$dhclientconf .= <<<EOD
3779

    
3780
}
3781

    
3782
EOD;
3783

    
3784
	// DHCP Config File Advanced
3785
	if ($wancfg['adv_dhcp_config_advanced']) { $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif); }
3786

    
3787
if(is_ipaddr($wancfg['alias-address'])) {
3788
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3789
	$dhclientconf .= <<<EOD
3790
alias {
3791
	interface  "{$wanif}";
3792
	fixed-address {$wancfg['alias-address']};
3793
	option subnet-mask {$subnetmask};
3794
}
3795

    
3796
EOD;
3797
}
3798

    
3799
	// DHCP Config File Override
3800
	if ($wancfg['adv_dhcp_config_file_override']) { $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif); }
3801

    
3802
	fwrite($fd, $dhclientconf);
3803
	fclose($fd);
3804

    
3805
	/* bring wan interface up before starting dhclient */
3806
	if($wanif)
3807
		interfaces_bring_up($wanif);
3808
	else
3809
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3810

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

    
3814
	return 0;
3815
}
3816

    
3817
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3818

    
3819
	$hostname = "";
3820
	if ($wancfg['dhcphostname'] != '') {
3821
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3822
	}
3823

    
3824
	/* DHCP Protocol Timings */
3825
	$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");
3826
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
3827
		$pt_variable = "{$Protocol_Timing}";
3828
		${$pt_variable} = "";
3829
		if ($wancfg[$Protocol_Timing] != "") {
3830
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
3831
		}
3832
	}
3833

    
3834
	$send_options = "";
3835
	if ($wancfg['adv_dhcp_send_options'] != '') {
3836
		$options = split(",", $wancfg['adv_dhcp_send_options']);
3837
		foreach ($options as $option) {
3838
			$send_options .= "\tsend " . trim($option) . ";\n";
3839
		}
3840
	}
3841

    
3842
	$request_options = "";
3843
	if ($wancfg['adv_dhcp_request_options'] != '') {
3844
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
3845
	}
3846

    
3847
	$required_options = "";
3848
	if ($wancfg['adv_dhcp_required_options'] != '') {
3849
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
3850
	}
3851

    
3852
	$option_modifiers = "";
3853
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
3854
		$modifiers = split(",", $wancfg['adv_dhcp_option_modifiers']);
3855
		foreach ($modifiers as $modifier) {
3856
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
3857
		}
3858
	}
3859

    
3860
 	$dhclientconf  = "interface \"{$wanif}\" {\n";
3861
 	$dhclientconf .= "\n";
3862
 	$dhclientconf .= "# DHCP Protocol Timing Values\n";
3863
 	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
3864
 	$dhclientconf .= "{$adv_dhcp_pt_retry}";
3865
 	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
3866
 	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
3867
 	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
3868
 	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
3869
 	$dhclientconf .= "\n";
3870
 	$dhclientconf .= "# DHCP Protocol Options\n";
3871
 	$dhclientconf .= "{$hostname}";
3872
 	$dhclientconf .= "{$send_options}";
3873
 	$dhclientconf .= "{$request_options}";
3874
 	$dhclientconf .= "{$required_options}";
3875
 	$dhclientconf .= "{$option_modifiers}";
3876
 	$dhclientconf .= "\n";
3877
 	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
3878
 	$dhclientconf .= "}\n";
3879

    
3880
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3881

    
3882
	return $dhclientconf;
3883
}
3884

    
3885

    
3886
function DHCP_Config_File_Override($wancfg, $wanif) {
3887

    
3888
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
3889
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3890

    
3891
	return $dhclientconf;
3892
}
3893

    
3894

    
3895
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
3896

    
3897
	/* Apply Interface Substitutions */
3898
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
3899

    
3900
	/* Apply Hostname Substitutions */
3901
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
3902

    
3903
	/* Arrays of MAC Address Types, Cases, Delimiters */
3904
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
3905
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
3906
	$various_mac_cases      = array("U", "L");
3907
	$various_mac_delimiters = array("", " ", ":", "-", ".");
3908

    
3909
	/* Apply MAC Address Substitutions */
3910
	foreach ($various_mac_types as $various_mac_type) {
3911
		foreach ($various_mac_cases as $various_mac_case) {
3912
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
3913

    
3914
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
3915
				if ($res !== false) {
3916

    
3917
					/* Get MAC Address as ASCII String With Colon (:) Celimiters */
3918
					if ("$various_mac_case" == "U") $dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
3919
					if ("$various_mac_case" == "L") $dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
3920

    
3921
					if ("$various_mac_type" == "mac_addr_hex") {
3922
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
3923
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
3924
						$dhcpclientconf_mac_hex = "";
3925
						$delimiter = "";
3926
						for($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
3927
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
3928
							$delimiter = ":";
3929
						}
3930
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
3931
					}
3932

    
3933
					/* MAC Address Delimiter Substitutions */
3934
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
3935

    
3936
					/* Apply MAC Address Substitutions */
3937
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
3938
				}
3939
			}
3940
		}
3941
	}
3942

    
3943
	return $dhclientconf;
3944
}
3945

    
3946
function interfaces_group_setup() {
3947
	global $config;
3948

    
3949
	if (!is_array($config['ifgroups']['ifgroupentry']))
3950
		return;
3951

    
3952
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3953
		interface_group_setup($groupar);
3954

    
3955
	return;
3956
}
3957

    
3958
function interface_group_setup(&$groupname /* The parameter is an array */) {
3959
	global $config;
3960

    
3961
	if (!is_array($groupname))
3962
		return;
3963
	$members = explode(" ", $groupname['members']);
3964
	foreach($members as $ifs) {
3965
		$realif = get_real_interface($ifs);
3966
		if ($realif)
3967
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3968
	}
3969

    
3970
	return;
3971
}
3972

    
3973
function is_interface_group($if) {
3974
	global $config;
3975

    
3976
	if (is_array($config['ifgroups']['ifgroupentry']))
3977
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
3978
			if ($groupentry['ifname'] === $if)
3979
				return true;
3980
		}
3981

    
3982
	return false;
3983
}
3984

    
3985
function interface_group_add_member($interface, $groupname) {
3986
	$interface = get_real_interface($interface);
3987
	mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
3988
}
3989

    
3990
/* COMPAT Function */
3991
function convert_friendly_interface_to_real_interface_name($interface) {
3992
	return get_real_interface($interface);
3993
}
3994

    
3995
/* COMPAT Function */
3996
function get_real_wan_interface($interface = "wan") {
3997
	return get_real_interface($interface);
3998
}
3999

    
4000
/* COMPAT Function */
4001
function get_current_wan_address($interface = "wan") {
4002
	return get_interface_ip($interface);
4003
}
4004

    
4005
/*
4006
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4007
 */
4008
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
4009
	global $config;
4010

    
4011
	/* XXX: For speed reasons reference directly the interface array */
4012
	$ifdescrs = &$config['interfaces'];
4013
	//$ifdescrs = get_configured_interface_list(false, true);
4014

    
4015
	foreach ($ifdescrs as $if => $ifname) {
4016
		if ($if == $interface || $config['interfaces'][$if]['if'] == $interface)
4017
			return $if;
4018

    
4019
		if (get_real_interface($if) == $interface)
4020
			return $if;
4021

    
4022
		// XXX: This case doesn't work anymore (segfaults - recursion?) - should be replaced with something else or just removed.
4023
		//      Not to be replaced with get_real_interface - causes slow interface listings here because of recursion!
4024
		/*
4025
		$int = get_parent_interface($if);
4026
		if ($int[0] == $interface)
4027
			return $ifname;
4028
		*/
4029
	}
4030

    
4031
	return NULL;
4032
}
4033

    
4034
/* attempt to resolve interface to friendly descr */
4035
function convert_friendly_interface_to_friendly_descr($interface) {
4036
	global $config;
4037

    
4038
	switch ($interface) {
4039
	case "l2tp":
4040
		$ifdesc = "L2TP";
4041
		break;
4042
	case "pptp":
4043
		$ifdesc = "PPTP";
4044
		break;
4045
	case "pppoe":
4046
		$ifdesc = "PPPoE";
4047
		break;
4048
	case "openvpn":
4049
		$ifdesc = "OpenVPN";
4050
		break;
4051
	case "enc0":
4052
	case "ipsec":
4053
		$ifdesc = "IPsec";
4054
		break;
4055
	default:
4056
		if (isset($config['interfaces'][$interface])) {
4057
			if (empty($config['interfaces'][$interface]['descr']))
4058
				$ifdesc = strtoupper($interface);
4059
			else
4060
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4061
			break;
4062
		} else if (stristr($interface, "_vip")) {
4063
			if (is_array($config['virtualip']['vip'])) {
4064
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
4065
					if ($vip['mode'] == "carp")  {
4066
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4067
							return "{$vip['subnet']} - {$vip['descr']}";
4068
					}
4069
				}
4070
			}
4071
		} else {
4072
			/* if list */
4073
			$ifdescrs = get_configured_interface_with_descr(false, true);
4074
			foreach ($ifdescrs as $if => $ifname) {
4075
				if ($if == $interface || $ifname == $interface)
4076
					return $ifname;
4077
			}
4078
		}
4079
		break;
4080
	}
4081

    
4082
	return $ifdesc;
4083
}
4084

    
4085
function convert_real_interface_to_friendly_descr($interface) {
4086
	global $config;
4087

    
4088
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4089

    
4090
	if ($ifdesc) {
4091
		$iflist = get_configured_interface_with_descr(false, true);
4092
		return $iflist[$ifdesc];
4093
	}
4094

    
4095
	return $interface;
4096
}
4097

    
4098
/*
4099
 *  get_parent_interface($interface):
4100
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4101
 *				or virtual interface (i.e. vlan)
4102
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4103
 *			-- returns $interface passed in if $interface parent is not found
4104
 *			-- returns empty array if an invalid interface is passed
4105
 *	(Only handles ppps and vlans now.)
4106
 */
4107
function get_parent_interface($interface) {
4108
	global $config;
4109

    
4110
	$parents = array();
4111
	//Check that we got a valid interface passed
4112
	$realif = get_real_interface($interface);
4113
	if ($realif == NULL)
4114
		return $parents;
4115

    
4116
	// If we got a real interface, find it's friendly assigned name
4117
	if ($interface == $realif)
4118
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4119

    
4120
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4121
		$ifcfg = $config['interfaces'][$interface];
4122
		switch ($ifcfg['ipaddr']) {
4123
			case "ppp":
4124
			case "pppoe":
4125
			case "pptp":
4126
			case "l2tp":
4127
				if (empty($parents))
4128
					if (is_array($config['ppps']['ppp']))
4129
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4130
							if ($ifcfg['if'] == $ppp['if']) {
4131
								$ports = explode(',', $ppp['ports']);
4132
								foreach ($ports as $pid => $parent_if)
4133
									$parents[$pid] = get_real_interface($parent_if);
4134
								break;
4135
							}
4136
						}
4137
				break;
4138
			case "dhcp":
4139
			case "static":
4140
			default:
4141
				// Handle _vlans
4142
				if (stristr($realif,"_vlan"))
4143
					if (is_array($config['vlans']['vlan']))
4144
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
4145
							if ($ifcfg['if'] == $vlan['vlanif']){
4146
								$parents[0] = $vlan['if'];
4147
								break;
4148
							}
4149
				break;
4150
		}
4151
	}
4152

    
4153
	if (empty($parents))
4154
		$parents[0] = $realif;
4155

    
4156
	return $parents;
4157
}
4158

    
4159
function interface_is_wireless_clone($wlif) {
4160
	if(!stristr($wlif, "_wlan")) {
4161
		return false;
4162
	} else {
4163
		return true;
4164
	}
4165
}
4166

    
4167
function interface_get_wireless_base($wlif) {
4168
	if(!stristr($wlif, "_wlan")) {
4169
		return $wlif;
4170
	} else {
4171
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4172
	}
4173
}
4174

    
4175
function interface_get_wireless_clone($wlif) {
4176
	if(!stristr($wlif, "_wlan")) {
4177
		return $wlif . "_wlan0";
4178
	} else {
4179
		return $wlif;
4180
	}
4181
}
4182

    
4183
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4184
	global $config, $g;
4185

    
4186
	$wanif = NULL;
4187

    
4188
	switch ($interface) {
4189
	case "l2tp":
4190
		$wanif = "l2tp";
4191
		break;
4192
	case "pptp":
4193
		$wanif = "pptp";
4194
		break;
4195
	case "pppoe":
4196
		$wanif = "pppoe";
4197
		break;
4198
	case "openvpn":
4199
		$wanif = "openvpn";
4200
		break;
4201
	case "ipsec":
4202
	case "enc0":
4203
		$wanif = "enc0";
4204
		break;
4205
	case "ppp":
4206
		$wanif = "ppp";
4207
		break;
4208
	default:
4209
		// If a real interface was alread passed simply
4210
		// pass the real interface back.  This encourages
4211
		// the usage of this function in more cases so that
4212
		// we can combine logic for more flexibility.
4213
		if(does_interface_exist($interface, $flush)) {
4214
			$wanif = $interface;
4215
			break;
4216
		}
4217

    
4218
		if (empty($config['interfaces'][$interface]))
4219
			break;
4220

    
4221
		$cfg = &$config['interfaces'][$interface];
4222

    
4223
		if ($family == "inet6") {
4224
			switch ($cfg['ipaddrv6']) {
4225
			case "6rd":
4226
			case "6to4":
4227
				$wanif = "{$interface}_stf";
4228
				break;
4229
			case 'pppoe':
4230
			case 'ppp':
4231
			case 'l2tp':
4232
			case 'pptp':
4233
				if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4234
					$wanif = interface_get_wireless_clone($cfg['if']);
4235
				else
4236
					$wanif = $cfg['if'];
4237
				break;
4238
			default:
4239
				switch ($cfg['ipaddr']) {
4240
				case 'pppoe':
4241
				case 'ppp':
4242
				case 'l2tp':
4243
				case 'pptp':
4244
					if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false)
4245
						$wanif = $cfg['if'];
4246
					else {
4247
						$parents = get_parent_interface($interface);
4248
						if (!empty($parents[0]))
4249
							$wanif = $parents[0];
4250
						else
4251
							$wanif = $cfg['if'];
4252
					}
4253
					break;
4254
				default:
4255
					if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4256
						$wanif = interface_get_wireless_clone($cfg['if']);
4257
					else
4258
						$wanif = $cfg['if'];
4259
					break;
4260
				}
4261
				break;
4262
			}
4263
		} else {
4264
			// Wireless cloned NIC support (FreeBSD 8+)
4265
			// interface name format: $parentnic_wlanparentnic#
4266
			// example: ath0_wlan0
4267
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4268
				$wanif = interface_get_wireless_clone($cfg['if']);
4269
			else
4270
				$wanif = $cfg['if'];
4271
		}
4272
		break;
4273
	}
4274

    
4275
	return $wanif;
4276
}
4277

    
4278
/* Guess the physical interface by providing a IP address */
4279
function guess_interface_from_ip($ipaddress) {
4280
	if(! is_ipaddr($ipaddress)) {
4281
		return false;
4282
	}
4283
	if(is_ipaddrv4($ipaddress)) {
4284
		/* create a route table we can search */
4285
		exec("netstat -rnWf inet", $output, $ret);
4286
		foreach($output as $line) {
4287
			if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
4288
				$fields = preg_split("/[ ]+/", $line);
4289
				if(ip_in_subnet($ipaddress, $fields[0])) {
4290
					return $fields[6];
4291
				}
4292
			}
4293
		}
4294
	}
4295
	/* FIXME: This works from cursory testing, regexp might need fine tuning */
4296
	if(is_ipaddrv6($ipaddress)) {
4297
		/* create a route table we can search */
4298
		exec("netstat -rnWf inet6", $output, $ret);
4299
		foreach($output as $line) {
4300
			if(preg_match("/[0-9a-f]+[:]+[0-9a-f]+[:]+[\/][0-9]+/", $line)) {
4301
				$fields = preg_split("/[ ]+/", $line);
4302
				if(ip_in_subnet($ipaddress, $fields[0])) {
4303
					return $fields[6];
4304
				}
4305
			}
4306
		}
4307
	}
4308
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
4309
	if(empty($ret)) {
4310
		return false;
4311
	}
4312
	return $ret;
4313
}
4314

    
4315
/*
4316
 * find_ip_interface($ip): return the interface where an ip is defined
4317
 *   (or if $bits is specified, where an IP within the subnet is defined)
4318
 */
4319
function find_ip_interface($ip, $bits = null) {
4320
	if (!is_ipaddr($ip))
4321
		return false;
4322

    
4323
	$isv6ip = is_ipaddrv6($ip);
4324

    
4325
	/* if list */
4326
	$ifdescrs = get_configured_interface_list();
4327

    
4328
	foreach ($ifdescrs as $ifdescr => $ifname) {
4329
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4330
		if (is_null($ifip))
4331
			continue;
4332
		if (is_null($bits)) {
4333
			if ($ip == $ifip) {
4334
				$int = get_real_interface($ifname);
4335
				return $int;
4336
			}
4337
		}
4338
		else {
4339
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4340
				$int = get_real_interface($ifname);
4341
				return $int;
4342
			}
4343
		}
4344
	}
4345

    
4346
	return false;
4347
}
4348

    
4349
/*
4350
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4351
 *   (or if $bits is specified, where an IP within the subnet is found)
4352
 */
4353
function find_virtual_ip_alias($ip, $bits = null) {
4354
	global $config;
4355

    
4356
	if (!is_array($config['virtualip']['vip'])) {
4357
		return false;
4358
	}
4359
	if (!is_ipaddr($ip))
4360
		return false;
4361

    
4362
	$isv6ip = is_ipaddrv6($ip);
4363

    
4364
	foreach ($config['virtualip']['vip'] as $vip) {
4365
		if ($vip['mode'] === "ipalias") {
4366
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4367
				continue;
4368
			if (is_null($bits)) {
4369
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4370
					return $vip;
4371
				}
4372
			}
4373
			else {
4374
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4375
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4376
					return $vip;
4377
				}
4378
			}
4379
		}
4380
	}
4381
	return false;
4382
}
4383

    
4384
/*
4385
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4386
 */
4387
function find_number_of_created_carp_interfaces() {
4388
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4389
}
4390

    
4391
function get_all_carp_interfaces() {
4392
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
4393
	$ints = explode(" ", $ints);
4394
	return $ints;
4395
}
4396

    
4397
/*
4398
 * find_carp_interface($ip): return the carp interface where an ip is defined
4399
 */
4400
function find_carp_interface($ip) {
4401
	global $config;
4402
	if (is_array($config['virtualip']['vip'])) {
4403
		foreach ($config['virtualip']['vip'] as $vip) {
4404
			if ($vip['mode'] == "carp") {
4405
				if(is_ipaddrv4($ip)) {
4406
					$carp_ip = get_interface_ip($vip['interface']);
4407
				}
4408
				if(is_ipaddrv6($ip)) {
4409
					$carp_ip = get_interface_ipv6($vip['interface']);
4410
				}
4411
				exec("/sbin/ifconfig", $output, $return);
4412
				foreach($output as $line) {
4413
					$elements = preg_split("/[ ]+/i", $line);
4414
					if(strstr($elements[0], "vip"))
4415
						$curif = str_replace(":", "", $elements[0]);
4416
					if(stristr($line, $ip)) {
4417
						$if = $curif;
4418
						continue;
4419
					}
4420
				}
4421

    
4422
				if ($if)
4423
					return $if;
4424
			}
4425
		}
4426
	}
4427
}
4428

    
4429
function link_carp_interface_to_parent($interface) {
4430
	global $config;
4431

    
4432
	if (empty($interface))
4433
		return;
4434

    
4435
	$carp_ip = get_interface_ip($interface);
4436
	$carp_ipv6 = get_interface_ipv6($interface);
4437

    
4438
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4439
		return;
4440

    
4441
	/* if list */
4442
	$ifdescrs = get_configured_interface_list();
4443
	foreach ($ifdescrs as $ifdescr => $ifname) {
4444
		/* check IPv4 */
4445
		if(is_ipaddrv4($carp_ip)) {
4446
			$interfaceip = get_interface_ip($ifname);
4447
			$subnet_bits = get_interface_subnet($ifname);
4448
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4449
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4450
				return $ifname;
4451
		}
4452
		/* Check IPv6 */
4453
		if(is_ipaddrv6($carp_ipv6)) {
4454
			$interfaceipv6 = get_interface_ipv6($ifname);
4455
			$prefixlen = get_interface_subnetv6($ifname);
4456
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4457
				return $ifname;
4458
		}
4459
	}
4460
	return "";
4461
}
4462

    
4463

    
4464
/****f* interfaces/link_ip_to_carp_interface
4465
 * NAME
4466
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4467
 * INPUTS
4468
 *   $ip
4469
 * RESULT
4470
 *   $carp_ints
4471
 ******/
4472
function link_ip_to_carp_interface($ip) {
4473
	global $config;
4474

    
4475
	if (!is_ipaddr($ip))
4476
		return;
4477

    
4478
	$carp_ints = "";
4479
	if (is_array($config['virtualip']['vip'])) {
4480
		$first = 0;
4481
		$carp_int = array();
4482
		foreach ($config['virtualip']['vip'] as $vip) {
4483
			if ($vip['mode'] == "carp") {
4484
				$carp_ip = $vip['subnet'];
4485
				$carp_sn = $vip['subnet_bits'];
4486
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4487
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4488
					$carp_int[] = get_real_interface($vip['interface']);
4489
				}
4490
			}
4491
		}
4492
		if (!empty($carp_int))
4493
			$carp_ints = implode(" ", array_unique($carp_int));
4494
	}
4495

    
4496
	return $carp_ints;
4497
}
4498

    
4499
function link_interface_to_track6($int, $action = "") {
4500
	global $config;
4501

    
4502
	if (empty($int))
4503
		return;
4504

    
4505
	if (is_array($config['interfaces'])) {
4506
		$list = array();
4507
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4508
			if (!isset($ifcfg['enable']))
4509
				continue;
4510
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4511
				if ($action == "update")
4512
					interface_track6_configure($ifname, $ifcfg);
4513
				else if ($action == "")
4514
					$list[$ifname] = $ifcfg;
4515
			}
4516
		}
4517
		return $list;
4518
	}
4519
}
4520

    
4521
function link_interface_to_vlans($int, $action = "") {
4522
	global $config;
4523

    
4524
	if (empty($int))
4525
		return;
4526

    
4527
	if (is_array($config['vlans']['vlan'])) {
4528
		$ifaces = array();
4529
		foreach ($config['vlans']['vlan'] as $vlan) {
4530
			if ($int == $vlan['if']) {
4531
				if ($action == "update") {
4532
					interfaces_bring_up($int);
4533
				} else if ($action == "")
4534
					$ifaces[$vlan['tag']] = $vlan;
4535
			}
4536
		}
4537
		if (!empty($ifaces))
4538
			return $ifaces;
4539
	}
4540
}
4541

    
4542
function link_interface_to_vips($int, $action = "") {
4543
	global $config;
4544

    
4545
	if (is_array($config['virtualip']['vip'])) {
4546
		$result = array();
4547
		foreach ($config['virtualip']['vip'] as $vip) {
4548
			if ($int == $vip['interface']) {
4549
				if ($action == "update")
4550
					interfaces_vips_configure($int);
4551
				else
4552
					$result[] = $vip;
4553
			}
4554
		}
4555
		return $result;
4556
	}
4557
}
4558

    
4559
/****f* interfaces/link_interface_to_bridge
4560
 * NAME
4561
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4562
 * INPUTS
4563
 *   $ip
4564
 * RESULT
4565
 *   bridge[0-99]
4566
 ******/
4567
function link_interface_to_bridge($int) {
4568
	global $config;
4569

    
4570
	if (is_array($config['bridges']['bridged'])) {
4571
		foreach ($config['bridges']['bridged'] as $bridge) {
4572
			if (in_array($int, explode(',', $bridge['members'])))
4573
				return "{$bridge['bridgeif']}";
4574
		}
4575
	}
4576
}
4577

    
4578
function link_interface_to_group($int) {
4579
	global $config;
4580

    
4581
	$result = array();
4582

    
4583
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4584
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4585
			if (in_array($int, explode(" ", $group['members'])))
4586
				$result[$group['ifname']] = $int;
4587
		}
4588
	}
4589

    
4590
	return $result;
4591
}
4592

    
4593
function link_interface_to_gre($interface) {
4594
	global $config;
4595

    
4596
	$result = array();
4597

    
4598
	if (is_array($config['gres']['gre'])) {
4599
		foreach ($config['gres']['gre'] as $gre)
4600
			if($gre['if'] == $interface)
4601
				$result[] = $gre;
4602
	}
4603

    
4604
	return $result;
4605
}
4606

    
4607
function link_interface_to_gif($interface) {
4608
	global $config;
4609

    
4610
	$result = array();
4611

    
4612
	if (is_array($config['gifs']['gif'])) {
4613
		foreach ($config['gifs']['gif'] as $gif)
4614
			if($gif['if'] == $interface)
4615
				$result[] = $gif;
4616
	}
4617

    
4618
	return $result;
4619
}
4620

    
4621
/*
4622
 * find_interface_ip($interface): return the interface ip (first found)
4623
 */
4624
function find_interface_ip($interface, $flush = false) {
4625
	global $interface_ip_arr_cache;
4626
	global $interface_sn_arr_cache;
4627

    
4628
	$interface = str_replace("\n", "", $interface);
4629

    
4630
	if (!does_interface_exist($interface))
4631
		return;
4632

    
4633
	/* Setup IP cache */
4634
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4635
		$ifinfo = pfSense_get_interface_addresses($interface);
4636
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4637
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4638
	}
4639

    
4640
	return $interface_ip_arr_cache[$interface];
4641
}
4642

    
4643
/*
4644
 * find_interface_ipv6($interface): return the interface ip (first found)
4645
 */
4646
function find_interface_ipv6($interface, $flush = false) {
4647
	global $interface_ipv6_arr_cache;
4648
	global $interface_snv6_arr_cache;
4649
	global $config;
4650

    
4651
	$interface = trim($interface);
4652
	$interface = get_real_interface($interface);
4653

    
4654
	if (!does_interface_exist($interface))
4655
		return;
4656

    
4657
	/* Setup IP cache */
4658
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4659
		$ifinfo = pfSense_get_interface_addresses($interface);
4660
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4661
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4662
	}
4663

    
4664
	return $interface_ipv6_arr_cache[$interface];
4665
}
4666

    
4667
/*
4668
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4669
 */
4670
function find_interface_ipv6_ll($interface, $flush = false) {
4671
	global $interface_llv6_arr_cache;
4672
	global $config;
4673

    
4674
	$interface = str_replace("\n", "", $interface);
4675

    
4676
	if (!does_interface_exist($interface))
4677
		return;
4678

    
4679
	/* Setup IP cache */
4680
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4681
		$ifinfo = pfSense_getall_interface_addresses($interface);
4682
		foreach($ifinfo as $line) {
4683
			if (strstr($line, ":")) {
4684
				$parts = explode("/", $line);
4685
				if(is_linklocal($parts[0])) {
4686
					$ifinfo['linklocal'] = $parts[0];
4687
				}
4688
			}
4689
		}
4690
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4691
	}
4692
	return $interface_llv6_arr_cache[$interface];
4693
}
4694

    
4695
function find_interface_subnet($interface, $flush = false) {
4696
	global $interface_sn_arr_cache;
4697
	global $interface_ip_arr_cache;
4698

    
4699
	$interface = str_replace("\n", "", $interface);
4700
	if (does_interface_exist($interface) == false)
4701
		return;
4702

    
4703
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4704
		$ifinfo = pfSense_get_interface_addresses($interface);
4705
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4706
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4707
	}
4708

    
4709
	return $interface_sn_arr_cache[$interface];
4710
}
4711

    
4712
function find_interface_subnetv6($interface, $flush = false) {
4713
	global $interface_snv6_arr_cache;
4714
	global $interface_ipv6_arr_cache;
4715

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

    
4720
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4721
		$ifinfo = pfSense_get_interface_addresses($interface);
4722
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4723
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4724
	}
4725

    
4726
	return $interface_snv6_arr_cache[$interface];
4727
}
4728

    
4729
function ip_in_interface_alias_subnet($interface, $ipalias) {
4730
	global $config;
4731

    
4732
	if (empty($interface) || !is_ipaddr($ipalias))
4733
		return false;
4734
	if (is_array($config['virtualip']['vip'])) {
4735
		foreach ($config['virtualip']['vip'] as $vip) {
4736
			switch ($vip['mode']) {
4737
			case "ipalias":
4738
				if ($vip['interface'] <> $interface)
4739
					break;
4740
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4741
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4742
					return true;
4743
				break;
4744
			}
4745
		}
4746
	}
4747

    
4748
	return false;
4749
}
4750

    
4751
function get_interface_ip($interface = "wan") {
4752
	$realif = get_failover_interface($interface);
4753
	if (!$realif) {
4754
		if (strstr($interface, "_vip"))
4755
			return get_configured_carp_interface_list($interface);
4756
		else
4757
			return null;
4758
	}
4759

    
4760
	$curip = find_interface_ip($realif);
4761
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4762
		return $curip;
4763
	else
4764
		return null;
4765
}
4766

    
4767
function get_interface_ipv6($interface = "wan", $flush = false) {
4768
	global $config;
4769

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

    
4778
	/*
4779
	 * NOTE: On the case when only the prefix is requested,
4780
	 * the communication on WAN will be done over link-local.
4781
	 */
4782
	if (is_array($config['interfaces'][$interface])) {
4783
		switch ($config['interfaces'][$interface]['ipaddr']) {
4784
		case 'pppoe':
4785
		case 'l2tp':
4786
		case 'pptp':
4787
		case 'ppp':
4788
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4789
				$realif = get_real_interface($interface, "inet6", true);
4790
			break;
4791
		}
4792
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4793
			$curip = find_interface_ipv6_ll($realif, $flush);
4794
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4795
				return $curip;
4796
		}
4797
	}
4798

    
4799
	$curip = find_interface_ipv6($realif, $flush);
4800
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4801
		return $curip;
4802
	else
4803
		return null;
4804
}
4805

    
4806
function get_interface_linklocal($interface = "wan") {
4807

    
4808
	$realif = get_failover_interface($interface, "inet6");
4809
	if (!$realif) {
4810
		if (strstr($interface, "_vip")) {
4811
			list($interface, $vhid) = explode("_vip", $interface);
4812
			$realif = get_real_interface($interface);
4813
		} else
4814
			return null;
4815
	}
4816

    
4817
	$curip = find_interface_ipv6_ll($realif);
4818
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4819
		return $curip;
4820
	else
4821
		return null;
4822
}
4823

    
4824
function get_interface_subnet($interface = "wan") {
4825
	$realif = get_real_interface($interface);
4826
	if (!$realif) {
4827
		if (strstr($interface, "_vip")) {
4828
			list($interface, $vhid) = explode("_vip", $interface);
4829
			$realif = get_real_interface($interface);
4830
		} else
4831
			return null;
4832
	}
4833

    
4834
	$cursn = find_interface_subnet($realif);
4835
	if (!empty($cursn))
4836
		return $cursn;
4837

    
4838
	return null;
4839
}
4840

    
4841
function get_interface_subnetv6($interface = "wan") {
4842
	global $config;
4843

    
4844
	$realif = get_real_interface($interface, "inet6");
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_subnetv6($realif);
4854
	if (!empty($cursn))
4855
		return $cursn;
4856

    
4857
	return null;
4858
}
4859

    
4860
/* return outside interfaces with a gateway */
4861
function get_interfaces_with_gateway() {
4862
	global $config;
4863

    
4864
	$ints = array();
4865

    
4866
	/* loop interfaces, check config for outbound */
4867
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4868
		switch ($ifname['ipaddr']) {
4869
			case "dhcp":
4870
			case "ppp";
4871
			case "pppoe":
4872
			case "pptp":
4873
			case "l2tp":
4874
			case "ppp";
4875
				$ints[$ifdescr] = $ifdescr;
4876
			break;
4877
			default:
4878
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
4879
				    !empty($ifname['gateway']))
4880
					$ints[$ifdescr] = $ifdescr;
4881
			break;
4882
		}
4883
	}
4884
	return $ints;
4885
}
4886

    
4887
/* return true if interface has a gateway */
4888
function interface_has_gateway($friendly) {
4889
	global $config;
4890

    
4891
	if (!empty($config['interfaces'][$friendly])) {
4892
		$ifname = &$config['interfaces'][$friendly];
4893
		switch ($ifname['ipaddr']) {
4894
			case "dhcp":
4895
			case "pppoe":
4896
			case "pptp":
4897
			case "l2tp":
4898
			case "ppp";
4899
				return true;
4900
			break;
4901
			default:
4902
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4903
					return true;
4904
				if (!empty($ifname['gateway']))
4905
					return true;
4906
			break;
4907
		}
4908
	}
4909

    
4910
	return false;
4911
}
4912

    
4913
/* return true if interface has a gateway */
4914
function interface_has_gatewayv6($friendly) {
4915
	global $config;
4916

    
4917
	if (!empty($config['interfaces'][$friendly])) {
4918
		$ifname = &$config['interfaces'][$friendly];
4919
		switch ($ifname['ipaddrv6']) {
4920
			case "slaac":
4921
			case "dhcp6":
4922
			case "6to4":
4923
			case "6rd":
4924
				return true;
4925
				break;
4926
			default:
4927
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4928
					return true;
4929
				if (!empty($ifname['gatewayv6']))
4930
					return true;
4931
				break;
4932
		}
4933
	}
4934

    
4935
	return false;
4936
}
4937

    
4938
/****f* interfaces/is_altq_capable
4939
 * NAME
4940
 *   is_altq_capable - Test if interface is capable of using ALTQ
4941
 * INPUTS
4942
 *   $int            - string containing interface name
4943
 * RESULT
4944
 *   boolean         - true or false
4945
 ******/
4946

    
4947
function is_altq_capable($int) {
4948
	/* Per:
4949
	 * http://www.freebsd.org/cgi/man.cgi?query=altq&manpath=FreeBSD+7.2-current&format=html
4950
	 * Only the following drivers have ALTQ support
4951
	 */
4952
	$capable = array("age", "alc", "ale", "an", "ath", "aue", "awi", "bce",
4953
			"bfe", "bge", "bridge", "cas", "dc", "de", "ed", "em", "ep", "fxp", "gem",
4954
			"hme", "igb", "ipw", "iwi", "jme", "le", "lem", "msk", "mxge", "my", "nfe",
4955
			"npe", "nve", "ral", "re", "rl", "rum", "run", "bwn", "sf", "sis", "sk",
4956
			"ste", "stge", "txp", "udav", "ural", "vge", "vr", "wi", "xl",
4957
			"ndis", "tun", "ovpns", "ovpnc", "vlan", "pppoe", "pptp", "ng",
4958
			"l2tp", "ppp", "vtnet");
4959

    
4960
	$int_family = remove_ifindex($int);
4961

    
4962
	if (in_array($int_family, $capable))
4963
		return true;
4964
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
4965
		return true;
4966
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
4967
		return true;
4968
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
4969
		return true;
4970
	else
4971
		return false;
4972
}
4973

    
4974
/****f* interfaces/is_interface_wireless
4975
 * NAME
4976
 *   is_interface_wireless - Returns if an interface is wireless
4977
 * RESULT
4978
 *   $tmp       - Returns if an interface is wireless
4979
 ******/
4980
function is_interface_wireless($interface) {
4981
	global $config, $g;
4982

    
4983
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
4984
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
4985
		if (preg_match($g['wireless_regex'], $interface)) {
4986
			if (isset($config['interfaces'][$friendly]))
4987
				$config['interfaces'][$friendly]['wireless'] = array();
4988
			return true;
4989
		}
4990
		return false;
4991
	} else
4992
		return true;
4993
}
4994

    
4995
function get_wireless_modes($interface) {
4996
	/* return wireless modes and channels */
4997
	$wireless_modes = array();
4998

    
4999
	$cloned_interface = get_real_interface($interface);
5000

    
5001
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5002
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5003
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5004
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5005

    
5006
		$interface_channels = "";
5007
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5008
		$interface_channel_count = count($interface_channels);
5009

    
5010
		$c = 0;
5011
		while ($c < $interface_channel_count) {
5012
			$channel_line = explode(",", $interface_channels["$c"]);
5013
			$wireless_mode = trim($channel_line[0]);
5014
			$wireless_channel = trim($channel_line[1]);
5015
			if(trim($wireless_mode) != "") {
5016
				/* if we only have 11g also set 11b channels */
5017
				if($wireless_mode == "11g") {
5018
					if(!isset($wireless_modes["11b"]))
5019
						$wireless_modes["11b"] = array();
5020
				} else if($wireless_mode == "11g ht") {
5021
					if(!isset($wireless_modes["11b"]))
5022
						$wireless_modes["11b"] = array();
5023
					if(!isset($wireless_modes["11g"]))
5024
						$wireless_modes["11g"] = array();
5025
					$wireless_mode = "11ng";
5026
				} else if($wireless_mode == "11a ht") {
5027
					if(!isset($wireless_modes["11a"]))
5028
						$wireless_modes["11a"] = array();
5029
					$wireless_mode = "11na";
5030
				}
5031
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5032
			}
5033
			$c++;
5034
		}
5035
	}
5036
	return($wireless_modes);
5037
}
5038

    
5039
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5040
function get_wireless_channel_info($interface) {
5041
	$wireless_channels = array();
5042

    
5043
	$cloned_interface = get_real_interface($interface);
5044

    
5045
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5046
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5047
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5048
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5049

    
5050
		$interface_channels = "";
5051
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5052

    
5053
		foreach ($interface_channels as $channel_line) {
5054
			$channel_line = explode(",", $channel_line);
5055
			if(!isset($wireless_channels[$channel_line[0]]))
5056
				$wireless_channels[$channel_line[0]] = $channel_line;
5057
		}
5058
	}
5059
	return($wireless_channels);
5060
}
5061

    
5062
/****f* interfaces/get_interface_mtu
5063
 * NAME
5064
 *   get_interface_mtu - Return the mtu of an interface
5065
 * RESULT
5066
 *   $tmp       - Returns the mtu of an interface
5067
 ******/
5068
function get_interface_mtu($interface) {
5069
	$mtu = pfSense_get_interface_addresses($interface);
5070
	return $mtu['mtu'];
5071
}
5072

    
5073
function get_interface_mac($interface) {
5074

    
5075
	$macinfo = pfSense_get_interface_addresses($interface);
5076
	return $macinfo["macaddr"];
5077
}
5078

    
5079
/****f* pfsense-utils/generate_random_mac_address
5080
 * NAME
5081
 *   generate_random_mac - generates a random mac address
5082
 * INPUTS
5083
 *   none
5084
 * RESULT
5085
 *   $mac - a random mac address
5086
 ******/
5087
function generate_random_mac_address() {
5088
	$mac = "02";
5089
	for($x=0; $x<5; $x++)
5090
		$mac .= ":" . dechex(rand(16, 255));
5091
	return $mac;
5092
}
5093

    
5094
/****f* interfaces/is_jumbo_capable
5095
 * NAME
5096
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5097
 * INPUTS
5098
 *   $int             - string containing interface name
5099
 * RESULT
5100
 *   boolean          - true or false
5101
 ******/
5102
function is_jumbo_capable($iface) {
5103
	$iface = trim($iface);
5104
	$capable = pfSense_get_interface_addresses($iface);
5105

    
5106
	if (isset($capable['caps']['vlanmtu']))
5107
		return true;
5108

    
5109
	return false;
5110
}
5111

    
5112
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5113
	global $g;
5114

    
5115
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5116

    
5117
	if(!empty($iface) && !empty($pppif)){
5118
		$cron_cmd = <<<EOD
5119
#!/bin/sh
5120
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5121
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5122

    
5123
EOD;
5124

    
5125
		@file_put_contents($cron_file, $cron_cmd);
5126
		chmod($cron_file, 0755);
5127
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5128
	} else
5129
		unlink_if_exists($cron_file);
5130
}
5131

    
5132
function get_interface_default_mtu($type = "ethernet") {
5133
	switch ($type) {
5134
	case "gre":
5135
		return 1476;
5136
		break;
5137
	case "gif":
5138
		return 1280;
5139
		break;
5140
	case "tun":
5141
	case "vlan":
5142
	case "tap":
5143
	case "ethernet":
5144
	default:
5145
		return 1500;
5146
		break;
5147
	}
5148

    
5149
	/* Never reached */
5150
	return 1500;
5151
}
5152

    
5153
function get_vip_descr($ipaddress) {
5154
	global $config;
5155

    
5156
	foreach ($config['virtualip']['vip'] as $vip) {
5157
		if ($vip['subnet'] == $ipaddress) {
5158
			return ($vip['descr']);
5159
		}
5160
	}
5161
	return "";
5162
}
5163

    
5164
function interfaces_staticarp_configure($if) {
5165
	global $config, $g;
5166
	if(isset($config['system']['developerspew'])) {
5167
		$mt = microtime();
5168
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5169
	}
5170

    
5171
	$ifcfg = $config['interfaces'][$if];
5172

    
5173
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5174
		return 0;
5175

    
5176
	/* Enable staticarp, if enabled */
5177
	if(isset($config['dhcpd'][$if]['staticarp'])) {
5178
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
5179
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5180
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5181

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

    
5185
			}
5186

    
5187
		}
5188
	} else {
5189
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
5190
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5191
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5192
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5193
				if (isset($arpent['arp_table_static_entry'])) {
5194
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5195
				}
5196
			}
5197
		}
5198
	}
5199

    
5200
	return 0;
5201
}
5202

    
5203
function get_failover_interface($interface, $family = "all") {
5204
	global $config;
5205

    
5206
	/* shortcut to get_real_interface if we find it in the config */
5207
	if (is_array($config['interfaces'][$interface])) {
5208
		return get_real_interface($interface, $family);
5209
	}
5210

    
5211
	/* compare against gateway groups */
5212
	$a_groups = return_gateway_groups_array();
5213
	if (is_array($a_groups[$interface])) {
5214
		/* we found a gateway group, fetch the interface or vip */
5215
		if ($a_groups[$interface][0]['vip'] <> "")
5216
			return $a_groups[$interface][0]['vip'];
5217
		else
5218
			return $a_groups[$interface][0]['int'];
5219
	}
5220
	/* fall through to get_real_interface */
5221
	/* XXX: Really needed? */
5222
	return get_real_interface($interface, $family);
5223
}
5224

    
5225
function remove_ifindex($ifname) {
5226
	return preg_replace("/[0-9]+$/", "", $ifname);
5227
}
5228

    
5229
?>
(25-25/67)