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
		if (!empty($config['interfaces'][$interface])) {
144
			switch ($config['interfaces'][$interface]['ipaddr']) {
145
			case "ppp":
146
			case "pppoe":
147
			case "l2tp":
148
			case "pptp":
149
				$found = true;
150
				break;
151
			default:
152
				$found = false;
153
				break;
154
			}
155
		}
156
	}
157
	if ($found == false) {
158
		$realif = get_real_interface($interface);
159
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
160
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
161

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

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

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

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

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

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

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

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

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

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

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

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

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

    
266
	interfaces_bring_up($vlanif);
267

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

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

    
274
	return $vlanif;
275
}
276

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

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

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

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

    
297
	$vlanif = interface_vlan_configure($vlan);
298

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

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

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

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

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

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

    
350
	return $vlanif;
351
}
352

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

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

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

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

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

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

    
393
	return $vlanif;
394
}
395

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

    
399
	if (platform_booting())
400
		echo gettext("Creating wireless clone interfaces...");
401

    
402
	$iflist = get_configured_interface_list();
403

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

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

    
423
}
424

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

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

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

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

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

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

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

    
476
	/* Calculate smaller mtu and enforce it */
477
	$smallermtu = 0;
478
	$commonrx = true;
479
	$commontx = true;
480
	$foundgif = false;
481
	foreach ($members as $member) {
482
		$realif = get_real_interface($member);
483
		$mtu = get_interface_mtu($realif);
484
		if (substr($realif, 0, 3) == "gif") {
485
			$foundgif = true;
486
			if ($checkmember == 1)
487
				return;
488
			if ($mtu <= 1500)
489
				continue;
490
		}
491
		if ($smallermtu == 0 && !empty($mtu))
492
			$smallermtu = $mtu;
493
		else if (!empty($mtu) && $mtu < $smallermtu)
494
			$smallermtu = $mtu;
495
	}
496
	if ($foundgif == false && $checkmember == 2)
497
		return;
498

    
499
	/* Just in case anything is not working well */
500
	if ($smallermtu == 0)
501
		$smallermtu = 1500;
502

    
503
	if (platform_booting() || !empty($bridge['bridgeif'])) {
504
		pfSense_interface_destroy($bridge['bridgeif']);
505
		pfSense_interface_create($bridge['bridgeif']);
506
		$bridgeif = escapeshellarg($bridge['bridgeif']);
507
	} else {
508
		$bridgeif = pfSense_interface_create("bridge");
509
		$bridge['bridgeif'] = $bridgeif;
510
	}
511

    
512
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
513
	if ($bridgemtu > $smallermtu)
514
		$smallermtu = $bridgemtu;
515

    
516
	$checklist = get_configured_interface_list();
517

    
518
	/* Add interfaces to bridge */
519
	foreach ($members as $member) {
520
		if (empty($checklist[$member]))
521
			continue;
522
		$realif = get_real_interface($member);
523
		if (!$realif) {
524
			log_error(gettext("realif not defined in interfaces bridge - up"));
525
			continue;
526
		}
527
		/* make sure the parent interface is up */
528
		pfSense_interface_mtu($realif, $smallermtu);
529
		interfaces_bring_up($realif);
530
		enable_hardware_offloading($member);
531
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
532
	}
533

    
534
	if (isset($bridge['enablestp'])) {
535
		/* Choose spanning tree proto */
536
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
537

    
538
		if (!empty($bridge['stp'])) {
539
			$stpifs = explode(',', $bridge['stp']);
540
			foreach ($stpifs as $stpif) {
541
				$realif = get_real_interface($stpif);
542
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
543
			}
544
		}
545
		if (!empty($bridge['maxage']))
546
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
547
		if (!empty($bridge['fwdelay']))
548
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
549
		if (!empty($bridge['hellotime']))
550
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
551
		if (!empty($bridge['priority']))
552
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
553
		if (!empty($bridge['holdcnt']))
554
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
555
		if (!empty($bridge['ifpriority'])) {
556
			$pconfig = explode(",", $bridge['ifpriority']);
557
			$ifpriority = array();
558
			foreach ($pconfig as $cfg) {
559
				$embcfg = explode_assoc(":", $cfg);
560
				foreach ($embcfg as $key => $value)
561
					$ifpriority[$key] = $value;
562
			}
563
			foreach ($ifpriority as $key => $value) {
564
				$realif = get_real_interface($key);
565
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
566
			}
567
		}
568
		if (!empty($bridge['ifpathcost'])) {
569
			$pconfig = explode(",", $bridge['ifpathcost']);
570
			$ifpathcost = array();
571
			foreach ($pconfig as $cfg) {
572
				$embcfg = explode_assoc(":", $cfg);
573
				foreach ($embcfg as $key => $value)
574
					$ifpathcost[$key] = $value;
575
			}
576
			foreach ($ifpathcost as $key => $value) {
577
				$realif = get_real_interface($key);
578
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
579
			}
580
		}
581
	}
582

    
583
	if ($bridge['maxaddr'] <> "")
584
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
585
	if ($bridge['timeout'] <> "")
586
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
587
	if ($bridge['span'] <> "") {
588
		$realif = get_real_interface($bridge['span']);
589
		mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
590
	}
591
	if (!empty($bridge['edge'])) {
592
		$edgeifs = explode(',', $bridge['edge']);
593
		foreach ($edgeifs as $edgeif) {
594
			$realif = get_real_interface($edgeif);
595
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
596
		}
597
	}
598
	if (!empty($bridge['autoedge'])) {
599
		$edgeifs = explode(',', $bridge['autoedge']);
600
		foreach ($edgeifs as $edgeif) {
601
			$realif = get_real_interface($edgeif);
602
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
603
		}
604
	}
605
	if (!empty($bridge['ptp'])) {
606
		$ptpifs = explode(',', $bridge['ptp']);
607
		foreach ($ptpifs as $ptpif) {
608
			$realif = get_real_interface($ptpif);
609
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
610
		}
611
	}
612
	if (!empty($bridge['autoptp'])) {
613
		$ptpifs = explode(',', $bridge['autoptp']);
614
		foreach ($ptpifs as $ptpif) {
615
			$realif = get_real_interface($ptpif);
616
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
617
		}
618
	}
619
	if (!empty($bridge['static'])) {
620
		$stickyifs = explode(',', $bridge['static']);
621
		foreach ($stickyifs as $stickyif) {
622
			$realif = get_real_interface($stickyif);
623
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
624
		}
625
	}
626
	if (!empty($bridge['private'])) {
627
		$privateifs = explode(',', $bridge['private']);
628
		foreach ($privateifs as $privateif) {
629
			$realif = get_real_interface($privateif);
630
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
631
		}
632
	}
633

    
634
	if ($bridge['bridgeif'])
635
		interfaces_bring_up($bridge['bridgeif']);
636
	else
637
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
638
}
639

    
640
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
641

    
642
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface))
643
		return;
644

    
645
	if ($flagsapplied == false) {
646
		$mtu = get_interface_mtu($bridgeif);
647
		$mtum = get_interface_mtu($interface);
648
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500))
649
			pfSense_interface_mtu($interface, $mtu);
650

    
651
		hardware_offloading_applyflags($interface);
652
		interfaces_bring_up($interface);
653
	}
654

    
655
	pfSense_bridge_add_member($bridgeif, $interface);
656
}
657

    
658
function interfaces_lagg_configure($realif = "") {
659
	global $config, $g;
660
	if (platform_booting())
661
		echo gettext("Configuring LAGG interfaces...");
662
	$i = 0;
663
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
664
		foreach ($config['laggs']['lagg'] as $lagg) {
665
			if(empty($lagg['laggif']))
666
				$lagg['laggif'] = "lagg{$i}";
667
			if (!empty($realif) && $realif != $lagg['laggif'])
668
				continue;
669
			/* XXX: Maybe we should report any errors?! */
670
			interface_lagg_configure($lagg);
671
			$i++;
672
		}
673
	}
674
	if (platform_booting())
675
		echo gettext("done.") . "\n";
