Project

General

Profile

Download (159 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
		$found = interface_isppp_type($interface);
144

    
145
	if ($found == false) {
146
		$realif = get_real_interface($interface);
147
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
148
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
149
				$ports = explode(',',$ppp['ports']);
150
				foreach($ports as $pid => $port){
151
					$port = get_real_interface($port);
152
					if ($realif == $port) {
153
						$found = true;
154
						break;
155
					}
156
					/* Find the parent interfaces of the vlans in the MLPPP configs
157
					* there should be only one element in the array here
158
					* -- this could be better . . . */
159
					$parent_if = get_parent_interface($port);
160
					if ($realif == $parent_if[0]) {
161
						$found = true;
162
						break;
163
					}
164
				}
165
			}
166
		}
167
	}
168

    
169
	if ($found == false) {
170
		$realif = get_real_interface($interface);
171
		pfSense_ngctl_detach("{$realif}:", $realif);
172
	}
173
	/* NOTE: We make sure for this on interface_ppps_configure()
174
	 *	no need to do it here agan.
175
	 *	else
176
	 *		pfSense_ngctl_attach(".", $realif);
177
	 */
178
}
179

    
180
function interfaces_loopback_configure() {
181
	global $g;
182

    
183
	if ($g['platform'] == 'jail')
184
		return;
185
	if (platform_booting())
186
		echo gettext("Configuring loopback interface...");
187
	pfSense_interface_setaddress("lo0", "127.0.0.1");
188
	interfaces_bring_up("lo0");
189
	if (platform_booting())
190
		echo gettext("done.") . "\n";
191
	return 0;
192
}
193

    
194
function interfaces_vlan_configure($realif = "") {
195
	global $config, $g;
196
	if (platform_booting())
197
		echo gettext("Configuring VLAN interfaces...");
198
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
199
		foreach ($config['vlans']['vlan'] as $vlan) {
200
			if (empty($vlan['vlanif']))
201
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
202
			if (!empty($realif) && $realif != $vlan['vlanif'])
203
				continue;
204

    
205
			/* XXX: Maybe we should report any errors?! */
206
			interface_vlan_configure($vlan);
207
		}
208
	}
209
	if (platform_booting())
210
		echo gettext("done.") . "\n";
211
}
212

    
213
function interface_vlan_configure(&$vlan) {
214
	global $config, $g;
215

    
216
	if (!is_array($vlan)) {
217
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
218
		return;
219
	}
220
	$if = $vlan['if'];
221
	$vlanif  = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
222
	$tag = $vlan['tag'];
223

    
224
	if (empty($if)) {
225
		log_error(gettext("interface_vlan_configure called with if undefined."));
226
		return;
227
	}
228

    
229
	/* make sure the parent interface is up */
230
	interfaces_bring_up($if);
231
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
232
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
233

    
234
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
235
		interface_bring_down($vlanif, true);
236
	} else {
237
		$tmpvlanif = pfSense_interface_create("vlan");
238
		pfSense_interface_rename($tmpvlanif, $vlanif);
239
		pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
240
	}
241

    
242
	pfSense_vlan_create($vlanif, $if, $tag);
243

    
244
	interfaces_bring_up($vlanif);
245

    
246
	/* invalidate interface cache */
247
	get_interface_arr(true);
248

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

    
252
	return $vlanif;
253
}
254

    
255
function interface_qinq_configure(&$vlan, $fd = NULL) {
256
	global $config, $g;
257

    
258
	if (!is_array($vlan)) {
259
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
260
		return;
261
	}
262

    
263
	$qinqif = $vlan['if'];
264
	$tag = $vlan['tag'];
265
	if(empty($qinqif)) {
266
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
267
		return;
268
	}
269

    
270
	if(!does_interface_exist($qinqif)) {
271
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
272
		return;
273
	}
274

    
275
	$vlanif = interface_vlan_configure($vlan);
276

    
277
	if ($fd == NULL) {
278
		$exec = true;
279
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
280
	} else
281
		$exec = false;
282
	/* make sure the parent is converted to ng_vlan(4) and is up */
283
	interfaces_bring_up($qinqif);
284

    
285
	pfSense_ngctl_attach(".", $qinqif);
286
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
287
		fwrite($fd, "shutdown {$qinqif}qinq:\n");
288
		exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
289
		if (empty($result)) {
290
			fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
291
			fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
292
			fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
293
		}
294
	} else {
295
		fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
296
		fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
297
		fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
298
	}
299

    
300
	/* invalidate interface cache */
301
	get_interface_arr(true);
302

    
303
	if (!stristr($qinqif, "_vlan"))
304
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
305

    
306
	$macaddr = get_interface_mac($qinqif);
307
	if (!empty($vlan['members'])) {
308
		$members = explode(" ", $vlan['members']);
309
		foreach ($members as $qtag) {
310
			$qinq = array();
311
			$qinq['tag'] = $qtag;
312
			$qinq['if'] = $vlanif;
313
			interface_qinq2_configure($qinq, $fd, $macaddr);
314
		}
315
	}
316
	if ($exec == true) {
317
		fclose($fd);
318
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
319
	}
320

    
321
	interfaces_bring_up($qinqif);
322
	if (!empty($vlan['members'])) {
323
		$members = explode(" ", $vlan['members']);
324
		foreach ($members as $qif)
325
			interfaces_bring_up("{$vlanif}_{$qif}");
326
	}
327

    
328
	return $vlanif;
329
}
330

    
331
function interfaces_qinq_configure() {
332
	global $config, $g;
333
	if (platform_booting())
334
		echo gettext("Configuring QinQ interfaces...");
335
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
336
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
337
			/* XXX: Maybe we should report any errors?! */
338
			interface_qinq_configure($qinq);
339
		}
340
	}
341
	if (platform_booting())
342
		echo gettext( "done.") . "\n";
343
}
344

    
345
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
346
	global $config, $g;
347

    
348
	if (!is_array($qinq)) {
349
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
350
		return;
351
	}
352

    
353
	$if = $qinq['if'];
354
	$tag = $qinq['tag'];
355
	$vlanif = "{$if}_{$tag}";
356
	if(empty($if)) {
357
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
358
		return;
359
	}
360

    
361
	fwrite($fd, "shutdown {$if}h{$tag}:\n");
362
	fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
363
	fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
364
	fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
365
	fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
366
	fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
367

    
368
	/* invalidate interface cache */
369
	get_interface_arr(true);
370

    
371
	return $vlanif;
372
}
373

    
374
function interfaces_create_wireless_clones() {
375
	global $config, $g;
376

    
377
	if (platform_booting())
378
		echo gettext("Creating wireless clone interfaces...");
379

    
380
	$iflist = get_configured_interface_list();
381

    
382
	foreach ($iflist as $if) {
383
		$realif = $config['interfaces'][$if]['if'];
384
		if (is_interface_wireless($realif))
385
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
386
	}
387

    
388
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
389
		foreach ($config['wireless']['clone'] as $clone) {
390
			if(empty($clone['cloneif']))
391
				continue;
392
			if(does_interface_exist($clone['cloneif']))
393
				continue;
394
			/* XXX: Maybe we should report any errors?! */
395
			interface_wireless_clone($clone['cloneif'], $clone);
396
		}
397
	}
398
	if (platform_booting())
399
		echo gettext("done.") . "\n";
400

    
401
}
402

    
403
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
404
	global $config;
405

    
406
	$i = 0;
407
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
408
		foreach ($config['bridges']['bridged'] as $bridge) {
409
			if (empty($bridge['bridgeif']))
410
				$bridge['bridgeif'] = "bridge{$i}";
411
			if (!empty($realif) && $realif != $bridge['bridgeif'])
412
				continue;
413

    
414
			if ($checkmember == 1) {
415
				if (strstr($bridge['if'], "_vip"))
416
					continue;
417
				$members = explode(',', $bridge['members']);
418
				foreach ($members as $member) {
419
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6")
420
						continue 2;
421
				}
422
			}
423
			else if ($checkmember == 2) {
424
				if (!strstr($bridge['if'], "_vip"))
425
					continue;
426
				$members = explode(',', $bridge['members']);
427
				foreach ($members as $member) {
428
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6")
429
						continue 2;
430
				}
431
			}
432
			/* XXX: Maybe we should report any errors?! */
433
			interface_bridge_configure($bridge, $checkmember);
434
			$i++;
435
		}
436
	}
437
}
438

    
439
function interface_bridge_configure(&$bridge, $checkmember = 0) {
440
	global $config, $g;
441

    
442
	if (!is_array($bridge))
443
		return;
444

    
445
	if (empty($bridge['members'])) {
446
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
447
		return;
448
	}
449

    
450
	$members = explode(',', $bridge['members']);
451
	if (!count($members))
452
		return;
453

    
454
	/* Calculate smaller mtu and enforce it */
455
	$smallermtu = 0;
456
	$commonrx = true;
457
	$commontx = true;
458
	$foundgif = false;
459
	foreach ($members as $member) {
460
		$realif = get_real_interface($member);
461
		$mtu = get_interface_mtu($realif);
462
		if (substr($realif, 0, 3) == "gif") {
463
			$foundgif = true;
464
			if ($checkmember == 1)
465
				return;
466
			if ($mtu <= 1500)
467
				continue;
468
		}
469
		if ($smallermtu == 0 && !empty($mtu))
470
			$smallermtu = $mtu;
471
		else if (!empty($mtu) && $mtu < $smallermtu)
472
			$smallermtu = $mtu;
473
	}
474
	if ($foundgif == false && $checkmember == 2)
475
		return;
476

    
477
	/* Just in case anything is not working well */
478
	if ($smallermtu == 0)
479
		$smallermtu = 1500;
480

    
481
	if (platform_booting() || !empty($bridge['bridgeif'])) {
482
		pfSense_interface_destroy($bridge['bridgeif']);
483
		pfSense_interface_create($bridge['bridgeif']);
484
		$bridgeif = escapeshellarg($bridge['bridgeif']);
485
	} else {
486
		$bridgeif = pfSense_interface_create("bridge");
487
		$bridge['bridgeif'] = $bridgeif;
488
	}
489

    
490
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
491
	if ($bridgemtu > $smallermtu)
492
		$smallermtu = $bridgemtu;
493

    
494
	$checklist = get_configured_interface_list();
495

    
496
	/* Add interfaces to bridge */
497
	foreach ($members as $member) {
498
		if (empty($checklist[$member]))
499
			continue;
500
		$realif = get_real_interface($member);
501
		if (!$realif) {
502
			log_error(gettext("realif not defined in interfaces bridge - up"));
503
			continue;
504
		}
505
		/* make sure the parent interface is up */
506
		pfSense_interface_mtu($realif, $smallermtu);
507
		interfaces_bring_up($realif);
508
		enable_hardware_offloading($member);
509
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
510
	}
511

    
512
	if (isset($bridge['enablestp'])) {
513
		/* Choose spanning tree proto */
514
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
515

    
516
		if (!empty($bridge['stp'])) {
517
			$stpifs = explode(',', $bridge['stp']);
518
			foreach ($stpifs as $stpif) {
519
				$realif = get_real_interface($stpif);
520
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
521
			}
522
		}
523
		if (!empty($bridge['maxage']))
524
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
525
		if (!empty($bridge['fwdelay']))
526
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
527
		if (!empty($bridge['hellotime']))
528
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
529
		if (!empty($bridge['priority']))
530
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
531
		if (!empty($bridge['holdcnt']))
532
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
533
		if (!empty($bridge['ifpriority'])) {
534
			$pconfig = explode(",", $bridge['ifpriority']);
535
			$ifpriority = array();
536
			foreach ($pconfig as $cfg) {
537
				$embcfg = explode_assoc(":", $cfg);
538
				foreach ($embcfg as $key => $value)
539
					$ifpriority[$key] = $value;
540
			}
541
			foreach ($ifpriority as $key => $value) {
542
				$realif = get_real_interface($key);
543
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
544
			}
545
		}
546
		if (!empty($bridge['ifpathcost'])) {
547
			$pconfig = explode(",", $bridge['ifpathcost']);
548
			$ifpathcost = array();
549
			foreach ($pconfig as $cfg) {
550
				$embcfg = explode_assoc(":", $cfg);
551
				foreach ($embcfg as $key => $value)
552
					$ifpathcost[$key] = $value;
553
			}
554
			foreach ($ifpathcost as $key => $value) {
555
				$realif = get_real_interface($key);
556
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
557
			}
558
		}
559
	}
560

    
561
	if ($bridge['maxaddr'] <> "")
562
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
563
	if ($bridge['timeout'] <> "")
564
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
565
	if ($bridge['span'] <> "") {
566
		$realif = get_real_interface($bridge['span']);
567
		mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
568
	}
569
	if (!empty($bridge['edge'])) {
570
		$edgeifs = explode(',', $bridge['edge']);
571
		foreach ($edgeifs as $edgeif) {
572
			$realif = get_real_interface($edgeif);
573
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
574
		}
575
	}
576
	if (!empty($bridge['autoedge'])) {
577
		$edgeifs = explode(',', $bridge['autoedge']);
578
		foreach ($edgeifs as $edgeif) {
579
			$realif = get_real_interface($edgeif);
580
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
581
		}
582
	}
583
	if (!empty($bridge['ptp'])) {
584
		$ptpifs = explode(',', $bridge['ptp']);
585
		foreach ($ptpifs as $ptpif) {
586
			$realif = get_real_interface($ptpif);
587
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
588
		}
589
	}
590
	if (!empty($bridge['autoptp'])) {
591
		$ptpifs = explode(',', $bridge['autoptp']);
592
		foreach ($ptpifs as $ptpif) {
593
			$realif = get_real_interface($ptpif);
594
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
595
		}
596
	}
597
	if (!empty($bridge['static'])) {
598
		$stickyifs = explode(',', $bridge['static']);
599
		foreach ($stickyifs as $stickyif) {
600
			$realif = get_real_interface($stickyif);
601
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
602
		}
603
	}
604
	if (!empty($bridge['private'])) {
605
		$privateifs = explode(',', $bridge['private']);
606
		foreach ($privateifs as $privateif) {
607
			$realif = get_real_interface($privateif);
608
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
609
		}
610
	}
611

    
612
	if ($bridge['bridgeif'])
613
		interfaces_bring_up($bridge['bridgeif']);
614
	else
615
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
616
}
617

    
618
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
619

    
620
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface))
621
		return;
622

    
623
	if ($flagsapplied == false) {
624
		$mtu = get_interface_mtu($bridgeif);
625
		$mtum = get_interface_mtu($interface);
626
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500))
627
			pfSense_interface_mtu($interface, $mtu);
628

    
629
		hardware_offloading_applyflags($interface);
630
		interfaces_bring_up($interface);
631
	}
632

    
633
	pfSense_bridge_add_member($bridgeif, $interface);
634
}
635

    
636
function interfaces_lagg_configure($realif = "") {
637
	global $config, $g;
638
	if (platform_booting())
639
		echo gettext("Configuring LAGG interfaces...");
640
	$i = 0;
641
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
642
		foreach ($config['laggs']['lagg'] as $lagg) {
643
			if(empty($lagg['laggif']))
644
				$lagg['laggif'] = "lagg{$i}";
645
			if (!empty($realif) && $realif != $lagg['laggif'])
646
				continue;
647
			/* XXX: Maybe we should report any errors?! */
648
			interface_lagg_configure($lagg);
649
			$i++;
650
		}
651
	}