676
}
677

    
678
function interface_lagg_configure($lagg) {
679
	global $config, $g;
680

    
681
	if (!is_array($lagg))
682
		return -1;
683

    
684
	$members = explode(',', $lagg['members']);
685
	if (!count($members))
686
		return -1;
687

    
688
	if (platform_booting() || !(empty($lagg['laggif']))) {
689
		pfSense_interface_destroy($lagg['laggif']);
690
		pfSense_interface_create($lagg['laggif']);
691
		$laggif = $lagg['laggif'];
692
	} else
693
		$laggif = pfSense_interface_create("lagg");
694

    
695
	/* Check if MTU was defined for this lagg interface */
696
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
697
	if ($lagg_mtu == 0) {
698
		/* Calculate smaller mtu and enforce it */
699
		$smallermtu = 0;
700
		foreach ($members as $member) {
701
			$mtu = get_interface_mtu($member);
702
			if ($smallermtu == 0 && !empty($mtu))
703
				$smallermtu = $mtu;
704
			else if (!empty($mtu) && $mtu < $smallermtu)
705
				$smallermtu = $mtu;
706
		}
707
		$lagg_mtu = $smallermtu;
708
	}
709

    
710
	/* Just in case anything is not working well */
711
	if ($lagg_mtu == 0)
712
		$lagg_mtu = 1500;
713

    
714
	foreach ($members as $member) {
715
		if (!does_interface_exist($member))
716
			continue;
717
		/* make sure the parent interface is up */
718
		pfSense_interface_mtu($member, $lagg_mtu);
719
		interfaces_bring_up($member);
720
		hardware_offloading_applyflags($member);
721
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
722
	}
723
	pfSense_interface_capabilities($laggif, -$flags_off);
724
	pfSense_interface_capabilities($laggif, $flags_on);
725

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

    
728
	interfaces_bring_up($laggif);
729

    
730
	return $laggif;
731
}
732

    
733
function interfaces_gre_configure($checkparent = 0, $realif = "") {
734
	global $config;
735

    
736
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
737
		foreach ($config['gres']['gre'] as $i => $gre) {
738
			if (empty($gre['greif']))
739
				$gre['greif'] = "gre{$i}";
740
			if (!empty($realif) && $realif != $gre['greif'])
741
				continue;
742

    
743
			if ($checkparent == 1) {
744
				if (strstr($gre['if'], "_vip"))
745
					continue;
746
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6")
747
					continue;
748
			}
749
			else if ($checkparent == 2) {
750
				if (!strstr($gre['if'], "_vip"))
751
					continue;
752
				if (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")
753
					continue;
754
			}
755
			/* XXX: Maybe we should report any errors?! */
756
			interface_gre_configure($gre);
757
		}
758
	}
759
}
760

    
761
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
762
function interface_gre_configure(&$gre, $grekey = "") {
763
	global $config, $g;
764

    
765
	if (!is_array($gre))
766
		return -1;
767

    
768
	$realif = get_real_interface($gre['if']);
769
	$realifip = get_interface_ip($gre['if']);
770

    
771
	/* make sure the parent interface is up */
772
	interfaces_bring_up($realif);
773

    
774
	if (platform_booting() || !(empty($gre['greif']))) {
775
		pfSense_interface_destroy($gre['greif']);
776
		pfSense_interface_create($gre['greif']);
777
		$greif = $gre['greif'];
778
	} else
779
		$greif = pfSense_interface_create("gre");
780

    
781
	/* Do not change the order here for more see gre(4) NOTES section. */
782
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
783
	if((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
784
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
785
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
786
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
787
	} else {
788
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
789
	}
790
	if (isset($gre['link0']))
791
		pfSense_interface_flags($greif, IFF_LINK0);
792
	if (isset($gre['link1']))
793
		pfSense_interface_flags($greif, IFF_LINK1);
794
	if (isset($gre['link2']))
795
		pfSense_interface_flags($greif, IFF_LINK2);
796

    
797
	if($greif)
798
		interfaces_bring_up($greif);
799
	else
800
		log_error(gettext("Could not bring greif up -- variable not defined."));
801

    
802
	if (isset($gre['link1']) && $gre['link1'])
803
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
804
	if(is_ipaddrv4($gre['tunnel-remote-addr']))
805
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
806
	if(is_ipaddrv6($gre['tunnel-remote-addr']))
807
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
808

    
809
	interfaces_bring_up($greif);
810

    
811
	return $greif;
812
}
813

    
814
function interfaces_gif_configure($checkparent = 0, $realif = "") {
815
	global $config;
816

    
817
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
818
		foreach ($config['gifs']['gif'] as $i => $gif) {
819
			if (empty($gif['gifif']))
820
				$gre['gifif'] = "gif{$i}";
821
			if (!empty($realif) && $realif != $gif['gifif'])
822
				continue;
823

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

    
842
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
843
function interface_gif_configure(&$gif, $gifkey = "") {
844
	global $config, $g;
845

    
846
	if (!is_array($gif))
847
		return -1;
848

    
849
	$realif = get_real_interface($gif['if']);
850
	$ipaddr = $gif['ipaddr'];
851

    
852
	if (is_ipaddrv4($gif['remote-addr'])) {
853
		if (is_ipaddrv4($ipaddr))
854
			$realifip = $ipaddr;
855
		else
856
			$realifip = get_interface_ip($gif['if']);
857
		$realifgw = get_interface_gateway($gif['if']);
858
	} else if (is_ipaddrv6($gif['remote-addr'])) {
859
		if (is_ipaddrv6($ipaddr))
860
			$realifip = $ipaddr;
861
		else
862
			$realifip = get_interface_ipv6($gif['if']);
863
		$realifgw = get_interface_gateway_v6($gif['if']);
864
	}
865
	/* make sure the parent interface is up */
866
	if($realif)
867
		interfaces_bring_up($realif);
868
	else
869
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
870

    
871
	if (platform_booting() || !(empty($gif['gifif']))) {
872
		pfSense_interface_destroy($gif['gifif']);
873
		pfSense_interface_create($gif['gifif']);
874
		$gifif = $gif['gifif'];
875
	} else
876
		$gifif = pfSense_interface_create("gif");
877

    
878
	/* Do not change the order here for more see gif(4) NOTES section. */
879
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
880
	if((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
881
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
882
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
883
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
884
	} else {
885
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
886
	}
887
	if (isset($gif['link0']))
888
		pfSense_interface_flags($gifif, IFF_LINK0);
889
	if (isset($gif['link1']))
890
		pfSense_interface_flags($gifif, IFF_LINK1);
891
	if($gifif)
892
		interfaces_bring_up($gifif);
893
	else
894
		log_error(gettext("could not bring gifif up -- variable not defined"));
895

    
896
	if (!platform_booting()) {
897
		$iflist = get_configured_interface_list();
898
		foreach($iflist as $ifname) {
899
			if($config['interfaces'][$ifname]['if'] == $gifif) {
900
				if(get_interface_gateway($ifname)) {
901
					system_routing_configure($ifname);
902
					break;
903
				}
904
				if(get_interface_gateway_v6($ifname)) {
905
					system_routing_configure($ifname);
906
					break;
907
				}
908
			}
909
		}
910
	}
911

    
912

    
913
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
914
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
915
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
916
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
917

    
918
	if (is_ipaddrv4($realifgw)) {
919
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
920
	}
921
	if (is_ipaddrv6($realifgw)) {
922
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
923
	}
924

    
925
	interfaces_bring_up($gifif);
926

    
927
	return $gifif;
928
}
929

    
930
function interfaces_configure() {
931
	global $config, $g;
932

    
933
	if ($g['platform'] == 'jail')
934
		return;
935

    
936
	/* Set up our loopback interface */
937
	interfaces_loopback_configure();
938

    
939
	/* create the unconfigured wireless clones */
940
	interfaces_create_wireless_clones();
941

    
942
	/* set up LAGG virtual interfaces */
943
	interfaces_lagg_configure();
944

    
945
	/* set up VLAN virtual interfaces */
946
	interfaces_vlan_configure();
947

    
948
	interfaces_qinq_configure();
949

    
950
	$iflist = get_configured_interface_with_descr();
951
	$delayed_list = array();
952
	$bridge_list = array();
953
	$track6_list = array();
954

    
955
	/* This is needed to speedup interfaces on bootup. */
956
	$reload = false;
957
	if (!platform_booting())
958
		$reload = true;
959

    
960
	foreach($iflist as $if => $ifname) {
961
		$realif = $config['interfaces'][$if]['if'];
962
		if (strstr($realif, "bridge"))
963
			$bridge_list[$if] = $ifname;
964
		else if (strstr($realif, "gre"))
965
			$delayed_list[$if] = $ifname;
966
		else if (strstr($realif, "gif"))
967
			$delayed_list[$if] = $ifname;
968
		else if (strstr($realif, "ovpn")) {
969
			//echo "Delaying OpenVPN interface configuration...done.\n";
970
			continue;
971
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
972
			$track6_list[$if] = $ifname;
973
		} else {
974
			if (platform_booting())
975
				printf(gettext("Configuring %s interface..."), $ifname);
976

    
977
			if($g['debug'])
978
				log_error(sprintf(gettext("Configuring %s"), $ifname));
979
			interface_configure($if, $reload);
980
			if (platform_booting())
981
				echo gettext( "done.") . "\n";
982
		}
983
	}
984

    
985
	/*
986
	 * NOTE: The following function parameter consists of
987
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
988
	 *	2 - Do load gre/gif/bridge with parent/member as vip
989
	 */
990

    
991
	/* set up GRE virtual interfaces */
992
	interfaces_gre_configure(1);
993

    
994
	/* set up GIF virtual interfaces */
995
	interfaces_gif_configure(1);
996

    
997
	/* set up BRIDGe virtual interfaces */
998
	interfaces_bridge_configure(1);
999

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

    
1006
		interface_configure($if, $reload);
1007

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

    
1012
	/* bring up vip interfaces */
1013
	interfaces_vips_configure();
1014

    
1015
	/* set up GRE virtual interfaces */
1016
	interfaces_gre_configure(2);
1017

    
1018
	/* set up GIF virtual interfaces */
1019
	interfaces_gif_configure(2);
1020

    
1021
	foreach ($delayed_list as $if => $ifname) {
1022
		if (platform_booting())
1023
			printf(gettext("Configuring %s interface..."), $ifname);
1024
		if ($g['debug'])
1025
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1026

    
1027
		interface_configure($if, $reload);
1028

    
1029
		if (platform_booting())
1030
			echo gettext("done.") . "\n";
1031
	}
1032

    
1033
	/* set up BRIDGe virtual interfaces */
1034
	interfaces_bridge_configure(2);
1035

    
1036
	foreach ($bridge_list as $if => $ifname) {
1037
		if (platform_booting())
1038
			printf(gettext("Configuring %s interface..."), $ifname);
1039
		if($g['debug'])
1040
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1041

    
1042
		interface_configure($if, $reload);
1043

    
1044
		if (platform_booting())
1045
			echo gettext("done.") . "\n";
1046
	}
1047

    
1048
	/* configure interface groups */
1049
	interfaces_group_setup();
1050

    
1051
	if (!platform_booting()) {
1052
		/* reconfigure static routes (kernel may have deleted them) */
1053
		system_routing_configure();
1054

    
1055
		/* reload IPsec tunnels */
1056
		vpn_ipsec_configure();
1057

    
1058
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1059
		services_dhcpd_configure();
1060

    
1061
		/* restart dnsmasq or unbound */
1062
		if (isset($config['dnsmasq']['enable']))
1063
			services_dnsmasq_configure();
1064
		elseif (isset($config['unbound']['enable']))
1065
			services_unbound_configure();
1066
	}
1067

    
1068
	return 0;
1069
}
1070

    
1071
function interface_reconfigure($interface = "wan", $reloadall = false) {
1072
	interface_bring_down($interface);
1073
	interface_configure($interface, $reloadall);
1074
}
1075

    
1076
function interface_vip_bring_down($vip) {
1077
	global $g;
1078

    
1079
	$vipif = get_real_interface($vip['interface']);
1080
	switch ($vip['mode']) {
1081
	case "proxyarp":
1082
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1083
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1084
		break;
1085
	case "ipalias":
1086
		if (does_interface_exist($vipif)) {
1087
			if (is_ipaddrv6($vip['subnet']))
1088
				mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1089
			else
1090
				pfSense_interface_deladdress($vipif, $vip['subnet']);
1091
		}
1092
		break;
1093
	case "carp":
1094
		/* XXX: Is enough to delete ip address? */
1095
		if (does_interface_exist($vipif)) {
1096
			if (is_ipaddrv6($vip['subnet']))
1097
				mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1098
			else
1099
				pfSense_interface_deladdress($vipif, $vip['subnet']);
1100
		}
1101
		break;
1102
	}
1103
}
1104

    
1105
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1106
	global $config, $g;
1107

    
1108
	if (!isset($config['interfaces'][$interface]))
1109
		return;
1110

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

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

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

    
1187
	$track6 = array();
1188
	switch ($ifcfg['ipaddrv6']) {
1189
	case "slaac":
1190
	case "dhcp6":
1191
		$pidv6 = find_dhcp6c_process($realif);
1192
		if($pidv6)
1193
			posix_kill($pidv6, SIGTERM);
1194
		sleep(3);
1195
		unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1196
		if (does_interface_exist($realifv6)) {
1197
			$ip6 = find_interface_ipv6($realifv6);
1198
			if (is_ipaddrv6($ip6) && $ip6 != "::")
1199
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1200
			interface_ipalias_cleanup($interface, "inet6");
1201
			if ($destroy == true)
1202
				pfSense_interface_flags($realif, -IFF_UP);
1203
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1204
		}
1205
		$track6 = link_interface_to_track6($interface);
1206
		break;
1207
	case "6rd":
1208
	case "6to4":
1209
		$realif = "{$interface}_stf";
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
			interface_ipalias_cleanup($interface, "inet6");
1215
			if ($destroy == true)
1216
				pfSense_interface_flags($realif, -IFF_UP);
1217
		}
1218
		$track6 = link_interface_to_track6($interface);
1219
		break;
1220
	default:
1221
		if(does_interface_exist("$realif")) {
1222
			$ip6 = get_interface_ipv6($interface);
1223
			if (is_ipaddrv6($ip6))
1224
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1225
			if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
1226
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1227
			interface_ipalias_cleanup($interface, "inet6");
1228
			if ($destroy == true)
1229
				pfSense_interface_flags($realif, -IFF_UP);
1230
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1231
		}
1232
		$track6 = link_interface_to_track6($interface);
1233
		break;
1234
	}
1235

    
1236
	if (!empty($track6) && is_array($track6)) {
1237
		if (!function_exists('services_dhcp_configure'))
1238
			require_once('services.inc');
1239
		/* Bring down radvd and dhcp6 on these interfaces */
1240
		services_dhcpd_configure('inet6', $track6);
1241
	}
1242

    
1243
	$old_router = '';
1244
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1245
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1246

    
1247
	/* remove interface up file if it exists */
1248
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1249
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1250
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1251
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1252
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1253
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1254
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1255

    
1256
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1257
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1258
	if (is_array($ifcfg['wireless'])) {
1259
		kill_hostapd($realif);
1260
		mwexec(kill_wpasupplicant($realif));
1261
	}
1262

    
1263
	if ($destroy == true) {
1264
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif))
1265
			pfSense_interface_destroy($realif);
1266
	}
1267

    
1268
	return;
1269
}
1270

    
1271
function interfaces_carp_set_maintenancemode($carp_maintenancemode){
1272
	global $config;
1273
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1274
		unset($config["virtualip_carp_maintenancemode"]);
1275
		write_config("Leave CARP maintenance mode");
1276
		if(is_array($config['virtualip']['vip'])) {
1277
			$viparr = &$config['virtualip']['vip'];
1278
			foreach ($viparr as $vip) {
1279
				switch ($vip['mode']) {
1280
				case "carp":
1281
					interface_vip_bring_down($vip);
1282
					//sleep(1);
1283
					break;
1284
				}
1285
			}
1286
		}
1287
	} else {
1288
		if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1289
			$config["virtualip_carp_maintenancemode"] = true;
1290
			write_config("Enter CARP maintenance mode");
1291
		}
1292
	}
1293

    
1294
	$viparr = &$config['virtualip']['vip'];
1295
	foreach ($viparr as $vip) {
1296
		if ($vip['mode'] == "carp") {
1297
			interface_carp_configure($vip);
1298
		}
1299
	}
1300
}
1301

    
1302
function interface_isppp_type($interface) {
1303
	global $config;
1304

    
1305
	if (!is_array($config['interfaces'][$interface]))
1306
		return false;
1307

    
1308
	switch ($config['interfaces'][$interface]['ipaddr']) {
1309
	case 'pptp':
1310
	case 'l2tp':
1311
	case 'pppoe':
1312
	case 'ppp':
1313
		return true;
1314
		break;
1315
	default:
1316
		return false;
1317
		break;
1318
	}
1319
}
1320

    
1321
function interfaces_ptpid_used($ptpid) {
1322
	global $config;
1323

    
1324
	if (is_array($config['ppps']['ppp']))
1325
		foreach ($config['ppps']['ppp'] as & $settings)
1326
			if ($ptpid == $settings['ptpid'])
1327
				return true;
1328

    
1329
	return false;
1330
}
1331

    
1332
function interfaces_ptpid_next() {
1333

    
1334
	$ptpid = 0;
1335
	while(interfaces_ptpid_used($ptpid))
1336
		$ptpid++;
1337

    
1338
	return $ptpid;
1339
}
1340

    
1341
function getMPDCRONSettings($pppif) {
1342
	global $config;
1343

    
1344
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1345
	if (is_array($config['cron']['item'])) {
1346
		foreach ($config['cron']['item'] as $i => $item) {
1347
			if (stripos($item['command'], $cron_cmd_file) !== false)
1348
				return array("ID" => $i, "ITEM" => $item);
1349
		}
1350
	}
1351

    
1352
	return NULL;
1353
}
1354

    
1355
function handle_pppoe_reset($post_array) {
1356
	global $config, $g;
1357

    
1358
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1359
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1360

    
1361
	if (!is_array($config['cron']['item']))
1362
		$config['cron']['item'] = array();
1363

    
1364
	$itemhash = getMPDCRONSettings($pppif);
1365

    
1366
	// reset cron items if necessary and return
1367
	if (empty($post_array['pppoe-reset-type'])) {
1368
		if (isset($itemhash))
1369
			unset($config['cron']['item'][$itemhash['ID']]);
1370
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1371
		return;
1372
	}
1373

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

    
1433
/*
1434
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1435
 * It writes the mpd config file to /var/etc every time the link is opened.
1436
 */
1437
function interface_ppps_configure($interface) {
1438
	global $config, $g;
1439

    
1440
	/* Return for unassigned interfaces. This is a minimum requirement. */
1441
	if (empty($config['interfaces'][$interface]))
1442
		return 0;
1443
	$ifcfg = $config['interfaces'][$interface];
1444
	if (!isset($ifcfg['enable']))
1445
		return 0;
1446

    
1447
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1448
	if(!is_dir("/var/spool/lock")) {
1449
		mkdir("/var/spool/lock", 0777, true);
1450
	}
1451
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1452
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1453
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1454

    
1455
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1456
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1457
			if ($ifcfg['if'] == $ppp['if'])
1458
				break;
1459
		}
1460
	}
1461
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1462
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1463
		return 0;
1464
	}
1465
	$pppif = $ifcfg['if'];
1466
	if ($ppp['type'] == "ppp")
1467
		$type = "modem";
1468
	else
1469
		$type = $ppp['type'];
1470
	$upper_type = strtoupper($ppp['type']);
1471

    
1472
	/* XXX: This does not make sense and may create trouble
1473
	 * comment it for now to be removed later on.
1474
	if (platform_booting()) {
1475
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1476
		echo "starting {$pppif} link...";
1477
		if(isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1478
			return 0;
1479
	}
1480
	*/
1481

    
1482
	$ports = explode(',',$ppp['ports']);
1483
	if ($type != "modem") {
1484
		foreach ($ports as $pid => $port) {
1485
			$ports[$pid] = get_real_interface($port);
1486
			if (empty($ports[$pid]))
1487
				return 0;
1488
		}
1489
	}
1490
	$localips = explode(',',$ppp['localip']);
1491
	$gateways = explode(',',$ppp['gateway']);
1492
	$subnets = explode(',',$ppp['subnet']);
1493

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

    
1516
				if(!is_ipaddr($localips[$pid])){
1517
					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!");
1518
					$localips[$pid] = "0.0.0.0";
1519
				}
1520
				if(!is_ipaddr($gateways[$pid])){
1521
					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));
1522
					return 0;
1523
				}
1524
				pfSense_ngctl_attach(".", $port);
1525
				break;
1526
			case "ppp":
1527
				if (!file_exists("{$port}")) {
1528
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1529
					return 0;
1530
				}
1531
				break;
1532
			default:
1533
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1534
				break;
1535
		}
1536
	}
1537

    
1538
	if (is_array($ports) && count($ports) > 1)
1539
		$multilink = "enable";
1540
	else
1541
		$multilink = "disable";
1542

    
1543
	if ($type == "modem"){
1544
		if (is_ipaddr($ppp['localip']))
1545
			$localip = $ppp['localip'];
1546
		else
1547
			$localip = '0.0.0.0';
1548

    
1549
		if (is_ipaddr($ppp['gateway']))
1550
			$gateway = $ppp['gateway'];
1551
		else
1552
			$gateway = "10.64.64.{$pppid}";
1553
		$ranges = "{$localip}/0 {$gateway}/0";
1554

    
1555
		if (empty($ppp['apnum']))
1556
			$ppp['apnum'] = 1;
1557
	} else
1558
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1559

    
1560
	if (isset($ppp['ondemand']))
1561
		$ondemand = "enable";
1562
	else
1563
		$ondemand = "disable";
1564
	if (!isset($ppp['idletimeout']))
1565
		$ppp['idletimeout'] = 0;
1566

    
1567
	if (empty($ppp['username']) && $type == "modem"){
1568
		$ppp['username'] = "user";
1569
		$ppp['password'] = "none";
1570
	}
1571
	if (empty($ppp['password']) && $type == "modem")
1572
		$passwd = "none";
1573
	else
1574
		$passwd = base64_decode($ppp['password']);
1575

    
1576
	$bandwidths = explode(',',$ppp['bandwidth']);
1577
	$defaultmtu = "1492";
1578
	if (!empty($ifcfg['mtu']))
1579
		$defaultmtu = intval($ifcfg['mtu']);
1580
	$mtus = explode(',',$ppp['mtu']);
1581
	$mrus = explode(',',$ppp['mru']);
1582

    
1583
	if (isset($ppp['mrru']))
1584
		$mrrus = explode(',',$ppp['mrru']);
1585

    
1586
	// Construct the mpd.conf file
1587
	$mpdconf = <<<EOD
1588
startup:
1589
	# configure the console
1590
	set console close
1591
	# configure the web server
1592
	set web close
1593

    
1594
default:
1595
{$ppp['type']}client:
1596
	create bundle static {$interface}
1597
	set bundle enable ipv6cp
1598
	set iface name {$pppif}
1599

    
1600
EOD;
1601
	$setdefaultgw = false;
1602
	$founddefaultgw = false;
1603
	if (is_array($config['gateways']['gateway_item'])) {
1604
		foreach($config['gateways']['gateway_item'] as $gateway) {
1605
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1606
				$setdefaultgw = true;
1607
				break;
1608
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1609
				$founddefaultgw = true;
1610
				break;
1611
			}
1612
		}
1613
	}
1614

    
1615
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1616
		$setdefaultgw = true;
1617
		$mpdconf .= <<<EOD
1618
	set iface route default
1619

    
1620
EOD;
1621
	}
1622
	$mpdconf .= <<<EOD
1623
	set iface {$ondemand} on-demand
1624
	set iface idle {$ppp['idletimeout']}
1625

    
1626
EOD;
1627

    
1628
	if (isset($ppp['ondemand']))
1629
		$mpdconf .= <<<EOD
1630
	set iface addrs 10.10.1.1 10.10.1.2
1631

    
1632
EOD;
1633

    
1634
	if (isset($ppp['tcpmssfix']))
1635
		$tcpmss = "disable";
1636
	else
1637
		$tcpmss = "enable";
1638
		$mpdconf .= <<<EOD
1639
	set iface {$tcpmss} tcpmssfix
1640

    
1641
EOD;
1642

    
1643
	$mpdconf .= <<<EOD
1644
	set iface up-script /usr/local/sbin/ppp-linkup
1645
	set iface down-script /usr/local/sbin/ppp-linkdown
1646
	set ipcp ranges {$ranges}
1647

    
1648
EOD;
1649
	if (isset($ppp['vjcomp']))
1650
		$mpdconf .= <<<EOD
1651
	set ipcp no vjcomp
1652

    
1653
EOD;
1654

    
1655
	if (isset($config['system']['dnsallowoverride']))
1656
		$mpdconf .= <<<EOD
1657
	set ipcp enable req-pri-dns
1658
	set ipcp enable req-sec-dns
1659

    
1660
EOD;
1661
	if (!isset($ppp['verbose_log']))
1662
		$mpdconf .= <<<EOD
1663
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1664

    
1665
EOD;
1666
	foreach($ports as $pid => $port){
1667
		$port = get_real_interface($port);
1668
		$mpdconf .= <<<EOD
1669

    
1670
	create link static {$interface}_link{$pid} {$type}
1671
	set link action bundle {$interface}
1672
	set link {$multilink} multilink
1673
	set link keep-alive 10 60
1674
	set link max-redial 0
1675

    
1676
EOD;
1677
		if (isset($ppp['shortseq']))
1678
			$mpdconf .= <<<EOD
1679
	set link no shortseq
1680

    
1681
EOD;
1682

    
1683
		if (isset($ppp['acfcomp']))
1684
			$mpdconf .= <<<EOD
1685
	set link no acfcomp
1686

    
1687
EOD;
1688

    
1689
		if (isset($ppp['protocomp']))
1690
			$mpdconf .= <<<EOD
1691
	set link no protocomp
1692

    
1693
EOD;
1694

    
1695
		$mpdconf .= <<<EOD
1696
	set link disable chap pap
1697
	set link accept chap pap eap
1698
	set link disable incoming
1699

    
1700
EOD;
1701

    
1702

    
1703
		if (!empty($bandwidths[$pid]))
1704
			$mpdconf .= <<<EOD
1705
	set link bandwidth {$bandwidths[$pid]}
1706

    
1707
EOD;
1708

    
1709
		if (empty($mtus[$pid]))
1710
			$mtus[$pid] = $defaultmtu;
1711
			$mpdconf .= <<<EOD
1712
	set link mtu {$mtus[$pid]}
1713

    
1714
EOD;
1715

    
1716
		if (!empty($mrus[$pid]))
1717
			$mpdconf .= <<<EOD
1718
	set link mru {$mrus[$pid]}
1719

    
1720
EOD;
1721

    
1722
		if (!empty($mrrus[$pid]))
1723
			$mpdconf .= <<<EOD
1724
	set link mrru {$mrrus[$pid]}
1725

    
1726
EOD;
1727

    
1728
		$mpdconf .= <<<EOD
1729
	set auth authname "{$ppp['username']}"
1730
	set auth password {$passwd}
1731

    
1732
EOD;
1733
		if ($type == "modem") {
1734
			$mpdconf .= <<<EOD
1735
	set modem device {$ppp['ports']}
1736
	set modem script DialPeer
1737
	set modem idle-script Ringback
1738
	set modem watch -cd
1739
	set modem var \$DialPrefix "DT"
1740
	set modem var \$Telephone "{$ppp['phone']}"
1741

    
1742
EOD;
1743
		}
1744
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1745
			$mpdconf .= <<<EOD
1746
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1747

    
1748
EOD;
1749
		}
1750
		if (isset($ppp['initstr']) && $type == "modem") {
1751
			$initstr = base64_decode($ppp['initstr']);
1752
			$mpdconf .= <<<EOD
1753
	set modem var \$InitString "{$initstr}"
1754

    
1755
EOD;
1756
		}
1757
		if (isset($ppp['simpin']) && $type == "modem") {
1758
			if($ppp['pin-wait'] == "")
1759
				$ppp['pin-wait'] = 0;
1760
			$mpdconf .= <<<EOD
1761
	set modem var \$SimPin "{$ppp['simpin']}"
1762
	set modem var \$PinWait "{$ppp['pin-wait']}"
1763

    
1764
EOD;
1765
		}
1766
		if (isset($ppp['apn']) && $type == "modem") {
1767
			$mpdconf .= <<<EOD
1768
	set modem var \$APN "{$ppp['apn']}"
1769
	set modem var \$APNum "{$ppp['apnum']}"
1770

    
1771
EOD;
1772
		}
1773
		if ($type == "pppoe") {
1774
			// Send a null service name if none is set.
1775
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1776
			$mpdconf .= <<<EOD
1777
	set pppoe service "{$provider}"
1778

    
1779
EOD;
1780
		}
1781
		if ($type == "pppoe")
1782
			$mpdconf .= <<<EOD
1783
	set pppoe iface {$port}
1784

    
1785
EOD;
1786

    
1787
		if ($type == "pptp" || $type == "l2tp") {
1788
			$mpdconf .= <<<EOD
1789
	set {$type} self {$localips[$pid]}
1790
	set {$type} peer {$gateways[$pid]}
1791

    
1792
EOD;
1793
		}
1794

    
1795
		$mpdconf .= "\topen\n";
1796
	} //end foreach($port)
1797

    
1798

    
1799
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1800
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1801
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1802
	else {
1803
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1804
		if (!$fd) {
1805
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1806
			return 0;
1807
		}
1808
		// Write out mpd_ppp.conf
1809
		fwrite($fd, $mpdconf);
1810
		fclose($fd);
1811
		unset($mpdconf);
1812
	}
1813

    
1814
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1815
	if (isset($ppp['uptime'])) {
1816
		if (!file_exists("/conf/{$pppif}.log")) {
1817
			conf_mount_rw();
1818
			file_put_contents("/conf/{$pppif}.log", '');
1819
			conf_mount_ro();
1820
		}
1821
	} else {
1822
		if (file_exists("/conf/{$pppif}.log")) {
1823
			conf_mount_rw();
1824
			@unlink("/conf/{$pppif}.log");
1825
			conf_mount_ro();
1826
		}
1827
	}
1828

    
1829
	/* clean up old lock files */
1830
	foreach($ports as $port) {
1831
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1832
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1833
	}
1834

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

    
1839
	// Check for PPPoE periodic reset request
1840
	if ($type == "pppoe") {
1841
		if (!empty($ppp['pppoe-reset-type']))
1842
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1843
		else
1844
			interface_setup_pppoe_reset_file($ppp['if']);
1845
	}
1846
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1847
	$i = 0;
1848
	while($i < 10) {
1849
		unset($out);
1850
		exec("/sbin/ifconfig " . escapeshellarg($ppp['if']) . " 2>&1", $out, $ret);
1851
		if($ret == 0)
1852
			break;
1853
		sleep(1);
1854
		$i++;
1855
	}
1856

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

    
1875
	return 1;