652
	if (platform_booting())
653
		echo gettext("done.") . "\n";
654
}
655

    
656
function interface_lagg_configure($lagg) {
657
	global $config, $g;
658

    
659
	if (!is_array($lagg))
660
		return -1;
661

    
662
	$members = explode(',', $lagg['members']);
663
	if (!count($members))
664
		return -1;
665

    
666
	if (platform_booting() || !(empty($lagg['laggif']))) {
667
		pfSense_interface_destroy($lagg['laggif']);
668
		pfSense_interface_create($lagg['laggif']);
669
		$laggif = $lagg['laggif'];
670
	} else
671
		$laggif = pfSense_interface_create("lagg");
672

    
673
	/* Check if MTU was defined for this lagg interface */
674
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
675
	if ($lagg_mtu == 0) {
676
		/* Calculate smaller mtu and enforce it */
677
		$smallermtu = 0;
678
		foreach ($members as $member) {
679
			$mtu = get_interface_mtu($member);
680
			if ($smallermtu == 0 && !empty($mtu))
681
				$smallermtu = $mtu;
682
			else if (!empty($mtu) && $mtu < $smallermtu)
683
				$smallermtu = $mtu;
684
		}
685
		$lagg_mtu = $smallermtu;
686
	}
687

    
688
	/* Just in case anything is not working well */
689
	if ($lagg_mtu == 0)
690
		$lagg_mtu = 1500;
691

    
692
	foreach ($members as $member) {
693
		if (!does_interface_exist($member))
694
			continue;
695
		/* make sure the parent interface is up */
696
		pfSense_interface_mtu($member, $lagg_mtu);
697
		interfaces_bring_up($member);
698
		hardware_offloading_applyflags($member);
699
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
700
	}
701
	pfSense_interface_capabilities($laggif, -$flags_off);
702
	pfSense_interface_capabilities($laggif, $flags_on);
703

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

    
706
	interfaces_bring_up($laggif);
707

    
708
	return $laggif;
709
}
710

    
711
function interfaces_gre_configure($checkparent = 0, $realif = "") {
712
	global $config;
713

    
714
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
715
		foreach ($config['gres']['gre'] as $i => $gre) {
716
			if (empty($gre['greif']))
717
				$gre['greif'] = "gre{$i}";
718
			if (!empty($realif) && $realif != $gre['greif'])
719
				continue;
720

    
721
			if ($checkparent == 1) {
722
				if (strstr($gre['if'], "_vip"))
723
					continue;
724
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6")
725
					continue;
726
			}
727
			else if ($checkparent == 2) {
728
				if (!strstr($gre['if'], "_vip"))
729
					continue;
730
				if (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")
731
					continue;
732
			}
733
			/* XXX: Maybe we should report any errors?! */
734
			interface_gre_configure($gre);
735
		}
736
	}
737
}
738

    
739
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
740
function interface_gre_configure(&$gre, $grekey = "") {
741
	global $config, $g;
742

    
743
	if (!is_array($gre))
744
		return -1;
745

    
746
	$realif = get_real_interface($gre['if']);
747
	$realifip = get_interface_ip($gre['if']);
748

    
749
	/* make sure the parent interface is up */
750
	interfaces_bring_up($realif);
751

    
752
	if (platform_booting() || !(empty($gre['greif']))) {
753
		pfSense_interface_destroy($gre['greif']);
754
		pfSense_interface_create($gre['greif']);
755
		$greif = $gre['greif'];
756
	} else
757
		$greif = pfSense_interface_create("gre");
758

    
759
	/* Do not change the order here for more see gre(4) NOTES section. */
760
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
761
	if((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
762
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
763
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
764
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
765
	} else {
766
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
767
	}
768
	if (isset($gre['link0']))
769
		pfSense_interface_flags($greif, IFF_LINK0);
770
	if (isset($gre['link1']))
771
		pfSense_interface_flags($greif, IFF_LINK1);
772
	if (isset($gre['link2']))
773
		pfSense_interface_flags($greif, IFF_LINK2);
774

    
775
	if($greif)
776
		interfaces_bring_up($greif);
777
	else
778
		log_error(gettext("Could not bring greif up -- variable not defined."));
779

    
780
	if (isset($gre['link1']) && $gre['link1'])
781
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
782
	if(is_ipaddrv4($gre['tunnel-remote-addr']))
783
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
784
	if(is_ipaddrv6($gre['tunnel-remote-addr']))
785
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
786

    
787
	interfaces_bring_up($greif);
788

    
789
	return $greif;
790
}
791

    
792
function interfaces_gif_configure($checkparent = 0, $realif = "") {
793
	global $config;
794

    
795
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
796
		foreach ($config['gifs']['gif'] as $i => $gif) {
797
			if (empty($gif['gifif']))
798
				$gre['gifif'] = "gif{$i}";
799
			if (!empty($realif) && $realif != $gif['gifif'])
800
				continue;
801

    
802
			if ($checkparent == 1) {
803
				if (strstr($gif['if'], "_vip"))
804
					continue;
805
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6")
806
					continue;
807
			}
808
			else if ($checkparent == 2) {
809
				if (!strstr($gif['if'], "_vip"))
810
					continue;
811
				if (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")
812
					continue;
813
			}
814
			/* XXX: Maybe we should report any errors?! */
815
			interface_gif_configure($gif);
816
		}
817
	}
818
}
819

    
820
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
821
function interface_gif_configure(&$gif, $gifkey = "") {
822
	global $config, $g;
823

    
824
	if (!is_array($gif))
825
		return -1;
826

    
827
	$realif = get_real_interface($gif['if']);
828
	$ipaddr = $gif['ipaddr'];
829

    
830
	if (is_ipaddrv4($gif['remote-addr'])) {
831
		if (is_ipaddrv4($ipaddr))
832
			$realifip = $ipaddr;
833
		else
834
			$realifip = get_interface_ip($gif['if']);
835
		$realifgw = get_interface_gateway($gif['if']);
836
	} else if (is_ipaddrv6($gif['remote-addr'])) {
837
		if (is_ipaddrv6($ipaddr))
838
			$realifip = $ipaddr;
839
		else
840
			$realifip = get_interface_ipv6($gif['if']);
841
		$realifgw = get_interface_gateway_v6($gif['if']);
842
	}
843
	/* make sure the parent interface is up */
844
	if($realif)
845
		interfaces_bring_up($realif);
846
	else
847
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
848

    
849
	if (platform_booting() || !(empty($gif['gifif']))) {
850
		pfSense_interface_destroy($gif['gifif']);
851
		pfSense_interface_create($gif['gifif']);
852
		$gifif = $gif['gifif'];
853
	} else
854
		$gifif = pfSense_interface_create("gif");
855

    
856
	/* Do not change the order here for more see gif(4) NOTES section. */
857
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
858
	if((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
859
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
860
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
861
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
862
	} else {
863
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
864
	}
865
	if (isset($gif['link0']))
866
		pfSense_interface_flags($gifif, IFF_LINK0);
867
	if (isset($gif['link1']))
868
		pfSense_interface_flags($gifif, IFF_LINK1);
869
	if($gifif)
870
		interfaces_bring_up($gifif);
871
	else
872
		log_error(gettext("could not bring gifif up -- variable not defined"));
873

    
874
	if (!platform_booting()) {
875
		$iflist = get_configured_interface_list();
876
		foreach($iflist as $ifname) {
877
			if($config['interfaces'][$ifname]['if'] == $gifif) {
878
				if(get_interface_gateway($ifname)) {
879
					system_routing_configure($ifname);
880
					break;
881
				}
882
				if(get_interface_gateway_v6($ifname)) {
883
					system_routing_configure($ifname);
884
					break;
885
				}
886
			}
887
		}
888
	}
889

    
890

    
891
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
892
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
893
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
894
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
895

    
896
	if (is_ipaddrv4($realifgw)) {
897
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
898
	}
899
	if (is_ipaddrv6($realifgw)) {
900
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
901
	}
902

    
903
	interfaces_bring_up($gifif);
904

    
905
	return $gifif;
906
}
907

    
908
function interfaces_configure() {
909
	global $config, $g;
910

    
911
	if ($g['platform'] == 'jail')
912
		return;
913

    
914
	/* Set up our loopback interface */
915
	interfaces_loopback_configure();
916

    
917
	/* create the unconfigured wireless clones */
918
	interfaces_create_wireless_clones();
919

    
920
	/* set up LAGG virtual interfaces */
921
	interfaces_lagg_configure();
922

    
923
	/* set up VLAN virtual interfaces */
924
	interfaces_vlan_configure();
925

    
926
	interfaces_qinq_configure();
927

    
928
	$iflist = get_configured_interface_with_descr();
929
	$delayed_list = array();
930
	$bridge_list = array();
931
	$track6_list = array();
932

    
933
	/* This is needed to speedup interfaces on bootup. */
934
	$reload = false;
935
	if (!platform_booting())
936
		$reload = true;
937

    
938
	foreach($iflist as $if => $ifname) {
939
		$realif = $config['interfaces'][$if]['if'];
940
		if (strstr($realif, "bridge"))
941
			$bridge_list[$if] = $ifname;
942
		else if (strstr($realif, "gre"))
943
			$delayed_list[$if] = $ifname;
944
		else if (strstr($realif, "gif"))
945
			$delayed_list[$if] = $ifname;
946
		else if (strstr($realif, "ovpn")) {
947
			//echo "Delaying OpenVPN interface configuration...done.\n";
948
			continue;
949
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
950
			$track6_list[$if] = $ifname;
951
		} else {
952
			if (platform_booting())
953
				printf(gettext("Configuring %s interface..."), $ifname);
954

    
955
			if($g['debug'])
956
				log_error(sprintf(gettext("Configuring %s"), $ifname));
957
			interface_configure($if, $reload);
958
			if (platform_booting())
959
				echo gettext( "done.") . "\n";
960
		}
961
	}
962

    
963
	/*
964
	 * NOTE: The following function parameter consists of
965
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
966
	 *	2 - Do load gre/gif/bridge with parent/member as vip
967
	 */
968

    
969
	/* set up GRE virtual interfaces */
970
	interfaces_gre_configure(1);
971

    
972
	/* set up GIF virtual interfaces */
973
	interfaces_gif_configure(1);
974

    
975
	/* set up BRIDGe virtual interfaces */
976
	interfaces_bridge_configure(1);
977

    
978
	foreach ($track6_list as $if => $ifname) {
979
		if (platform_booting())
980
			printf(gettext("Configuring %s interface..."), $ifname);
981
		if ($g['debug'])
982
			log_error(sprintf(gettext("Configuring %s"), $ifname));
983

    
984
		interface_configure($if, $reload);
985

    
986
		if (platform_booting())
987
			echo gettext("done.") . "\n";
988
	}
989

    
990
	/* bring up vip interfaces */
991
	interfaces_vips_configure();
992

    
993
	/* set up GRE virtual interfaces */
994
	interfaces_gre_configure(2);
995

    
996
	/* set up GIF virtual interfaces */
997
	interfaces_gif_configure(2);
998

    
999
	foreach ($delayed_list as $if => $ifname) {
1000
		if (platform_booting())
1001
			printf(gettext("Configuring %s interface..."), $ifname);
1002
		if ($g['debug'])
1003
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1004

    
1005
		interface_configure($if, $reload);
1006

    
1007
		if (platform_booting())
1008
			echo gettext("done.") . "\n";
1009
	}
1010

    
1011
	/* set up BRIDGe virtual interfaces */
1012
	interfaces_bridge_configure(2);
1013

    
1014
	foreach ($bridge_list as $if => $ifname) {
1015
		if (platform_booting())
1016
			printf(gettext("Configuring %s interface..."), $ifname);
1017
		if($g['debug'])
1018
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1019

    
1020
		interface_configure($if, $reload);
1021

    
1022
		if (platform_booting())
1023
			echo gettext("done.") . "\n";
1024
	}
1025

    
1026
	/* configure interface groups */
1027
	interfaces_group_setup();
1028

    
1029
	if (!platform_booting()) {
1030
		/* reconfigure static routes (kernel may have deleted them) */
1031
		system_routing_configure();
1032

    
1033
		/* reload IPsec tunnels */
1034
		vpn_ipsec_configure();
1035

    
1036
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1037
		services_dhcpd_configure();
1038

    
1039
		/* restart dnsmasq or unbound */
1040
		if (isset($config['dnsmasq']['enable']))
1041
			services_dnsmasq_configure();
1042
		elseif (isset($config['unbound']['enable']))
1043
			services_unbound_configure();
1044
	}
1045

    
1046
	return 0;
1047
}
1048

    
1049
function interface_reconfigure($interface = "wan", $reloadall = false) {
1050
	interface_bring_down($interface);
1051
	interface_configure($interface, $reloadall);
1052
}
1053

    
1054
function interface_vip_bring_down($vip) {
1055
	global $g;
1056

    
1057
	if (strpos($vip['interface'], '_vip')) {
1058
		if (is_ipaddrv6($vip['subnet']))
1059
			$family = 'inet6';
1060
		else
1061
			$family = 'inet';
1062

    
1063
		$carpvip = get_configured_carp_interface_list($vip['interface'], $family, 'vip');
1064
		$iface = $carpvip['interface'];
1065
	} else
1066
		$iface = $vip['interface'];
1067

    
1068
	$vipif = get_real_interface($iface);
1069
	switch ($vip['mode']) {
1070
	case "proxyarp":
1071
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1072
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1073
		break;
1074
	case "ipalias":
1075
		if (does_interface_exist($vipif)) {
1076
			if (is_ipaddrv6($vip['subnet']))
1077
				mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1078
			else
1079
				pfSense_interface_deladdress($vipif, $vip['subnet']);
1080
		}
1081
		break;
1082
	case "carp":
1083
		/* XXX: Is enough to delete ip address? */
1084
		if (does_interface_exist($vipif)) {
1085
			if (is_ipaddrv6($vip['subnet']))
1086
				mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1087
			else
1088
				pfSense_interface_deladdress($vipif, $vip['subnet']);
1089
		}
1090
		break;
1091
	}
1092
}
1093

    
1094
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1095
	global $config, $g;
1096

    
1097
	if (!isset($config['interfaces'][$interface]))
1098
		return;
1099

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

    
1103
	/*
1104
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1105
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1106
	 * Keep this in mind while doing changes here!
1107
	 */
1108
	if ($ifacecfg === false) {
1109
		$ifcfg = $config['interfaces'][$interface];
1110
		$ppps = $config['ppps']['ppp'];
1111
		$realif = get_real_interface($interface);
1112
		$realifv6 = get_real_interface($interface, "inet6", true);
1113
	} elseif (!is_array($ifacecfg)) {
1114
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1115
		$ifcfg = $config['interfaces'][$interface];
1116
		$ppps = $config['ppps']['ppp'];
1117
		$realif = get_real_interface($interface);
1118
		$realifv6 = get_real_interface($interface, "inet6", true);
1119
	} else {
1120
		$ifcfg = $ifacecfg['ifcfg'];
1121
		$ppps = $ifacecfg['ppps'];
1122
		if (isset($ifacecfg['ifcfg']['realif'])) {
1123
			$realif = $ifacecfg['ifcfg']['realif'];
1124
			/* XXX: Any better way? */
1125
			$realifv6 = $realif;
1126
		} else {
1127
			$realif = get_real_interface($interface);
1128
			$realifv6 = get_real_interface($interface, "inet6", true);
1129
		}
1130
	}
1131

    
1132
	switch ($ifcfg['ipaddr']) {
1133
	case "ppp":
1134
	case "pppoe":
1135
	case "pptp":
1136
	case "l2tp":
1137
		if (is_array($ppps) && count($ppps)) {
1138
			foreach ($ppps as $pppid => $ppp) {
1139
				if ($realif == $ppp['if']) {
1140
					if (isset($ppp['ondemand']) && !$destroy){
1141
						send_event("interface reconfigure {$interface}");
1142
						break;
1143
					}
1144
					if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1145
						killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1146
						sleep(2);
1147
					}
1148
					unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1149
					break;
1150
				}
1151
			}
1152
		}
1153
		break;
1154
	case "dhcp":
1155
		kill_dhclient_process($realif);
1156
		unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1157
		if(does_interface_exist("$realif")) {
1158
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1159
			interface_ipalias_cleanup($interface);
1160
			if ($destroy == true)
1161
				pfSense_interface_flags($realif, -IFF_UP);
1162
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1163
		}
1164
		break;
1165
	default:
1166
		if(does_interface_exist("$realif")) {
1167
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1168
			interface_ipalias_cleanup($interface);
1169
			if ($destroy == true)
1170
				pfSense_interface_flags($realif, -IFF_UP);
1171
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1172
		}
1173
		break;
1174
	}
1175

    
1176
	$track6 = array();
1177
	switch ($ifcfg['ipaddrv6']) {
1178
	case "slaac":
1179
	case "dhcp6":
1180
		$pidv6 = find_dhcp6c_process($realif);
1181
		if($pidv6)
1182
			posix_kill($pidv6, SIGTERM);
1183
		sleep(3);
1184
		unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1185
		if (does_interface_exist($realifv6)) {
1186
			$ip6 = find_interface_ipv6($realifv6);
1187
			if (is_ipaddrv6($ip6) && $ip6 != "::")
1188
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1189
			interface_ipalias_cleanup($interface, "inet6");
1190
			if ($destroy == true)
1191
				pfSense_interface_flags($realif, -IFF_UP);
1192
			//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1193
		}
1194
		$track6 = link_interface_to_track6($interface);
1195
		break;
1196
	case "6rd":
1197
	case "6to4":
1198
		$realif = "{$interface}_stf";
1199
		if(does_interface_exist("$realif")) {
1200
			$ip6 = get_interface_ipv6($interface);
1201
			if (is_ipaddrv6($ip6))
1202
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1203
			interface_ipalias_cleanup($interface, "inet6");
1204
			if ($destroy == true)
1205
				pfSense_interface_flags($realif, -IFF_UP);
1206
		}
1207
		$track6 = link_interface_to_track6($interface);
1208
		break;
1209
	default:
1210
		if(does_interface_exist("$realif")) {
1211
			$ip6 = get_interface_ipv6($interface);
1212
			if (is_ipaddrv6($ip6))
1213
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1214
			if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
1215
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1216
			interface_ipalias_cleanup($interface, "inet6");
1217
			if ($destroy == true)
1218
				pfSense_interface_flags($realif, -IFF_UP);
1219
			//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1220
		}
1221
		$track6 = link_interface_to_track6($interface);
1222
		break;
1223
	}
1224

    
1225
	if (!empty($track6) && is_array($track6)) {
1226
		if (!function_exists('services_dhcp_configure'))
1227
			require_once('services.inc');
1228
		/* Bring down radvd and dhcp6 on these interfaces */
1229
		services_dhcpd_configure('inet6', $track6);
1230
	}
1231

    
1232
	$old_router = '';
1233
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1234
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1235

    
1236
	/* remove interface up file if it exists */
1237
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1238
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1239
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1240
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1241
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1242
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1243
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1244

    
1245
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1246
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1247
	if (is_array($ifcfg['wireless'])) {
1248
		kill_hostapd($realif);
1249
		mwexec(kill_wpasupplicant($realif));
1250
	}
1251

    
1252
	if ($destroy == true) {
1253
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif))
1254
			pfSense_interface_destroy($realif);