1876
}
1877

    
1878
function interfaces_sync_setup() {
1879
	global $g, $config;
1880

    
1881
	if (isset($config['system']['developerspew'])) {
1882
		$mt = microtime();
1883
		echo "interfaces_sync_setup() being called $mt\n";
1884
	}
1885

    
1886
	if (platform_booting()) {
1887
		echo gettext("Configuring CARP settings...");
1888
		mute_kernel_msgs();
1889
	}
1890

    
1891
	/* suck in configuration items */
1892
	if ($config['hasync']) {
1893
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1894
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1895
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1896
	} else {
1897
		unset($pfsyncinterface);
1898
		unset($pfsyncenabled);
1899
	}
1900

    
1901
	set_sysctl(array(
1902
		"net.inet.carp.preempt" => "1",
1903
		"net.inet.carp.log" => "1")
1904
	);
1905

    
1906
	if (!empty($pfsyncinterface))
1907
		$carp_sync_int = get_real_interface($pfsyncinterface);
1908
	else
1909
		unset($carp_sync_int);
1910

    
1911
	/* setup pfsync interface */
1912
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
1913
		if (is_ipaddr($pfsyncpeerip))
1914
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1915
		else
1916
			$syncpeer = "-syncpeer";
1917

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

    
1920
		sleep(1);
1921

    
1922
		/* 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
1923
		 * for existing sessions.
1924
		 */
1925
		log_error("waiting for pfsync...");
1926
		$i = 0;
1927
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1928
			$i++;
1929
			sleep(1);
1930
		}
1931
		log_error("pfsync done in $i seconds.");
1932
		log_error("Configuring CARP settings finalize...");
1933
	} else {
1934
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
1935
	}
1936

    
1937
	if($config['virtualip']['vip'])
1938
		set_single_sysctl("net.inet.carp.allow", "1");
1939
	else
1940
		set_single_sysctl("net.inet.carp.allow", "0");
1941

    
1942
	if (platform_booting()) {
1943
		unmute_kernel_msgs();
1944
		echo gettext("done.") . "\n";
1945
	}
1946
}
1947

    
1948
function interface_proxyarp_configure($interface = "") {
1949
	global $config, $g;
1950
	if(isset($config['system']['developerspew'])) {
1951
		$mt = microtime();
1952
		echo "interface_proxyarp_configure() being called $mt\n";
1953
	}
1954

    
1955
	/* kill any running choparp */
1956
	if (empty($interface))
1957
		killbyname("choparp");
1958
	else {
1959
		$vipif = get_real_interface($interface);
1960
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1961
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1962
	}
1963

    
1964
	$paa = array();
1965
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1966

    
1967
		/* group by interface */
1968
		foreach ($config['virtualip']['vip'] as $vipent) {
1969
			if ($vipent['mode'] === "proxyarp") {
1970
				if ($vipent['interface'])
1971
					$proxyif = $vipent['interface'];
1972
				else
1973
					$proxyif = "wan";
1974

    
1975
				if (!empty($interface) && $interface != $proxyif)
1976
					continue;
1977

    
1978
				if (!is_array($paa[$proxyif]))
1979
					$paa[$proxyif] = array();
1980

    
1981
				$paa[$proxyif][] = $vipent;
1982
			}
1983
		}
1984
	}
1985

    
1986
	if (!empty($interface)) {
1987
		if (is_array($paa[$interface])) {
1988
			$paaifip = get_interface_ip($interface);
1989
			if (!is_ipaddr($paaifip))
1990
				return;
1991
			$args = get_real_interface($interface) . " auto";
1992
			foreach ($paa[$interface] as $paent) {
1993
				if (isset($paent['subnet']))
1994
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1995
				else if (isset($paent['range']))
1996
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1997
			}
1998
			mwexec_bg("/usr/local/sbin/choparp " . $args);
1999
		}
2000
	} else if (count($paa) > 0) {
2001
		foreach ($paa as $paif => $paents)  {
2002
			$paaifip = get_interface_ip($paif);
2003
			if (!is_ipaddr($paaifip))
2004
				continue;
2005
			$args = get_real_interface($paif) . " auto";
2006
			foreach ($paents as $paent) {
2007
				if (isset($paent['subnet']))
2008
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2009
				else if (isset($paent['range']))
2010
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2011
			}
2012
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2013
		}
2014
	}
2015
}
2016

    
2017
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2018
	global $g, $config;
2019

    
2020
	if (is_array($config['virtualip']['vip'])) {
2021
		foreach ($config['virtualip']['vip'] as $vip) {
2022
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2023
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2024
					interface_vip_bring_down($vip);
2025
				else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2026
					interface_vip_bring_down($vip);
2027
			}
2028
		}
2029
	}
2030
}
2031

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

    
2071
function interface_ipalias_configure(&$vip) {
2072
	global $config;
2073

    
2074
	if ($vip['mode'] != 'ipalias')
2075
		return;
2076

    
2077
	if ($vip['interface'] != 'lo0' && stripos($vip['interface'], '_vip') === false) {
2078
		if (!isset($config['interfaces'][$vip['interface']]))
2079
			return;
2080

    
2081
		if (!isset($config['interfaces'][$vip['interface']]['enable']))
2082
			return;
2083
	}
2084

    
2085
	$af = 'inet';
2086
	if(is_ipaddrv6($vip['subnet']))
2087
		$af = 'inet6';
2088
	$iface = $vip['interface'];
2089
	$vipadd = '';
2090
	if (strpos($vip['interface'], '_vip')) {
2091
		$carpvip = get_configured_carp_interface_list($vip['interface'], $af, 'vip');
2092
		$iface = $carpvip['interface'];
2093
		$vipadd = "vhid {$carpvip['vhid']}";
2094
	}
2095
	$if = get_real_interface($iface);
2096
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vipadd}");
2097
	unset($iface, $af, $if, $carpvip, $vipadd);
2098
}
2099

    
2100
function interface_reload_carps($cif) {
2101
	global $config;
2102

    
2103
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2104
	if (empty($carpifs))
2105
		return;
2106

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

    
2129
function interface_carp_configure(&$vip) {
2130
	global $config, $g;
2131
	if(isset($config['system']['developerspew'])) {
2132
		$mt = microtime();
2133
		echo "interface_carp_configure() being called $mt\n";
2134
	}
2135

    
2136
	if ($vip['mode'] != "carp")
2137
		return;
2138

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

    
2146
	if (is_ipaddrv4($vip['subnet'])) {
2147
		/* Ensure a IP on this interface exists prior to configuring CARP. */
2148
		$ww_subnet_ip = find_interface_ip($realif);
2149
		if (!is_ipaddrv4($ww_subnet_ip)) {
2150
			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", "");
2151
			return;
2152
		}
2153
	} else if (is_ipaddrv6($vip['subnet'])) {
2154
		/* Ensure a IP on this interface exists prior to configuring CARP. */
2155
		$ww_subnet_ip = find_interface_ipv6($realif);
2156
		if (!is_ipaddrv6($ww_subnet_ip)) {
2157
			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", "");
2158
			return;
2159
		}
2160
	}
2161

    
2162
	$vip_password = $vip['password'];
2163
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2164
	if ($vip['password'] != "")
2165
		$password = " pass {$vip_password}";
2166

    
2167
	$advbase = "";
2168
	if (!empty($vip['advbase']))
2169
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2170

    
2171
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2172
	if ($carp_maintenancemode)
2173
		$advskew = "advskew 254";
2174
	else
2175
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2176
	
2177
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) . " {$advskew} {$advbase} {$password}");
2178

    
2179
	if (is_ipaddrv4($vip['subnet']))
2180
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2181
	else if (is_ipaddrv6($vip['subnet']))
2182
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2183

    
2184
	return $realif;
2185
}
2186

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

    
2228
	if($needs_clone == true) {
2229
		/* remove previous instance if it exists */
2230
		if(does_interface_exist($realif))
2231
			pfSense_interface_destroy($realif);
2232

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

    
2251
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2252
	global $config, $g;
2253

    
2254
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2255
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2256
				 'regdomain', 'regcountry', 'reglocation');
2257

    
2258
	if(!is_interface_wireless($ifcfg['if']))
2259
		return;
2260

    
2261
	$baseif = interface_get_wireless_base($ifcfg['if']);
2262

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

    
2287
	// Read or write settings at shared area
2288
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2289
		foreach ($shared_settings as $setting) {
2290
			if ($sync_changes) {
2291
				if (isset($ifcfg['wireless'][$setting]))
2292
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2293
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2294
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2295
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2296
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2297
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2298
				else if (isset($ifcfg['wireless'][$setting]))
2299
					unset($ifcfg['wireless'][$setting]);
2300
			}
2301
		}
2302
	}
2303

    
2304
	// Sync the mode on the clone creation page with the configured mode on the interface
2305
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2306
		foreach ($config['wireless']['clone'] as &$clone) {
2307
			if ($clone['cloneif'] == $ifcfg['if']) {
2308
				if ($sync_changes) {
2309
					$clone['mode'] = $ifcfg['wireless']['mode'];
2310
				} else {
2311
					$ifcfg['wireless']['mode'] = $clone['mode'];
2312
				}
2313
				break;
2314
			}
2315
		}
2316
		unset($clone);
2317
	}
2318
}
2319

    
2320
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2321
	global $config, $g;
2322

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

    
2330
	// Remove script file
2331
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2332

    
2333
	// Clone wireless nic if needed.
2334
	interface_wireless_clone($if, $wl);
2335

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

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

    
2343
	/* set values for /path/program */
2344
	$hostapd = "/usr/sbin/hostapd";
2345
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2346
	$ifconfig = "/sbin/ifconfig";
2347
	$sysctl = "/sbin/sysctl";
2348
	$killall = "/usr/bin/killall";
2349

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

    
2352
	$wlcmd = array();
2353
	$wl_sysctl = array();
2354
	/* Make sure it's up */
2355
	$wlcmd[] = "up";
2356
	/* Set a/b/g standard */
2357
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2358
	$wlcmd[] = "mode " . escapeshellarg($standard);
2359

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

    
2365
	/* Set ssid */
2366
	if($wlcfg['ssid'])
2367
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2368

    
2369
	/* Set 802.11g protection mode */
2370
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2371

    
2372
	/* set wireless channel value */
2373
	if(isset($wlcfg['channel'])) {
2374
		if($wlcfg['channel'] == "0") {
2375
			$wlcmd[] = "channel any";
2376
		} else {
2377
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2378
		}
2379
	}
2380

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

    
2385
	/* Set txantenna value */
2386
	if(isset($wlcfg['txantenna']))
2387
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2388

    
2389
	/* Set rxantenna value */
2390
	if(isset($wlcfg['rxantenna']))
2391
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2392

    
2393
	/* set Distance value */
2394
	if($wlcfg['distance'])
2395
		$distance = escapeshellarg($wlcfg['distance']);
2396

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

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

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

    
2413
	/* handle hide ssid option */
2414
	if(isset($wlcfg['hidessid']['enable'])) {
2415
		$wlcmd[] = "hidessid";
2416
	} else {
2417
		$wlcmd[] = "-hidessid";
2418
	}
2419

    
2420
	/* handle pureg (802.11g) only option */
2421
	if(isset($wlcfg['pureg']['enable'])) {
2422
		$wlcmd[] = "mode 11g pureg";
2423
	} else {
2424
		$wlcmd[] = "-pureg";
2425
	}
2426

    
2427
	/* handle puren (802.11n) only option */
2428
	if(isset($wlcfg['puren']['enable'])) {
2429
		$wlcmd[] = "puren";
2430
	} else {
2431
		$wlcmd[] = "-puren";
2432
	}
2433

    
2434
	/* enable apbridge option */
2435
	if(isset($wlcfg['apbridge']['enable'])) {
2436
		$wlcmd[] = "apbridge";
2437
	} else {
2438
		$wlcmd[] = "-apbridge";
2439
	}
2440

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

    
2448
	/* handle txpower setting */
2449
	/* if($wlcfg['txpower'] <> "")
2450
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2451
	*/
2452
	/* handle wme option */
2453
	if(isset($wlcfg['wme']['enable'])) {
2454
		$wlcmd[] = "wme";
2455
	} else {
2456
		$wlcmd[] = "-wme";
2457
	}
2458

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

    
2485
	kill_hostapd($if);
2486
	mwexec(kill_wpasupplicant("{$if}"));
2487

    
2488
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2489
	conf_mount_rw();
2490

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

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

    
2544
EOD;
2545

    
2546
			if (isset($wlcfg['wpa']['rsn_preauth'])) {
2547
				$wpa .= <<<EOD
2548
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2549
rsn_preauth=1
2550
rsn_preauth_interfaces={$if}
2551

    
2552
EOD;
2553
			}
2554
			if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2555
				$wpa .= "ieee8021x=1\n";
2556

    
2557
			if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2558
				$auth_server_port = "1812";
2559
				if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port']))
2560
					$auth_server_port = intval($wlcfg['auth_server_port']);
2561
				$wpa .= <<<EOD
2562

    
2563
auth_server_addr={$wlcfg['auth_server_addr']}
2564
auth_server_port={$auth_server_port}
2565
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2566

    
2567
EOD;
2568
				if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2569
					$auth_server_port2 = "1812";
2570
					if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2']))
2571
						$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2572

    
2573
					$wpa .= <<<EOD
2574
auth_server_addr={$wlcfg['auth_server_addr2']}
2575
auth_server_port={$auth_server_port2}
2576
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2577

    
2578
EOD;
2579
					}
2580
				}
2581
			}
2582

    
2583
			@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2584
			unset($wpa);
2585
		}
2586
		break;
2587
	}
2588

    
2589
	/*
2590
	 *    all variables are set, lets start up everything
2591
	 */
2592

    
2593
	$baseif = interface_get_wireless_base($if);
2594
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2595
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2596

    
2597
	/* set sysctls for the wireless interface */
2598
	if (!empty($wl_sysctl)) {
2599
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2600
		foreach ($wl_sysctl as $wl_sysctl_line) {
2601
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2602
		}
2603
	}
2604

    
2605
	/* set ack timers according to users preference (if he/she has any) */
2606
	if($distance) {
2607
		fwrite($fd_set, "# Enable ATH distance settings\n");
2608
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2609
	}
2610

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

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

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

    
2639
	fclose($fd_set);
2640
	conf_mount_ro();
2641

    
2642
	/* Making sure regulatory settings have actually changed
2643
	 * before applying, because changing them requires bringing
2644
	 * down all wireless networks on the interface. */
2645
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2646
	$ifconfig_str = implode($output);
2647
	unset($output);
2648
	$reg_changing = false;
2649

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

    
2662
	if ($reg_changing) {
2663
		/* set regulatory domain */
2664
		if($wlcfg['regdomain'])
2665
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2666

    
2667
		/* set country */
2668
		if($wlcfg['regcountry'])
2669
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2670

    
2671
		/* set location */
2672
		if($wlcfg['reglocation'])
2673
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2674

    
2675
		$wlregcmd_args = implode(" ", $wlregcmd);
2676

    
2677
		/* build a complete list of the wireless clones for this interface */
2678
		$clone_list = array();
2679
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2680
			$clone_list[] = interface_get_wireless_clone($baseif);
2681
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2682
			foreach ($config['wireless']['clone'] as $clone) {
2683
				if ($clone['if'] == $baseif)
2684
					$clone_list[] = $clone['cloneif'];
2685
			}
2686
		}
2687

    
2688
		/* find which clones are up and bring them down */
2689
		$clones_up = array();
2690
		foreach ($clone_list as $clone_if) {
2691
			$clone_status = pfSense_get_interface_addresses($clone_if);
2692
			if ($clone_status['status'] == 'up') {
2693
				$clones_up[] = $clone_if;
2694
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2695
			}
2696
		}
2697

    
2698
		/* apply the regulatory settings */
2699
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2700

    
2701
		/* bring the clones back up that were previously up */
2702
		foreach ($clones_up as $clone_if) {
2703
			interfaces_bring_up($clone_if);
2704

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

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

    
2725
	/* configure wireless */
2726
	$wlcmd_args = implode(" ", $wlcmd);
2727
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2728
	unset($wlcmd_args, $wlcmd);
2729

    
2730

    
2731
	sleep(1);
2732
	/* execute hostapd and wpa_supplicant if required in shell */
2733
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2734

    
2735
	return 0;
2736

    
2737
}
2738

    
2739
function kill_hostapd($interface) {
2740
	global $g;
2741

    
2742
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2743
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2744
}
2745

    
2746
function kill_wpasupplicant($interface) {
2747
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2748
}
2749

    
2750
function find_dhclient_process($interface) {
2751
	if ($interface)
2752
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2753
	else
2754
		$pid = 0;
2755

    
2756
	return intval($pid);
2757
}
2758

    
2759
function kill_dhclient_process($interface) {
2760
	if (empty($interface) || !does_interface_exist($interface))
2761
		return;
2762

    
2763
	$i = 0;
2764
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2765
		/* 3rd time make it die for sure */
2766
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2767
		posix_kill($pid, $sig);
2768
		sleep(1);
2769
		$i++;
2770
	}
2771
	unset($i);
2772
}
2773

    
2774
function find_dhcp6c_process($interface) {
2775
	global $g;
2776

    
2777
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid"))
2778
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2779
	else
2780
		return(false);
2781

    
2782
	return intval($pid);
2783
}
2784

    
2785
function interface_virtual_create($interface) {
2786
	global $config;
2787

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

    
2825
function interface_vlan_mtu_configured($realhwif, $mtu) {
2826
	global $config;
2827

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

    
2840
	return $mtu;
2841
}
2842

    
2843
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2844
	global $config;
2845

    
2846
	if (!is_array($vlanifs))
2847
		return;
2848

    
2849
	/* All vlans need to use the same mtu value as their parent. */
2850
	foreach ($vlanifs as $vlan) {
2851
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2852
		if (!empty($assignedport)) {
2853
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
2854
				pfSense_interface_mtu($vlan['vlanif'], $config['interfaces'][$assignedport]['mtu']);
2855
			} else {
2856
				if (get_interface_mtu($vlan['vlanif']) != $mtu)
2857
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2858
			}
2859
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2860
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
2861
	}
2862
}
2863

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

    
2869
	$wancfg = $config['interfaces'][$interface];
2870

    
2871
	if (!isset($wancfg['enable']))
2872
		return;
2873

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

    
2879
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
2880
		/* remove all IPv4 and IPv6 addresses */
2881
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2882
		if (is_array($tmpifaces)) {
2883
			foreach ($tmpifaces as $tmpiface) {
2884
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
2885
					if (!is_linklocal($tmpiface))
2886
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2887
				} else {
2888
					if (is_subnetv4($tmpiface)) {
2889
						$tmpip = explode('/', $tmpiface);
2890
						$tmpip = $tmpip[0];
2891
					} else
2892
						$tmpip = $tmpiface;
2893
					pfSense_interface_deladdress($realif, $tmpip);
2894
				}
2895
			}
2896
		}
2897

    
2898
		/* only bring down the interface when both v4 and v6 are set to NONE */
2899
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6']))
2900
			interface_bring_down($interface);
2901
	}
2902

    
2903
	$interface_to_check = $realif;
2904
	switch ($wancfg['ipaddr']) {
2905
	case 'pppoe':
2906
	case 'l2tp':
2907
	case 'pptp':
2908
	case 'ppp':
2909
		$interface_to_check = $realhwif;
2910
		break;
2911
	}
2912

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

    
2917
	/* Disable Accepting router advertisements unless specifically requested */
2918
	if ($g['debug'])
2919
		log_error("Deny router advertisements for interface {$interface}");
2920
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
2921

    
2922
	/* wireless configuration? */
2923
	if (is_array($wancfg['wireless']))
2924
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2925

    
2926
	$mac = get_interface_mac($realhwif);
2927
	/*
2928
	 * Don't try to reapply the spoofed MAC if it's already applied.
2929
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2930
	 * the interface config again, which attempts to spoof the MAC again,
2931
	 * which cycles the link again...
2932
	 */
2933
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
2934
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2935
			" link " . escapeshellarg($wancfg['spoofmac']));
2936
	}  else {
2937

    
2938
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2939
			/*   this is not a valid mac address.  generate a
2940
			 *   temporary mac address so the machine can get online.
2941
			 */
2942
			echo gettext("Generating new MAC address.");
2943
			$random_mac = generate_random_mac_address();
2944
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2945
				" link " . escapeshellarg($random_mac));
2946
			$wancfg['spoofmac'] = $random_mac;
2947
			write_config();
2948
			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");
2949
		}
2950
	}
2951

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

    
2962
	/* Apply hw offloading policies as configured */
2963
	enable_hardware_offloading($interface);
2964

    
2965
	/* invalidate interface/ip/sn cache */
2966
	get_interface_arr(true);
2967
	unset($interface_ip_arr_cache[$realif]);
2968
	unset($interface_sn_arr_cache[$realif]);
2969
	unset($interface_ipv6_arr_cache[$realif]);
2970
	unset($interface_snv6_arr_cache[$realif]);
2971

    
2972
	$tunnelif = substr($realif, 0, 3);
2973
	switch ($wancfg['ipaddr']) {
2974
	case 'dhcp':
2975
		interface_dhcp_configure($interface);
2976
		break;
2977
	case 'pppoe':
2978
	case 'l2tp':
2979
	case 'pptp':
2980
	case 'ppp':
2981
		interface_ppps_configure($interface);
2982
		break;
2983
	default:
2984
		/* XXX: Kludge for now related to #3280 */
2985
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
2986
			if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "")
2987
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
2988
		}
2989
		break;
2990
	}
2991

    
2992
	switch ($wancfg['ipaddrv6']) {
2993
	case 'slaac':
2994
	case 'dhcp6':
2995
		interface_dhcpv6_configure($interface, $wancfg);
2996
		break;
2997
	case '6rd':
2998
		interface_6rd_configure($interface, $wancfg);
2999
		break;
3000
	case '6to4':
3001
		interface_6to4_configure($interface, $wancfg);
3002
		break;
3003
	case 'track6':
3004
		interface_track6_configure($interface, $wancfg, $linkupevent);
3005
		break;
3006
	default:
3007
		/* XXX: Kludge for now related to #3280 */
3008
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3009
			if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3010
				//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3011
				// FIXME: Add IPv6 Support to the pfSense module
3012
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3013
			}
3014
		}
3015
		break;
3016
	}
3017

    
3018
	if (!empty($wancfg['mtu'])) {
3019
		if (stristr($realif, "_vlan")) {
3020
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3021
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3022
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3023
				if ($wancfg['mtu'] > $parentmtu)
3024
					log_error("There is a conflict on MTU between parent {$realhwif} and VLAN({$realif})");
3025
			} else
3026
				$parentmtu = 0;
3027

    
3028
			$parentmtu = interface_vlan_mtu_configured($realhwif, $parentmtu);
3029

    
3030
			if (get_interface_mtu($realhwif) != $parentmtu)
3031
				pfSense_interface_mtu($realhwif, $parentmtu);
3032

    
3033
			/* All vlans need to use the same mtu value as their parent. */
3034
			interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $parentmtu);
3035
		} else if (substr($realif, 0, 4) == 'lagg') {
3036
			/* LAGG interface must be destroyed and re-created to change MTU */
3037
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3038
				if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3039
					foreach ($config['laggs']['lagg'] as $lagg) {
3040
						if ($lagg['laggif'] == $realif) {
3041
							interface_lagg_configure($lagg);
3042
							break;
3043
						}
3044
					}
3045
				}
3046
			}
3047
		} else {
3048
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3049
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3050

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

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

    
3063
	interface_netgraph_needed($interface);
3064

    
3065
	if (!platform_booting()) {
3066
		link_interface_to_vips($interface, "update");
3067

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

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

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

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

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

    
3093
		if ($reloadall == true) {
3094

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

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

    
3101
			/* restart dnsmasq or unbound */
3102
			if (isset($config['dnsmasq']['enable']))
3103
				services_dnsmasq_configure();
3104
			elseif (isset($config['unbound']['enable']))
3105
				services_unbound_configure();
3106

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

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

    
3116
	interfaces_staticarp_configure($interface);
3117
	return 0;
3118
}
3119

    
3120
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3121
	global $config, $g;
3122

    
3123
	if (!is_array($wancfg))
3124
		return;
3125

    
3126
	if (!isset($wancfg['enable']))
3127
		return;
3128

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

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

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

    
3148
	switch($trackcfg['ipaddrv6']) {
3149
	case "6to4":
3150
		if ($g['debug'])
3151
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3152
		interface_track6_6to4_configure($interface, $wancfg);
3153
		break;
3154
	case "6rd":
3155
		if ($g['debug'])
3156
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3157
		interface_track6_6rd_configure($interface, $wancfg);
3158
		break;
3159
	case "dhcp6":
3160
		if ($linkupevent == true) {
3161
			/* 
3162
			 * NOTE: Usually come here from rc.linkup calling so just call directly intead of generating event
3163
			 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3164
			 *
3165
			 * XXX: Probably DHCPv6 client should handle this autmagically itself?
3166
			 */
3167
			$parentrealif = get_real_interface($wancfg['track6-interface']);
3168
			$pidv6 = find_dhcp6c_process($parentrealif);
3169
			if($pidv6)
3170
				posix_kill($pidv6, SIGHUP);
3171
		}
3172
		break;
3173
	}
3174

    
3175
	if (!platform_booting() && $linkupevent == false) {
3176
		if (!function_exists('services_dhcpd_configure'))
3177
			require_once("services.inc");
3178

    
3179
		services_dhcpd_configure("inet6");
3180
	}
3181

    
3182
	return 0;
3183
}
3184

    
3185
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3186
	global $config, $g;
3187
	global $interface_ipv6_arr_cache;
3188
	global $interface_snv6_arr_cache;
3189

    
3190
	if (!is_array($lancfg))
3191
		return;
3192

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

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

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

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

    
3215
	/* binary presentation of the prefix for all 128 bits. */
3216
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3217

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

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

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

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

    
3243
	return 0;
3244
}
3245

    
3246
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3247
	global $config, $g;
3248
	global $interface_ipv6_arr_cache;
3249
	global $interface_snv6_arr_cache;
3250

    
3251
	if (!is_array($lancfg))
3252
		return;
3253

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

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

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

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

    
3276
	/* binary presentation of the prefix for all 128 bits. */
3277
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3278

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

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

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

    
3300
	return 0;