1255
	}
1256

    
1257
	return;
1258
}
1259

    
1260
function interfaces_carp_set_maintenancemode($carp_maintenancemode){
1261
	global $config;
1262
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1263
		unset($config["virtualip_carp_maintenancemode"]);
1264
		write_config("Leave CARP maintenance mode");
1265
		if(is_array($config['virtualip']['vip'])) {
1266
			$viparr = &$config['virtualip']['vip'];
1267
			foreach ($viparr as $vip) {
1268
				switch ($vip['mode']) {
1269
				case "carp":
1270
					interface_vip_bring_down($vip);
1271
					//sleep(1);
1272
					break;
1273
				}
1274
			}
1275
		}
1276
	} else {
1277
		if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1278
			$config["virtualip_carp_maintenancemode"] = true;
1279
			write_config("Enter CARP maintenance mode");
1280
		}
1281
	}
1282

    
1283
	$viparr = &$config['virtualip']['vip'];
1284
	foreach ($viparr as $vip) {
1285
		if ($vip['mode'] == "carp") {
1286
			interface_carp_configure($vip);
1287
		}
1288
	}
1289
}
1290

    
1291
function interface_isppp_type($interface) {
1292
	global $config;
1293

    
1294
	if (!is_array($config['interfaces'][$interface]))
1295
		return false;
1296

    
1297
	switch ($config['interfaces'][$interface]['ipaddr']) {
1298
	case 'pptp':
1299
	case 'l2tp':
1300
	case 'pppoe':
1301
	case 'ppp':
1302
		return true;
1303
		break;
1304
	default:
1305
		return false;
1306
		break;
1307
	}
1308
}
1309

    
1310
function interfaces_ptpid_used($ptpid) {
1311
	global $config;
1312

    
1313
	if (is_array($config['ppps']['ppp']))
1314
		foreach ($config['ppps']['ppp'] as & $settings)
1315
			if ($ptpid == $settings['ptpid'])
1316
				return true;
1317

    
1318
	return false;
1319
}
1320

    
1321
function interfaces_ptpid_next() {
1322

    
1323
	$ptpid = 0;
1324
	while(interfaces_ptpid_used($ptpid))
1325
		$ptpid++;
1326

    
1327
	return $ptpid;
1328
}
1329

    
1330
function getMPDCRONSettings($pppif) {
1331
	global $config;
1332

    
1333
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1334
	if (is_array($config['cron']['item'])) {
1335
		foreach ($config['cron']['item'] as $i => $item) {
1336
			if (stripos($item['command'], $cron_cmd_file) !== false)
1337
				return array("ID" => $i, "ITEM" => $item);
1338
		}
1339
	}
1340

    
1341
	return NULL;
1342
}
1343

    
1344
function handle_pppoe_reset($post_array) {
1345
	global $config, $g;
1346

    
1347
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1348
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1349

    
1350
	if (!is_array($config['cron']['item']))
1351
		$config['cron']['item'] = array();
1352

    
1353
	$itemhash = getMPDCRONSettings($pppif);
1354

    
1355
	// reset cron items if necessary and return
1356
	if (empty($post_array['pppoe-reset-type'])) {
1357
		if (isset($itemhash))
1358
			unset($config['cron']['item'][$itemhash['ID']]);
1359
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1360
		return;
1361
	}
1362

    
1363
	if (empty($itemhash))
1364
		$itemhash = array();
1365
	$item = array();
1366
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1367
		$item['minute'] = $post_array['pppoe_resetminute'];
1368
		$item['hour'] = $post_array['pppoe_resethour'];
1369
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1370
			$date = explode("/", $post_array['pppoe_resetdate']);
1371
			$item['mday'] = $date[1];
1372
			$item['month'] = $date[0];
1373
		} else {
1374
			$item['mday'] = "*";
1375
			$item['month'] = "*";
1376
		}
1377
		$item['wday'] = "*";
1378
		$item['who'] = "root";
1379
		$item['command'] = $cron_cmd_file;
1380
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1381
		switch ($post_array['pppoe_pr_preset_val']) {
1382
		case "monthly":
1383
			$item['minute'] = "0";
1384
			$item['hour'] = "0";
1385
			$item['mday'] = "1";
1386
			$item['month'] = "*";
1387
			$item['wday'] = "*";
1388
			break;
1389
		case "weekly":
1390
			$item['minute'] = "0";
1391
			$item['hour'] = "0";
1392
			$item['mday'] = "*";
1393
			$item['month'] = "*";
1394
			$item['wday'] = "0";
1395
			break;
1396
		case "daily":
1397
			$item['minute'] = "0";
1398
			$item['hour'] = "0";
1399
			$item['mday'] = "*";
1400
			$item['month'] = "*";
1401
			$item['wday'] = "*";
1402
			break;
1403
		case "hourly":
1404
			$item['minute'] = "0";
1405
			$item['hour'] = "*";
1406
			$item['mday'] = "*";
1407
			$item['month'] = "*";
1408
			$item['wday'] = "*";
1409
			break;
1410
		} // end switch
1411
		$item['who'] = "root";
1412
		$item['command'] = $cron_cmd_file;
1413
	}
1414
	if (empty($item))
1415
		return;
1416
	if (isset($itemhash['ID']))
1417
		$config['cron']['item'][$itemhash['ID']] = $item;
1418
	else
1419
		$config['cron']['item'][] = $item;
1420
}
1421

    
1422
/*
1423
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1424
 * It writes the mpd config file to /var/etc every time the link is opened.
1425
 */
1426
function interface_ppps_configure($interface) {
1427
	global $config, $g;
1428

    
1429
	/* Return for unassigned interfaces. This is a minimum requirement. */
1430
	if (empty($config['interfaces'][$interface]))
1431
		return 0;
1432
	$ifcfg = $config['interfaces'][$interface];
1433
	if (!isset($ifcfg['enable']))
1434
		return 0;
1435

    
1436
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1437
	if(!is_dir("/var/spool/lock")) {
1438
		mkdir("/var/spool/lock", 0777, true);
1439
	}
1440
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1441
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1442
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1443

    
1444
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1445
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1446
			if ($ifcfg['if'] == $ppp['if'])
1447
				break;
1448
		}
1449
	}
1450
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1451
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1452
		return 0;
1453
	}
1454
	$pppif = $ifcfg['if'];
1455
	if ($ppp['type'] == "ppp")
1456
		$type = "modem";
1457
	else
1458
		$type = $ppp['type'];
1459
	$upper_type = strtoupper($ppp['type']);
1460

    
1461
	/* XXX: This does not make sense and may create trouble
1462
	 * comment it for now to be removed later on.
1463
	if (platform_booting()) {
1464
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1465
		echo "starting {$pppif} link...";
1466
		if(isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1467
			return 0;
1468
	}
1469
	*/
1470

    
1471
	$ports = explode(',',$ppp['ports']);
1472
	if ($type != "modem") {
1473
		foreach ($ports as $pid => $port) {
1474
			$ports[$pid] = get_real_interface($port);
1475
			if (empty($ports[$pid]))
1476
				return 0;
1477
		}
1478
	}
1479
	$localips = explode(',',$ppp['localip']);
1480
	$gateways = explode(',',$ppp['gateway']);
1481
	$subnets = explode(',',$ppp['subnet']);
1482

    
1483
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1484
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1485
	 */
1486
	foreach($ports as $pid => $port){
1487
		switch ($ppp['type']) {
1488
			case "pppoe":
1489
				/* Bring the parent interface up */
1490
				interfaces_bring_up($port);
1491
				pfSense_ngctl_attach(".", $port);
1492
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1493
				mwexec("ngctl msg {$port}: setautosrc 1");
1494
				break;
1495
			case "pptp":
1496
			case "l2tp":
1497
				/* configure interface */
1498
				if(is_ipaddr($localips[$pid])){
1499
					// Manually configure interface IP/subnet
1500
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1501
					interfaces_bring_up($port);
1502
				} else if (empty($localips[$pid]))
1503
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1504

    
1505
				if(!is_ipaddr($localips[$pid])){
1506
					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!");
1507
					$localips[$pid] = "0.0.0.0";
1508
				}
1509
				if(!is_ipaddr($gateways[$pid])){
1510
					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));
1511
					return 0;
1512
				}
1513
				pfSense_ngctl_attach(".", $port);
1514
				break;
1515
			case "ppp":
1516
				if (!file_exists("{$port}")) {
1517
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1518
					return 0;
1519
				}
1520
				break;
1521
			default:
1522
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1523
				break;
1524
		}
1525
	}
1526

    
1527
	if (is_array($ports) && count($ports) > 1)
1528
		$multilink = "enable";
1529
	else
1530
		$multilink = "disable";
1531

    
1532
	if ($type == "modem"){
1533
		if (is_ipaddr($ppp['localip']))
1534
			$localip = $ppp['localip'];
1535
		else
1536
			$localip = '0.0.0.0';
1537

    
1538
		if (is_ipaddr($ppp['gateway']))
1539
			$gateway = $ppp['gateway'];
1540
		else
1541
			$gateway = "10.64.64.{$pppid}";
1542
		$ranges = "{$localip}/0 {$gateway}/0";
1543

    
1544
		if (empty($ppp['apnum']))
1545
			$ppp['apnum'] = 1;
1546
	} else
1547
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1548

    
1549
	if (isset($ppp['ondemand']))
1550
		$ondemand = "enable";
1551
	else
1552
		$ondemand = "disable";
1553
	if (!isset($ppp['idletimeout']))
1554
		$ppp['idletimeout'] = 0;
1555

    
1556
	if (empty($ppp['username']) && $type == "modem"){
1557
		$ppp['username'] = "user";
1558
		$ppp['password'] = "none";
1559
	}
1560
	if (empty($ppp['password']) && $type == "modem")
1561
		$passwd = "none";
1562
	else
1563
		$passwd = base64_decode($ppp['password']);
1564

    
1565
	$bandwidths = explode(',',$ppp['bandwidth']);
1566
	$defaultmtu = "1492";
1567
	if (!empty($ifcfg['mtu']))
1568
		$defaultmtu = intval($ifcfg['mtu']);
1569
	$mtus = explode(',',$ppp['mtu']);
1570
	$mrus = explode(',',$ppp['mru']);
1571

    
1572
	if (isset($ppp['mrru']))
1573
		$mrrus = explode(',',$ppp['mrru']);
1574

    
1575
	// Construct the mpd.conf file
1576
	$mpdconf = <<<EOD
1577
startup:
1578
	# configure the console
1579
	set console close
1580
	# configure the web server
1581
	set web close
1582

    
1583
default:
1584
{$ppp['type']}client:
1585
	create bundle static {$interface}
1586
	set bundle enable ipv6cp
1587
	set iface name {$pppif}
1588

    
1589
EOD;
1590
	$setdefaultgw = false;
1591
	$founddefaultgw = false;
1592
	if (is_array($config['gateways']['gateway_item'])) {
1593
		foreach($config['gateways']['gateway_item'] as $gateway) {
1594
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1595
				$setdefaultgw = true;
1596
				break;
1597
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1598
				$founddefaultgw = true;
1599
				break;
1600
			}
1601
		}
1602
	}