3301
}
3302

    
3303
function interface_6rd_configure($interface = "wan", $wancfg) {
3304
	global $config, $g;
3305

    
3306
	/* because this is a tunnel interface we can only function
3307
	 *	with a public IPv4 address on the interface */
3308

    
3309
	if (!is_array($wancfg))
3310
		return;
3311

    
3312
	if (!is_module_loaded('if_stf.ko'))
3313
		mwexec('/sbin/kldload if_stf.ko');
3314

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

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

    
3326
	/* create the long prefix notation for math, save the prefix length */
3327
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3328
	$rd6prefixlen = $rd6prefix[1];
3329
	$brgw = explode('.', $wancfg['gateway-6rd']);
3330
	$rd6brgw = rtrim($rd6prefix[0], ':') . ':' . dechex($brgw[0]) . dechex($brgw[1]) . ':' . dechex($brgw[2]) . dechex($brgw[3]) . '::';
3331
	unset($brgw);
3332
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3333

    
3334
	/* binary presentation of the prefix for all 128 bits. */
3335
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3336

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

    
3344
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3345
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3346

    
3347

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

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

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

    
3372
	/* configure dependent interfaces */
3373
	if (!platform_booting())
3374
		link_interface_to_track6($interface, "update");
3375

    
3376
	return 0;
3377
}
3378

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

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

    
3385
	if (!is_array($wancfg))
3386
		return;
3387

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3469
	if (!platform_booting())
3470
		link_interface_to_track6($interface, "update");
3471

    
3472
	return 0;
3473
}
3474

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

    
3478
	if (!is_array($wancfg))
3479
		return;
3480

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

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

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

    
3503
		$dhcp6cconf .= "};\n";
3504

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

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

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

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

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

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

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

    
3579
	/* accept router advertisements for this interface */
3580
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3581
	log_error("Accept router advertisements on interface {$wanif} ");
3582
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3583

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

    
3591
	/* NOTE: will be called from rtsold invoked script
3592
	 * link_interface_to_track6($interface, "update");
3593
	 */
3594

    
3595
	return 0;
3596
}
3597

    
3598
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3599
	global $g;
3600

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

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

    
3617
	$information_only = "";
3618
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') 
3619
		$information_only = "\tinformation-only;\n";
3620

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

    
3625
	$interface_statement  = "interface";
3626
	$interface_statement .= " {$wanif}";
3627
	$interface_statement .= " {\n";
3628
	$interface_statement .= "$send_options";
3629
	$interface_statement .= "$request_options";
3630
	$interface_statement .= "$information_only";
3631
	$interface_statement .= "$script";
3632
	$interface_statement .= "};\n";
3633

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

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

    
3654
		$id_assoc_statement_address  .= "};\n";
3655
	}
3656

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

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

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

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

    
3693
		$id_assoc_statement_prefix  .= "};\n";
3694
	}
3695

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

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

    
3726
	$dhcp6cconf  = $interface_statement;
3727
	$dhcp6cconf .= $id_assoc_statement_address;
3728
	$dhcp6cconf .= $id_assoc_statement_prefix;
3729
	$dhcp6cconf .= $authentication_statement;
3730
	$dhcp6cconf .= $key_info_statement;
3731

    
3732
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3733

    
3734
	return $dhcp6cconf;
3735
}
3736

    
3737

    
3738
function DHCP6_Config_File_Override($wancfg, $wanif) {
3739

    
3740
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
3741
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3742

    
3743
	return $dhcp6cconf;
3744
}
3745

    
3746

    
3747
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
3748

    
3749
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3750

    
3751
	return $dhcp6cconf;
3752
}
3753

    
3754

    
3755
function interface_dhcp_configure($interface = "wan") {
3756
	global $config, $g;
3757

    
3758
	$wancfg = $config['interfaces'][$interface];
3759
	$wanif = $wancfg['if'];
3760
	if (empty($wancfg))
3761
		$wancfg = array();
3762

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

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

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

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

    
3794
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3795
	$dhclientconf .= <<<EOD
3796

    
3797
	reject {$wancfg['dhcprejectfrom']};
3798
EOD;
3799
}
3800
	$dhclientconf .= <<<EOD
3801

    
3802
}
3803

    
3804
EOD;
3805

    
3806
	// DHCP Config File Advanced
3807
	if ($wancfg['adv_dhcp_config_advanced']) { $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif); }
3808

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

    
3818
EOD;
3819
}
3820

    
3821
	// DHCP Config File Override
3822
	if ($wancfg['adv_dhcp_config_file_override']) { $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif); }
3823

    
3824
	fwrite($fd, $dhclientconf);
3825
	fclose($fd);
3826

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

    
3833
	/* Make sure dhclient is not running */
3834
	kill_dhclient_process($wanif);
3835

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

    
3839
	return 0;
3840
}
3841

    
3842
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3843

    
3844
	$hostname = "";
3845
	if ($wancfg['dhcphostname'] != '') {
3846
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3847
	}
3848

    
3849
	/* DHCP Protocol Timings */
3850
	$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");
3851
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
3852
		$pt_variable = "{$Protocol_Timing}";
3853
		${$pt_variable} = "";
3854
		if ($wancfg[$Protocol_Timing] != "") {
3855
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
3856
		}
3857
	}
3858

    
3859
	$send_options = "";
3860
	if ($wancfg['adv_dhcp_send_options'] != '') {
3861
		$options = split(",", $wancfg['adv_dhcp_send_options']);
3862
		foreach ($options as $option) {
3863
			$send_options .= "\tsend " . trim($option) . ";\n";
3864
		}
3865
	}
3866

    
3867
	$request_options = "";
3868
	if ($wancfg['adv_dhcp_request_options'] != '') {
3869
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
3870
	}
3871

    
3872
	$required_options = "";
3873
	if ($wancfg['adv_dhcp_required_options'] != '') {
3874
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
3875
	}
3876

    
3877
	$option_modifiers = "";
3878
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
3879
		$modifiers = split(",", $wancfg['adv_dhcp_option_modifiers']);
3880
		foreach ($modifiers as $modifier) {
3881
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
3882
		}
3883
	}
3884

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

    
3905
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3906

    
3907
	return $dhclientconf;
3908
}
3909

    
3910

    
3911
function DHCP_Config_File_Override($wancfg, $wanif) {
3912

    
3913
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
3914
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3915

    
3916
	return $dhclientconf;
3917
}
3918

    
3919

    
3920
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
3921

    
3922
	/* Apply Interface Substitutions */
3923
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
3924

    
3925
	/* Apply Hostname Substitutions */
3926
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
3927

    
3928
	/* Arrays of MAC Address Types, Cases, Delimiters */
3929
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
3930
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
3931
	$various_mac_cases      = array("U", "L");
3932
	$various_mac_delimiters = array("", " ", ":", "-", ".");
3933

    
3934
	/* Apply MAC Address Substitutions */
3935
	foreach ($various_mac_types as $various_mac_type) {
3936
		foreach ($various_mac_cases as $various_mac_case) {
3937
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
3938

    
3939
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
3940
				if ($res !== false) {
3941

    
3942
					/* Get MAC Address as ASCII String With Colon (:) Celimiters */
3943
					if ("$various_mac_case" == "U") $dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
3944
					if ("$various_mac_case" == "L") $dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
3945

    
3946
					if ("$various_mac_type" == "mac_addr_hex") {
3947
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
3948
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
3949
						$dhcpclientconf_mac_hex = "";
3950
						$delimiter = "";
3951
						for($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
3952
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
3953
							$delimiter = ":";
3954
						}
3955
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
3956
					}
3957

    
3958
					/* MAC Address Delimiter Substitutions */
3959
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
3960

    
3961
					/* Apply MAC Address Substitutions */
3962
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
3963
				}
3964
			}
3965
		}
3966
	}
3967

    
3968
	return $dhclientconf;
3969
}
3970

    
3971
function interfaces_group_setup() {
3972
	global $config;
3973

    
3974
	if (!is_array($config['ifgroups']['ifgroupentry']))
3975
		return;
3976

    
3977
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3978
		interface_group_setup($groupar);
3979

    
3980
	return;
3981
}
3982

    
3983
function interface_group_setup(&$groupname /* The parameter is an array */) {
3984
	global $config;
3985

    
3986
	if (!is_array($groupname))
3987
		return;
3988
	$members = explode(" ", $groupname['members']);
3989
	foreach($members as $ifs) {
3990
		$realif = get_real_interface($ifs);
3991
		if ($realif)
3992
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3993
	}
3994

    
3995
	return;
3996
}
3997

    
3998
function is_interface_group($if) {
3999
	global $config;
4000

    
4001
	if (is_array($config['ifgroups']['ifgroupentry']))
4002
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4003
			if ($groupentry['ifname'] === $if)
4004
				return true;
4005
		}
4006

    
4007
	return false;
4008
}
4009

    
4010
function interface_group_add_member($interface, $groupname) {
4011
	$interface = get_real_interface($interface);
4012
	mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4013
}
4014

    
4015
/* COMPAT Function */
4016
function convert_friendly_interface_to_real_interface_name($interface) {
4017
	return get_real_interface($interface);
4018
}
4019

    
4020
/* COMPAT Function */
4021
function get_real_wan_interface($interface = "wan") {
4022
	return get_real_interface($interface);
4023
}
4024

    
4025
/* COMPAT Function */
4026
function get_current_wan_address($interface = "wan") {
4027
	return get_interface_ip($interface);
4028
}
4029

    
4030
/*
4031
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4032
 */
4033
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4034
	global $config;
4035

    
4036
	if (stripos($interface, "_vip")) {
4037
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
4038
			if ($vip['mode'] == "carp")  {
4039
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4040
				return $vip['interface'];
4041
			}
4042
		}
4043
	}
4044

    
4045
	/* XXX: For speed reasons reference directly the interface array */
4046
	$ifdescrs = &$config['interfaces'];
4047
	//$ifdescrs = get_configured_interface_list(false, true);
4048

    
4049
	foreach ($ifdescrs as $if => $ifname) {
4050
		if ($if == $interface || $ifname['if'] == $interface)
4051
			return $if;
4052

    
4053
		if (get_real_interface($if) == $interface)
4054
			return $if;
4055

    
4056
		if ($checkparent == false)
4057
			continue;
4058

    
4059
		$int = get_parent_interface($if, true);
4060
		if (is_array($int)) {
4061
			foreach ($int as $iface) {
4062
				if ($iface == $interface)
4063
					return $if;
4064
			}
4065
		}
4066
	}
4067

    
4068
	if ($interface == "enc0")
4069
		return 'IPsec';
4070
}
4071

    
4072
/* attempt to resolve interface to friendly descr */
4073
function convert_friendly_interface_to_friendly_descr($interface) {
4074
	global $config;
4075

    
4076
	switch ($interface) {
4077
	case "l2tp":
4078
		$ifdesc = "L2TP";
4079
		break;
4080
	case "pptp":
4081
		$ifdesc = "PPTP";
4082
		break;
4083
	case "pppoe":
4084
		$ifdesc = "PPPoE";
4085
		break;
4086
	case "openvpn":
4087
		$ifdesc = "OpenVPN";
4088
		break;
4089
	case "enc0":
4090
	case "ipsec":
4091
	case "IPsec":
4092
		$ifdesc = "IPsec";
4093
		break;
4094
	default:
4095
		if (isset($config['interfaces'][$interface])) {
4096
			if (empty($config['interfaces'][$interface]['descr']))
4097
				$ifdesc = strtoupper($interface);
4098
			else
4099
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4100
			break;
4101
		} else if (stristr($interface, "_vip")) {
4102
			if (is_array($config['virtualip']['vip'])) {
4103
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
4104
					if ($vip['mode'] == "carp")  {
4105
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4106
							return "{$vip['subnet']} - {$vip['descr']}";
4107
					}
4108
				}
4109
			}
4110
		} else {
4111
			/* if list */
4112
			$ifdescrs = get_configured_interface_with_descr(false, true);
4113
			foreach ($ifdescrs as $if => $ifname) {
4114
				if ($if == $interface || $ifname == $interface)
4115
					return $ifname;
4116
			}
4117
		}
4118
		break;
4119
	}
4120

    
4121
	return $ifdesc;
4122
}
4123

    
4124
function convert_real_interface_to_friendly_descr($interface) {
4125

    
4126
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4127

    
4128
	if (!empty($ifdesc))
4129
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4130

    
4131
	return $interface;
4132
}
4133

    
4134
/*
4135
 *  get_parent_interface($interface):
4136
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4137
 *				or virtual interface (i.e. vlan)
4138
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4139
 *			-- returns $interface passed in if $interface parent is not found
4140
 *			-- returns empty array if an invalid interface is passed
4141
 *	(Only handles ppps and vlans now.)
4142
 */
4143
function get_parent_interface($interface, $avoidrecurse = false) {
4144
	global $config;
4145

    
4146
	$parents = array();
4147
	//Check that we got a valid interface passed
4148
	$realif = get_real_interface($interface);
4149
	if ($realif == NULL)
4150
		return $parents;
4151

    
4152
	// If we got a real interface, find it's friendly assigned name
4153
	if ($interface == $realif && $avoidrecurse == false)
4154
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4155

    
4156
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4157
		$ifcfg = $config['interfaces'][$interface];
4158
		switch ($ifcfg['ipaddr']) {
4159
			case "ppp":
4160
			case "pppoe":
4161
			case "pptp":
4162
			case "l2tp":
4163
				if (empty($parents))
4164
					if (is_array($config['ppps']['ppp']))
4165
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4166
							if ($ifcfg['if'] == $ppp['if']) {
4167
								$ports = explode(',', $ppp['ports']);
4168
								foreach ($ports as $pid => $parent_if)
4169
									$parents[$pid] = get_real_interface($parent_if);
4170
								break;
4171
							}
4172
						}
4173
				break;
4174
			case "dhcp":
4175
			case "static":
4176
			default:
4177
				// Handle _vlans
4178
				if (strpos($realif, '_vlan') !== FALSE) {
4179
					if (is_array($config['vlans']['vlan'])) {
4180
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4181
							if ($ifcfg['if'] == $vlan['vlanif']) {
4182
								$parents[0] = $vlan['if'];
4183
								break;
4184
							}
4185
						}
4186
					}
4187
				}