1603

    
1604
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1605
		$setdefaultgw = true;
1606
		$mpdconf .= <<<EOD
1607
	set iface route default
1608

    
1609
EOD;
1610
	}
1611
	$mpdconf .= <<<EOD
1612
	set iface {$ondemand} on-demand
1613
	set iface idle {$ppp['idletimeout']}
1614

    
1615
EOD;
1616

    
1617
	if (isset($ppp['ondemand']))
1618
		$mpdconf .= <<<EOD
1619
	set iface addrs 10.10.1.1 10.10.1.2
1620

    
1621
EOD;
1622

    
1623
	if (isset($ppp['tcpmssfix']))
1624
		$tcpmss = "disable";
1625
	else
1626
		$tcpmss = "enable";
1627
		$mpdconf .= <<<EOD
1628
	set iface {$tcpmss} tcpmssfix
1629

    
1630
EOD;
1631

    
1632
	$mpdconf .= <<<EOD
1633
	set iface up-script /usr/local/sbin/ppp-linkup
1634
	set iface down-script /usr/local/sbin/ppp-linkdown
1635
	set ipcp ranges {$ranges}
1636

    
1637
EOD;
1638
	if (isset($ppp['vjcomp']))
1639
		$mpdconf .= <<<EOD
1640
	set ipcp no vjcomp
1641

    
1642
EOD;
1643

    
1644
	if (isset($config['system']['dnsallowoverride']))
1645
		$mpdconf .= <<<EOD
1646
	set ipcp enable req-pri-dns
1647
	set ipcp enable req-sec-dns
1648

    
1649
EOD;
1650
	if (!isset($ppp['verbose_log']))
1651
		$mpdconf .= <<<EOD
1652
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1653

    
1654
EOD;
1655
	foreach($ports as $pid => $port){
1656
		$port = get_real_interface($port);
1657
		$mpdconf .= <<<EOD
1658

    
1659
	create link static {$interface}_link{$pid} {$type}
1660
	set link action bundle {$interface}
1661
	set link {$multilink} multilink
1662
	set link keep-alive 10 60
1663
	set link max-redial 0
1664

    
1665
EOD;
1666
		if (isset($ppp['shortseq']))
1667
			$mpdconf .= <<<EOD
1668
	set link no shortseq
1669

    
1670
EOD;
1671

    
1672
		if (isset($ppp['acfcomp']))
1673
			$mpdconf .= <<<EOD
1674
	set link no acfcomp
1675

    
1676
EOD;
1677

    
1678
		if (isset($ppp['protocomp']))
1679
			$mpdconf .= <<<EOD
1680
	set link no protocomp
1681

    
1682
EOD;
1683

    
1684
		$mpdconf .= <<<EOD
1685
	set link disable chap pap
1686
	set link accept chap pap eap
1687
	set link disable incoming
1688

    
1689
EOD;
1690

    
1691

    
1692
		if (!empty($bandwidths[$pid]))
1693
			$mpdconf .= <<<EOD
1694
	set link bandwidth {$bandwidths[$pid]}
1695

    
1696
EOD;
1697

    
1698
		if (empty($mtus[$pid]))
1699
			$mtus[$pid] = $defaultmtu;
1700
			$mpdconf .= <<<EOD
1701
	set link mtu {$mtus[$pid]}
1702

    
1703
EOD;
1704

    
1705
		if (!empty($mrus[$pid]))
1706
			$mpdconf .= <<<EOD
1707
	set link mru {$mrus[$pid]}
1708

    
1709
EOD;
1710

    
1711
		if (!empty($mrrus[$pid]))
1712
			$mpdconf .= <<<EOD
1713
	set link mrru {$mrrus[$pid]}
1714

    
1715
EOD;
1716

    
1717
		$mpdconf .= <<<EOD
1718
	set auth authname "{$ppp['username']}"
1719
	set auth password {$passwd}
1720

    
1721
EOD;
1722
		if ($type == "modem") {
1723
			$mpdconf .= <<<EOD
1724
	set modem device {$ppp['ports']}
1725
	set modem script DialPeer
1726
	set modem idle-script Ringback
1727
	set modem watch -cd
1728
	set modem var \$DialPrefix "DT"
1729
	set modem var \$Telephone "{$ppp['phone']}"
1730

    
1731
EOD;
1732
		}
1733
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1734
			$mpdconf .= <<<EOD
1735
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1736

    
1737
EOD;
1738
		}
1739
		if (isset($ppp['initstr']) && $type == "modem") {
1740
			$initstr = base64_decode($ppp['initstr']);
1741
			$mpdconf .= <<<EOD
1742
	set modem var \$InitString "{$initstr}"
1743

    
1744
EOD;
1745
		}
1746
		if (isset($ppp['simpin']) && $type == "modem") {
1747
			if($ppp['pin-wait'] == "")
1748
				$ppp['pin-wait'] = 0;
1749
			$mpdconf .= <<<EOD
1750
	set modem var \$SimPin "{$ppp['simpin']}"
1751
	set modem var \$PinWait "{$ppp['pin-wait']}"
1752

    
1753
EOD;
1754
		}
1755
		if (isset($ppp['apn']) && $type == "modem") {
1756
			$mpdconf .= <<<EOD
1757
	set modem var \$APN "{$ppp['apn']}"
1758
	set modem var \$APNum "{$ppp['apnum']}"
1759

    
1760
EOD;
1761
		}
1762
		if ($type == "pppoe") {
1763
			// Send a null service name if none is set.
1764
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1765
			$mpdconf .= <<<EOD
1766
	set pppoe service "{$provider}"
1767

    
1768
EOD;
1769
		}
1770
		if ($type == "pppoe")
1771
			$mpdconf .= <<<EOD
1772
	set pppoe iface {$port}
1773

    
1774
EOD;
1775

    
1776
		if ($type == "pptp" || $type == "l2tp") {
1777
			$mpdconf .= <<<EOD
1778
	set {$type} self {$localips[$pid]}
1779
	set {$type} peer {$gateways[$pid]}
1780

    
1781
EOD;
1782
		}
1783

    
1784
		$mpdconf .= "\topen\n";
1785
	} //end foreach($port)
1786

    
1787

    
1788
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1789
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1790
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1791
	else {
1792
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1793
		if (!$fd) {
1794
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1795
			return 0;
1796
		}
1797
		// Write out mpd_ppp.conf
1798
		fwrite($fd, $mpdconf);
1799
		fclose($fd);
1800
		unset($mpdconf);
1801
	}
1802

    
1803
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1804
	if (isset($ppp['uptime'])) {
1805
		if (!file_exists("/conf/{$pppif}.log")) {
1806
			conf_mount_rw();
1807
			file_put_contents("/conf/{$pppif}.log", '');
1808
			conf_mount_ro();
1809
		}
1810
	} else {
1811
		if (file_exists("/conf/{$pppif}.log")) {
1812
			conf_mount_rw();
1813
			@unlink("/conf/{$pppif}.log");
1814
			conf_mount_ro();
1815
		}
1816
	}
1817

    
1818
	/* clean up old lock files */
1819
	foreach($ports as $port) {
1820
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1821
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1822
	}
1823

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

    
1828
	// Check for PPPoE periodic reset request
1829
	if ($type == "pppoe") {
1830
		if (!empty($ppp['pppoe-reset-type']))
1831
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1832
		else
1833
			interface_setup_pppoe_reset_file($ppp['if']);
1834
	}
1835
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1836
	$i = 0;
1837
	while($i < 3) {
1838
		sleep(10);
1839
		if (does_interface_exist($ppp['if'], true))
1840
			break;
1841
		$i++;
1842
	}
1843

    
1844
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
1845
	/* We should be able to launch the right version for each modem */
1846
	/* We can also guess the mondev from the manufacturer */
1847
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
1848
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
1849
	foreach($ports as $port) {
1850
		if(preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1851
			$mondev  = substr(basename($port), 0, -1);
1852
			$devlist = glob("/dev/{$mondev}?");
1853
			$mondev = basename(end($devlist));
1854
		}
1855
		if(preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1856
			$mondev  = substr(basename($port), 0, -1) . "1";
1857
		}
1858
		if($mondev != '') {
1859
			log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
1860
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
1861
		}
1862
	}
1863

    
1864
	return 1;
1865
}
1866

    
1867
function interfaces_sync_setup() {
1868
	global $g, $config;
1869

    
1870
	if (isset($config['system']['developerspew'])) {
1871
		$mt = microtime();
1872
		echo "interfaces_sync_setup() being called $mt\n";
1873
	}
1874

    
1875
	if (platform_booting()) {
1876
		echo gettext("Configuring CARP settings...");
1877
		mute_kernel_msgs();
1878
	}
1879

    
1880
	/* suck in configuration items */
1881
	if ($config['hasync']) {
1882
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1883
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1884
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1885
	} else {
1886
		unset($pfsyncinterface);
1887
		unset($pfsyncenabled);
1888
	}
1889

    
1890
	set_sysctl(array(
1891
		"net.inet.carp.preempt" => "1",
1892
		"net.inet.carp.log" => "1")
1893
	);
1894

    
1895
	if (!empty($pfsyncinterface))
1896
		$carp_sync_int = get_real_interface($pfsyncinterface);
1897
	else
1898
		unset($carp_sync_int);
1899

    
1900
	/* setup pfsync interface */
1901
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
1902
		if (is_ipaddr($pfsyncpeerip))
1903
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1904
		else
1905
			$syncpeer = "-syncpeer";
1906

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

    
1909
		sleep(1);
1910

    
1911
		/* 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
1912
		 * for existing sessions.
1913
		 */
1914
		log_error("waiting for pfsync...");
1915
		$i = 0;
1916
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1917
			$i++;
1918
			sleep(1);
1919
		}
1920
		log_error("pfsync done in $i seconds.");
1921
		log_error("Configuring CARP settings finalize...");
1922
	} else {
1923
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
1924
	}
1925

    
1926
	if($config['virtualip']['vip'])
1927
		set_single_sysctl("net.inet.carp.allow", "1");
1928
	else
1929
		set_single_sysctl("net.inet.carp.allow", "0");
1930

    
1931
	if (platform_booting()) {
1932
		unmute_kernel_msgs();
1933
		echo gettext("done.") . "\n";
1934
	}
1935
}
1936

    
1937
function interface_proxyarp_configure($interface = "") {
1938
	global $config, $g;
1939
	if(isset($config['system']['developerspew'])) {
1940
		$mt = microtime();
1941
		echo "interface_proxyarp_configure() being called $mt\n";
1942
	}
1943

    
1944
	/* kill any running choparp */
1945
	if (empty($interface))
1946
		killbyname("choparp");
1947
	else {
1948
		$vipif = get_real_interface($interface);
1949
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1950
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1951
	}
1952

    
1953
	$paa = array();
1954
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1955

    
1956
		/* group by interface */
1957
		foreach ($config['virtualip']['vip'] as $vipent) {
1958
			if ($vipent['mode'] === "proxyarp") {
1959
				if ($vipent['interface'])
1960
					$proxyif = $vipent['interface'];
1961
				else
1962
					$proxyif = "wan";
1963

    
1964
				if (!empty($interface) && $interface != $proxyif)
1965
					continue;
1966

    
1967
				if (!is_array($paa[$proxyif]))
1968
					$paa[$proxyif] = array();
1969

    
1970
				$paa[$proxyif][] = $vipent;
1971
			}
1972
		}
1973
	}
1974

    
1975
	if (!empty($interface)) {
1976
		if (is_array($paa[$interface])) {
1977
			$paaifip = get_interface_ip($interface);
1978
			if (!is_ipaddr($paaifip))
1979
				return;
1980
			$args = get_real_interface($interface) . " auto";
1981
			foreach ($paa[$interface] as $paent) {
1982
				if (isset($paent['subnet']))
1983
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1984
				else if (isset($paent['range']))
1985
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1986
			}
1987
			mwexec_bg("/usr/local/sbin/choparp " . $args);
1988
		}
1989
	} else if (count($paa) > 0) {
1990
		foreach ($paa as $paif => $paents)  {
1991
			$paaifip = get_interface_ip($paif);
1992
			if (!is_ipaddr($paaifip))
1993
				continue;
1994
			$args = get_real_interface($paif) . " auto";
1995
			foreach ($paents as $paent) {
1996
				if (isset($paent['subnet']))
1997
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1998
				else if (isset($paent['range']))
1999
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2000
			}
2001
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2002
		}
2003
	}
2004
}
2005

    
2006
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2007
	global $g, $config;
2008

    
2009
	if (is_array($config['virtualip']['vip'])) {
2010
		foreach ($config['virtualip']['vip'] as $vip) {
2011
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2012
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2013
					interface_vip_bring_down($vip);
2014
				else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2015
					interface_vip_bring_down($vip);
2016
			}
2017
		}
2018
	}
2019
}
2020

    
2021
function interfaces_vips_configure($interface = "") {
2022
	global $g, $config;
2023
	if(isset($config['system']['developerspew'])) {
2024
		$mt = microtime();
2025
		echo "interfaces_vips_configure() being called $mt\n";
2026
	}
2027
	$paa = array();
2028
	if(is_array($config['virtualip']['vip'])) {
2029
		$carp_setuped = false;
2030
		$anyproxyarp = false;
2031
		foreach ($config['virtualip']['vip'] as $vip) {
2032
			switch ($vip['mode']) {
2033
			case "proxyarp":
2034
				/* nothing it is handled on interface_proxyarp_configure() */
2035
				if ($interface <> "" && $vip['interface'] <> $interface)
2036
					continue;
2037
				$anyproxyarp = true;
2038
				break;
2039
			case "ipalias":
2040
				if ($interface <> "" && $vip['interface'] <> $interface)
2041
					continue;
2042
				interface_ipalias_configure($vip);
2043
				break;
2044
			case "carp":
2045
				if ($interface <> "" && $vip['interface'] <> $interface)
2046
					continue;
2047
				if ($carp_setuped == false)
2048
					$carp_setuped = true;
2049
				interface_carp_configure($vip);
2050
				break;
2051
			}
2052
		}
2053
		if ($carp_setuped == true)
2054
			interfaces_sync_setup();
2055
		if ($anyproxyarp == true)
2056
			interface_proxyarp_configure();
2057
	}
2058
}
2059

    
2060
function interface_ipalias_configure(&$vip) {
2061
	global $config;
2062

    
2063
	if ($vip['mode'] != 'ipalias')
2064
		return;
2065

    
2066
	if ($vip['interface'] != 'lo0' && stripos($vip['interface'], '_vip') === false) {
2067
		if (!isset($config['interfaces'][$vip['interface']]))
2068
			return;
2069

    
2070
		if (!isset($config['interfaces'][$vip['interface']]['enable']))
2071
			return;
2072
	}
2073

    
2074
	$af = 'inet';
2075
	if(is_ipaddrv6($vip['subnet']))
2076
		$af = 'inet6';
2077
	$iface = $vip['interface'];
2078
	$vipadd = '';
2079
	if (strpos($vip['interface'], '_vip')) {
2080
		$carpvip = get_configured_carp_interface_list($vip['interface'], $af, 'vip');
2081
		$iface = $carpvip['interface'];
2082
		$vipadd = "vhid {$carpvip['vhid']}";
2083
	}
2084
	$if = get_real_interface($iface);
2085
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vipadd}");
2086
	unset($iface, $af, $if, $carpvip, $vipadd);