4188
				break;
4189
		}
4190
	}
4191

    
4192
	if (empty($parents))
4193
		$parents[0] = $realif;
4194

    
4195
	return $parents;
4196
}
4197

    
4198
function interface_is_wireless_clone($wlif) {
4199
	if(!stristr($wlif, "_wlan")) {
4200
		return false;
4201
	} else {
4202
		return true;
4203
	}
4204
}
4205

    
4206
function interface_get_wireless_base($wlif) {
4207
	if(!stristr($wlif, "_wlan")) {
4208
		return $wlif;
4209
	} else {
4210
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4211
	}
4212
}
4213

    
4214
function interface_get_wireless_clone($wlif) {
4215
	if(!stristr($wlif, "_wlan")) {
4216
		return $wlif . "_wlan0";
4217
	} else {
4218
		return $wlif;
4219
	}
4220
}
4221

    
4222
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4223
	global $config, $g;
4224

    
4225
	$wanif = NULL;
4226

    
4227
	switch ($interface) {
4228
	case "l2tp":
4229
		$wanif = "l2tp";
4230
		break;
4231
	case "pptp":
4232
		$wanif = "pptp";
4233
		break;
4234
	case "pppoe":
4235
		$wanif = "pppoe";
4236
		break;
4237
	case "openvpn":
4238
		$wanif = "openvpn";
4239
		break;
4240
	case "ipsec":
4241
	case "enc0":
4242
		$wanif = "enc0";
4243
		break;
4244
	case "ppp":
4245
		$wanif = "ppp";
4246
		break;
4247
	default:
4248
		// If a real interface was alread passed simply
4249
		// pass the real interface back.  This encourages
4250
		// the usage of this function in more cases so that
4251
		// we can combine logic for more flexibility.
4252
		if(does_interface_exist($interface, $flush)) {
4253
			$wanif = $interface;
4254
			break;
4255
		}
4256

    
4257
		if (empty($config['interfaces'][$interface]))
4258
			break;
4259

    
4260
		$cfg = &$config['interfaces'][$interface];
4261

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

    
4314
	return $wanif;
4315
}
4316

    
4317
/* Guess the physical interface by providing a IP address */
4318
function guess_interface_from_ip($ipaddress) {
4319

    
4320
	$family = '';
4321
	if(is_ipaddrv4($ipaddress))
4322
		$family = 'inet';
4323
	if (empty($family) && is_ipaddrv6($ipaddress))
4324
		$family = 'inet6';
4325

    
4326
	if (empty($family))
4327
		return false;
4328

    
4329
	/* create a route table we can search */
4330
	$output = '';
4331
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4332
	$output[0] = trim($output[0], " \n");
4333
	if (!empty($output[0]))
4334
		return $output[0];
4335

    
4336
	return false;
4337
}
4338

    
4339
/*
4340
 * find_ip_interface($ip): return the interface where an ip is defined
4341
 *   (or if $bits is specified, where an IP within the subnet is defined)
4342
 */
4343
function find_ip_interface($ip, $bits = null) {
4344
	if (!is_ipaddr($ip))
4345
		return false;
4346

    
4347
	$isv6ip = is_ipaddrv6($ip);
4348

    
4349
	/* if list */
4350
	$ifdescrs = get_configured_interface_list();
4351

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

    
4370
	return false;
4371
}
4372

    
4373
/*
4374
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4375
 *   (or if $bits is specified, where an IP within the subnet is found)
4376
 */
4377
function find_virtual_ip_alias($ip, $bits = null) {
4378
	global $config;
4379

    
4380
	if (!is_array($config['virtualip']['vip'])) {
4381
		return false;
4382
	}
4383
	if (!is_ipaddr($ip))
4384
		return false;
4385

    
4386
	$isv6ip = is_ipaddrv6($ip);
4387

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

    
4408
/*
4409
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4410
 */
4411
function find_number_of_created_carp_interfaces() {
4412
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4413
}
4414

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

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

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

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

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

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

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

    
4481

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

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

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

    
4514
	return $carp_ints;
4515
}
4516

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

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

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

    
4539
function interface_find_child_cfgmtu($realiface) {
4540
	global $config;
4541

    
4542
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
4543
	$vlans = link_interface_to_vlans($realiface);
4544
	$bridge = link_interface_to_bridge($realiface);
4545
	if (!empty($interface)) {
4546
		$gifs = link_interface_to_gif($interface);
4547
		$gres = link_interface_to_gre($interface);
4548
	} else {
4549
		$gifs = array();
4550
		$gres = array();
4551
	}
4552

    
4553
	$mtu = 0;
4554
	if (is_array($vlans)) {
4555
		foreach ($vlans as $vlan) {
4556
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4557
			if (empty($ifass))
4558
				continue;
4559
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4560
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu)
4561
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4562
			}
4563
		}
4564
	}
4565
	if (is_array($gifs)) {
4566
		foreach ($gifs as $vlan) {
4567
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['gifif']);
4568
			if (empty($ifass))
4569
				continue;
4570
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4571
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu)
4572
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4573
			}
4574
		}
4575
	}
4576
	if (is_array($gres)) {
4577
		foreach ($gres as $vlan) {
4578
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['greif']);
4579
			if (empty($ifass))
4580
				continue;
4581
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4582
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu)
4583
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4584
			}
4585
		}
4586
	}
4587
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
4588
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
4589
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu)
4590
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
4591
	}
4592
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
4593

    
4594
	return $mtu;
4595
}
4596

    
4597
function link_interface_to_vlans($int, $action = "") {
4598
	global $config;
4599

    
4600
	if (empty($int))
4601
		return;
4602

    
4603
	if (is_array($config['vlans']['vlan'])) {
4604
		$ifaces = array();
4605
		foreach ($config['vlans']['vlan'] as $vlan) {
4606
			if ($int == $vlan['if']) {
4607
				if ($action == "update") {
4608
					interfaces_bring_up($int);
4609
				} else
4610
					$ifaces[$vlan['tag']] = $vlan;
4611
			}
4612
		}
4613
		if (!empty($ifaces))
4614
			return $ifaces;
4615
	}
4616
}
4617

    
4618
function link_interface_to_vips($int, $action = "") {
4619
	global $config;
4620

    
4621
	if (is_array($config['virtualip']['vip'])) {
4622
		$result = array();
4623
		foreach ($config['virtualip']['vip'] as $vip) {
4624
			if ($int == $vip['interface']) {
4625
				if ($action == "update")
4626
					interfaces_vips_configure($int);
4627
				else
4628
					$result[] = $vip;
4629
			}
4630
		}
4631
		return $result;
4632
	}
4633
}
4634

    
4635
/****f* interfaces/link_interface_to_bridge
4636
 * NAME
4637
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4638
 * INPUTS
4639
 *   $ip
4640
 * RESULT
4641
 *   bridge[0-99]
4642
 ******/
4643
function link_interface_to_bridge($int) {
4644
	global $config;
4645

    
4646
	if (is_array($config['bridges']['bridged'])) {
4647
		foreach ($config['bridges']['bridged'] as $bridge) {
4648
			if (in_array($int, explode(',', $bridge['members'])))
4649
				return "{$bridge['bridgeif']}";
4650
		}
4651
	}
4652
}
4653

    
4654
function link_interface_to_group($int) {
4655
	global $config;
4656

    
4657
	$result = array();
4658

    
4659
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4660
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4661
			if (in_array($int, explode(" ", $group['members'])))
4662
				$result[$group['ifname']] = $int;
4663
		}
4664
	}
4665

    
4666
	return $result;
4667
}
4668

    
4669
function link_interface_to_gre($interface) {
4670
	global $config;
4671

    
4672
	$result = array();
4673

    
4674
	if (is_array($config['gres']['gre'])) {
4675
		foreach ($config['gres']['gre'] as $gre)
4676
			if($gre['if'] == $interface)
4677
				$result[] = $gre;
4678
	}
4679

    
4680
	return $result;
4681
}
4682

    
4683
function link_interface_to_gif($interface) {
4684
	global $config;
4685

    
4686
	$result = array();
4687

    
4688
	if (is_array($config['gifs']['gif'])) {
4689
		foreach ($config['gifs']['gif'] as $gif)
4690
			if($gif['if'] == $interface)
4691
				$result[] = $gif;
4692
	}
4693

    
4694
	return $result;
4695
}
4696

    
4697
/*
4698
 * find_interface_ip($interface): return the interface ip (first found)
4699
 */
4700
function find_interface_ip($interface, $flush = false) {
4701
	global $interface_ip_arr_cache;
4702
	global $interface_sn_arr_cache;
4703

    
4704
	$interface = str_replace("\n", "", $interface);
4705

    
4706
	if (!does_interface_exist($interface))
4707
		return;
4708

    
4709
	/* Setup IP cache */
4710
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4711
		$ifinfo = pfSense_get_interface_addresses($interface);
4712
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4713
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4714
	}
4715

    
4716
	return $interface_ip_arr_cache[$interface];
4717
}
4718

    
4719
/*
4720
 * find_interface_ipv6($interface): return the interface ip (first found)
4721
 */
4722
function find_interface_ipv6($interface, $flush = false) {
4723
	global $interface_ipv6_arr_cache;
4724
	global $interface_snv6_arr_cache;
4725
	global $config;
4726

    
4727
	$interface = trim($interface);
4728
	$interface = get_real_interface($interface);
4729

    
4730
	if (!does_interface_exist($interface))
4731
		return;
4732

    
4733
	/* Setup IP cache */
4734
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4735
		$ifinfo = pfSense_get_interface_addresses($interface);
4736
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4737
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4738
	}
4739

    
4740
	return $interface_ipv6_arr_cache[$interface];
4741
}
4742

    
4743
/*
4744
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4745
 */
4746
function find_interface_ipv6_ll($interface, $flush = false) {
4747
	global $interface_llv6_arr_cache;
4748
	global $config;
4749

    
4750
	$interface = str_replace("\n", "", $interface);
4751

    
4752
	if (!does_interface_exist($interface))
4753
		return;
4754

    
4755
	/* Setup IP cache */
4756
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4757
		$ifinfo = pfSense_getall_interface_addresses($interface);
4758
		foreach($ifinfo as $line) {
4759
			if (strstr($line, ":")) {
4760
				$parts = explode("/", $line);
4761
				if(is_linklocal($parts[0])) {
4762
					$ifinfo['linklocal'] = $parts[0];
4763
				}
4764
			}
4765
		}
4766
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4767
	}
4768
	return $interface_llv6_arr_cache[$interface];
4769
}
4770

    
4771
function find_interface_subnet($interface, $flush = false) {
4772
	global $interface_sn_arr_cache;
4773
	global $interface_ip_arr_cache;
4774

    
4775
	$interface = str_replace("\n", "", $interface);
4776
	if (does_interface_exist($interface) == false)
4777
		return;
4778

    
4779
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4780
		$ifinfo = pfSense_get_interface_addresses($interface);
4781
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4782
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4783
	}
4784

    
4785
	return $interface_sn_arr_cache[$interface];
4786
}
4787

    
4788
function find_interface_subnetv6($interface, $flush = false) {
4789
	global $interface_snv6_arr_cache;
4790
	global $interface_ipv6_arr_cache;
4791

    
4792
	$interface = str_replace("\n", "", $interface);
4793
	if (does_interface_exist($interface) == false)
4794
		return;
4795

    
4796
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4797
		$ifinfo = pfSense_get_interface_addresses($interface);
4798
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4799
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4800
	}
4801

    
4802
	return $interface_snv6_arr_cache[$interface];
4803
}
4804

    
4805
function ip_in_interface_alias_subnet($interface, $ipalias) {
4806
	global $config;
4807

    
4808
	if (empty($interface) || !is_ipaddr($ipalias))
4809
		return false;
4810
	if (is_array($config['virtualip']['vip'])) {
4811
		foreach ($config['virtualip']['vip'] as $vip) {
4812
			switch ($vip['mode']) {
4813
			case "ipalias":
4814
				if ($vip['interface'] <> $interface)
4815
					break;
4816
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4817
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4818
					return true;
4819
				break;
4820
			}
4821
		}
4822
	}
4823

    
4824
	return false;
4825
}
4826

    
4827
function get_interface_ip($interface = "wan") {
4828
	$realif = get_failover_interface($interface);
4829
	if (!$realif) {
4830
		if (strstr($interface, "_vip"))
4831
			return get_configured_carp_interface_list($interface);
4832
		else
4833
			return null;
4834
	}
4835

    
4836
	$curip = find_interface_ip($realif);
4837
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4838
		return $curip;
4839
	else
4840
		return null;
4841
}
4842

    
4843
function get_interface_ipv6($interface = "wan", $flush = false) {
4844
	global $config;
4845

    
4846
	$realif = get_failover_interface($interface, "inet6");
4847
	if (!$realif) {
4848
		if (strstr($interface, "_vip"))
4849
			return get_configured_carp_interface_list($interface, "inet6");
4850
		else
4851
			return null;
4852
	}
4853

    
4854
	/*
4855
	 * NOTE: On the case when only the prefix is requested,
4856
	 * the communication on WAN will be done over link-local.
4857
	 */
4858
	if (is_array($config['interfaces'][$interface])) {
4859
		switch ($config['interfaces'][$interface]['ipaddr']) {
4860
		case 'pppoe':
4861
		case 'l2tp':
4862
		case 'pptp':
4863
		case 'ppp':
4864
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4865
				$realif = get_real_interface($interface, "inet6", true);
4866
			break;
4867
		}
4868
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4869
			$curip = find_interface_ipv6_ll($realif, $flush);
4870
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4871
				return $curip;
4872
		}
4873
	}