2087
}
2088

    
2089
function interface_reload_carps($cif) {
2090
	global $config;
2091

    
2092
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2093
	if (empty($carpifs))
2094
		return;
2095

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

    
2118
function interface_carp_configure(&$vip) {
2119
	global $config, $g;
2120
	if(isset($config['system']['developerspew'])) {
2121
		$mt = microtime();
2122
		echo "interface_carp_configure() being called $mt\n";
2123
	}
2124

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

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

    
2135
	if (is_ipaddrv4($vip['subnet'])) {
2136
		/* Ensure a IP on this interface exists prior to configuring CARP. */
2137
		$ww_subnet_ip = find_interface_ip($realif);
2138
		if (!is_ipaddrv4($ww_subnet_ip)) {
2139
			file_notice("CARP", sprintf(gettext("Interface does not have required IP address in the subnet of virtual IP address %s. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2140
			return;
2141
		}
2142
	} else if (is_ipaddrv6($vip['subnet'])) {
2143
		/* Ensure a IP on this interface exists prior to configuring CARP. */
2144
		$ww_subnet_ip = find_interface_ipv6($realif);
2145
		if (!is_ipaddrv6($ww_subnet_ip)) {
2146
			file_notice("CARP", sprintf(gettext("Interface does not have required IPv6 address in the subnet of virtual IPv6 address %s. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2147
			return;
2148
		}
2149
	}
2150

    
2151
	$vip_password = $vip['password'];
2152
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2153
	if ($vip['password'] != "")
2154
		$password = " pass {$vip_password}";
2155

    
2156
	$advbase = "";
2157
	if (!empty($vip['advbase']))
2158
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2159

    
2160
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2161
	if ($carp_maintenancemode)
2162
		$advskew = "advskew 254";
2163
	else
2164
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2165
	
2166
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) . " {$advskew} {$advbase} {$password}");
2167

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

    
2173
	return $realif;
2174
}
2175

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

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

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

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

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

    
2247
	if(!is_interface_wireless($ifcfg['if']))
2248
		return;
2249

    
2250
	$baseif = interface_get_wireless_base($ifcfg['if']);
2251

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

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

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

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

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

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

    
2322
	// Clone wireless nic if needed.
2323
	interface_wireless_clone($if, $wl);
2324

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2474
	kill_hostapd($if);
2475
	mwexec(kill_wpasupplicant("{$if}"));
2476

    
2477
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2478
	conf_mount_rw();
2479

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

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

    
2533
EOD;
2534

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

    
2541
EOD;
2542
			}
2543
			if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2544
				$wpa .= "ieee8021x=1\n";
2545

    
2546
			if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2547
				$auth_server_port = "1812";
2548
				if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port']))
2549
					$auth_server_port = intval($wlcfg['auth_server_port']);
2550
				$wpa .= <<<EOD
2551

    
2552
auth_server_addr={$wlcfg['auth_server_addr']}
2553
auth_server_port={$auth_server_port}
2554
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2555

    
2556
EOD;
2557
				if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2558
					$auth_server_port2 = "1812";
2559
					if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2']))
2560
						$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2561

    
2562
					$wpa .= <<<EOD
2563
auth_server_addr={$wlcfg['auth_server_addr2']}
2564
auth_server_port={$auth_server_port2}
2565
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2566

    
2567
EOD;
2568
					}
2569
				}
2570
			}
2571

    
2572
			@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2573
			unset($wpa);
2574
		}
2575
		break;
2576
	}
2577

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2690
		/* bring the clones back up that were previously up */
2691
		foreach ($clones_up as $clone_if) {
2692
			interfaces_bring_up($clone_if);
2693

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

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

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

    
2719

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

    
2724
	return 0;
2725

    
2726
}
2727

    
2728
function kill_hostapd($interface) {
2729
	global $g;
2730

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

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

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

    
2745
	return intval($pid);
2746
}
2747

    
2748
function kill_dhclient_process($interface) {
2749
	if (empty($interface) || !does_interface_exist($interface))
2750
		return;
2751

    
2752
	$i = 0;
2753
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2754
		/* 3rd time make it die for sure */
2755
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2756
		posix_kill($pid, $sig);
2757
		sleep(1);
2758
		$i++;
2759
	}
2760
	unset($i);
2761
}
2762

    
2763
function find_dhcp6c_process($interface) {
2764
	global $g;
2765

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

    
2771
	return intval($pid);
2772
}
2773

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

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

    
2814
function interface_vlan_mtu_configured($realhwif, $mtu) {
2815
	global $config;
2816

    
2817
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
2818
		foreach ($config['vlans']['vlan'] as $vlan) {
2819
			if ($vlan['if'] != $realhwif)
2820
				continue;
2821
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2822
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
2823
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2824
					$mtu = $config['interfaces'][$assignedport]['mtu'];
2825
			}
2826
		}
2827
	}
2828

    
2829
	return $mtu;
2830
}
2831

    
2832
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2833
	global $config;
2834

    
2835
	if (!is_array($vlanifs))
2836
		return;
2837

    
2838
	/* All vlans need to use the same mtu value as their parent. */
2839
	foreach ($vlanifs as $vlan) {
2840
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2841
		if (!empty($assignedport)) {
2842
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
2843
				pfSense_interface_mtu($vlan['vlanif'], $config['interfaces'][$assignedport]['mtu']);
2844
			} else {
2845
				if (get_interface_mtu($vlan['vlanif']) != $mtu)
2846
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2847
			}
2848
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2849
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
2850
	}
2851
}
2852

    
2853
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2854
	global $config, $g;
2855
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2856
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2857

    
2858
	$wancfg = $config['interfaces'][$interface];
2859

    
2860
	if (!isset($wancfg['enable']))
2861
		return;
2862

    
2863
	$realif = get_real_interface($interface);
2864
	$realhwif_array = get_parent_interface($interface);
2865
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2866
	$realhwif = $realhwif_array[0];
2867

    
2868
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
2869
		/* remove all IPv4 and IPv6 addresses */
2870
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2871
		if (is_array($tmpifaces)) {
2872
			foreach ($tmpifaces as $tmpiface) {
2873
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
2874
					if (!is_linklocal($tmpiface))
2875
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2876
				} else {
2877
					if (is_subnetv4($tmpiface)) {
2878
						$tmpip = explode('/', $tmpiface);
2879
						$tmpip = $tmpip[0];
2880
					} else
2881
						$tmpip = $tmpiface;
2882
					pfSense_interface_deladdress($realif, $tmpip);
2883
				}
2884
			}
2885
		}
2886

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

    
2892
	$interface_to_check = $realif;
2893
	if (interface_isppp_type($interface))
2894
		$interface_to_check = $realhwif;
2895

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

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

    
2905
	/* wireless configuration? */
2906
	if (is_array($wancfg['wireless']))
2907
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2908

    
2909
	$mac = get_interface_mac($realhwif);
2910
	/*
2911
	 * Don't try to reapply the spoofed MAC if it's already applied.
2912
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2913
	 * the interface config again, which attempts to spoof the MAC again,
2914
	 * which cycles the link again...
2915
	 */
2916
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
2917
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2918
			" link " . escapeshellarg($wancfg['spoofmac']));
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

    
2945
	/* Apply hw offloading policies as configured */
2946
	enable_hardware_offloading($interface);
2947

    
2948
	/* invalidate interface/ip/sn cache */
2949
	get_interface_arr(true);
2950
	unset($interface_ip_arr_cache[$realif]);
2951
	unset($interface_sn_arr_cache[$realif]);
2952
	unset($interface_ipv6_arr_cache[$realif]);
2953
	unset($interface_snv6_arr_cache[$realif]);
2954

    
2955
	$tunnelif = substr($realif, 0, 3);
2956
	switch ($wancfg['ipaddr']) {
2957
	case 'dhcp':
2958
		interface_dhcp_configure($interface);
2959
		break;
2960
	case 'pppoe':
2961
	case 'l2tp':
2962
	case 'pptp':
2963
	case 'ppp':
2964
		interface_ppps_configure($interface);
2965
		break;
2966
	default:
2967
		/* XXX: Kludge for now related to #3280 */
2968
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
2969
			if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "")
2970
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
2971
		}
2972
		break;
2973
	}
2974

    
2975
	switch ($wancfg['ipaddrv6']) {
2976
	case 'slaac':
2977
	case 'dhcp6':
2978
		interface_dhcpv6_configure($interface, $wancfg);
2979
		break;
2980
	case '6rd':
2981
		interface_6rd_configure($interface, $wancfg);
2982
		break;
2983
	case '6to4':
2984
		interface_6to4_configure($interface, $wancfg);
2985
		break;
2986
	case 'track6':
2987
		interface_track6_configure($interface, $wancfg, $linkupevent);
2988
		break;
2989
	default:
2990
		/* XXX: Kludge for now related to #3280 */
2991
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
2992
			if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
2993
				//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
2994
				// FIXME: Add IPv6 Support to the pfSense module
2995
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
2996
			}
2997
		}
2998
		break;
2999
	}
3000

    
3001
	if (!empty($wancfg['mtu'])) {
3002
		if (stristr($realif, "_vlan")) {
3003
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3004
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3005
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3006
				if ($wancfg['mtu'] > $parentmtu)
3007
					log_error("There is a conflict on MTU between parent {$realhwif} and VLAN({$realif})");
3008
			} else
3009
				$parentmtu = 0;
3010

    
3011
			$parentmtu = interface_vlan_mtu_configured($realhwif, $parentmtu);
3012

    
3013
			if (get_interface_mtu($realhwif) != $parentmtu)
3014
				pfSense_interface_mtu($realhwif, $parentmtu);
3015

    
3016
			/* All vlans need to use the same mtu value as their parent. */
3017
			interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $parentmtu);
3018
		} else if (substr($realif, 0, 4) == 'lagg') {
3019
			/* LAGG interface must be destroyed and re-created to change MTU */
3020
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3021
				if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3022
					foreach ($config['laggs']['lagg'] as $lagg) {
3023
						if ($lagg['laggif'] == $realif) {
3024
							interface_lagg_configure($lagg);
3025
							break;
3026
						}
3027
					}
3028
				}
3029
			}
3030
		} else {
3031
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3032
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3033

    
3034
			/* This case is needed when the parent of vlans is being configured */
3035
			$vlans = link_interface_to_vlans($realif);
3036
			if (is_array($vlans))
3037
				interface_vlan_adapt_mtu($vlans, $wancfg['mtu']);
3038
			unset($vlans);
3039
		}
3040
		/* XXX: What about gre/gif/.. ? */
3041
	}
3042

    
3043
	if (does_interface_exist($wancfg['if']))
3044
		interfaces_bring_up($wancfg['if']);
3045

    
3046
	interface_netgraph_needed($interface);
3047

    
3048
	if (!platform_booting()) {
3049
		link_interface_to_vips($interface, "update");
3050

    
3051
		unset($gre);
3052
		$gre = link_interface_to_gre($interface);
3053
		if (!empty($gre))
3054
			array_walk($gre, 'interface_gre_configure');
3055

    
3056
		unset($gif);
3057
		$gif = link_interface_to_gif($interface);
3058
		if (!empty($gif))
3059
			array_walk($gif, 'interface_gif_configure');
3060

    
3061
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3062
			unset($bridgetmp);
3063
			$bridgetmp = link_interface_to_bridge($interface);
3064
			if (!empty($bridgetmp))
3065
				interface_bridge_add_member($bridgetmp, $realif);
3066
		}
3067

    
3068
		$grouptmp = link_interface_to_group($interface);
3069
		if (!empty($grouptmp))
3070
			array_walk($grouptmp, 'interface_group_add_member');
3071

    
3072
		if ($interface == "lan")
3073
			/* make new hosts file */
3074
			system_hosts_generate();
3075

    
3076
		if ($reloadall == true) {
3077

    
3078
			/* reconfigure static routes (kernel may have deleted them) */
3079
			system_routing_configure($interface);
3080

    
3081
			/* reload ipsec tunnels */
3082
			vpn_ipsec_configure();
3083

    
3084
			/* restart dnsmasq or unbound */
3085
			if (isset($config['dnsmasq']['enable']))
3086
				services_dnsmasq_configure();
3087
			elseif (isset($config['unbound']['enable']))
3088
				services_unbound_configure();
3089

    
3090
			/* update dyndns */
3091
			send_event("service reload dyndns {$interface}");
3092

    
3093
			/* XXX: which CPZONE? Needed? */
3094
			/* reload captive portal */
3095
			captiveportal_init_rules();
3096
		}
3097
	}
3098

    
3099
	interfaces_staticarp_configure($interface);
3100
	return 0;
3101
}
3102

    
3103
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3104
	global $config, $g;
3105

    
3106
	if (!is_array($wancfg))
3107
		return;
3108

    
3109
	if (!isset($wancfg['enable']))
3110
		return;
3111

    
3112
	/* If the interface is not configured via another, exit */
3113
	if (empty($wancfg['track6-interface']))
3114
		return;
3115

    
3116
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3117
	$realif = get_real_interface($interface);
3118
	$linklocal = find_interface_ipv6_ll($realif);
3119
	if (!empty($linklocal))
3120
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3121
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3122
	/* XXX: Probably should remove? */
3123
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3124

    
3125
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3126
	if (!isset($trackcfg['enable'])) {
3127
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3128
		return;
3129
	}
3130

    
3131
	switch($trackcfg['ipaddrv6']) {
3132
	case "6to4":
3133
		if ($g['debug'])
3134
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3135
		interface_track6_6to4_configure($interface, $wancfg);
3136
		break;
3137
	case "6rd":
3138
		if ($g['debug'])
3139
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3140
		interface_track6_6rd_configure($interface, $wancfg);
3141
		break;
3142
	case "dhcp6":
3143
		if ($linkupevent == true) {
3144
			/* 
3145
			 * NOTE: Usually come here from rc.linkup calling so just call directly intead of generating event
3146
			 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3147
			 *
3148
			 * XXX: Probably DHCPv6 client should handle this autmagically itself?
3149
			 */
3150
			$parentrealif = get_real_interface($wancfg['track6-interface']);
3151
			$pidv6 = find_dhcp6c_process($parentrealif);
3152
			if($pidv6)
3153
				posix_kill($pidv6, SIGHUP);
3154
		}
3155
		break;
3156
	}
3157

    
3158
	if ($linkupevent == false) {
3159
		if (!function_exists('services_dhcpd_configure'))
3160
			require_once("services.inc");
3161

    
3162
		if (isset($config['unbound']['enable']))
3163
			services_unbound_configure();
3164

    
3165
		services_dhcpd_configure("inet6");
3166
	}
3167

    
3168
	return 0;
3169
}
3170

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

    
3176
	if (!is_array($lancfg))
3177
		return;
3178

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

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

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

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

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

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

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

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

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

    
3229
	return 0;
3230
}
3231

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

    
3237
	if (!is_array($lancfg))
3238
		return;
3239

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

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

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

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

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

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

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

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

    
3286
	return 0;
3287
}
3288

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

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

    
3295
	if (!is_array($wancfg))
3296
		return;
3297

    
3298
	if (!is_module_loaded('if_stf.ko'))
3299
		mwexec('/sbin/kldload if_stf.ko');
3300

    
3301
	$wanif = get_real_interface($interface);
3302
	$ip4address = find_interface_ip($wanif);
3303
	if (!is_ipaddrv4($ip4address)) {
3304
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3305
		return false;
3306
	}
3307
	$hexwanv4 = return_hex_ipv4($ip4address);
3308

    
3309
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3310
		$wancfg['prefix-6rd-v4plen'] = 0;
3311

    
3312
	/* create the long prefix notation for math, save the prefix length */
3313
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3314
	$rd6prefixlen = $rd6prefix[1];
3315
	$brgw = explode('.', $wancfg['gateway-6rd']);
3316
	$rd6brgw = rtrim($rd6prefix[0], ':') . ':' . dechex($brgw[0]) . dechex($brgw[1]) . ':' . dechex($brgw[2]) . dechex($brgw[3]) . '::';
3317
	unset($brgw);
3318
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3319

    
3320
	/* binary presentation of the prefix for all 128 bits. */
3321
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3322

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

    
3330
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3331
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3332

    
3333

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

    
3350
	/* write out a default router file */
3351
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3352
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3353

    
3354
	$ip4gateway = get_interface_gateway($interface);
3355
	if (is_ipaddrv4($ip4gateway))
3356
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3357

    
3358
	/* configure dependent interfaces */
3359
	if (!platform_booting())
3360
		link_interface_to_track6($interface, "update");
3361

    
3362
	return 0;
3363
}
3364

    
3365
function interface_6to4_configure($interface = "wan", $wancfg){
3366
	global $config, $g;
3367

    
3368
	/* because this is a tunnel interface we can only function
3369
	 *	with a public IPv4 address on the interface */
3370

    
3371
	if (!is_array($wancfg))
3372
		return;
3373

    
3374
	$wanif = get_real_interface($interface);
3375
	$ip4address = find_interface_ip($wanif);
3376
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3377
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3378
		return false;
3379
	}
3380

    
3381
	/* create the long prefix notation for math, save the prefix length */
3382
	$stfprefixlen = 16;
3383
	$stfprefix = Net_IPv6::uncompress("2002::");
3384
	$stfarr = explode(":", $stfprefix);
3385
	$v4prefixlen = "0";
3386

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

    
3393
	/* we need the hex form of the broker IPv4 address */
3394
	$ip4arr = explode(".", "192.88.99.1");
3395
	$hexbrv4 = "";
3396
	foreach($ip4arr as $octet)
3397
		$hexbrv4 .= sprintf("%02x", $octet);
3398

    
3399
	/* binary presentation of the prefix for all 128 bits. */
3400
	$stfprefixbin = "";
3401
	foreach($stfarr as $element) {
3402
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3403
	}
3404
	/* just save the left prefix length bits */
3405
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3406

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

    
3411
	/* for the local subnet too. */
3412
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3413
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3414

    
3415
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3416
	$stfbrarr = array();
3417
	$stfbrbinarr = array();
3418
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3419
	foreach($stfbrbinarr as $bin)
3420
		$stfbrarr[] = dechex(bindec($bin));
3421
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3422

    
3423
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3424
	$stflanarr = array();
3425
	$stflanbinarr = array();
3426
	$stflanbinarr = str_split($stflanbin, 16);
3427
	foreach($stflanbinarr as $bin)
3428
		$stflanarr[] = dechex(bindec($bin));
3429
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3430
	$stflanarr[7] = 1;
3431
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3432

    
3433
	/* setup the stf interface */
3434
	if (!is_module_loaded("if_stf"))
3435
		mwexec("/sbin/kldload if_stf.ko");
3436
	$stfiface = "{$interface}_stf";
3437
	if (does_interface_exist($stfiface))
3438
		pfSense_interface_destroy($stfiface);
3439
	$tmpstfiface = pfSense_interface_create("stf");
3440
	pfSense_interface_rename($tmpstfiface, $stfiface);
3441
	pfSense_interface_flags($stfiface, IFF_LINK2);
3442
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3443

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

    
3447
	/* write out a default router file */
3448
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3449
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3450

    
3451
	$ip4gateway = get_interface_gateway($interface);
3452
	if (is_ipaddrv4($ip4gateway))
3453
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3454

    
3455
	if (!platform_booting())
3456
		link_interface_to_track6($interface, "update");
3457

    
3458
	return 0;
3459
}
3460

    
3461
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3462
	global $config, $g;
3463

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

    
3467
	$wanif = get_real_interface($interface, "inet6");
3468
	$dhcp6cconf = "";
3469
	$dhcp6cconf .= "interface {$wanif} {\n";
3470

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

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

    
3489
		$dhcp6cconf .= "};\n";
3490

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

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

    
3517
	// DHCP6 Config File Advanced
3518
	if ($wancfg['adv_dhcp6_config_advanced']) { $dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif); }
3519

    
3520
	// DHCP6 Config File Override
3521
	if ($wancfg['adv_dhcp6_config_file_override']) { $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif); }
3522

    
3523
	/* wide-dhcp6c works for now. */
3524
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3525
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3526
		unset($dhcp6cconf);
3527
		return 1;
3528
	}
3529
	unset($dhcp6cconf);
3530

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

    
3545
	$rtsoldscript = "#!/bin/sh\n";
3546
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3547
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3548
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3549
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Recieved RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
3550
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3551
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3552
	$rtsoldscript .= "\t/bin/sleep 1\n";
3553
	$rtsoldscript .= "fi\n";
3554
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3555
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3556
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3557
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3558
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3559
		unset($rtsoldscript);
3560
		return 1;
3561
	}
3562
	unset($rtsoldscript);
3563
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3564

    
3565
	/* accept router advertisements for this interface */
3566
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3567
	log_error("Accept router advertisements on interface {$wanif} ");
3568
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3569

    
3570
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3571
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3572
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3573
		sleep(2);
3574
	}
3575
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3576

    
3577
	/* NOTE: will be called from rtsold invoked script
3578
	 * link_interface_to_track6($interface, "update");
3579
	 */
3580

    
3581
	return 0;
3582
}
3583

    
3584
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3585
	global $g;
3586

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

    
3595
	$request_options = "";
3596
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3597
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_request_options']);
3598
		foreach ($options as $option) {
3599
			$request_options .= "\trequest " . trim($option) . ";\n";
3600
		}
3601
	}
3602

    
3603
	$information_only = "";
3604
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') 
3605
		$information_only = "\tinformation-only;\n";
3606

    
3607
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3608
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '')
3609
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3610

    
3611
	$interface_statement  = "interface";
3612
	$interface_statement .= " {$wanif}";
3613
	$interface_statement .= " {\n";
3614
	$interface_statement .= "$send_options";
3615
	$interface_statement .= "$request_options";
3616
	$interface_statement .= "$information_only";
3617
	$interface_statement .= "$script";
3618
	$interface_statement .= "};\n";
3619

    
3620
	$id_assoc_statement_address = "";
3621
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3622
		$id_assoc_statement_address .= "id-assoc";
3623
		$id_assoc_statement_address .= " na";
3624
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) 
3625
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3626
		$id_assoc_statement_address .= " { ";
3627

    
3628
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') && 
3629
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) || 
3630
			 ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity')) ) {
3631
			$id_assoc_statement_address .= "\n\taddress";
3632
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3633
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3634
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) || 
3635
							($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity') ) 
3636
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3637
			$id_assoc_statement_address .= ";\n";
3638
		}
3639

    
3640
		$id_assoc_statement_address  .= "};\n";
3641
	}
3642

    
3643
	$id_assoc_statement_prefix = "";
3644
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3645
		$id_assoc_statement_prefix .= "id-assoc";
3646
		$id_assoc_statement_prefix .= " pd";
3647
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) 
3648
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3649
		$id_assoc_statement_prefix .= " { ";
3650

    
3651
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') && 
3652
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) || 
3653
			 ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity')) ) {
3654
			$id_assoc_statement_prefix .= "\n\tprefix";
3655
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3656
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3657
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) || 
3658
						  ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity') ) 
3659
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3660
			$id_assoc_statement_prefix .= ";";
3661
		}
3662

    
3663
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3664
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3665
			$id_assoc_statement_prefix .= " {$wanif}";
3666
			$id_assoc_statement_prefix .= " {\n";
3667
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3668
			if ( ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) && 
3669
				 ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128) ) 
3670
				 $id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3671
			$id_assoc_statement_prefix .= "\t};";
3672
		}
3673

    
3674
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') || 
3675
			 (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) ) { 
3676
			$id_assoc_statement_prefix .= "\n";
3677
		}
3678

    
3679
		$id_assoc_statement_prefix  .= "};\n";
3680
	}
3681

    
3682
	$authentication_statement = "";
3683
	if ( ($wancfg['adv_dhcp6_authentication_statement_authname'] != '') && 
3684
		 ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed') ) {
3685
		$authentication_statement .= "authentication";
3686
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
3687
		$authentication_statement .= " {\n";
3688
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
3689
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) 
3690
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
3691
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') 
3692
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
3693
		$authentication_statement .= "};\n";
3694
	}
3695

    
3696
	$key_info_statement = "";
3697
	if ( ($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') && 
3698
		 ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') && 
3699
		 (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) && 
3700
		 ($wancfg['adv_dhcp6_key_info_statement_secret'] != '') ) {
3701
		$key_info_statement .= "keyinfo";
3702
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
3703
		$key_info_statement .= " {\n";
3704
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
3705
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
3706
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
3707
		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'])) 
3708
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
3709
		$key_info_statement .= "};\n";
3710
	}
3711

    
3712
	$dhcp6cconf  = $interface_statement;
3713
	$dhcp6cconf .= $id_assoc_statement_address;
3714
	$dhcp6cconf .= $id_assoc_statement_prefix;
3715
	$dhcp6cconf .= $authentication_statement;
3716
	$dhcp6cconf .= $key_info_statement;
3717

    
3718
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3719

    
3720
	return $dhcp6cconf;
3721
}
3722

    
3723

    
3724
function DHCP6_Config_File_Override($wancfg, $wanif) {
3725

    
3726
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
3727
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3728

    
3729
	return $dhcp6cconf;
3730
}
3731

    
3732

    
3733
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
3734

    
3735
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3736

    
3737
	return $dhcp6cconf;
3738
}
3739

    
3740

    
3741
function interface_dhcp_configure($interface = "wan") {
3742
	global $config, $g;
3743

    
3744
	$wancfg = $config['interfaces'][$interface];
3745
	$wanif = $wancfg['if'];
3746
	if (empty($wancfg))
3747
		$wancfg = array();
3748

    
3749
	/* generate dhclient_wan.conf */
3750
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3751
	if (!$fd) {
3752
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3753
		return 1;
3754
	}
3755

    
3756
	if ($wancfg['dhcphostname']) {
3757
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3758
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3759
	} else {
3760
		$dhclientconf_hostname = "";
3761
	}
3762

    
3763
	$wanif = get_real_interface($interface);
3764
	if (empty($wanif)) {
3765
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3766
		return 0;
3767
	}
3768
	$dhclientconf = "";
3769

    
3770
	$dhclientconf .= <<<EOD
3771
interface "{$wanif}" {
3772
timeout 60;
3773
retry 15;
3774
select-timeout 0;
3775
initial-interval 1;
3776
	{$dhclientconf_hostname}
3777
	script "/sbin/dhclient-script";
3778
EOD;
3779

    
3780
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3781
	$dhclientconf .= <<<EOD
3782

    
3783
	reject {$wancfg['dhcprejectfrom']};
3784
EOD;
3785
}
3786
	$dhclientconf .= <<<EOD
3787

    
3788
}
3789

    
3790
EOD;
3791

    
3792
	// DHCP Config File Advanced
3793
	if ($wancfg['adv_dhcp_config_advanced']) { $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif); }
3794

    
3795
if(is_ipaddr($wancfg['alias-address'])) {
3796
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3797
	$dhclientconf .= <<<EOD
3798
alias {
3799
	interface  "{$wanif}";
3800
	fixed-address {$wancfg['alias-address']};
3801
	option subnet-mask {$subnetmask};
3802
}
3803

    
3804
EOD;
3805
}
3806

    
3807
	// DHCP Config File Override
3808
	if ($wancfg['adv_dhcp_config_file_override']) { $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif); }
3809

    
3810
	fwrite($fd, $dhclientconf);
3811
	fclose($fd);
3812

    
3813
	/* bring wan interface up before starting dhclient */
3814
	if($wanif)
3815
		interfaces_bring_up($wanif);
3816
	else
3817
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3818

    
3819
	/* Make sure dhclient is not running */
3820
	kill_dhclient_process($wanif);
3821

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

    
3825
	return 0;
3826
}
3827

    
3828
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3829

    
3830
	$hostname = "";
3831
	if ($wancfg['dhcphostname'] != '') {
3832
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3833
	}
3834

    
3835
	/* DHCP Protocol Timings */
3836
	$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");
3837
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
3838
		$pt_variable = "{$Protocol_Timing}";
3839
		${$pt_variable} = "";
3840
		if ($wancfg[$Protocol_Timing] != "") {
3841
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
3842
		}
3843
	}
3844

    
3845
	$send_options = "";
3846
	if ($wancfg['adv_dhcp_send_options'] != '') {
3847
		$options = split(",", $wancfg['adv_dhcp_send_options']);
3848
		foreach ($options as $option) {
3849
			$send_options .= "\tsend " . trim($option) . ";\n";
3850
		}
3851
	}
3852

    
3853
	$request_options = "";
3854
	if ($wancfg['adv_dhcp_request_options'] != '') {
3855
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
3856
	}
3857

    
3858
	$required_options = "";
3859
	if ($wancfg['adv_dhcp_required_options'] != '') {
3860
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
3861
	}
3862

    
3863
	$option_modifiers = "";
3864
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
3865
		$modifiers = split(",", $wancfg['adv_dhcp_option_modifiers']);
3866
		foreach ($modifiers as $modifier) {
3867
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
3868
		}
3869
	}
3870

    
3871
 	$dhclientconf  = "interface \"{$wanif}\" {\n";
3872
 	$dhclientconf .= "\n";
3873
 	$dhclientconf .= "# DHCP Protocol Timing Values\n";
3874
 	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
3875
 	$dhclientconf .= "{$adv_dhcp_pt_retry}";
3876
 	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
3877
 	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
3878
 	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
3879
 	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
3880
 	$dhclientconf .= "\n";
3881
 	$dhclientconf .= "# DHCP Protocol Options\n";
3882
 	$dhclientconf .= "{$hostname}";
3883
 	$dhclientconf .= "{$send_options}";
3884
 	$dhclientconf .= "{$request_options}";
3885
 	$dhclientconf .= "{$required_options}";
3886
 	$dhclientconf .= "{$option_modifiers}";
3887
 	$dhclientconf .= "\n";
3888
 	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
3889
 	$dhclientconf .= "}\n";
3890

    
3891
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3892

    
3893
	return $dhclientconf;
3894
}
3895

    
3896

    
3897
function DHCP_Config_File_Override($wancfg, $wanif) {
3898

    
3899
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
3900
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3901

    
3902
	return $dhclientconf;
3903
}
3904

    
3905

    
3906
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
3907

    
3908
	/* Apply Interface Substitutions */
3909
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
3910

    
3911
	/* Apply Hostname Substitutions */
3912
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
3913

    
3914
	/* Arrays of MAC Address Types, Cases, Delimiters */