4874

    
4875
	$curip = find_interface_ipv6($realif, $flush);
4876
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4877
		return $curip;
4878
	else
4879
		return null;
4880
}
4881

    
4882
function get_interface_linklocal($interface = "wan") {
4883

    
4884
	$realif = get_failover_interface($interface, "inet6");
4885
	if (!$realif) {
4886
		if (strstr($interface, "_vip")) {
4887
			list($interface, $vhid) = explode("_vip", $interface);
4888
			$realif = get_real_interface($interface);
4889
		} else
4890
			return null;
4891
	}
4892

    
4893
	$curip = find_interface_ipv6_ll($realif);
4894
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4895
		return $curip;
4896
	else
4897
		return null;
4898
}
4899

    
4900
function get_interface_subnet($interface = "wan") {
4901
	$realif = get_real_interface($interface);
4902
	if (!$realif) {
4903
		if (strstr($interface, "_vip")) {
4904
			list($interface, $vhid) = explode("_vip", $interface);
4905
			$realif = get_real_interface($interface);
4906
		} else
4907
			return null;
4908
	}
4909

    
4910
	$cursn = find_interface_subnet($realif);
4911
	if (!empty($cursn))
4912
		return $cursn;
4913

    
4914
	return null;
4915
}
4916

    
4917
function get_interface_subnetv6($interface = "wan") {
4918
	global $config;
4919

    
4920
	$realif = get_real_interface($interface, "inet6");
4921
	if (!$realif) {
4922
		if (strstr($interface, "_vip")) {
4923
			list($interface, $vhid) = explode("_vip", $interface);
4924
			$realif = get_real_interface($interface);
4925
		} else
4926
			return null;
4927
	}
4928

    
4929
	$cursn = find_interface_subnetv6($realif);
4930
	if (!empty($cursn))
4931
		return $cursn;
4932

    
4933
	return null;
4934
}
4935

    
4936
/* return outside interfaces with a gateway */
4937
function get_interfaces_with_gateway() {
4938
	global $config;
4939

    
4940
	$ints = array();
4941

    
4942
	/* loop interfaces, check config for outbound */
4943
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4944
		switch ($ifname['ipaddr']) {
4945
			case "dhcp":
4946
			case "ppp";
4947
			case "pppoe":
4948
			case "pptp":
4949
			case "l2tp":
4950
			case "ppp";
4951
				$ints[$ifdescr] = $ifdescr;
4952
			break;
4953
			default:
4954
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
4955
				    !empty($ifname['gateway']))
4956
					$ints[$ifdescr] = $ifdescr;
4957
			break;
4958
		}
4959
	}
4960
	return $ints;
4961
}
4962

    
4963
/* return true if interface has a gateway */
4964
function interface_has_gateway($friendly) {
4965
	global $config;
4966

    
4967
	if (!empty($config['interfaces'][$friendly])) {
4968
		$ifname = &$config['interfaces'][$friendly];
4969
		switch ($ifname['ipaddr']) {
4970
			case "dhcp":
4971
			case "pppoe":
4972
			case "pptp":
4973
			case "l2tp":
4974
			case "ppp";
4975
				return true;
4976
			break;
4977
			default:
4978
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4979
					return true;
4980
				$tunnelif = substr($ifname['if'], 0, 3);
4981
				if ($tunnelif == "gif" || $tunnelif == "gre")
4982
					return true;
4983
				if (!empty($ifname['gateway']))
4984
					return true;
4985
			break;
4986
		}
4987
	}
4988

    
4989
	return false;
4990
}
4991

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

    
4996
	if (!empty($config['interfaces'][$friendly])) {
4997
		$ifname = &$config['interfaces'][$friendly];
4998
		switch ($ifname['ipaddrv6']) {
4999
			case "slaac":
5000
			case "dhcp6":
5001
			case "6to4":
5002
			case "6rd":
5003
				return true;
5004
				break;
5005
			default:
5006
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
5007
					return true;
5008
				$tunnelif = substr($ifname['if'], 0, 3);
5009
				if ($tunnelif == "gif" || $tunnelif == "gre")
5010
					return true;
5011
				if (!empty($ifname['gatewayv6']))
5012
					return true;
5013
				break;
5014
		}
5015
	}
5016

    
5017
	return false;
5018
}
5019

    
5020
/****f* interfaces/is_altq_capable
5021
 * NAME
5022
 *   is_altq_capable - Test if interface is capable of using ALTQ
5023
 * INPUTS
5024
 *   $int            - string containing interface name
5025
 * RESULT
5026
 *   boolean         - true or false
5027
 ******/
5028

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

    
5042
	$int_family = remove_ifindex($int);
5043

    
5044
	if (in_array($int_family, $capable))
5045
		return true;
5046
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
5047
		return true;
5048
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
5049
		return true;
5050
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
5051
		return true;
5052
	else
5053
		return false;
5054
}
5055

    
5056
/****f* interfaces/is_interface_wireless
5057
 * NAME
5058
 *   is_interface_wireless - Returns if an interface is wireless
5059
 * RESULT
5060
 *   $tmp       - Returns if an interface is wireless
5061
 ******/
5062
function is_interface_wireless($interface) {
5063
	global $config, $g;
5064

    
5065
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5066
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
5067
		if (preg_match($g['wireless_regex'], $interface)) {
5068
			if (isset($config['interfaces'][$friendly]))
5069
				$config['interfaces'][$friendly]['wireless'] = array();
5070
			return true;
5071
		}
5072
		return false;
5073
	} else
5074
		return true;
5075
}
5076

    
5077
function get_wireless_modes($interface) {
5078
	/* return wireless modes and channels */
5079
	$wireless_modes = array();
5080

    
5081
	$cloned_interface = get_real_interface($interface);
5082

    
5083
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5084
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5085
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5086
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5087

    
5088
		$interface_channels = "";
5089
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5090
		$interface_channel_count = count($interface_channels);
5091

    
5092
		$c = 0;
5093
		while ($c < $interface_channel_count) {
5094
			$channel_line = explode(",", $interface_channels["$c"]);
5095
			$wireless_mode = trim($channel_line[0]);
5096
			$wireless_channel = trim($channel_line[1]);
5097
			if(trim($wireless_mode) != "") {
5098
				/* if we only have 11g also set 11b channels */
5099
				if($wireless_mode == "11g") {
5100
					if(!isset($wireless_modes["11b"]))
5101
						$wireless_modes["11b"] = array();
5102
				} else if($wireless_mode == "11g ht") {
5103
					if(!isset($wireless_modes["11b"]))
5104
						$wireless_modes["11b"] = array();
5105
					if(!isset($wireless_modes["11g"]))
5106
						$wireless_modes["11g"] = array();
5107
					$wireless_mode = "11ng";
5108
				} else if($wireless_mode == "11a ht") {
5109
					if(!isset($wireless_modes["11a"]))
5110
						$wireless_modes["11a"] = array();
5111
					$wireless_mode = "11na";
5112
				}
5113
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5114
			}
5115
			$c++;
5116
		}
5117
	}
5118
	return($wireless_modes);
5119
}
5120

    
5121
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5122
function get_wireless_channel_info($interface) {
5123
	$wireless_channels = array();
5124

    
5125
	$cloned_interface = get_real_interface($interface);
5126

    
5127
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5128
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5129
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5130
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5131

    
5132
		$interface_channels = "";
5133
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5134

    
5135
		foreach ($interface_channels as $channel_line) {
5136
			$channel_line = explode(",", $channel_line);
5137
			if(!isset($wireless_channels[$channel_line[0]]))
5138
				$wireless_channels[$channel_line[0]] = $channel_line;
5139
		}
5140
	}
5141
	return($wireless_channels);
5142
}
5143

    
5144
/****f* interfaces/get_interface_mtu
5145
 * NAME
5146
 *   get_interface_mtu - Return the mtu of an interface
5147
 * RESULT
5148
 *   $tmp       - Returns the mtu of an interface
5149
 ******/
5150
function get_interface_mtu($interface) {
5151
	$mtu = pfSense_interface_getmtu($interface);
5152
	return $mtu['mtu'];
5153
}
5154

    
5155
function get_interface_mac($interface) {
5156

    
5157
	$macinfo = pfSense_get_interface_addresses($interface);
5158
	return $macinfo["macaddr"];
5159
}
5160

    
5161
/****f* pfsense-utils/generate_random_mac_address
5162
 * NAME
5163
 *   generate_random_mac - generates a random mac address
5164
 * INPUTS
5165
 *   none
5166
 * RESULT
5167
 *   $mac - a random mac address
5168
 ******/
5169
function generate_random_mac_address() {
5170
	$mac = "02";
5171
	for($x=0; $x<5; $x++)
5172
		$mac .= ":" . dechex(rand(16, 255));
5173
	return $mac;
5174
}
5175

    
5176
/****f* interfaces/is_jumbo_capable
5177
 * NAME
5178
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5179
 * INPUTS
5180
 *   $int             - string containing interface name
5181
 * RESULT
5182
 *   boolean          - true or false
5183
 ******/
5184
function is_jumbo_capable($iface) {
5185
	$iface = trim($iface);
5186
	$capable = pfSense_get_interface_addresses($iface);
5187

    
5188
	if (isset($capable['caps']['vlanmtu']))
5189
		return true;
5190

    
5191
	return false;
5192
}
5193

    
5194
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5195
	global $g;
5196

    
5197
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5198

    
5199
	if(!empty($iface) && !empty($pppif)){
5200
		$cron_cmd = <<<EOD
5201
#!/bin/sh
5202
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5203
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5204

    
5205
EOD;
5206

    
5207
		@file_put_contents($cron_file, $cron_cmd);
5208
		chmod($cron_file, 0755);
5209
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5210
	} else
5211
		unlink_if_exists($cron_file);
5212
}
5213

    
5214
function get_interface_default_mtu($type = "ethernet") {
5215
	switch ($type) {
5216
	case "gre":
5217
		return 1476;
5218
		break;
5219
	case "gif":
5220
		return 1280;
5221
		break;
5222
	case "tun":
5223
	case "vlan":
5224
	case "tap":
5225
	case "ethernet":
5226
	default:
5227
		return 1500;
5228
		break;
5229
	}
5230

    
5231
	/* Never reached */
5232
	return 1500;
5233
}
5234

    
5235
function get_vip_descr($ipaddress) {
5236
	global $config;
5237

    
5238
	foreach ($config['virtualip']['vip'] as $vip) {
5239
		if ($vip['subnet'] == $ipaddress) {
5240
			return ($vip['descr']);
5241
		}
5242
	}
5243
	return "";
5244
}
5245

    
5246
function interfaces_staticarp_configure($if) {
5247
	global $config, $g;
5248
	if(isset($config['system']['developerspew'])) {
5249
		$mt = microtime();
5250
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5251
	}
5252

    
5253
	$ifcfg = $config['interfaces'][$if];
5254

    
5255
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5256
		return 0;
5257

    
5258
	/* Enable staticarp, if enabled */
5259
	if(isset($config['dhcpd'][$if]['staticarp'])) {
5260
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
5261
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5262
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5263

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

    
5267
			}
5268

    
5269
		}
5270
	} else {
5271
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
5272
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5273
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5274
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5275
				if (isset($arpent['arp_table_static_entry'])) {
5276
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5277
				}
5278
			}
5279
		}
5280
	}
5281

    
5282
	return 0;
5283
}
5284

    
5285
function get_failover_interface($interface, $family = "all") {
5286
	global $config;
5287

    
5288
	/* shortcut to get_real_interface if we find it in the config */
5289
	if (is_array($config['interfaces'][$interface])) {
5290
		return get_real_interface($interface, $family);
5291
	}
5292

    
5293
	/* compare against gateway groups */
5294
	$a_groups = return_gateway_groups_array();
5295
	if (is_array($a_groups[$interface])) {
5296
		/* we found a gateway group, fetch the interface or vip */
5297
		if ($a_groups[$interface][0]['vip'] <> "")
5298
			return $a_groups[$interface][0]['vip'];
5299
		else
5300
			return $a_groups[$interface][0]['int'];
5301
	}
5302
	/* fall through to get_real_interface */
5303
	/* XXX: Really needed? */
5304
	return get_real_interface($interface, $family);
5305
}
5306

    
5307
function remove_ifindex($ifname) {
5308
	return preg_replace("/[0-9]+$/", "", $ifname);
5309
}
5310

    
5311
?>
(26-26/68)