3915
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
3916
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
3917
	$various_mac_cases      = array("U", "L");
3918
	$various_mac_delimiters = array("", " ", ":", "-", ".");
3919

    
3920
	/* Apply MAC Address Substitutions */
3921
	foreach ($various_mac_types as $various_mac_type) {
3922
		foreach ($various_mac_cases as $various_mac_case) {
3923
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
3924

    
3925
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
3926
				if ($res !== false) {
3927

    
3928
					/* Get MAC Address as ASCII String With Colon (:) Celimiters */
3929
					if ("$various_mac_case" == "U") $dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
3930
					if ("$various_mac_case" == "L") $dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
3931

    
3932
					if ("$various_mac_type" == "mac_addr_hex") {
3933
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
3934
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
3935
						$dhcpclientconf_mac_hex = "";
3936
						$delimiter = "";
3937
						for($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
3938
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
3939
							$delimiter = ":";
3940
						}
3941
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
3942
					}
3943

    
3944
					/* MAC Address Delimiter Substitutions */
3945
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
3946

    
3947
					/* Apply MAC Address Substitutions */
3948
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
3949
				}
3950
			}
3951
		}
3952
	}
3953

    
3954
	return $dhclientconf;
3955
}
3956

    
3957
function interfaces_group_setup() {
3958
	global $config;
3959

    
3960
	if (!is_array($config['ifgroups']['ifgroupentry']))
3961
		return;
3962

    
3963
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3964
		interface_group_setup($groupar);
3965

    
3966
	return;
3967
}
3968

    
3969
function interface_group_setup(&$groupname /* The parameter is an array */) {
3970
	global $config;
3971

    
3972
	if (!is_array($groupname))
3973
		return;
3974
	$members = explode(" ", $groupname['members']);
3975
	foreach($members as $ifs) {
3976
		$realif = get_real_interface($ifs);
3977
		if ($realif && does_interface_exist($realif))
3978
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3979
	}
3980

    
3981
	return;
3982
}
3983

    
3984
function is_interface_group($if) {
3985
	global $config;
3986

    
3987
	if (is_array($config['ifgroups']['ifgroupentry']))
3988
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
3989
			if ($groupentry['ifname'] === $if)
3990
				return true;
3991
		}
3992

    
3993
	return false;
3994
}
3995

    
3996
function interface_group_add_member($interface, $groupname) {
3997
	$interface = get_real_interface($interface);
3998
	if (does_interface_exist($interface))
3999
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4000
}
4001

    
4002
/* COMPAT Function */
4003
function convert_friendly_interface_to_real_interface_name($interface) {
4004
	return get_real_interface($interface);
4005
}
4006

    
4007
/* COMPAT Function */
4008
function get_real_wan_interface($interface = "wan") {
4009
	return get_real_interface($interface);
4010
}
4011

    
4012
/* COMPAT Function */
4013
function get_current_wan_address($interface = "wan") {
4014
	return get_interface_ip($interface);
4015
}
4016

    
4017
/*
4018
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4019
 */
4020
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4021
	global $config;
4022

    
4023
	if (stripos($interface, "_vip")) {
4024
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
4025
			if ($vip['mode'] == "carp")  {
4026
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4027
				return $vip['interface'];
4028
			}
4029
		}
4030
	}
4031

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

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

    
4040
		if (get_real_interface($if) == $interface)
4041
			return $if;
4042

    
4043
		if ($checkparent == false)
4044
			continue;
4045

    
4046
		$int = get_parent_interface($if, true);
4047
		if (is_array($int)) {
4048
			foreach ($int as $iface) {
4049
				if ($iface == $interface)
4050
					return $if;
4051
			}
4052
		}
4053
	}
4054

    
4055
	if ($interface == "enc0")
4056
		return 'IPsec';
4057
}
4058

    
4059
/* attempt to resolve interface to friendly descr */
4060
function convert_friendly_interface_to_friendly_descr($interface) {
4061
	global $config;
4062

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

    
4108
	return $ifdesc;
4109
}
4110

    
4111
function convert_real_interface_to_friendly_descr($interface) {
4112

    
4113
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4114

    
4115
	if (!empty($ifdesc))
4116
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4117

    
4118
	return $interface;
4119
}
4120

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

    
4133
	$parents = array();
4134
	//Check that we got a valid interface passed
4135
	$realif = get_real_interface($interface);
4136
	if ($realif == NULL)
4137
		return $parents;
4138

    
4139
	// If we got a real interface, find it's friendly assigned name
4140
	if ($interface == $realif && $avoidrecurse == false)
4141
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4142

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

    
4179
	if (empty($parents))
4180
		$parents[0] = $realif;
4181

    
4182
	return $parents;
4183
}
4184

    
4185
function interface_is_wireless_clone($wlif) {
4186
	if(!stristr($wlif, "_wlan")) {
4187
		return false;
4188
	} else {
4189
		return true;
4190
	}
4191
}
4192

    
4193
function interface_get_wireless_base($wlif) {
4194
	if(!stristr($wlif, "_wlan")) {
4195
		return $wlif;
4196
	} else {
4197
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4198
	}
4199
}
4200

    
4201
function interface_get_wireless_clone($wlif) {
4202
	if(!stristr($wlif, "_wlan")) {
4203
		return $wlif . "_wlan0";
4204
	} else {
4205
		return $wlif;
4206
	}
4207
}
4208

    
4209
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4210
	global $config, $g;
4211

    
4212
	$wanif = NULL;
4213

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

    
4244
		if (empty($config['interfaces'][$interface]))
4245
			break;
4246

    
4247
		$cfg = &$config['interfaces'][$interface];
4248

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

    
4301
	return $wanif;
4302
}
4303

    
4304
/* Guess the physical interface by providing a IP address */
4305
function guess_interface_from_ip($ipaddress) {
4306

    
4307
	$family = '';
4308
	if(is_ipaddrv4($ipaddress))
4309
		$family = 'inet';
4310
	if (empty($family) && is_ipaddrv6($ipaddress))
4311
		$family = 'inet6';
4312

    
4313
	if (empty($family))
4314
		return false;
4315

    
4316
	/* create a route table we can search */
4317
	$output = '';
4318
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4319
	$output[0] = trim($output[0], " \n");
4320
	if (!empty($output[0]))
4321
		return $output[0];
4322

    
4323
	return false;
4324
}
4325

    
4326
/*
4327
 * find_ip_interface($ip): return the interface where an ip is defined
4328
 *   (or if $bits is specified, where an IP within the subnet is defined)
4329
 */
4330
function find_ip_interface($ip, $bits = null) {
4331
	if (!is_ipaddr($ip))
4332
		return false;
4333

    
4334
	$isv6ip = is_ipaddrv6($ip);
4335

    
4336
	/* if list */
4337
	$ifdescrs = get_configured_interface_list();
4338

    
4339
	foreach ($ifdescrs as $ifdescr => $ifname) {
4340
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4341
		if (is_null($ifip))
4342
			continue;
4343
		if (is_null($bits)) {
4344
			if ($ip == $ifip) {
4345
				$int = get_real_interface($ifname);
4346
				return $int;
4347
			}
4348
		}
4349
		else {
4350
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4351
				$int = get_real_interface($ifname);
4352
				return $int;
4353
			}
4354
		}
4355
	}
4356

    
4357
	return false;
4358
}
4359

    
4360
/*
4361
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4362
 *   (or if $bits is specified, where an IP within the subnet is found)
4363
 */
4364
function find_virtual_ip_alias($ip, $bits = null) {
4365
	global $config;
4366

    
4367
	if (!is_array($config['virtualip']['vip'])) {
4368
		return false;
4369
	}
4370
	if (!is_ipaddr($ip))
4371
		return false;
4372

    
4373
	$isv6ip = is_ipaddrv6($ip);
4374

    
4375
	foreach ($config['virtualip']['vip'] as $vip) {
4376
		if ($vip['mode'] === "ipalias") {
4377
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4378
				continue;
4379
			if (is_null($bits)) {
4380
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4381
					return $vip;
4382
				}
4383
			}
4384
			else {
4385
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4386
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4387
					return $vip;
4388
				}
4389
			}
4390
		}
4391
	}
4392
	return false;
4393
}
4394

    
4395
/*
4396
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4397
 */
4398
function find_number_of_created_carp_interfaces() {
4399
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4400
}
4401

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

    
4427
				if ($if)
4428
					return $if;
4429
			}
4430
		}
4431
	}
4432
}
4433

    
4434
function link_carp_interface_to_parent($interface) {
4435
	global $config;
4436

    
4437
	if (empty($interface))
4438
		return;
4439

    
4440
	$carp_ip = get_interface_ip($interface);
4441
	$carp_ipv6 = get_interface_ipv6($interface);
4442

    
4443
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4444
		return;
4445

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

    
4468

    
4469
/****f* interfaces/link_ip_to_carp_interface
4470
 * NAME
4471
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4472
 * INPUTS
4473
 *   $ip
4474
 * RESULT
4475
 *   $carp_ints
4476
 ******/
4477
function link_ip_to_carp_interface($ip) {
4478
	global $config;
4479

    
4480
	if (!is_ipaddr($ip))
4481
		return;
4482

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

    
4501
	return $carp_ints;
4502
}
4503

    
4504
function link_interface_to_track6($int, $action = "") {
4505
	global $config;
4506

    
4507
	if (empty($int))
4508
		return;
4509

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

    
4526
function interface_find_child_cfgmtu($realiface) {
4527
	global $config;
4528

    
4529
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
4530
	$vlans = link_interface_to_vlans($realiface);
4531
	$bridge = link_interface_to_bridge($realiface);
4532
	if (!empty($interface)) {
4533
		$gifs = link_interface_to_gif($interface);
4534
		$gres = link_interface_to_gre($interface);
4535
	} else {
4536
		$gifs = array();
4537
		$gres = array();
4538
	}
4539

    
4540
	$mtu = 0;
4541
	if (is_array($vlans)) {
4542
		foreach ($vlans as $vlan) {
4543
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4544
			if (empty($ifass))
4545
				continue;
4546
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4547
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu)
4548
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4549
			}
4550
		}
4551
	}
4552
	if (is_array($gifs)) {
4553
		foreach ($gifs as $vlan) {
4554
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['gifif']);
4555
			if (empty($ifass))
4556
				continue;
4557
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4558
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu)
4559
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4560
			}
4561
		}
4562
	}
4563
	if (is_array($gres)) {
4564
		foreach ($gres as $vlan) {
4565
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['greif']);
4566
			if (empty($ifass))
4567
				continue;
4568
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4569
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu)
4570
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4571
			}
4572
		}
4573
	}
4574
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
4575
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
4576
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu)
4577
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
4578
	}
4579
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
4580

    
4581
	return $mtu;
4582
}
4583

    
4584
function link_interface_to_vlans($int, $action = "") {
4585
	global $config;
4586

    
4587
	if (empty($int))
4588
		return;
4589

    
4590
	if (is_array($config['vlans']['vlan'])) {
4591
		$ifaces = array();
4592
		foreach ($config['vlans']['vlan'] as $vlan) {
4593
			if ($int == $vlan['if']) {
4594
				if ($action == "update") {
4595
					interfaces_bring_up($int);
4596
				} else
4597
					$ifaces[$vlan['tag']] = $vlan;
4598
			}
4599
		}
4600
		if (!empty($ifaces))
4601
			return $ifaces;
4602
	}
4603
}
4604

    
4605
function link_interface_to_vips($int, $action = "") {
4606
	global $config;
4607

    
4608
	if (is_array($config['virtualip']['vip'])) {
4609
		$result = array();
4610
		foreach ($config['virtualip']['vip'] as $vip) {
4611
			if ($int == $vip['interface']) {
4612
				if ($action == "update")
4613
					interfaces_vips_configure($int);
4614
				else
4615
					$result[] = $vip;
4616
			}
4617
		}
4618
		return $result;
4619
	}
4620
}
4621

    
4622
/****f* interfaces/link_interface_to_bridge
4623
 * NAME
4624
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4625
 * INPUTS
4626
 *   $ip
4627
 * RESULT
4628
 *   bridge[0-99]
4629
 ******/
4630
function link_interface_to_bridge($int) {
4631
	global $config;
4632

    
4633
	if (is_array($config['bridges']['bridged'])) {
4634
		foreach ($config['bridges']['bridged'] as $bridge) {
4635
			if (in_array($int, explode(',', $bridge['members'])))
4636
				return "{$bridge['bridgeif']}";
4637
		}
4638
	}
4639
}
4640

    
4641
function link_interface_to_group($int) {
4642
	global $config;
4643

    
4644
	$result = array();
4645

    
4646
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4647
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4648
			if (in_array($int, explode(" ", $group['members'])))
4649
				$result[$group['ifname']] = $int;
4650
		}
4651
	}
4652

    
4653
	return $result;
4654
}
4655

    
4656
function link_interface_to_gre($interface) {
4657
	global $config;
4658

    
4659
	$result = array();
4660

    
4661
	if (is_array($config['gres']['gre'])) {
4662
		foreach ($config['gres']['gre'] as $gre)
4663
			if($gre['if'] == $interface)
4664
				$result[] = $gre;
4665
	}
4666

    
4667
	return $result;
4668
}
4669

    
4670
function link_interface_to_gif($interface) {
4671
	global $config;
4672

    
4673
	$result = array();
4674

    
4675
	if (is_array($config['gifs']['gif'])) {
4676
		foreach ($config['gifs']['gif'] as $gif)
4677
			if($gif['if'] == $interface)
4678
				$result[] = $gif;
4679
	}
4680

    
4681
	return $result;
4682
}
4683

    
4684
/*
4685
 * find_interface_ip($interface): return the interface ip (first found)
4686
 */
4687
function find_interface_ip($interface, $flush = false) {
4688
	global $interface_ip_arr_cache;
4689
	global $interface_sn_arr_cache;
4690

    
4691
	$interface = str_replace("\n", "", $interface);
4692

    
4693
	if (!does_interface_exist($interface))
4694
		return;
4695

    
4696
	/* Setup IP cache */
4697
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4698
		$ifinfo = pfSense_get_interface_addresses($interface);
4699
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4700
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4701
	}
4702

    
4703
	return $interface_ip_arr_cache[$interface];
4704
}
4705

    
4706
/*
4707
 * find_interface_ipv6($interface): return the interface ip (first found)
4708
 */
4709
function find_interface_ipv6($interface, $flush = false) {
4710
	global $interface_ipv6_arr_cache;
4711
	global $interface_snv6_arr_cache;
4712
	global $config;
4713

    
4714
	$interface = trim($interface);
4715
	$interface = get_real_interface($interface);
4716

    
4717
	if (!does_interface_exist($interface))
4718
		return;
4719

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

    
4727
	return $interface_ipv6_arr_cache[$interface];
4728
}
4729

    
4730
/*
4731
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4732
 */
4733
function find_interface_ipv6_ll($interface, $flush = false) {
4734
	global $interface_llv6_arr_cache;
4735
	global $config;
4736

    
4737
	$interface = str_replace("\n", "", $interface);
4738

    
4739
	if (!does_interface_exist($interface))
4740
		return;
4741

    
4742
	/* Setup IP cache */
4743
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4744
		$ifinfo = pfSense_getall_interface_addresses($interface);
4745
		foreach($ifinfo as $line) {
4746
			if (strstr($line, ":")) {
4747
				$parts = explode("/", $line);
4748
				if(is_linklocal($parts[0])) {
4749
					$ifinfo['linklocal'] = $parts[0];
4750
				}
4751
			}
4752
		}
4753
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4754
	}
4755
	return $interface_llv6_arr_cache[$interface];
4756
}
4757

    
4758
function find_interface_subnet($interface, $flush = false) {
4759
	global $interface_sn_arr_cache;
4760
	global $interface_ip_arr_cache;
4761

    
4762
	$interface = str_replace("\n", "", $interface);
4763
	if (does_interface_exist($interface) == false)
4764
		return;
4765

    
4766
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4767
		$ifinfo = pfSense_get_interface_addresses($interface);
4768
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4769
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4770
	}
4771

    
4772
	return $interface_sn_arr_cache[$interface];
4773
}
4774

    
4775
function find_interface_subnetv6($interface, $flush = false) {
4776
	global $interface_snv6_arr_cache;
4777
	global $interface_ipv6_arr_cache;
4778

    
4779
	$interface = str_replace("\n", "", $interface);
4780
	if (does_interface_exist($interface) == false)
4781
		return;
4782

    
4783
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4784
		$ifinfo = pfSense_get_interface_addresses($interface);
4785
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4786
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4787
	}
4788

    
4789
	return $interface_snv6_arr_cache[$interface];
4790
}
4791

    
4792
function ip_in_interface_alias_subnet($interface, $ipalias) {
4793
	global $config;
4794

    
4795
	if (empty($interface) || !is_ipaddr($ipalias))
4796
		return false;
4797
	if (is_array($config['virtualip']['vip'])) {
4798
		foreach ($config['virtualip']['vip'] as $vip) {
4799
			switch ($vip['mode']) {
4800
			case "ipalias":
4801
				if ($vip['interface'] <> $interface)
4802
					break;
4803
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4804
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4805
					return true;
4806
				break;
4807
			}
4808
		}
4809
	}
4810

    
4811
	return false;
4812
}
4813

    
4814
function get_interface_ip($interface = "wan") {
4815
	
4816
	$realif = get_failover_interface($interface);
4817
	if (!$realif) {
4818
		if (strstr($interface, "_vip"))
4819
			return get_configured_carp_interface_list($interface);
4820
		else
4821
			return null;
4822
	}
4823

    
4824
	$curip = find_interface_ip($realif);
4825
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4826
		return $curip;
4827
	else
4828
		return null;
4829
}
4830

    
4831
function get_interface_ipv6($interface = "wan", $flush = false) {
4832
	global $config;
4833

    
4834
	$realif = get_failover_interface($interface, "inet6");
4835
	if (!$realif) {
4836
		if (strstr($interface, "_vip"))
4837
			return get_configured_carp_interface_list($interface, "inet6");
4838
		else
4839
			return null;
4840
	}
4841

    
4842
	/*
4843
	 * NOTE: On the case when only the prefix is requested,
4844
	 * the communication on WAN will be done over link-local.
4845
	 */
4846
	if (is_array($config['interfaces'][$interface])) {
4847
		switch ($config['interfaces'][$interface]['ipaddr']) {
4848
		case 'pppoe':
4849
		case 'l2tp':
4850
		case 'pptp':
4851
		case 'ppp':
4852
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4853
				$realif = get_real_interface($interface, "inet6", true);
4854
			break;
4855
		}
4856
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4857
			$curip = find_interface_ipv6_ll($realif, $flush);
4858
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4859
				return $curip;
4860
		}
4861
	}
4862

    
4863
	$curip = find_interface_ipv6($realif, $flush);
4864
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4865
		return $curip;
4866
	else
4867
		return null;
4868
}
4869

    
4870
function get_interface_linklocal($interface = "wan") {
4871

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

    
4881
	$curip = find_interface_ipv6_ll($realif);
4882
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4883
		return $curip;
4884
	else
4885
		return null;
4886
}
4887

    
4888
function get_interface_subnet($interface = "wan") {
4889
	$realif = get_real_interface($interface);
4890
	if (!$realif) {
4891
		if (strstr($interface, "_vip")) {
4892
			list($interface, $vhid) = explode("_vip", $interface);
4893
			$realif = get_real_interface($interface);
4894
		} else
4895
			return null;
4896
	}
4897

    
4898
	$cursn = find_interface_subnet($realif);
4899
	if (!empty($cursn))
4900
		return $cursn;
4901

    
4902
	return null;
4903
}
4904

    
4905
function get_interface_subnetv6($interface = "wan") {
4906
	global $config;
4907

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

    
4917
	$cursn = find_interface_subnetv6($realif);
4918
	if (!empty($cursn))
4919
		return $cursn;
4920

    
4921
	return null;
4922
}
4923

    
4924
/* return outside interfaces with a gateway */
4925
function get_interfaces_with_gateway() {
4926
	global $config;
4927

    
4928
	$ints = array();
4929

    
4930
	/* loop interfaces, check config for outbound */
4931
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4932
		switch ($ifname['ipaddr']) {
4933
			case "dhcp":
4934
			case "ppp";
4935
			case "pppoe":
4936
			case "pptp":
4937
			case "l2tp":
4938
			case "ppp";
4939
				$ints[$ifdescr] = $ifdescr;
4940
			break;
4941
			default:
4942
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
4943
				    !empty($ifname['gateway']))
4944
					$ints[$ifdescr] = $ifdescr;
4945
			break;
4946
		}
4947
	}
4948
	return $ints;
4949
}
4950

    
4951
/* return true if interface has a gateway */
4952
function interface_has_gateway($friendly) {
4953
	global $config;
4954

    
4955
	if (!empty($config['interfaces'][$friendly])) {
4956
		$ifname = &$config['interfaces'][$friendly];
4957
		switch ($ifname['ipaddr']) {
4958
			case "dhcp":
4959
			case "pppoe":
4960
			case "pptp":
4961
			case "l2tp":
4962
			case "ppp";
4963
				return true;
4964
			break;
4965
			default:
4966
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4967
					return true;
4968
				$tunnelif = substr($ifname['if'], 0, 3);
4969
				if ($tunnelif == "gif" || $tunnelif == "gre")
4970
					return true;
4971
				if (!empty($ifname['gateway']))
4972
					return true;
4973
			break;
4974
		}
4975
	}
4976

    
4977
	return false;
4978
}
4979

    
4980
/* return true if interface has a gateway */
4981
function interface_has_gatewayv6($friendly) {
4982
	global $config;
4983

    
4984
	if (!empty($config['interfaces'][$friendly])) {
4985
		$ifname = &$config['interfaces'][$friendly];
4986
		switch ($ifname['ipaddrv6']) {
4987
			case "slaac":
4988
			case "dhcp6":
4989
			case "6to4":
4990
			case "6rd":
4991
				return true;
4992
				break;
4993
			default:
4994
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4995
					return true;
4996
				$tunnelif = substr($ifname['if'], 0, 3);
4997
				if ($tunnelif == "gif" || $tunnelif == "gre")
4998
					return true;
4999
				if (!empty($ifname['gatewayv6']))
5000
					return true;
5001
				break;
5002
		}
5003
	}
5004

    
5005
	return false;
5006
}
5007

    
5008
/****f* interfaces/is_altq_capable
5009
 * NAME
5010
 *   is_altq_capable - Test if interface is capable of using ALTQ
5011
 * INPUTS
5012
 *   $int            - string containing interface name
5013
 * RESULT
5014
 *   boolean         - true or false
5015
 ******/
5016

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

    
5030
	$int_family = remove_ifindex($int);
5031

    
5032
	if (in_array($int_family, $capable))
5033
		return true;
5034
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
5035
		return true;
5036
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
5037
		return true;
5038
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
5039
		return true;
5040
	else
5041
		return false;
5042
}
5043

    
5044
/****f* interfaces/is_interface_wireless
5045
 * NAME
5046
 *   is_interface_wireless - Returns if an interface is wireless
5047
 * RESULT
5048
 *   $tmp       - Returns if an interface is wireless
5049
 ******/
5050
function is_interface_wireless($interface) {
5051
	global $config, $g;
5052

    
5053
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5054
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
5055
		if (preg_match($g['wireless_regex'], $interface)) {
5056
			if (isset($config['interfaces'][$friendly]))
5057
				$config['interfaces'][$friendly]['wireless'] = array();
5058
			return true;
5059
		}
5060
		return false;
5061
	} else
5062
		return true;
5063
}
5064

    
5065
function get_wireless_modes($interface) {
5066
	/* return wireless modes and channels */
5067
	$wireless_modes = array();
5068

    
5069
	$cloned_interface = get_real_interface($interface);
5070

    
5071
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5072
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5073
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5074
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5075

    
5076
		$interface_channels = "";
5077
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5078
		$interface_channel_count = count($interface_channels);
5079

    
5080
		$c = 0;
5081
		while ($c < $interface_channel_count) {
5082
			$channel_line = explode(",", $interface_channels["$c"]);
5083
			$wireless_mode = trim($channel_line[0]);
5084
			$wireless_channel = trim($channel_line[1]);
5085
			if(trim($wireless_mode) != "") {
5086
				/* if we only have 11g also set 11b channels */
5087
				if($wireless_mode == "11g") {
5088
					if(!isset($wireless_modes["11b"]))
5089
						$wireless_modes["11b"] = array();
5090
				} else if($wireless_mode == "11g ht") {
5091
					if(!isset($wireless_modes["11b"]))
5092
						$wireless_modes["11b"] = array();
5093
					if(!isset($wireless_modes["11g"]))
5094
						$wireless_modes["11g"] = array();
5095
					$wireless_mode = "11ng";
5096
				} else if($wireless_mode == "11a ht") {
5097
					if(!isset($wireless_modes["11a"]))
5098
						$wireless_modes["11a"] = array();
5099
					$wireless_mode = "11na";
5100
				}
5101
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5102
			}
5103
			$c++;
5104
		}
5105
	}
5106
	return($wireless_modes);
5107
}
5108

    
5109
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5110
function get_wireless_channel_info($interface) {
5111
	$wireless_channels = array();
5112

    
5113
	$cloned_interface = get_real_interface($interface);
5114

    
5115
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5116
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5117
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5118
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5119

    
5120
		$interface_channels = "";
5121
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5122

    
5123
		foreach ($interface_channels as $channel_line) {
5124
			$channel_line = explode(",", $channel_line);
5125
			if(!isset($wireless_channels[$channel_line[0]]))
5126
				$wireless_channels[$channel_line[0]] = $channel_line;
5127
		}
5128
	}
5129
	return($wireless_channels);
5130
}
5131

    
5132
/****f* interfaces/get_interface_mtu
5133
 * NAME
5134
 *   get_interface_mtu - Return the mtu of an interface
5135
 * RESULT
5136
 *   $tmp       - Returns the mtu of an interface
5137
 ******/
5138
function get_interface_mtu($interface) {
5139
	$mtu = pfSense_interface_getmtu($interface);
5140
	return $mtu['mtu'];
5141
}
5142

    
5143
function get_interface_mac($interface) {
5144

    
5145
	$macinfo = pfSense_get_interface_addresses($interface);
5146
	return $macinfo["macaddr"];
5147
}
5148

    
5149
/****f* pfsense-utils/generate_random_mac_address
5150
 * NAME
5151
 *   generate_random_mac - generates a random mac address
5152
 * INPUTS
5153
 *   none
5154
 * RESULT
5155
 *   $mac - a random mac address
5156
 ******/
5157
function generate_random_mac_address() {
5158
	$mac = "02";
5159
	for($x=0; $x<5; $x++)
5160
		$mac .= ":" . dechex(rand(16, 255));
5161
	return $mac;
5162
}
5163

    
5164
/****f* interfaces/is_jumbo_capable
5165
 * NAME
5166
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5167
 * INPUTS
5168
 *   $int             - string containing interface name
5169
 * RESULT
5170
 *   boolean          - true or false
5171
 ******/
5172
function is_jumbo_capable($iface) {
5173
	$iface = trim($iface);
5174
	$capable = pfSense_get_interface_addresses($iface);
5175

    
5176
	if (isset($capable['caps']['vlanmtu']))
5177
		return true;
5178

    
5179
	return false;
5180
}
5181

    
5182
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5183
	global $g;
5184

    
5185
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5186

    
5187
	if(!empty($iface) && !empty($pppif)){
5188
		$cron_cmd = <<<EOD
5189
#!/bin/sh
5190
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5191
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5192

    
5193
EOD;
5194

    
5195
		@file_put_contents($cron_file, $cron_cmd);
5196
		chmod($cron_file, 0755);
5197
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5198
	} else
5199
		unlink_if_exists($cron_file);
5200
}
5201

    
5202
function get_interface_default_mtu($type = "ethernet") {
5203
	switch ($type) {
5204
	case "gre":
5205
		return 1476;
5206
		break;
5207
	case "gif":
5208
		return 1280;
5209
		break;
5210
	case "tun":
5211
	case "vlan":
5212
	case "tap":
5213
	case "ethernet":
5214
	default:
5215
		return 1500;
5216
		break;
5217
	}
5218

    
5219
	/* Never reached */
5220
	return 1500;
5221
}
5222

    
5223
function get_vip_descr($ipaddress) {
5224
	global $config;
5225

    
5226
	foreach ($config['virtualip']['vip'] as $vip) {
5227
		if ($vip['subnet'] == $ipaddress) {
5228
			return ($vip['descr']);
5229
		}
5230
	}
5231
	return "";
5232
}
5233

    
5234
function interfaces_staticarp_configure($if) {
5235
	global $config, $g;
5236
	if(isset($config['system']['developerspew'])) {
5237
		$mt = microtime();
5238
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5239
	}
5240

    
5241
	$ifcfg = $config['interfaces'][$if];
5242

    
5243
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5244
		return 0;
5245

    
5246
	/* Enable staticarp, if enabled */
5247
	if(isset($config['dhcpd'][$if]['staticarp'])) {
5248
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
5249
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5250
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5251

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

    
5255
			}
5256

    
5257
		}
5258
	} else {
5259
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
5260
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5261
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5262
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5263
				if (isset($arpent['arp_table_static_entry'])) {
5264
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5265
				}
5266
			}
5267
		}
5268
	}
5269

    
5270
	return 0;
5271
}
5272

    
5273
function get_failover_interface($interface, $family = "all") {
5274
	global $config;
5275

    
5276
	/* shortcut to get_real_interface if we find it in the config */
5277
	if (is_array($config['interfaces'][$interface])) {
5278
		return get_real_interface($interface, $family);
5279
	}
5280

    
5281
	/* compare against gateway groups */
5282
	$a_groups = return_gateway_groups_array();
5283
	if (is_array($a_groups[$interface])) {
5284
		/* we found a gateway group, fetch the interface or vip */
5285
		if ($a_groups[$interface][0]['vip'] <> "")
5286
			return $a_groups[$interface][0]['vip'];
5287
		else
5288
			return $a_groups[$interface][0]['int'];
5289
	}
5290
	/* fall through to get_real_interface */
5291
	/* XXX: Really needed? */
5292
	return get_real_interface($interface, $family);
5293
}
5294

    
5295
function remove_ifindex($ifname) {
5296
	return preg_replace("/[0-9]+$/", "", $ifname);
5297
}
5298

    
5299
?>
(26-26/68)