Project

General

Profile

Download (162 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	interfaces.inc
4
	Copyright (C) 2004-2008 Scott Ullrich
5
	Copyright (C) 2008-2009 Ermal Lu?i
6
	All rights reserved.
7

    
8
	function interfaces_wireless_configure is
9
	Copyright (C) 2005 Espen Johansen
10
	All rights reserved.
11

    
12
	originally part of m0n0wall (http://m0n0.ch/wall)
13
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
14
	All rights reserved.
15

    
16
	Redistribution and use in source and binary forms, with or without
17
	modification, are permitted provided that the following conditions are met:
18

    
19
	1. Redistributions of source code must retain the above copyright notices,
20
	   this list of conditions and the following disclaimer.
21

    
22
	2. Redistributions in binary form must reproduce the above copyright
23
	   notices, this list of conditions and the following disclaimer in the
24
	   documentation and/or other materials provided with the distribution.
25

    
26
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
27
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
28
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
	POSSIBILITY OF SUCH DAMAGE.
36

    
37
	pfSense_BUILDER_BINARIES:	/sbin/dhclient	/bin/sh	/usr/bin/grep	/usr/bin/xargs	/usr/bin/awk	/usr/local/sbin/choparp
38
	pfSense_BUILDER_BINARIES:	/sbin/ifconfig	/sbin/route	/usr/sbin/ngctl	/usr/sbin/arp	/bin/kill	/usr/local/sbin/mpd5
39
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/dhcp6c
40
	pfSense_MODULE:	interfaces
41

    
42
*/
43

    
44
/* include all configuration functions */
45
require_once("globals.inc");
46
require_once("util.inc");
47
require_once("gwlb.inc");
48

    
49
function interfaces_bring_up($interface) {
50
	if(!$interface) {
51
		log_error(gettext("interfaces_bring_up() was called but no variable defined."));
52
		log_error( "Backtrace: " . debug_backtrace() );
53
		return;
54
	}
55
	pfSense_interface_flags($interface, IFF_UP);
56
}
57

    
58
/*
59
 * Return the interface array
60
 */
61
function get_interface_arr($flush = false) {
62
	global $interface_arr_cache;
63

    
64
	/* If the cache doesn't exist, build it */
65
	if (!isset($interface_arr_cache) or $flush)
66
		$interface_arr_cache = pfSense_interface_listget();
67

    
68
	return $interface_arr_cache;
69
}
70

    
71
/*
72
 * does_interface_exist($interface): return true or false if a interface is
73
 * detected.
74
 */
75
function does_interface_exist($interface, $flush = true) {
76
	global $config;
77

    
78
	if(!$interface)
79
		return false;
80

    
81
	$ints = get_interface_arr($flush);
82
	if (in_array($interface, $ints))
83
		return true;
84
	else
85
		return false;
86
}
87

    
88
/*
89
 * does_vip_exist($vip): return true or false if a vip is
90
 * configured.
91
 */
92
function does_vip_exist($vip) {
93
	global $config;
94

    
95
	if(!$vip)
96
		return false;
97

    
98

    
99
	switch ($vip['mode']) {
100
	case "carp":
101
	case "ipalias":
102
		/* XXX: Make proper checks? */
103
		$realif = get_real_interface($vip['interface']);
104
		if (!does_interface_exist($realif)) {
105
			return false;
106
		}
107
		break;
108
	case "proxyarp":
109
		/* XXX: Implement this */
110
	default:
111
		return false;
112
	}
113

    
114
	$ifacedata = pfSense_getall_interface_addresses($realif);
115
	foreach ($ifacedata as $vipips) {
116
		if ($vipips == "{$vip['subnet']}/{$vip['subnet_bits']}")
117
			return true;
118
	}
119

    
120
	return false;
121
}
122

    
123
function interface_netgraph_needed($interface = "wan") {
124
	global $config;
125

    
126
	$found = false;
127
	if (!empty($config['pptpd']) &&
128
		$config['pptpd']['mode'] == "server")
129
		$found = true;
130
	if ($found == false && !empty($config['l2tp']) &&
131
		$config['l2tp']['mode'] == "server")
132
		$found = true;
133
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
134
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
135
			if ($pppoe['mode'] != "server")
136
				continue;
137
			if ($pppoe['interface'] == $interface)
138
				$found = true;
139
				break;
140
		}
141
	}
142
	if ($found == false) {
143
		if (!empty($config['interfaces'][$interface])) {
144
			switch ($config['interfaces'][$interface]['ipaddr']) {
145
			case "ppp":
146
			case "pppoe":
147
			case "l2tp":
148
			case "pptp":
149
				$found = true;
150
				break;
151
			default:
152
				$found = false;
153
				break;
154
			}
155
		}
156
	}
157
	if ($found == false) {
158
		$realif = get_real_interface($interface);
159
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
160
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
161

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

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

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

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

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

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

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

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

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

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

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

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

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

    
266
	interfaces_bring_up($vlanif);
267

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

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

    
274
	return $vlanif;
275
}
276

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

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

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

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

    
297
	$vlanif = interface_vlan_configure($vlan);
298

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

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

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

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

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

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

    
350
	return $vlanif;
351
}
352

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

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

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

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

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

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

    
393
	return $vlanif;
394
}
395

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

    
399
	if($g['booting'])
400
		echo gettext("Creating wireless clone interfaces...");
401

    
402
	$iflist = get_configured_interface_list();
403

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

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

    
423
}
424

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

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

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

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

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

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

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

    
476
	/* Calculate smaller mtu and enforce it */
477
	$smallermtu = 0;
478
	$commonrx = true;
479
	$commontx = true;
480
	$foundgif = false;
481
	foreach ($members as $member) {
482
		$realif = get_real_interface($member);
483
		$opts = pfSense_get_interface_addresses($realif);
484
		$mtu = $opts['mtu'];
485
		if (substr($realif, 0, 3) == "gif") {
486
			$foundgif = true;
487
			if ($checkmember == 1)
488
				return;
489
			if ($mtu <= 1500)
490
				continue;
491
		}
492
		if (!isset($opts['caps']['txcsum']))
493
			$commontx = false;
494
		if (!isset($opts['caps']['rxcsum']))
495
			$commonrx = false;
496
		if (!isset($opts['caps']['tso4']))
497
			$commontso4 = false;
498
		if (!isset($opts['caps']['tso6']))
499
			$commontso6 = false;
500
		if (!isset($opts['caps']['lro']))
501
			$commonlro = false;
502
		if ($smallermtu == 0 && !empty($mtu))
503
			$smallermtu = $mtu;
504
		else if (!empty($mtu) && $mtu < $smallermtu)
505
			$smallermtu = $mtu;
506
	}
507
	if ($foundgif == false && $checkmember == 2)
508
		return;
509

    
510
	/* Just in case anything is not working well */
511
	if ($smallermtu == 0)
512
		$smallermtu = 1500;
513

    
514
	$flags_on = 0;
515
	$flags_off = 0;
516
	if (isset($config['system']['disablechecksumoffloading']) || ($commonrx === false))
517
		$flags_off |= IFCAP_RXCSUM;
518
	else
519
		$flags_on |= IFCAP_RXCSUM;
520
	if (isset($config['system']['disablechecksumoffloading']) || ($commontx === false))
521
		$flags_off |= IFCAP_TXCSUM;
522
	else
523
		$flags_on |= IFCAP_TXCSUM;
524
	if (isset($config['system']['disablesegmentationoffloading']) || ($commontso4 === false))
525
		$flags_off |= IFCAP_TSO4;
526
	else
527
		$flags_on |= IFCAP_TSO4;
528
	if (isset($config['system']['disablesegmentationoffloading']) || ($commontso6 === false))
529
		$flags_off |= IFCAP_TSO6;
530
	else
531
		$flags_on |= IFCAP_TSO6;
532
	if (isset($config['system']['disablelargereceiveoffloading']) || ($commonlro === false))
533
		$flags_off |= IFCAP_LRO;
534
	else
535
		$flags_on |= IFCAP_LRO;
536

    
537
	if ($g['booting'] || !empty($bridge['bridgeif'])) {
538
		pfSense_interface_destroy($bridge['bridgeif']);
539
		pfSense_interface_create($bridge['bridgeif']);
540
		$bridgeif = escapeshellarg($bridge['bridgeif']);
541
	} else {
542
		$bridgeif = pfSense_interface_create("bridge");
543
		$bridge['bridgeif'] = $bridgeif;
544
	}
545

    
546
	$checklist = get_configured_interface_list();
547

    
548
	/* Add interfaces to bridge */
549
	foreach ($members as $member) {
550
		if (empty($checklist[$member]))
551
			continue;
552
		$realif = get_real_interface($member);
553
		if (!$realif) {
554
			log_error(gettext("realif not defined in interfaces bridge - up"));
555
			continue;
556
		}
557
		/* make sure the parent interface is up */
558
		pfSense_interface_mtu($realif, $smallermtu);
559
		pfSense_interface_capabilities($realif, -$flags_off);
560
		pfSense_interface_capabilities($realif, $flags_on);
561
		interfaces_bring_up($realif);
562
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
563
	}
564

    
565
	if (isset($bridge['enablestp'])) {
566
		/* Choose spanning tree proto */
567
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
568

    
569
		if (!empty($bridge['stp'])) {
570
			$stpifs = explode(',', $bridge['stp']);
571
			foreach ($stpifs as $stpif) {
572
				$realif = get_real_interface($stpif);
573
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
574
			}
575
		}
576
		if (!empty($bridge['maxage']))
577
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
578
		if (!empty($bridge['fwdelay']))
579
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
580
		if (!empty($bridge['hellotime']))
581
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
582
		if (!empty($bridge['priority']))
583
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
584
		if (!empty($bridge['holdcnt']))
585
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
586
		if (!empty($bridge['ifpriority'])) {
587
			$pconfig = explode(",", $bridge['ifpriority']);
588
			$ifpriority = array();
589
			foreach ($pconfig as $cfg) {
590
				$embcfg = explode_assoc(":", $cfg);
591
				foreach ($embcfg as $key => $value)
592
					$ifpriority[$key] = $value;
593
			}
594
			foreach ($ifpriority as $key => $value) {
595
				$realif = get_real_interface($key);
596
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
597
			}
598
		}
599
		if (!empty($bridge['ifpathcost'])) {
600
			$pconfig = explode(",", $bridge['ifpathcost']);
601
			$ifpathcost = array();
602
			foreach ($pconfig as $cfg) {
603
				$embcfg = explode_assoc(":", $cfg);
604
				foreach ($embcfg as $key => $value)
605
					$ifpathcost[$key] = $value;
606
			}
607
			foreach ($ifpathcost as $key => $value) {
608
				$realif = get_real_interface($key);
609
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
610
			}
611
		}
612
	}
613

    
614
	if ($bridge['maxaddr'] <> "")
615
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
616
	if ($bridge['timeout'] <> "")
617
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
618
	if ($bridge['span'] <> "") {
619
		$realif = get_real_interface($bridge['span']);
620
		mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
621
	}
622
	if (!empty($bridge['edge'])) {
623
		$edgeifs = explode(',', $bridge['edge']);
624
		foreach ($edgeifs as $edgeif) {
625
			$realif = get_real_interface($edgeif);
626
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
627
		}
628
	}
629
	if (!empty($bridge['autoedge'])) {
630
		$edgeifs = explode(',', $bridge['autoedge']);
631
		foreach ($edgeifs as $edgeif) {
632
			$realif = get_real_interface($edgeif);
633
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
634
		}
635
	}
636
	if (!empty($bridge['ptp'])) {
637
		$ptpifs = explode(',', $bridge['ptp']);
638
		foreach ($ptpifs as $ptpif) {
639
			$realif = get_real_interface($ptpif);
640
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
641
		}
642
	}
643
	if (!empty($bridge['autoptp'])) {
644
		$ptpifs = explode(',', $bridge['autoptp']);
645
		foreach ($ptpifs as $ptpif) {
646
			$realif = get_real_interface($ptpif);
647
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
648
		}
649
	}
650
	if (!empty($bridge['static'])) {
651
		$stickyifs = explode(',', $bridge['static']);
652
		foreach ($stickyifs as $stickyif) {
653
			$realif = get_real_interface($stickyif);
654
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
655
		}
656
	}
657
	if (!empty($bridge['private'])) {
658
		$privateifs = explode(',', $bridge['private']);
659
		foreach ($privateifs as $privateif) {
660
			$realif = get_real_interface($privateif);
661
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
662
		}
663
	}
664

    
665
	if ($bridge['bridgeif'])
666
		interfaces_bring_up($bridge['bridgeif']);
667
	else
668
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
669
}
670

    
671
function interface_bridge_add_member($bridgeif, $interface) {
672

    
673
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface))
674
		return;
675

    
676
	$mtu = get_interface_mtu($bridgeif);
677
	$mtum = get_interface_mtu($interface);
678

    
679
	if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500))
680
		pfSense_interface_mtu($interface, $mtu);
681

    
682
	$options = pfSense_get_interface_addresses($bridgeif);
683
	$flags_on = 0;
684
	$flags_off = 0;
685
	if (isset($options['encaps']['txcsum']))
686
		$flags_on |= IFCAP_TXCSUM;
687
	else
688
		$flags_off |= IFCAP_TXCSUM;
689
	if (isset($options['encaps']['rxcsum']))
690
		$flags_on |= IFCAP_RXCSUM;
691
	else
692
		$flags_off |= IFCAP_RXCSUM;
693
	if (isset($options['encaps']['tso4']))
694
		$flags_on |= IFCAP_TSO4;
695
	else
696
		$flags_off |= IFCAP_TSO4;
697
	if (isset($options['encaps']['tso6']))
698
		$flags_on |= IFCAP_TSO6;
699
	else
700
		$flags_off |= IFCAP_TSO6;
701
	if (isset($options['encaps']['lro']))
702
		$flags_on |= IFCAP_LRO;
703
	else
704
		$flags_off |= IFCAP_LRO;
705

    
706
	pfSense_interface_capabilities($interface, -$flags_off);
707
	pfSense_interface_capabilities($interface, $flags_on);
708

    
709
	interfaces_bring_up($interface);
710
	pfSense_bridge_add_member($bridgeif, $interface);
711
}
712

    
713
function interfaces_lagg_configure($realif = "") {
714
	global $config, $g;
715
	if($g['booting'])
716
		echo gettext("Configuring LAGG interfaces...");
717
	$i = 0;
718
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
719
		foreach ($config['laggs']['lagg'] as $lagg) {
720
			if(empty($lagg['laggif']))
721
				$lagg['laggif'] = "lagg{$i}";
722
			if (!empty($realif) && $realif != $lagg['laggif'])
723
				continue;
724
			/* XXX: Maybe we should report any errors?! */
725
			interface_lagg_configure($lagg);
726
			$i++;
727
		}
728
	}
729
	if($g['booting'])
730
		echo gettext("done.") . "\n";
731
}
732

    
733
function interface_lagg_configure($lagg) {
734
	global $config, $g;
735

    
736
	if (!is_array($lagg))
737
		return -1;
738

    
739
	$members = explode(',', $lagg['members']);
740
	if (!count($members))
741
		return -1;
742

    
743
	if ($g['booting'] || !(empty($lagg['laggif']))) {
744
		pfSense_interface_destroy($lagg['laggif']);
745
		pfSense_interface_create($lagg['laggif']);
746
		$laggif = $lagg['laggif'];
747
	} else
748
		$laggif = pfSense_interface_create("lagg");
749

    
750
	/* Check if MTU was defined for this lagg interface */
751
	$lagg_mtu = 0;
752
	if (is_array($config['interfaces'])) {
753
		foreach ($config['interfaces'] as $ifname => $ifdata) {
754
			if ($ifdata['if'] != $laggif)
755
				continue;
756

    
757
			if (isset($ifdata['mtu']) && !empty($ifdata['mtu'])) {
758
				$lagg_mtu = $ifdata['mtu'];
759
				break;
760
			}
761
		}
762
	}
763

    
764
	if ($lagg_mtu == 0) {
765
		/* Calculate smaller mtu and enforce it */
766
		$smallermtu = 0;
767
		foreach ($members as $member) {
768
			$opts = pfSense_get_interface_addresses($member);
769
			$mtu = $opts['mtu'];
770
			if (!isset($opts['caps']['txcsum']))
771
				$commontx = false;
772
			if (!isset($opts['caps']['rxcsum']))
773
				$commonrx = false;
774
			if (!isset($opts['caps']['tso4']))
775
				$commontso4 = false;
776
			if (!isset($opts['caps']['tso6']))
777
				$commontso6 = false;
778
			if (!isset($opts['caps']['lro']))
779
				$commonlro = false;
780
			if ($smallermtu == 0 && !empty($mtu))
781
				$smallermtu = $mtu;
782
			else if (!empty($mtu) && $mtu < $smallermtu)
783
				$smallermtu = $mtu;
784
		}
785
		$lagg_mtu = $smallermtu;
786
	}
787

    
788
	/* Just in case anything is not working well */
789
	if ($lagg_mtu == 0)
790
		$lagg_mtu = 1500;
791

    
792
	$flags_on = 0;
793
	$flags_off = 0;
794
	if (isset($config['system']['disablechecksumoffloading']) || ($commonrx === false))
795
		$flags_off |= IFCAP_RXCSUM;
796
	else
797
		$flags_on |= IFCAP_RXCSUM;
798
	if (isset($config['system']['disablechecksumoffloading']) || ($commontx === false))
799
		$flags_off |= IFCAP_TXCSUM;
800
	else
801
		$flags_on |= IFCAP_TXCSUM;
802
	if (isset($config['system']['disablesegmentationoffloading']) || ($commontso4 === false))
803
		$flags_off |= IFCAP_TSO4;
804
	else
805
		$flags_on |= IFCAP_TSO4;
806
	if (isset($config['system']['disablesegmentationoffloading']) || ($commontso6 === false))
807
		$flags_off |= IFCAP_TSO6;
808
	else
809
		$flags_on |= IFCAP_TSO6;
810
	if (isset($config['system']['disablelargereceiveoffloading']) || ($commonlro === false))
811
		$flags_off |= IFCAP_LRO;
812
	else
813
		$flags_on |= IFCAP_LRO;
814

    
815
	$checklist = get_interface_list();
816

    
817
	foreach ($members as $member) {
818
		if (!array_key_exists($member, $checklist))
819
			continue;
820
		/* make sure the parent interface is up */
821
		pfSense_interface_mtu($member, $lagg_mtu);
822
		pfSense_interface_capabilities($member, -$flags_off);
823
		pfSense_interface_capabilities($member, $flags_on);
824
		interfaces_bring_up($member);
825
		mwexec("/sbin/ifconfig {$laggif} laggport {$member}");
826
	}
827

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

    
830
	interfaces_bring_up($laggif);
831

    
832
	return $laggif;
833
}
834

    
835
function interfaces_gre_configure($checkparent = 0, $realif = "") {
836
	global $config;
837

    
838
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
839
		foreach ($config['gres']['gre'] as $i => $gre) {
840
			if (empty($gre['greif']))
841
				$gre['greif'] = "gre{$i}";
842
			if (!empty($realif) && $realif != $gre['greif'])
843
				continue;
844

    
845
			if ($checkparent == 1) {
846
				if (strstr($gre['if'], "_vip"))
847
					continue;
848
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6")
849
					continue;
850
			}
851
			else if ($checkparent == 2) {
852
				if (strstr($gre['if'], "_vip"))
853
					continue;
854
				if (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")
855
					continue;
856
			}
857
			/* XXX: Maybe we should report any errors?! */
858
			interface_gre_configure($gre);
859
		}
860
	}
861
}
862

    
863
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
864
function interface_gre_configure(&$gre, $grekey = "") {
865
	global $config, $g;
866

    
867
	if (!is_array($gre))
868
		return -1;
869

    
870
	$realif = get_real_interface($gre['if']);
871
	$realifip = get_interface_ip($gre['if']);
872

    
873
	/* make sure the parent interface is up */
874
	interfaces_bring_up($realif);
875

    
876
	if ($g['booting'] || !(empty($gre['greif']))) {
877
		pfSense_interface_destroy($gre['greif']);
878
		pfSense_interface_create($gre['greif']);
879
		$greif = $gre['greif'];
880
	} else
881
		$greif = pfSense_interface_create("gre");
882

    
883
	/* Do not change the order here for more see gre(4) NOTES section. */
884
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
885
	if((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
886
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
887
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
888
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
889
	} else {
890
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
891
	}
892
	if (isset($gre['link0']))
893
		pfSense_interface_flags($greif, IFF_LINK0);
894
	if (isset($gre['link1']))
895
		pfSense_interface_flags($greif, IFF_LINK1);
896
	if (isset($gre['link2']))
897
		pfSense_interface_flags($greif, IFF_LINK2);
898

    
899
	if($greif)
900
		interfaces_bring_up($greif);
901
	else
902
		log_error(gettext("Could not bring greif up -- variable not defined."));
903

    
904
	if (isset($gre['link1']) && $gre['link1'])
905
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
906
	if(is_ipaddrv4($gre['tunnel-remote-addr']))
907
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
908
	if(is_ipaddrv6($gre['tunnel-remote-addr']))
909
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
910

    
911
	interfaces_bring_up($greif);
912

    
913
	return $greif;
914
}
915

    
916
function interfaces_gif_configure($checkparent = 0, $realif = "") {
917
	global $config;
918

    
919
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
920
		foreach ($config['gifs']['gif'] as $i => $gif) {
921
			if (empty($gif['gifif']))
922
				$gre['gifif'] = "gif{$i}";
923
			if (!empty($realif) && $realif != $gif['gifif'])
924
				continue;
925

    
926
			if ($checkparent == 1) {
927
				if (strstr($gif['if'], "_vip"))
928
					continue;
929
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6")
930
					continue;
931
			}
932
			else if ($checkparent == 2) {
933
				if (strstr($gif['if'], "_vip"))
934
					continue;
935
				if (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")
936
					continue;
937
			}
938
			/* XXX: Maybe we should report any errors?! */
939
			interface_gif_configure($gif);
940
		}
941
	}
942
}
943

    
944
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
945
function interface_gif_configure(&$gif, $gifkey = "") {
946
	global $config, $g;
947

    
948
	if (!is_array($gif))
949
		return -1;
950

    
951
	$realif = get_real_interface($gif['if']);
952
	$ipaddr = $gif['ipaddr'];
953

    
954
	if (is_ipaddrv4($gif['remote-addr'])) {
955
		if (is_ipaddrv4($ipaddr))
956
			$realifip = $ipaddr;
957
		else
958
			$realifip = get_interface_ip($gif['if']);
959
		$realifgw = get_interface_gateway($gif['if']);
960
	} else if (is_ipaddrv6($gif['remote-addr'])) {
961
		if (is_ipaddrv6($ipaddr))
962
			$realifip = $ipaddr;
963
		else
964
			$realifip = get_interface_ipv6($gif['if']);
965
		$realifgw = get_interface_gateway_v6($gif['if']);
966
	}
967
	/* make sure the parent interface is up */
968
	if($realif)
969
		interfaces_bring_up($realif);
970
	else
971
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
972

    
973
	if ($g['booting'] || !(empty($gif['gifif']))) {
974
		pfSense_interface_destroy($gif['gifif']);
975
		pfSense_interface_create($gif['gifif']);
976
		$gifif = $gif['gifif'];
977
	} else
978
		$gifif = pfSense_interface_create("gif");
979

    
980
	/* Do not change the order here for more see gif(4) NOTES section. */
981
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
982
	if((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
983
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
984
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
985
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
986
	} else {
987
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
988
	}
989
	if (isset($gif['link0']))
990
		pfSense_interface_flags($gifif, IFF_LINK0);
991
	if (isset($gif['link1']))
992
		pfSense_interface_flags($gifif, IFF_LINK1);
993
	if($gifif)
994
		interfaces_bring_up($gifif);
995
	else
996
		log_error(gettext("could not bring gifif up -- variable not defined"));
997

    
998
	$iflist = get_configured_interface_list();
999
	foreach($iflist as $ifname) {
1000
		if($config['interfaces'][$ifname]['if'] == $gifif) {
1001
			if(get_interface_gateway($ifname)) {
1002
				system_routing_configure($ifname);
1003
				break;
1004
			}
1005
			if(get_interface_gateway_v6($ifname)) {
1006
				system_routing_configure($ifname);
1007
				break;
1008
			}
1009
		}
1010
	}
1011

    
1012

    
1013
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
1014
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1015
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
1016
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1017

    
1018
	if (is_ipaddrv4($realifgw)) {
1019
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1020
	}
1021
	if (is_ipaddrv6($realifgw)) {
1022
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1023
	}
1024

    
1025
	interfaces_bring_up($gifif);
1026

    
1027
	return $gifif;
1028
}
1029

    
1030
function interfaces_configure() {
1031
	global $config, $g;
1032

    
1033
	if ($g['platform'] == 'jail')
1034
		return;
1035

    
1036
	/* Set up our loopback interface */
1037
	interfaces_loopback_configure();
1038

    
1039
	/* create the unconfigured wireless clones */
1040
	interfaces_create_wireless_clones();
1041

    
1042
	/* set up LAGG virtual interfaces */
1043
	interfaces_lagg_configure();
1044

    
1045
	/* set up VLAN virtual interfaces */
1046
	interfaces_vlan_configure();
1047

    
1048
	interfaces_qinq_configure();
1049

    
1050
	$iflist = get_configured_interface_with_descr();
1051
	$delayed_list = array();
1052
	$bridge_list = array();
1053
	$track6_list = array();
1054

    
1055
	/* This is needed to speedup interfaces on bootup. */
1056
	$reload = false;
1057
	if (!$g['booting'])
1058
		$reload = true;
1059

    
1060
	foreach($iflist as $if => $ifname) {
1061
		$realif = $config['interfaces'][$if]['if'];
1062
		if (strstr($realif, "bridge"))
1063
			$bridge_list[$if] = $ifname;
1064
		else if (strstr($realif, "gre"))
1065
			$delayed_list[$if] = $ifname;
1066
		else if (strstr($realif, "gif"))
1067
			$delayed_list[$if] = $ifname;
1068
		else if (strstr($realif, "ovpn")) {
1069
			//echo "Delaying OpenVPN interface configuration...done.\n";
1070
			continue;
1071
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1072
			$track6_list[$if] = $ifname;
1073
		} else {
1074
			if ($g['booting'])
1075
				printf(gettext("Configuring %s interface..."), $ifname);
1076

    
1077
			if($g['debug'])
1078
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1079
			interface_configure($if, $reload);
1080
			if ($g['booting'])
1081
				echo gettext( "done.") . "\n";
1082
		}
1083
	}
1084

    
1085
	/*
1086
	 * NOTE: The following function parameter consists of
1087
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1088
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1089
	 */
1090

    
1091
	/* set up GRE virtual interfaces */
1092
	interfaces_gre_configure(1);
1093

    
1094
	/* set up GIF virtual interfaces */
1095
	interfaces_gif_configure(1);
1096

    
1097
	/* set up BRIDGe virtual interfaces */
1098
	interfaces_bridge_configure(1);
1099

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

    
1106
		interface_configure($if, $reload);
1107

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

    
1112
	/* bring up vip interfaces */
1113
	interfaces_vips_configure();
1114

    
1115
	/* set up GRE virtual interfaces */
1116
	interfaces_gre_configure(2);
1117

    
1118
	/* set up GIF virtual interfaces */
1119
	interfaces_gif_configure(2);
1120

    
1121
	foreach ($delayed_list as $if => $ifname) {
1122
		if ($g['booting'])
1123
			printf(gettext("Configuring %s interface..."), $ifname);
1124
		if ($g['debug'])
1125
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1126

    
1127
		interface_configure($if, $reload);
1128

    
1129
		if ($g['booting'])
1130
			echo gettext("done.") . "\n";
1131
	}
1132

    
1133
	/* set up BRIDGe virtual interfaces */
1134
	interfaces_bridge_configure(2);
1135

    
1136
	foreach ($bridge_list as $if => $ifname) {
1137
		if ($g['booting'])
1138
			printf(gettext("Configuring %s interface..."), $ifname);
1139
		if($g['debug'])
1140
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1141

    
1142
		interface_configure($if, $reload);
1143

    
1144
		if ($g['booting'])
1145
			echo gettext("done.") . "\n";
1146
	}
1147

    
1148
	/* configure interface groups */
1149
	interfaces_group_setup();
1150

    
1151
	if (!$g['booting']) {
1152
		/* reconfigure static routes (kernel may have deleted them) */
1153
		system_routing_configure();
1154

    
1155
		/* reload IPsec tunnels */
1156
		vpn_ipsec_configure();
1157

    
1158
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1159
		services_dhcpd_configure();
1160

    
1161
		/* restart dnsmasq or unbound */
1162
		if (isset($config['dnsmasq']['enable']))
1163
			services_dnsmasq_configure();
1164
		elseif (isset($config['unbound']['enable']))
1165
			services_unbound_configure();
1166
	}
1167

    
1168
	return 0;
1169
}
1170

    
1171
function interface_reconfigure($interface = "wan", $reloadall = false) {
1172
	interface_bring_down($interface);
1173
	interface_configure($interface, $reloadall);
1174
}
1175

    
1176
function interface_vip_bring_down($vip) {
1177
	global $g;
1178

    
1179
	$vipif = get_real_interface($vip['interface']);
1180
	switch ($vip['mode']) {
1181
	case "proxyarp":
1182
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1183
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1184
		break;
1185
	case "ipalias":
1186
		if (does_interface_exist($vipif)) {
1187
			if (is_ipaddrv6($vip['subnet']))
1188
				mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1189
			else
1190
				pfSense_interface_deladdress($vipif, $vip['subnet']);
1191
		}
1192
		break;
1193
	case "carp":
1194
		/* XXX: Is enough to delete ip address? */
1195
		if (does_interface_exist($vipif))
1196
			pfSense_interface_deladdress($vipif, $vip['subnet']);
1197
		break;
1198
	}
1199
}
1200

    
1201
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1202
	global $config, $g;
1203

    
1204
	if (!isset($config['interfaces'][$interface]))
1205
		return;
1206

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

    
1210
	/*
1211
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1212
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1213
	 * Keep this in mind while doing changes here!
1214
	 */
1215
	if ($ifacecfg === false) {
1216
		$ifcfg = $config['interfaces'][$interface];
1217
		$ppps = $config['ppps']['ppp'];
1218
		$realif = get_real_interface($interface);
1219
		$realifv6 = get_real_interface($interface, "inet6", true);
1220
	} elseif (!is_array($ifacecfg)) {
1221
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1222
		$ifcfg = $config['interfaces'][$interface];
1223
		$ppps = $config['ppps']['ppp'];
1224
		$realif = get_real_interface($interface);
1225
		$realifv6 = get_real_interface($interface, "inet6", true);
1226
	} else {
1227
		$ifcfg = $ifacecfg['ifcfg'];
1228
		$ppps = $ifacecfg['ppps'];
1229
		if (isset($ifacecfg['ifcfg']['realif'])) {
1230
			$realif = $ifacecfg['ifcfg']['realif'];
1231
			/* XXX: Any better way? */
1232
			$realifv6 = $realif;
1233
		} else {
1234
			$realif = get_real_interface($interface);
1235
			$realifv6 = get_real_interface($interface, "inet6", true);
1236
		}
1237
	}
1238

    
1239
	switch ($ifcfg['ipaddr']) {
1240
	case "ppp":
1241
	case "pppoe":
1242
	case "pptp":
1243
	case "l2tp":
1244
		if (is_array($ppps) && count($ppps)) {
1245
			foreach ($ppps as $pppid => $ppp) {
1246
				if ($realif == $ppp['if']) {
1247
					if (isset($ppp['ondemand']) && !$destroy){
1248
						send_event("interface reconfigure {$interface}");
1249
						break;
1250
					}
1251
					if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1252
						killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1253
						sleep(2);
1254
					}
1255
					unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1256
					break;
1257
				}
1258
			}
1259
		}
1260
		break;
1261
	case "dhcp":
1262
		kill_dhclient_process($realif);
1263
		unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1264
		if(does_interface_exist("$realif")) {
1265
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1266
			interface_ipalias_cleanup($interface);
1267
			if ($destroy == true)
1268
				pfSense_interface_flags($realif, -IFF_UP);
1269
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1270
		}
1271
		break;
1272
	default:
1273
		if(does_interface_exist("$realif")) {
1274
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1275
			interface_ipalias_cleanup($interface);
1276
			if ($destroy == true)
1277
				pfSense_interface_flags($realif, -IFF_UP);
1278
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1279
		}
1280
		break;
1281
	}
1282

    
1283
	$track6 = array();
1284
	switch ($ifcfg['ipaddrv6']) {
1285
	case "slaac":
1286
	case "dhcp6":
1287
		$pidv6 = find_dhcp6c_process($realif);
1288
		if($pidv6)
1289
			posix_kill($pidv6, SIGTERM);
1290
		sleep(3);
1291
		unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1292
		if (does_interface_exist($realifv6)) {
1293
			$ip6 = find_interface_ipv6($realifv6);
1294
			if (is_ipaddrv6($ip6) && $ip6 != "::")
1295
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1296
			interface_ipalias_cleanup($interface, "inet6");
1297
			if ($destroy == true)
1298
				pfSense_interface_flags($realif, -IFF_UP);
1299
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1300
		}
1301
		$track6 = link_interface_to_track6($interface);
1302
		break;
1303
	case "6rd":
1304
	case "6to4":
1305
		$realif = "{$interface}_stf";
1306
		if(does_interface_exist("$realif")) {
1307
			$ip6 = get_interface_ipv6($interface);
1308
			if (is_ipaddrv6($ip6))
1309
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1310
			interface_ipalias_cleanup($interface, "inet6");
1311
			if ($destroy == true)
1312
				pfSense_interface_flags($realif, -IFF_UP);
1313
		}
1314
		$track6 = link_interface_to_track6($interface);
1315
		break;
1316
	default:
1317
		if(does_interface_exist("$realif")) {
1318
			$ip6 = get_interface_ipv6($interface);
1319
			if (is_ipaddrv6($ip6))
1320
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1321
			if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
1322
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1323
			interface_ipalias_cleanup($interface, "inet6");
1324
			if ($destroy == true)
1325
				pfSense_interface_flags($realif, -IFF_UP);
1326
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1327
		}
1328
		$track6 = link_interface_to_track6($interface);
1329
		break;
1330
	}
1331

    
1332
	if (!empty($track6) && is_array($track6)) {
1333
		if (!function_exists('services_dhcp_configure'))
1334
			require_once('services.inc');
1335
		/* Bring down radvd and dhcp6 on these interfaces */
1336
		services_dhcpd_configure('inet6', $track6);
1337
	}
1338

    
1339
	$old_router = '';
1340
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1341
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1342
//	log_error("Checking for old router states: {$g['tmp_path']}/{$realif}_router = {$old_router}");
1343
	if (!empty($old_router)) {
1344
		log_error("Clearing states to old gateway {$old_router}.");
1345
		mwexec("/sbin/pfctl -i " . escapeshellarg($realif) . " -Fs");
1346
	}
1347

    
1348
	/* remove interface up file if it exists */
1349
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1350
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1351
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1352
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1353
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1354
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1355
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1356

    
1357
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1358
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1359
	if (is_array($ifcfg['wireless'])) {
1360
		kill_hostapd($realif);
1361
		mwexec(kill_wpasupplicant($realif));
1362
	}
1363

    
1364
	if ($destroy == true) {
1365
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif))
1366
			pfSense_interface_destroy($realif);
1367
	}
1368

    
1369
	return;
1370
}
1371

    
1372
function interfaces_carp_set_maintenancemode($carp_maintenancemode){
1373
	global $config;
1374
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1375
		unset($config["virtualip_carp_maintenancemode"]);
1376
		write_config("Leave CARP maintenance mode");
1377
		if(is_array($config['virtualip']['vip'])) {
1378
			$viparr = &$config['virtualip']['vip'];
1379
			foreach ($viparr as $vip) {
1380
				switch ($vip['mode']) {
1381
				case "carp":
1382
					interface_vip_bring_down($vip);
1383
					//sleep(1);
1384
					break;
1385
				}
1386
			}
1387
		}
1388
	} else {
1389
		if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1390
			$config["virtualip_carp_maintenancemode"] = true;
1391
			write_config("Enter CARP maintenance mode");
1392
		}
1393
	}
1394

    
1395
	$viparr = &$config['virtualip']['vip'];
1396
	foreach ($viparr as $vip) {
1397
		if ($vip['mode'] == "carp") {
1398
			interface_carp_configure($vip);
1399
		}
1400
	}
1401
}
1402

    
1403
function interfaces_ptpid_used($ptpid) {
1404
	global $config;
1405

    
1406
	if (is_array($config['ppps']['ppp']))
1407
		foreach ($config['ppps']['ppp'] as & $settings)
1408
			if ($ptpid == $settings['ptpid'])
1409
				return true;
1410

    
1411
	return false;
1412
}
1413

    
1414
function interfaces_ptpid_next() {
1415

    
1416
	$ptpid = 0;
1417
	while(interfaces_ptpid_used($ptpid))
1418
		$ptpid++;
1419

    
1420
	return $ptpid;
1421
}
1422

    
1423
function getMPDCRONSettings($pppif) {
1424
	global $config;
1425

    
1426
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1427
	if (is_array($config['cron']['item'])) {
1428
		foreach ($config['cron']['item'] as $i => $item) {
1429
			if (stripos($item['command'], $cron_cmd_file) !== false)
1430
				return array("ID" => $i, "ITEM" => $item);
1431
		}
1432
	}
1433

    
1434
	return NULL;
1435
}
1436

    
1437
function handle_pppoe_reset($post_array) {
1438
	global $config, $g;
1439

    
1440
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1441
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1442

    
1443
	if (!is_array($config['cron']['item']))
1444
		$config['cron']['item'] = array();
1445

    
1446
	$itemhash = getMPDCRONSettings($pppif);
1447

    
1448
	// reset cron items if necessary and return
1449
	if (empty($post_array['pppoe-reset-type'])) {
1450
		if (isset($itemhash))
1451
			unset($config['cron']['item'][$itemhash['ID']]);
1452
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1453
		return;
1454
	}
1455

    
1456
	if (empty($itemhash))
1457
		$itemhash = array();
1458
	$item = array();
1459
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1460
		$item['minute'] = $post_array['pppoe_resetminute'];
1461
		$item['hour'] = $post_array['pppoe_resethour'];
1462
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1463
			$date = explode("/", $post_array['pppoe_resetdate']);
1464
			$item['mday'] = $date[1];
1465
			$item['month'] = $date[0];
1466
		} else {
1467
			$item['mday'] = "*";
1468
			$item['month'] = "*";
1469
		}
1470
		$item['wday'] = "*";
1471
		$item['who'] = "root";
1472
		$item['command'] = $cron_cmd_file;
1473
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1474
		switch ($post_array['pppoe_pr_preset_val']) {
1475
		case "monthly":
1476
			$item['minute'] = "0";
1477
			$item['hour'] = "0";
1478
			$item['mday'] = "1";
1479
			$item['month'] = "*";
1480
			$item['wday'] = "*";
1481
			break;
1482
		case "weekly":
1483
			$item['minute'] = "0";
1484
			$item['hour'] = "0";
1485
			$item['mday'] = "*";
1486
			$item['month'] = "*";
1487
			$item['wday'] = "0";
1488
			break;
1489
		case "daily":
1490
			$item['minute'] = "0";
1491
			$item['hour'] = "0";
1492
			$item['mday'] = "*";
1493
			$item['month'] = "*";
1494
			$item['wday'] = "*";
1495
			break;
1496
		case "hourly":
1497
			$item['minute'] = "0";
1498
			$item['hour'] = "*";
1499
			$item['mday'] = "*";
1500
			$item['month'] = "*";
1501
			$item['wday'] = "*";
1502
			break;
1503
		} // end switch
1504
		$item['who'] = "root";
1505
		$item['command'] = $cron_cmd_file;
1506
	}
1507
	if (empty($item))
1508
		return;
1509
	if (isset($itemhash['ID']))
1510
		$config['cron']['item'][$itemhash['ID']] = $item;
1511
	else
1512
		$config['cron']['item'][] = $item;
1513
}
1514

    
1515
/*
1516
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1517
 * It writes the mpd config file to /var/etc every time the link is opened.
1518
 */
1519
function interface_ppps_configure($interface) {
1520
	global $config, $g;
1521

    
1522
	/* Return for unassigned interfaces. This is a minimum requirement. */
1523
	if (empty($config['interfaces'][$interface]))
1524
		return 0;
1525
	$ifcfg = $config['interfaces'][$interface];
1526
	if (!isset($ifcfg['enable']))
1527
		return 0;
1528

    
1529
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1530
	if(!is_dir("/var/spool/lock")) {
1531
		mkdir("/var/spool/lock", 0777, true);
1532
	}
1533
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1534
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1535
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1536

    
1537
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1538
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1539
			if ($ifcfg['if'] == $ppp['if'])
1540
				break;
1541
		}
1542
	}
1543
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1544
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1545
		return 0;
1546
	}
1547
	$pppif = $ifcfg['if'];
1548
	if ($ppp['type'] == "ppp")
1549
		$type = "modem";
1550
	else
1551
		$type = $ppp['type'];
1552
	$upper_type = strtoupper($ppp['type']);
1553

    
1554
	if($g['booting']) {
1555
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1556
		echo "starting {$pppif} link...";
1557
		// Do not re-configure the interface if we are booting and it's already been started
1558
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1559
			return 0;
1560
	}
1561

    
1562
	$ports = explode(',',$ppp['ports']);
1563
	if ($type != "modem") {
1564
		foreach ($ports as $pid => $port) {
1565
			$ports[$pid] = get_real_interface($port);
1566
			if (empty($ports[$pid]))
1567
				return 0;
1568
		}
1569
	}
1570
	$localips = explode(',',$ppp['localip']);
1571
	$gateways = explode(',',$ppp['gateway']);
1572
	$subnets = explode(',',$ppp['subnet']);
1573

    
1574
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1575
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1576
	 */
1577
	foreach($ports as $pid => $port){
1578
		switch ($ppp['type']) {
1579
			case "pppoe":
1580
				/* Bring the parent interface up */
1581
				interfaces_bring_up($port);
1582
				pfSense_ngctl_attach(".", $port);
1583
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1584
				mwexec("ngctl msg {$port}: setautosrc 1");
1585
				break;
1586
			case "pptp":
1587
			case "l2tp":
1588
				/* configure interface */
1589
				if(is_ipaddr($localips[$pid])){
1590
					// Manually configure interface IP/subnet
1591
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1592
					interfaces_bring_up($port);
1593
				} else if (empty($localips[$pid]))
1594
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1595

    
1596
				if(!is_ipaddr($localips[$pid])){
1597
					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!");
1598
					$localips[$pid] = "0.0.0.0";
1599
				}
1600
				if(!is_ipaddr($gateways[$pid])){
1601
					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));
1602
					return 0;
1603
				}
1604
				pfSense_ngctl_attach(".", $port);
1605
				break;
1606
			case "ppp":
1607
				if (!file_exists("{$port}")) {
1608
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1609
					return 0;
1610
				}
1611
				break;
1612
			default:
1613
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1614
				break;
1615
		}
1616
	}
1617

    
1618
	if (is_array($ports) && count($ports) > 1)
1619
		$multilink = "enable";
1620
	else
1621
		$multilink = "disable";
1622

    
1623
	if ($type == "modem"){
1624
		if (is_ipaddr($ppp['localip']))
1625
			$localip = $ppp['localip'];
1626
		else
1627
			$localip = '0.0.0.0';
1628

    
1629
		if (is_ipaddr($ppp['gateway']))
1630
			$gateway = $ppp['gateway'];
1631
		else
1632
			$gateway = "10.64.64.{$pppid}";
1633
		$ranges = "{$localip}/0 {$gateway}/0";
1634

    
1635
		if (empty($ppp['apnum']))
1636
			$ppp['apnum'] = 1;
1637
	} else
1638
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1639

    
1640
	if (isset($ppp['ondemand']))
1641
		$ondemand = "enable";
1642
	else
1643
		$ondemand = "disable";
1644
	if (!isset($ppp['idletimeout']))
1645
		$ppp['idletimeout'] = 0;
1646

    
1647
	if (empty($ppp['username']) && $type == "modem"){
1648
		$ppp['username'] = "user";
1649
		$ppp['password'] = "none";
1650
	}
1651
	if (empty($ppp['password']) && $type == "modem")
1652
		$passwd = "none";
1653
	else
1654
		$passwd = base64_decode($ppp['password']);
1655

    
1656
	$bandwidths = explode(',',$ppp['bandwidth']);
1657
	$defaultmtu = "1492";
1658
	if (!empty($ifcfg['mtu']))
1659
		$defaultmtu = intval($ifcfg['mtu']);
1660
	$mtus = explode(',',$ppp['mtu']);
1661
	$mrus = explode(',',$ppp['mru']);
1662

    
1663
	if (isset($ppp['mrru']))
1664
		$mrrus = explode(',',$ppp['mrru']);
1665

    
1666
	// Construct the mpd.conf file
1667
	$mpdconf = <<<EOD
1668
startup:
1669
	# configure the console
1670
	set console close
1671
	# configure the web server
1672
	set web close
1673

    
1674
default:
1675
{$ppp['type']}client:
1676
	create bundle static {$interface}
1677
	set bundle enable ipv6cp
1678
	set iface name {$pppif}
1679

    
1680
EOD;
1681
	$setdefaultgw = false;
1682
	$founddefaultgw = false;
1683
	if (is_array($config['gateways']['gateway_item'])) {
1684
		foreach($config['gateways']['gateway_item'] as $gateway) {
1685
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1686
				$setdefaultgw = true;
1687
				break;
1688
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1689
				$founddefaultgw = true;
1690
				break;
1691
			}
1692
		}
1693
	}
1694

    
1695
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1696
		$setdefaultgw = true;
1697
		$mpdconf .= <<<EOD
1698
	set iface route default
1699

    
1700
EOD;
1701
	}
1702
	$mpdconf .= <<<EOD
1703
	set iface {$ondemand} on-demand
1704
	set iface idle {$ppp['idletimeout']}
1705

    
1706
EOD;
1707

    
1708
	if (isset($ppp['ondemand']))
1709
		$mpdconf .= <<<EOD
1710
	set iface addrs 10.10.1.1 10.10.1.2
1711

    
1712
EOD;
1713

    
1714
	if (isset($ppp['tcpmssfix']))
1715
		$tcpmss = "disable";
1716
	else
1717
		$tcpmss = "enable";
1718
		$mpdconf .= <<<EOD
1719
	set iface {$tcpmss} tcpmssfix
1720

    
1721
EOD;
1722

    
1723
	$mpdconf .= <<<EOD
1724
	set iface up-script /usr/local/sbin/ppp-linkup
1725
	set iface down-script /usr/local/sbin/ppp-linkdown
1726
	set ipcp ranges {$ranges}
1727

    
1728
EOD;
1729
	if (isset($ppp['vjcomp']))
1730
		$mpdconf .= <<<EOD
1731
	set ipcp no vjcomp
1732

    
1733
EOD;
1734

    
1735
	if (isset($config['system']['dnsallowoverride']))
1736
		$mpdconf .= <<<EOD
1737
	set ipcp enable req-pri-dns
1738
	set ipcp enable req-sec-dns
1739

    
1740
EOD;
1741
	if (!isset($ppp['verbose_log']))
1742
		$mpdconf .= <<<EOD
1743
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1744

    
1745
EOD;
1746
	foreach($ports as $pid => $port){
1747
		$port = get_real_interface($port);
1748
		$mpdconf .= <<<EOD
1749

    
1750
	create link static {$interface}_link{$pid} {$type}
1751
	set link action bundle {$interface}
1752
	set link {$multilink} multilink
1753
	set link keep-alive 10 60
1754
	set link max-redial 0
1755

    
1756
EOD;
1757
		if (isset($ppp['shortseq']))
1758
			$mpdconf .= <<<EOD
1759
	set link no shortseq
1760

    
1761
EOD;
1762

    
1763
		if (isset($ppp['acfcomp']))
1764
			$mpdconf .= <<<EOD
1765
	set link no acfcomp
1766

    
1767
EOD;
1768

    
1769
		if (isset($ppp['protocomp']))
1770
			$mpdconf .= <<<EOD
1771
	set link no protocomp
1772

    
1773
EOD;
1774

    
1775
		$mpdconf .= <<<EOD
1776
	set link disable chap pap
1777
	set link accept chap pap eap
1778
	set link disable incoming
1779

    
1780
EOD;
1781

    
1782

    
1783
		if (!empty($bandwidths[$pid]))
1784
			$mpdconf .= <<<EOD
1785
	set link bandwidth {$bandwidths[$pid]}
1786

    
1787
EOD;
1788

    
1789
		if (empty($mtus[$pid]))
1790
			$mtus[$pid] = $defaultmtu;
1791
			$mpdconf .= <<<EOD
1792
	set link mtu {$mtus[$pid]}
1793

    
1794
EOD;
1795

    
1796
		if (!empty($mrus[$pid]))
1797
			$mpdconf .= <<<EOD
1798
	set link mru {$mrus[$pid]}
1799

    
1800
EOD;
1801

    
1802
		if (!empty($mrrus[$pid]))
1803
			$mpdconf .= <<<EOD
1804
	set link mrru {$mrrus[$pid]}
1805

    
1806
EOD;
1807

    
1808
		$mpdconf .= <<<EOD
1809
	set auth authname "{$ppp['username']}"
1810
	set auth password {$passwd}
1811

    
1812
EOD;
1813
		if ($type == "modem") {
1814
			$mpdconf .= <<<EOD
1815
	set modem device {$ppp['ports']}
1816
	set modem script DialPeer
1817
	set modem idle-script Ringback
1818
	set modem watch -cd
1819
	set modem var \$DialPrefix "DT"
1820
	set modem var \$Telephone "{$ppp['phone']}"
1821

    
1822
EOD;
1823
		}
1824
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1825
			$mpdconf .= <<<EOD
1826
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1827

    
1828
EOD;
1829
		}
1830
		if (isset($ppp['initstr']) && $type == "modem") {
1831
			$initstr = base64_decode($ppp['initstr']);
1832
			$mpdconf .= <<<EOD
1833
	set modem var \$InitString "{$initstr}"
1834

    
1835
EOD;
1836
		}
1837
		if (isset($ppp['simpin']) && $type == "modem") {
1838
			if($ppp['pin-wait'] == "")
1839
				$ppp['pin-wait'] = 0;
1840
			$mpdconf .= <<<EOD
1841
	set modem var \$SimPin "{$ppp['simpin']}"
1842
	set modem var \$PinWait "{$ppp['pin-wait']}"
1843

    
1844
EOD;
1845
		}
1846
		if (isset($ppp['apn']) && $type == "modem") {
1847
			$mpdconf .= <<<EOD
1848
	set modem var \$APN "{$ppp['apn']}"
1849
	set modem var \$APNum "{$ppp['apnum']}"
1850

    
1851
EOD;
1852
		}
1853
		if ($type == "pppoe") {
1854
			// Send a null service name if none is set.
1855
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1856
			$mpdconf .= <<<EOD
1857
	set pppoe service "{$provider}"
1858

    
1859
EOD;
1860
		}
1861
		if ($type == "pppoe")
1862
			$mpdconf .= <<<EOD
1863
	set pppoe iface {$port}
1864

    
1865
EOD;
1866

    
1867
		if ($type == "pptp" || $type == "l2tp") {
1868
			$mpdconf .= <<<EOD
1869
	set {$type} self {$localips[$pid]}
1870
	set {$type} peer {$gateways[$pid]}
1871

    
1872
EOD;
1873
		}
1874

    
1875
		$mpdconf .= "\topen\n";
1876
	} //end foreach($port)
1877

    
1878

    
1879
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1880
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1881
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1882
	else {
1883
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1884
		if (!$fd) {
1885
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1886
			return 0;
1887
		}
1888
		// Write out mpd_ppp.conf
1889
		fwrite($fd, $mpdconf);
1890
		fclose($fd);
1891
		unset($mpdconf);
1892
	}
1893

    
1894
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1895
	if (isset($ppp['uptime'])) {
1896
		if (!file_exists("/conf/{$pppif}.log")) {
1897
			conf_mount_rw();
1898
			file_put_contents("/conf/{$pppif}.log", '');
1899
			conf_mount_ro();
1900
		}
1901
	} else {
1902
		if (file_exists("/conf/{$pppif}.log")) {
1903
			conf_mount_rw();
1904
			@unlink("/conf/{$pppif}.log");
1905
			conf_mount_ro();
1906
		}
1907
	}
1908

    
1909
	/* clean up old lock files */
1910
	foreach($ports as $port) {
1911
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1912
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1913
	}
1914

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

    
1919
	// Check for PPPoE periodic reset request
1920
	if ($type == "pppoe") {
1921
		if (!empty($ppp['pppoe-reset-type']))
1922
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1923
		else
1924
			interface_setup_pppoe_reset_file($ppp['if']);
1925
	}
1926
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1927
	$i = 0;
1928
	while($i < 10) {
1929
		exec("/sbin/ifconfig " . escapeshellarg($ppp['if']) . " 2>&1", $out, $ret);
1930
		if($ret == 0)
1931
			break;
1932
		sleep(1);
1933
		$i++;
1934
	}
1935

    
1936
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
1937
	/* We should be able to launch the right version for each modem */
1938
	/* We can also guess the mondev from the manufacturer */
1939
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
1940
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
1941
	foreach($ports as $port) {
1942
		if(preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1943
			$mondev  = substr(basename($port), 0, -1);
1944
			$devlist = glob("/dev/{$mondev}?");
1945
			$mondev = basename(end($devlist));
1946
		}
1947
		if(preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1948
			$mondev  = substr(basename($port), 0, -1) . "1";
1949
		}
1950
		log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
1951
		mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
1952
	}
1953

    
1954
	return 1;
1955
}
1956

    
1957
function interfaces_sync_setup() {
1958
	global $g, $config;
1959

    
1960
	if (isset($config['system']['developerspew'])) {
1961
		$mt = microtime();
1962
		echo "interfaces_sync_setup() being called $mt\n";
1963
	}
1964

    
1965
	if ($g['booting']) {
1966
		echo gettext("Configuring CARP settings...");
1967
		mute_kernel_msgs();
1968
	}
1969

    
1970
	/* suck in configuration items */
1971
	if ($config['hasync']) {
1972
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1973
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1974
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1975
	} else {
1976
		unset($pfsyncinterface);
1977
		unset($pfsyncenabled);
1978
	}
1979

    
1980
	set_sysctl(array(
1981
		"net.inet.carp.preempt" => "1",
1982
		"net.inet.carp.log" => "1")
1983
	);
1984

    
1985
	if (!empty($pfsyncinterface))
1986
		$carp_sync_int = get_real_interface($pfsyncinterface);
1987
	else
1988
		unset($carp_sync_int);
1989

    
1990
	/* setup pfsync interface */
1991
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
1992
		if (is_ipaddr($pfsyncpeerip))
1993
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1994
		else
1995
			$syncpeer = "-syncpeer";
1996

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

    
1999
		sleep(1);
2000

    
2001
		/* 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
2002
		 * for existing sessions.
2003
		 */
2004
		log_error("waiting for pfsync...");
2005
		$i = 0;
2006
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2007
			$i++;
2008
			sleep(1);
2009
		}
2010
		log_error("pfsync done in $i seconds.");
2011
		log_error("Configuring CARP settings finalize...");
2012
	} else {
2013
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2014
	}
2015

    
2016
	if($config['virtualip']['vip'])
2017
		set_single_sysctl("net.inet.carp.allow", "1");
2018
	else
2019
		set_single_sysctl("net.inet.carp.allow", "0");
2020

    
2021
	if ($g['booting']) {
2022
		unmute_kernel_msgs();
2023
		echo gettext("done.") . "\n";
2024
	}
2025
}
2026

    
2027
function interface_proxyarp_configure($interface = "") {
2028
	global $config, $g;
2029
	if(isset($config['system']['developerspew'])) {
2030
		$mt = microtime();
2031
		echo "interface_proxyarp_configure() being called $mt\n";
2032
	}
2033

    
2034
	/* kill any running choparp */
2035
	if (empty($interface))
2036
		killbyname("choparp");
2037
	else {
2038
		$vipif = get_real_interface($interface);
2039
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
2040
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2041
	}
2042

    
2043
	$paa = array();
2044
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2045

    
2046
		/* group by interface */
2047
		foreach ($config['virtualip']['vip'] as $vipent) {
2048
			if ($vipent['mode'] === "proxyarp") {
2049
				if ($vipent['interface'])
2050
					$proxyif = $vipent['interface'];
2051
				else
2052
					$proxyif = "wan";
2053

    
2054
				if (!empty($interface) && $interface != $proxyif)
2055
					continue;
2056

    
2057
				if (!is_array($paa[$proxyif]))
2058
					$paa[$proxyif] = array();
2059

    
2060
				$paa[$proxyif][] = $vipent;
2061
			}
2062
		}
2063
	}
2064

    
2065
	if (!empty($interface)) {
2066
		if (is_array($paa[$interface])) {
2067
			$paaifip = get_interface_ip($interface);
2068
			if (!is_ipaddr($paaifip))
2069
				return;
2070
			$args = get_real_interface($interface) . " auto";
2071
			foreach ($paa[$interface] as $paent) {
2072
				if (isset($paent['subnet']))
2073
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2074
				else if (isset($paent['range']))
2075
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2076
			}
2077
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2078
		}
2079
	} else if (count($paa) > 0) {
2080
		foreach ($paa as $paif => $paents)  {
2081
			$paaifip = get_interface_ip($paif);
2082
			if (!is_ipaddr($paaifip))
2083
				continue;
2084
			$args = get_real_interface($paif) . " auto";
2085
			foreach ($paents as $paent) {
2086
				if (isset($paent['subnet']))
2087
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2088
				else if (isset($paent['range']))
2089
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2090
			}
2091
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2092
		}
2093
	}
2094
}
2095

    
2096
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2097
	global $g, $config;
2098

    
2099
	if (is_array($config['virtualip']['vip'])) {
2100
		foreach ($config['virtualip']['vip'] as $vip) {
2101
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2102
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2103
					interface_vip_bring_down($vip);
2104
				else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2105
					interface_vip_bring_down($vip);
2106
			}
2107
		}
2108
	}
2109
}
2110

    
2111
function interfaces_vips_configure($interface = "") {
2112
	global $g, $config;
2113
	if(isset($config['system']['developerspew'])) {
2114
		$mt = microtime();
2115
		echo "interfaces_vips_configure() being called $mt\n";
2116
	}
2117
	$paa = array();
2118
	if(is_array($config['virtualip']['vip'])) {
2119
		$carp_setuped = false;
2120
		$anyproxyarp = false;
2121
		foreach ($config['virtualip']['vip'] as $vip) {
2122
			switch ($vip['mode']) {
2123
			case "proxyarp":
2124
				/* nothing it is handled on interface_proxyarp_configure() */
2125
				if ($interface <> "" && $vip['interface'] <> $interface)
2126
					continue;
2127
				$anyproxyarp = true;
2128
				break;
2129
			case "ipalias":
2130
				if ($interface <> "" && $vip['interface'] <> $interface)
2131
					continue;
2132
				interface_ipalias_configure($vip);
2133
				break;
2134
			case "carp":
2135
				if ($interface <> "" && $vip['interface'] <> $interface)
2136
					continue;
2137
				if ($carp_setuped == false)
2138
					$carp_setuped = true;
2139
				interface_carp_configure($vip);
2140
				break;
2141
			}
2142
		}
2143
		if ($carp_setuped == true)
2144
			interfaces_sync_setup();
2145
		if ($anyproxyarp == true)
2146
			interface_proxyarp_configure();
2147
	}
2148
}
2149

    
2150
function interface_ipalias_configure(&$vip) {
2151
	global $config;
2152

    
2153
	if ($vip['mode'] != 'ipalias')
2154
		return;
2155

    
2156
	if ($vip['interface'] != 'lo0' && stripos($vip['interface'], '_vip') === false) {
2157
		if (!isset($config['interfaces'][$vip['interface']]))
2158
			return;
2159

    
2160
		if (!isset($config['interfaces'][$vip['interface']]['enable']))
2161
			return;
2162
	}
2163

    
2164
	$af = 'inet';
2165
	if(is_ipaddrv6($vip['subnet']))
2166
		$af = 'inet6';
2167
	$iface = $vip['interface'];
2168
	$vipadd = '';
2169
	if (stripos($vip['interface'], '_vip')) {
2170
		$carpvip = get_configured_carp_interface_list($vip['interface'], $af, 'vip');
2171
		$iface = $carpvip['interface'];
2172
		$vipadd = "vhid {$carpvip['vhid']}";
2173
	}
2174
	$if = get_real_interface($vip['interface']);
2175
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vipadd}");
2176
	unset($iface, $af, $if, $carpvip, $vipadd);
2177
}
2178

    
2179
function interface_reload_carps($cif) {
2180
	global $config;
2181

    
2182
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2183
	if (empty($carpifs))
2184
		return;
2185

    
2186
	$carps = explode(" ", $carpifs);
2187
	if(is_array($config['virtualip']['vip'])) {
2188
		$viparr = &$config['virtualip']['vip'];
2189
		foreach ($viparr as $vip) {
2190
			if (in_array($vip['carpif'], $carps)) {
2191
				switch ($vip['mode']) {
2192
				case "carp":
2193
					interface_vip_bring_down($vip);
2194
					sleep(1);
2195
					interface_carp_configure($vip);
2196
					break;
2197
				case "ipalias":
2198
					interface_vip_bring_down($vip);
2199
					sleep(1);
2200
					interface_ipalias_configure($vip);
2201
					break;
2202
				}
2203
			}
2204
		}
2205
	}
2206
}
2207

    
2208
function interface_carp_configure(&$vip) {
2209
	global $config, $g;
2210
	if(isset($config['system']['developerspew'])) {
2211
		$mt = microtime();
2212
		echo "interface_carp_configure() being called $mt\n";
2213
	}
2214

    
2215
	if ($vip['mode'] != "carp")
2216
		return;
2217

    
2218
	/* NOTE: Maybe its useless nowdays */
2219
	$realif = get_real_interface($vip['interface']);
2220
	if (!does_interface_exist($realif)) {
2221
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2222
		return;
2223
	}
2224

    
2225
	if (is_ipaddrv4($vip['subnet'])) {
2226
		/* Ensure a IP on this interface exists prior to configuring CARP. */
2227
		$ww_subnet_ip = find_interface_ip($realif);
2228
		if (!is_ipaddrv4($ww_subnet_ip)) {
2229
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a required assigned ip address on the interface for the virtual IP address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2230
			return;
2231
		}
2232
	} else if (is_ipaddrv6($vip['subnet'])) {
2233
		/* Ensure a IP on this interface exists prior to configuring CARP. */
2234
		$ww_subnet_ip = find_interface_ipv6($realif);
2235
		if (!is_ipaddrv6($ww_subnet_ip)) {
2236
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a required assigned ip address on the interface for the virtual IPv6 address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2237
			return;
2238
		}
2239
	}
2240

    
2241
	$vip_password = $vip['password'];
2242
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2243
	if ($vip['password'] != "")
2244
		$password = " pass {$vip_password}";
2245

    
2246
	$advbase = "";
2247
	if (!empty($vip['advbase']))
2248
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2249

    
2250
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2251
	if ($carp_maintenancemode)
2252
		$advskew = "advskew 254";
2253
	else
2254
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2255
	
2256
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) . " {$advskew} {$advbase} {$password}");
2257

    
2258
	if (is_ipaddrv4($vip['subnet']))
2259
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2260
	else if (is_ipaddrv6($vip['subnet']))
2261
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2262

    
2263
	return $realif;
2264
}
2265

    
2266
function interface_wireless_clone($realif, $wlcfg) {
2267
	global $config, $g;
2268
	/*   Check to see if interface has been cloned as of yet.
2269
	 *   If it has not been cloned then go ahead and clone it.
2270
	 */
2271
	$needs_clone = false;
2272
	if(is_array($wlcfg['wireless']))
2273
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2274
	else
2275
		$wlcfg_mode = $wlcfg['mode'];
2276
	switch($wlcfg_mode) {
2277
	case "hostap":
2278
		$mode = "wlanmode hostap";
2279
		break;
2280
	case "adhoc":
2281
		$mode = "wlanmode adhoc";
2282
		break;
2283
	default:
2284
		$mode = "";
2285
		break;
2286
	}
2287
	$baseif = interface_get_wireless_base($wlcfg['if']);
2288
	if(does_interface_exist($realif)) {
2289
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2290
		$ifconfig_str = implode($output);
2291
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
2292
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2293
			$needs_clone = true;
2294
		}
2295
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
2296
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2297
			$needs_clone = true;
2298
		}
2299
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2300
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2301
			$needs_clone = true;
2302
		}
2303
	} else {
2304
		$needs_clone = true;
2305
	}
2306

    
2307
	if($needs_clone == true) {
2308
		/* remove previous instance if it exists */
2309
		if(does_interface_exist($realif))
2310
			pfSense_interface_destroy($realif);
2311

    
2312
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2313
		// Create the new wlan interface. FreeBSD returns the new interface name.
2314
		// example:  wlan2
2315
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2316
		if($ret <> 0) {
2317
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2318
			return false;
2319
		}
2320
		$newif = trim($out[0]);
2321
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2322
		pfSense_interface_rename($newif, $realif);
2323
		// FIXME: not sure what ngctl is for. Doesn't work.
2324
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
2325
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2326
	}
2327
	return true;
2328
}
2329

    
2330
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2331
	global $config, $g;
2332

    
2333
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2334
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2335
				 'regdomain', 'regcountry', 'reglocation');
2336

    
2337
	if(!is_interface_wireless($ifcfg['if']))
2338
		return;
2339

    
2340
	$baseif = interface_get_wireless_base($ifcfg['if']);
2341

    
2342
	// Sync shared settings for assigned clones
2343
	$iflist = get_configured_interface_list(false, true);
2344
	foreach ($iflist as $if) {
2345
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2346
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2347
				foreach ($shared_settings as $setting) {
2348
					if ($sync_changes) {
2349
						if (isset($ifcfg['wireless'][$setting]))
2350
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2351
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2352
							unset($config['interfaces'][$if]['wireless'][$setting]);
2353
					} else {
2354
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2355
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2356
						else if (isset($ifcfg['wireless'][$setting]))
2357
							unset($ifcfg['wireless'][$setting]);
2358
					}
2359
				}
2360
				if (!$sync_changes)
2361
					break;
2362
			}
2363
		}
2364
	}
2365

    
2366
	// Read or write settings at shared area
2367
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2368
		foreach ($shared_settings as $setting) {
2369
			if ($sync_changes) {
2370
				if (isset($ifcfg['wireless'][$setting]))
2371
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2372
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2373
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2374
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2375
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2376
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2377
				else if (isset($ifcfg['wireless'][$setting]))
2378
					unset($ifcfg['wireless'][$setting]);
2379
			}
2380
		}
2381
	}
2382

    
2383
	// Sync the mode on the clone creation page with the configured mode on the interface
2384
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2385
		foreach ($config['wireless']['clone'] as &$clone) {
2386
			if ($clone['cloneif'] == $ifcfg['if']) {
2387
				if ($sync_changes) {
2388
					$clone['mode'] = $ifcfg['wireless']['mode'];
2389
				} else {
2390
					$ifcfg['wireless']['mode'] = $clone['mode'];
2391
				}
2392
				break;
2393
			}
2394
		}
2395
		unset($clone);
2396
	}
2397
}
2398

    
2399
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2400
	global $config, $g;
2401

    
2402
	/*    open up a shell script that will be used to output the commands.
2403
	 *    since wireless is changing a lot, these series of commands are fragile
2404
	 *    and will sometimes need to be verified by a operator by executing the command
2405
	 *    and returning the output of the command to the developers for inspection.  please
2406
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2407
	 */
2408

    
2409
	// Remove script file
2410
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2411

    
2412
	// Clone wireless nic if needed.
2413
	interface_wireless_clone($if, $wl);
2414

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

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

    
2422
	/* set values for /path/program */
2423
	$hostapd = "/usr/sbin/hostapd";
2424
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2425
	$ifconfig = "/sbin/ifconfig";
2426
	$sysctl = "/sbin/sysctl";
2427
	$killall = "/usr/bin/killall";
2428

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

    
2431
	$wlcmd = array();
2432
	$wl_sysctl = array();
2433
	/* Make sure it's up */
2434
	$wlcmd[] = "up";
2435
	/* Set a/b/g standard */
2436
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2437
	$wlcmd[] = "mode " . escapeshellarg($standard);
2438

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

    
2444
	/* Set ssid */
2445
	if($wlcfg['ssid'])
2446
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2447

    
2448
	/* Set 802.11g protection mode */
2449
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2450

    
2451
	/* set wireless channel value */
2452
	if(isset($wlcfg['channel'])) {
2453
		if($wlcfg['channel'] == "0") {
2454
			$wlcmd[] = "channel any";
2455
		} else {
2456
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2457
		}
2458
	}
2459

    
2460
	/* Set antenna diversity value */
2461
	if(isset($wlcfg['diversity']))
2462
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2463

    
2464
	/* Set txantenna value */
2465
	if(isset($wlcfg['txantenna']))
2466
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2467

    
2468
	/* Set rxantenna value */
2469
	if(isset($wlcfg['rxantenna']))
2470
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2471

    
2472
	/* set Distance value */
2473
	if($wlcfg['distance'])
2474
		$distance = escapeshellarg($wlcfg['distance']);
2475

    
2476
	/* Set wireless hostap mode */
2477
	if ($wlcfg['mode'] == "hostap") {
2478
		$wlcmd[] = "mediaopt hostap";
2479
	} else {
2480
		$wlcmd[] = "-mediaopt hostap";
2481
	}
2482

    
2483
	/* Set wireless adhoc mode */
2484
	if ($wlcfg['mode'] == "adhoc") {
2485
		$wlcmd[] = "mediaopt adhoc";
2486
	} else {
2487
		$wlcmd[] = "-mediaopt adhoc";
2488
	}
2489

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

    
2492
	/* handle hide ssid option */
2493
	if(isset($wlcfg['hidessid']['enable'])) {
2494
		$wlcmd[] = "hidessid";
2495
	} else {
2496
		$wlcmd[] = "-hidessid";
2497
	}
2498

    
2499
	/* handle pureg (802.11g) only option */
2500
	if(isset($wlcfg['pureg']['enable'])) {
2501
		$wlcmd[] = "mode 11g pureg";
2502
	} else {
2503
		$wlcmd[] = "-pureg";
2504
	}
2505

    
2506
	/* handle puren (802.11n) only option */
2507
	if(isset($wlcfg['puren']['enable'])) {
2508
		$wlcmd[] = "puren";
2509
	} else {
2510
		$wlcmd[] = "-puren";
2511
	}
2512

    
2513
	/* enable apbridge option */
2514
	if(isset($wlcfg['apbridge']['enable'])) {
2515
		$wlcmd[] = "apbridge";
2516
	} else {
2517
		$wlcmd[] = "-apbridge";
2518
	}
2519

    
2520
	/* handle turbo option */
2521
	if(isset($wlcfg['turbo']['enable'])) {
2522
		$wlcmd[] = "mediaopt turbo";
2523
	} else {
2524
		$wlcmd[] = "-mediaopt turbo";
2525
	}
2526

    
2527
	/* handle txpower setting */
2528
	/* if($wlcfg['txpower'] <> "")
2529
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2530
	*/
2531
	/* handle wme option */
2532
	if(isset($wlcfg['wme']['enable'])) {
2533
		$wlcmd[] = "wme";
2534
	} else {
2535
		$wlcmd[] = "-wme";
2536
	}
2537

    
2538
	/* set up wep if enabled */
2539
	$wepset = "";
2540
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2541
		switch($wlcfg['wpa']['auth_algs']) {
2542
			case "1":
2543
				$wepset .= "authmode open wepmode on ";
2544
				break;
2545
			case "2":
2546
				$wepset .= "authmode shared wepmode on ";
2547
				break;
2548
			case "3":
2549
				$wepset .= "authmode mixed wepmode on ";
2550
		}
2551
		$i = 1;
2552
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2553
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2554
			if (isset($wepkey['txkey'])) {
2555
				$wlcmd[] = "weptxkey {$i} ";
2556
			}
2557
			$i++;
2558
		}
2559
		$wlcmd[] = $wepset;
2560
	} else {
2561
		$wlcmd[] = "authmode open wepmode off ";
2562
	}
2563

    
2564
	kill_hostapd($if);
2565
	mwexec(kill_wpasupplicant("{$if}"));
2566

    
2567
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2568
	conf_mount_rw();
2569

    
2570
	switch ($wlcfg['mode']) {
2571
	case 'bss':
2572
		if (isset($wlcfg['wpa']['enable'])) {
2573
			$wpa .= <<<EOD
2574
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2575
ctrl_interface_group=0
2576
ap_scan=1
2577
#fast_reauth=1
2578
network={
2579
ssid="{$wlcfg['ssid']}"
2580
scan_ssid=1
2581
priority=5
2582
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2583
psk="{$wlcfg['wpa']['passphrase']}"
2584
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2585
group={$wlcfg['wpa']['wpa_pairwise']}
2586
}
2587
EOD;
2588

    
2589
			@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2590
			unset($wpa);
2591
		}
2592
		break;
2593
	case 'hostap':
2594
		if (!empty($wlcfg['wpa']['passphrase']))
2595
			$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2596
		else
2597
			$wpa_passphrase = "";
2598
		if (isset($wlcfg['wpa']['enable'])) {
2599
			$wpa .= <<<EOD
2600
interface={$if}
2601
driver=bsd
2602
logger_syslog=-1
2603
logger_syslog_level=0
2604
logger_stdout=-1
2605
logger_stdout_level=0
2606
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2607
ctrl_interface={$g['varrun_path']}/hostapd
2608
ctrl_interface_group=wheel
2609
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2610
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2611
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2612
ssid={$wlcfg['ssid']}
2613
debug={$wlcfg['wpa']['debug_mode']}
2614
auth_algs={$wlcfg['wpa']['auth_algs']}
2615
wpa={$wlcfg['wpa']['wpa_mode']}
2616
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2617
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2618
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2619
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2620
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2621
{$wpa_passphrase}
2622

    
2623
EOD;
2624

    
2625
			if (isset($wlcfg['wpa']['rsn_preauth'])) {
2626
				$wpa .= <<<EOD
2627
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2628
rsn_preauth=1
2629
rsn_preauth_interfaces={$if}
2630

    
2631
EOD;
2632
			}
2633
			if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2634
				$wpa .= "ieee8021x=1\n";
2635

    
2636
			if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2637
				$auth_server_port = "1812";
2638
				if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port']))
2639
					$auth_server_port = intval($wlcfg['auth_server_port']);
2640
				$wpa .= <<<EOD
2641

    
2642
auth_server_addr={$wlcfg['auth_server_addr']}
2643
auth_server_port={$auth_server_port}
2644
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2645

    
2646
EOD;
2647
				if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2648
					$auth_server_port2 = "1812";
2649
					if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2']))
2650
						$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2651

    
2652
					$wpa .= <<<EOD
2653
auth_server_addr={$wlcfg['auth_server_addr2']}
2654
auth_server_port={$auth_server_port2}
2655
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2656

    
2657
EOD;
2658
					}
2659
				}
2660
			}
2661

    
2662
			@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2663
			unset($wpa);
2664
		}
2665
		break;
2666
	}
2667

    
2668
	/*
2669
	 *    all variables are set, lets start up everything
2670
	 */
2671

    
2672
	$baseif = interface_get_wireless_base($if);
2673
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2674
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2675

    
2676
	/* set sysctls for the wireless interface */
2677
	if (!empty($wl_sysctl)) {
2678
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2679
		foreach ($wl_sysctl as $wl_sysctl_line) {
2680
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2681
		}
2682
	}
2683

    
2684
	/* set ack timers according to users preference (if he/she has any) */
2685
	if($distance) {
2686
		fwrite($fd_set, "# Enable ATH distance settings\n");
2687
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2688
	}
2689

    
2690
	if (isset($wlcfg['wpa']['enable'])) {
2691
		if ($wlcfg['mode'] == "bss") {
2692
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2693
		}
2694
		if ($wlcfg['mode'] == "hostap") {
2695
			/* add line to script to restore old mac to make hostapd happy */
2696
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2697
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2698
				if (is_macaddr($if_oldmac))
2699
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2700
						" link " . escapeshellarg($if_oldmac) . "\n");
2701
			}
2702

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

    
2705
			/* add line to script to restore spoofed mac after running hostapd */
2706
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2707
				if ($wl['spoofmac'])
2708
					$if_curmac = $wl['spoofmac'];
2709
				else
2710
					$if_curmac = get_interface_mac($if);
2711
				if (is_macaddr($if_curmac))
2712
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2713
						" link " . escapeshellarg($if_curmac) . "\n");
2714
			}
2715
		}
2716
	}
2717

    
2718
	fclose($fd_set);
2719
	conf_mount_ro();
2720

    
2721
	/* Making sure regulatory settings have actually changed
2722
	 * before applying, because changing them requires bringing
2723
	 * down all wireless networks on the interface. */
2724
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2725
	$ifconfig_str = implode($output);
2726
	unset($output);
2727
	$reg_changing = false;
2728

    
2729
	/* special case for the debug country code */
2730
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2731
		$reg_changing = true;
2732
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2733
		$reg_changing = true;
2734
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2735
		$reg_changing = true;
2736
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2737
		$reg_changing = true;
2738
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2739
		$reg_changing = true;
2740

    
2741
	if ($reg_changing) {
2742
		/* set regulatory domain */
2743
		if($wlcfg['regdomain'])
2744
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2745

    
2746
		/* set country */
2747
		if($wlcfg['regcountry'])
2748
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2749

    
2750
		/* set location */
2751
		if($wlcfg['reglocation'])
2752
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2753

    
2754
		$wlregcmd_args = implode(" ", $wlregcmd);
2755

    
2756
		/* build a complete list of the wireless clones for this interface */
2757
		$clone_list = array();
2758
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2759
			$clone_list[] = interface_get_wireless_clone($baseif);
2760
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2761
			foreach ($config['wireless']['clone'] as $clone) {
2762
				if ($clone['if'] == $baseif)
2763
					$clone_list[] = $clone['cloneif'];
2764
			}
2765
		}
2766

    
2767
		/* find which clones are up and bring them down */
2768
		$clones_up = array();
2769
		foreach ($clone_list as $clone_if) {
2770
			$clone_status = pfSense_get_interface_addresses($clone_if);
2771
			if ($clone_status['status'] == 'up') {
2772
				$clones_up[] = $clone_if;
2773
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2774
			}
2775
		}
2776

    
2777
		/* apply the regulatory settings */
2778
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2779

    
2780
		/* bring the clones back up that were previously up */
2781
		foreach ($clones_up as $clone_if) {
2782
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2783

    
2784
			/*
2785
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2786
			 * is in infrastructure mode, and WPA is enabled.
2787
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2788
			 */
2789
			if ($clone_if != $if) {
2790
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2791
				if ( !empty($friendly_if)
2792
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2793
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2794
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2795
				}
2796
			}
2797
		}
2798
	}
2799

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

    
2804
	/* configure wireless */
2805
	$wlcmd_args = implode(" ", $wlcmd);
2806
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2807
	unset($wlcmd_args, $wlcmd);
2808

    
2809

    
2810
	sleep(1);
2811
	/* execute hostapd and wpa_supplicant if required in shell */
2812
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2813

    
2814
	return 0;
2815

    
2816
}
2817

    
2818
function kill_hostapd($interface) {
2819
	global $g;
2820

    
2821
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2822
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2823
}
2824

    
2825
function kill_wpasupplicant($interface) {
2826
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2827
}
2828

    
2829
function find_dhclient_process($interface) {
2830
	if ($interface)
2831
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2832
	else
2833
		$pid = 0;
2834

    
2835
	return intval($pid);
2836
}
2837

    
2838
function kill_dhclient_process($interface) {
2839
	if (empty($interface) || !does_interface_exist($interface))
2840
		return;
2841

    
2842
	$i = 0;
2843
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2844
		/* 3rd time make it die for sure */
2845
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2846
		posix_kill($pid, $sig);
2847
		sleep(1);
2848
		$i++;
2849
	}
2850
	unset($i);
2851
}
2852

    
2853
function find_dhcp6c_process($interface) {
2854
	global $g;
2855

    
2856
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid"))
2857
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2858
	else
2859
		return(false);
2860

    
2861
	return intval($pid);
2862
}
2863

    
2864
function interface_vlan_mtu_configured($realhwif, $mtu) {
2865
	global $config;
2866

    
2867
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
2868
		foreach ($config['vlans']['vlan'] as $vlan) {
2869
			if ($vlan['if'] != $realhwif)
2870
				continue;
2871
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2872
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
2873
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2874
					$mtu = $portmtu;
2875
			}
2876
		}
2877
	}
2878

    
2879
	return $mtu;
2880
}
2881

    
2882
function interface_virtual_create($interface) {
2883
	global $config;
2884

    
2885
	if (strstr($interface, "_vlan")) {
2886
		interfaces_vlan_configure($vlan);
2887
	} else if (substr($interface, 0, 3) == "gre") {
2888
		interfaces_gre_configure(0, $interface);
2889
	} else if (substr($interface, 0, 3) == "gif") {
2890
		interfaces_gif_configure(0, $interface);
2891
	} else if (substr($interface, 0, 5) == "ovpns") {
2892
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
2893
			foreach ($config['openvpn']['openvpn-server'] as $server) {
2894
				if ($interface == "ovpns{$server['vpnid']}") {
2895
					if (!function_exists('openvpn_resync'))
2896
						require_once('openvpn.inc');
2897
					log_error("OpenVPN: Resync server {$server['description']}");
2898
					openvpn_resync('server', $server);
2899
				}
2900
			}
2901
			unset($server);
2902
		}
2903
	} else if (substr($interface, 0, 5) == "ovpnc") {
2904
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
2905
			foreach ($config['openvpn']['openvpn-client'] as $client) {
2906
				if ($interface == "ovpnc{$client['vpnid']}") {
2907
					if (!function_exists('openvpn_resync'))
2908
						require_once('openvpn.inc');
2909
					log_error("OpenVPN: Resync server {$client['description']}");
2910
					openvpn_resync('client', $client);
2911
				}
2912
			}
2913
			unset($client);
2914
		}
2915
	} else if (substr($interface, 0, 4) == "lagg") {
2916
		interfaces_lagg_configure($interface);
2917
	} else if (substr($interface, 0, 6) == "bridge") {
2918
		interfaces_bridge_configure(0, $interface);
2919
	}
2920
}
2921

    
2922
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2923
	global $config;
2924

    
2925
	if (!is_array($vlanifs))
2926
		return;
2927

    
2928
	/* All vlans need to use the same mtu value as their parent. */
2929
	foreach ($vlanifs as $vlan) {
2930
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2931
		if (!empty($assignedport)) {
2932
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
2933
				/*
2934
				* XXX: This is really never going to happen just keep the code for safety and readbility.
2935
				* It never happens since interface_vlan_mtu_configured finds the biggest mtu on vlans.
2936
				* Also if it has a lower mtu configured just respect user choice.
2937
				*/
2938
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2939
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2940
			} else {
2941
				if (get_interface_mtu($vlan['vlanif']) != $mtu)
2942
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2943
			}
2944
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2945
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
2946
	}
2947
}
2948

    
2949
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2950
	global $config, $g;
2951
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2952
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2953

    
2954
	$wancfg = $config['interfaces'][$interface];
2955

    
2956
	if (!isset($wancfg['enable']))
2957
		return;
2958

    
2959
	$realif = get_real_interface($interface);
2960
	$realhwif_array = get_parent_interface($interface);
2961
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2962
	$realhwif = $realhwif_array[0];
2963

    
2964
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2965
		/* remove all IPv4 and IPv6 addresses */
2966
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2967
		if (is_array($tmpifaces)) {
2968
			foreach ($tmpifaces as $tmpiface) {
2969
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
2970
					if (!is_linklocal($tmpiface))
2971
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2972
				} else {
2973
					if (is_subnetv4($tmpiface)) {
2974
						$tmpip = explode('/', $tmpiface);
2975
						$tmpip = $tmpip[0];
2976
					} else
2977
						$tmpip = $tmpiface;
2978
					pfSense_interface_deladdress($realif, $tmpip);
2979
				}
2980
			}
2981
		}
2982

    
2983
		/* only bring down the interface when both v4 and v6 are set to NONE */
2984
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6']))
2985
			interface_bring_down($interface);
2986
	}
2987

    
2988
	$interface_to_check = $realif;
2989
	switch ($wancfg['ipaddr']) {
2990
	case 'pppoe':
2991
	case 'l2tp':
2992
	case 'pptp':
2993
	case 'ppp':
2994
		$interface_to_check = $realhwif;
2995
		break;
2996
	}
2997

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

    
3002
	/* Disable Accepting router advertisements unless specifically requested */
3003
	if ($g['debug'])
3004
		log_error("Deny router advertisements for interface {$interface}");
3005
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
3006

    
3007
	/* wireless configuration? */
3008
	if (is_array($wancfg['wireless']))
3009
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3010

    
3011
	$mac = get_interface_mac($realhwif);
3012
	/*
3013
	 * Don't try to reapply the spoofed MAC if it's already applied.
3014
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3015
	 * the interface config again, which attempts to spoof the MAC again,
3016
	 * which cycles the link again...
3017
	 */
3018
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
3019
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3020
			" link " . escapeshellarg($wancfg['spoofmac']));
3021

    
3022
		/*
3023
		 * All vlans need to spoof their parent mac address, too.  see
3024
		 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
3025
		 */
3026
		if (is_array($config['vlans']['vlan'])) {
3027
			foreach ($config['vlans']['vlan'] as $vlan) {
3028
				if ($vlan['if'] == $realhwif)
3029
					mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
3030
					" link " . escapeshellarg($wancfg['spoofmac']));
3031
			}
3032
		}
3033
	}  else {
3034

    
3035
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3036
			/*   this is not a valid mac address.  generate a
3037
			 *   temporary mac address so the machine can get online.
3038
			 */
3039
			echo gettext("Generating new MAC address.");
3040
			$random_mac = generate_random_mac_address();
3041
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3042
				" link " . escapeshellarg($random_mac));
3043
			$wancfg['spoofmac'] = $random_mac;
3044
			write_config();
3045
			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");
3046
		}
3047
	}
3048

    
3049
	/* media */
3050
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3051
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3052
		if ($wancfg['media'])
3053
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3054
		if ($wancfg['mediaopt'])
3055
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3056
		mwexec($cmd);
3057
	}
3058
	$options = pfSense_get_interface_addresses($realhwif);
3059

    
3060
	/* skip vlans for checksumming and polling */
3061
	if (!stristr($realif, "_vlan") && is_array($options)) {
3062
		$flags_on = 0;
3063
		$flags_off = 0;
3064
		if(isset($config['system']['disablechecksumoffloading'])) {
3065
			if (isset($options['encaps']['txcsum']))
3066
				$flags_off |= IFCAP_TXCSUM;
3067
			if (isset($options['encaps']['rxcsum']))
3068
				$flags_off |= IFCAP_RXCSUM;
3069
		} else {
3070
			if (isset($options['caps']['txcsum']))
3071
				$flags_on |= IFCAP_TXCSUM;
3072
			if (isset($options['caps']['rxcsum']))
3073
				$flags_on |= IFCAP_RXCSUM;
3074
		}
3075

    
3076
		if(isset($config['system']['disablesegmentationoffloading']))
3077
			$flags_off |= IFCAP_TSO;
3078
		else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6']))
3079
			$flags_on |= IFCAP_TSO;
3080

    
3081
		if(isset($config['system']['disablelargereceiveoffloading']))
3082
			$flags_off |= IFCAP_LRO;
3083
		else if (isset($options['caps']['lro']))
3084
			$flags_on |= IFCAP_LRO;
3085

    
3086
		/* if the NIC supports polling *AND* it is enabled in the GUI */
3087
		if (!isset($config['system']['polling']))
3088
			$flags_off |= IFCAP_POLLING;
3089
		else if (isset($options['caps']['polling']))
3090
			$flags_on |= IFCAP_POLLING;
3091

    
3092
		pfSense_interface_capabilities($realhwif, -$flags_off);
3093
		pfSense_interface_capabilities($realhwif, $flags_on);
3094
	}
3095

    
3096
	/* invalidate interface/ip/sn cache */
3097
	get_interface_arr(true);
3098
	unset($interface_ip_arr_cache[$realif]);
3099
	unset($interface_sn_arr_cache[$realif]);
3100
	unset($interface_ipv6_arr_cache[$realif]);
3101
	unset($interface_snv6_arr_cache[$realif]);
3102

    
3103
	$tunnelif = substr($realif, 0, 3);
3104
	switch ($wancfg['ipaddr']) {
3105
	case 'dhcp':
3106
		interface_dhcp_configure($interface);
3107
		break;
3108
	case 'pppoe':
3109
	case 'l2tp':
3110
	case 'pptp':
3111
	case 'ppp':
3112
		interface_ppps_configure($interface);
3113
		break;
3114
	default:
3115
		/* XXX: Kludge for now related to #3280 */
3116
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3117
			if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "")
3118
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3119
		}
3120
		break;
3121
	}
3122

    
3123
	switch ($wancfg['ipaddrv6']) {
3124
	case 'slaac':
3125
	case 'dhcp6':
3126
		interface_dhcpv6_configure($interface, $wancfg);
3127
		break;
3128
	case '6rd':
3129
		interface_6rd_configure($interface, $wancfg);
3130
		break;
3131
	case '6to4':
3132
		interface_6to4_configure($interface, $wancfg);
3133
		break;
3134
	case 'track6':
3135
		interface_track6_configure($interface, $wancfg, $linkupevent);
3136
		break;
3137
	default:
3138
		/* XXX: Kludge for now related to #3280 */
3139
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3140
			if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3141
				//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3142
				// FIXME: Add IPv6 Support to the pfSense module
3143
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3144
			}
3145
		}
3146
		break;
3147
	}
3148

    
3149
	if (!empty($wancfg['mtu'])) {
3150
		if (stristr($realif, "_vlan")) {
3151
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3152
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
3153
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3154
			else
3155
				$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
3156

    
3157
			if ($wancfg['mtu'] > $parentmtu) {
3158
				if (get_interface_mtu($realhwif) != $wancfg['mtu'])
3159
					pfSense_interface_mtu($realhwif, $wancfg['mtu']);
3160

    
3161
				/* All vlans need to use the same mtu value as their parent. */
3162
				interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $wancfg['mtu']);
3163
			} else
3164
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3165
		} else if (substr($realif, 0, 4) == 'lagg') {
3166
			/* LAGG interface must be destroyed and re-created to change MTU */
3167
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3168
				if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3169
					foreach ($config['laggs']['lagg'] as $lagg) {
3170
						if ($lagg['laggif'] == $realif) {
3171
							interface_lagg_configure($lagg);
3172
							break;
3173
						}
3174
					}
3175
				}
3176
			}
3177
		} else {
3178
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3179
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3180

    
3181
			/* This case is needed when the parent of vlans is being configured */
3182
			interface_vlan_adapt_mtu(link_interface_to_vlans($realif), $wancfg['mtu']);
3183
		}
3184
		/* XXX: What about gre/gif/.. ? */
3185
	}
3186

    
3187
	if (does_interface_exist($wancfg['if']))
3188
		interfaces_bring_up($wancfg['if']);
3189

    
3190
	interface_netgraph_needed($interface);
3191

    
3192
	if (!$g['booting']) {
3193
		link_interface_to_vips($interface, "update");
3194

    
3195
		unset($gre);
3196
		$gre = link_interface_to_gre($interface);
3197
		if (!empty($gre))
3198
			array_walk($gre, 'interface_gre_configure');
3199

    
3200
		unset($gif);
3201
		$gif = link_interface_to_gif($interface);
3202
		if (!empty($gif))
3203
			array_walk($gif, 'interface_gif_configure');
3204

    
3205
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3206
			unset($bridgetmp);
3207
			$bridgetmp = link_interface_to_bridge($interface);
3208
			if (!empty($bridgetmp))
3209
				interface_bridge_add_member($bridgetmp, $realif);
3210
		}
3211

    
3212
		$grouptmp = link_interface_to_group($interface);
3213
		if (!empty($grouptmp))
3214
			array_walk($grouptmp, 'interface_group_add_member');
3215

    
3216
		if ($interface == "lan")
3217
			/* make new hosts file */
3218
			system_hosts_generate();
3219

    
3220
		if ($reloadall == true) {
3221

    
3222
			/* reconfigure static routes (kernel may have deleted them) */
3223
			system_routing_configure($interface);
3224

    
3225
			/* reload ipsec tunnels */
3226
			vpn_ipsec_configure();
3227

    
3228
			/* restart dnsmasq or unbound */
3229
			if (isset($config['dnsmasq']['enable']))
3230
				services_dnsmasq_configure();
3231
			elseif (isset($config['unbound']['enable']))
3232
				services_unbound_configure();
3233

    
3234
			/* update dyndns */
3235
			send_event("service reload dyndns {$interface}");
3236

    
3237
			/* XXX: which CPZONE? Needed? */
3238
			/* reload captive portal */
3239
			captiveportal_init_rules();
3240
		}
3241
	}
3242

    
3243
	interfaces_staticarp_configure($interface);
3244
	return 0;
3245
}
3246

    
3247
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3248
	global $config, $g;
3249

    
3250
	if (!is_array($wancfg))
3251
		return;
3252

    
3253
	if (!isset($wancfg['enable']))
3254
		return;
3255

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

    
3260
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3261
	$realif = get_real_interface($interface);
3262
	$linklocal = find_interface_ipv6_ll($realif);
3263
	if (!empty($linklocal))
3264
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3265
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3266
	/* XXX: Probably should remove? */
3267
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3268

    
3269
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3270
	if (!isset($trackcfg['enable'])) {
3271
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3272
		return;
3273
	}
3274

    
3275
	switch($trackcfg['ipaddrv6']) {
3276
	case "6to4":
3277
		if ($g['debug'])
3278
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3279
		interface_track6_6to4_configure($interface, $wancfg);
3280
		break;
3281
	case "6rd":
3282
		if ($g['debug'])
3283
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3284
		interface_track6_6rd_configure($interface, $wancfg);
3285
		break;
3286
	case "dhcp6":
3287
		if ($linkupevent == true) {
3288
			/* 
3289
			 * NOTE: Usually come here from rc.linkup calling so just call directly intead of generating event
3290
			 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3291
			 *
3292
			 * XXX: Probably DHCPv6 client should handle this autmagically itself?
3293
			 */
3294
			$parentrealif = get_real_interface($wancfg['track6-interface']);
3295
			$pidv6 = find_dhcp6c_process($parentrealif);
3296
			if($pidv6)
3297
				posix_kill($pidv6, SIGHUP);
3298
		}
3299
		break;
3300
	}
3301

    
3302
	if (!$g['booting'] && $linkupevent == false) {
3303
		if (!function_exists('services_dhcpd_configure'))
3304
			require_once("services.inc");
3305

    
3306
		services_dhcpd_configure("inet6");
3307
	}
3308

    
3309
	return 0;
3310
}
3311

    
3312
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3313
	global $config, $g;
3314
	global $interface_ipv6_arr_cache;
3315
	global $interface_snv6_arr_cache;
3316

    
3317
	if (!is_array($lancfg))
3318
		return;
3319

    
3320
	/* If the interface is not configured via another, exit */
3321
	if (empty($lancfg['track6-interface']))
3322
		return;
3323

    
3324
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3325
	if (empty($wancfg)) {
3326
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3327
		return;
3328
	}
3329

    
3330
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3331
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3332
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3333
		return;
3334
	}
3335
	$hexwanv4 = return_hex_ipv4($ip4address);
3336

    
3337
	/* create the long prefix notation for math, save the prefix length */
3338
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3339
	$rd6prefixlen = $rd6prefix[1];
3340
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3341

    
3342
	/* binary presentation of the prefix for all 128 bits. */
3343
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3344

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

    
3350
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3351
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3352
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3353
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3354
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3355
	/* fill the rest out with zeros */
3356
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3357

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

    
3361
	$lanif = get_real_interface($interface);
3362
	$oip = find_interface_ipv6($lanif);
3363
	if (is_ipaddrv6($oip))
3364
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3365
	unset($interface_ipv6_arr_cache[$lanif]);
3366
	unset($interface_snv6_arr_cache[$lanif]);
3367
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3368
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3369

    
3370
	return 0;
3371
}
3372

    
3373
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3374
	global $config, $g;
3375
	global $interface_ipv6_arr_cache;
3376
	global $interface_snv6_arr_cache;
3377

    
3378
	if (!is_array($lancfg))
3379
		return;
3380

    
3381
	/* If the interface is not configured via another, exit */
3382
	if (empty($lancfg['track6-interface']))
3383
		return;
3384

    
3385
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3386
	if (empty($wancfg)) {
3387
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3388
		return;
3389
	}
3390

    
3391
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3392
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3393
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3394
		return;
3395
	}
3396
	$hexwanv4 = return_hex_ipv4($ip4address);
3397

    
3398
	/* create the long prefix notation for math, save the prefix length */
3399
	$sixto4prefix = "2002::";
3400
	$sixto4prefixlen = 16;
3401
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3402

    
3403
	/* binary presentation of the prefix for all 128 bits. */
3404
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3405

    
3406
	/* just save the left prefix length bits */
3407
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3408
	/* add the v4 address */
3409
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3410
	/* add the custom prefix id */
3411
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3412
	/* fill the rest out with zeros */
3413
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3414

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

    
3418
	$lanif = get_real_interface($interface);
3419
	$oip = find_interface_ipv6($lanif);
3420
	if (is_ipaddrv6($oip))
3421
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3422
	unset($interface_ipv6_arr_cache[$lanif]);
3423
	unset($interface_snv6_arr_cache[$lanif]);
3424
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3425
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3426

    
3427
	return 0;
3428
}
3429

    
3430
function interface_6rd_configure($interface = "wan", $wancfg) {
3431
	global $config, $g;
3432

    
3433
	/* because this is a tunnel interface we can only function
3434
	 *	with a public IPv4 address on the interface */
3435

    
3436
	if (!is_array($wancfg))
3437
		return;
3438

    
3439
	if (!is_module_loaded('if_stf.ko'))
3440
		mwexec('/sbin/kldload if_stf.ko');
3441

    
3442
	$wanif = get_real_interface($interface);
3443
	$ip4address = find_interface_ip($wanif);
3444
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3445
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3446
		return false;
3447
	}
3448
	$hexwanv4 = return_hex_ipv4($ip4address);
3449

    
3450
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3451
		$wancfg['prefix-6rd-v4plen'] = 0;
3452

    
3453
	/* create the long prefix notation for math, save the prefix length */
3454
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3455
	$rd6prefixlen = $rd6prefix[1];
3456
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3457

    
3458
	/* binary presentation of the prefix for all 128 bits. */
3459
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3460

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

    
3468
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3469
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3470

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

    
3473
	/* XXX: need to extend to support variable prefix size for v4 */
3474
	if (!is_module_loaded("if_stf"))
3475
		mwexec("/sbin/kldload if_stf.ko");
3476
	$stfiface = "{$interface}_stf";
3477
	if (does_interface_exist($stfiface))
3478
		pfSense_interface_destroy($stfiface);
3479
	$tmpstfiface = pfSense_interface_create("stf");
3480
	pfSense_interface_rename($tmpstfiface, $stfiface);
3481
	pfSense_interface_flags($stfiface, IFF_LINK2);
3482
	if ($wancfg['prefix-6rd-v4plen'] > 0)
3483
		$rd6prefixlen += intval($wancfg['prefix-6rd-v4plen']);
3484
	else
3485
		$rd6prefixlen += 32;
3486
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3487
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3488
	if ($wancfg['prefix-6rd-v4plen'] > 0 && $wancfg['prefix-6rd-v4plen'] < 32)
3489
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/{$wancfg['prefix-6rd-v4plen']}");
3490
	if ($g['debug'])
3491
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3492

    
3493
	/* write out a default router file */
3494
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3495
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3496

    
3497
	$ip4gateway = get_interface_gateway($interface);
3498
	if (is_ipaddrv4($ip4gateway))
3499
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3500

    
3501
	/* configure dependent interfaces */
3502
	if (!$g['booting'])
3503
		link_interface_to_track6($interface, "update");
3504

    
3505
	return 0;
3506
}
3507

    
3508
function interface_6to4_configure($interface = "wan", $wancfg){
3509
	global $config, $g;
3510

    
3511
	/* because this is a tunnel interface we can only function
3512
	 *	with a public IPv4 address on the interface */
3513

    
3514
	if (!is_array($wancfg))
3515
		return;
3516

    
3517
	$wanif = get_real_interface($interface);
3518
	$ip4address = find_interface_ip($wanif);
3519
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3520
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3521
		return false;
3522
	}
3523

    
3524
	/* create the long prefix notation for math, save the prefix length */
3525
	$stfprefixlen = 16;
3526
	$stfprefix = Net_IPv6::uncompress("2002::");
3527
	$stfarr = explode(":", $stfprefix);
3528
	$v4prefixlen = "0";
3529

    
3530
	/* we need the hex form of the interface IPv4 address */
3531
	$ip4arr = explode(".", $ip4address);
3532
	$hexwanv4 = "";
3533
	foreach($ip4arr as $octet)
3534
		$hexwanv4 .= sprintf("%02x", $octet);
3535

    
3536
	/* we need the hex form of the broker IPv4 address */
3537
	$ip4arr = explode(".", "192.88.99.1");
3538
	$hexbrv4 = "";
3539
	foreach($ip4arr as $octet)
3540
		$hexbrv4 .= sprintf("%02x", $octet);
3541

    
3542
	/* binary presentation of the prefix for all 128 bits. */
3543
	$stfprefixbin = "";
3544
	foreach($stfarr as $element) {
3545
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3546
	}
3547
	/* just save the left prefix length bits */
3548
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3549

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

    
3554
	/* for the local subnet too. */
3555
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3556
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3557

    
3558
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3559
	$stfbrarr = array();
3560
	$stfbrbinarr = array();
3561
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3562
	foreach($stfbrbinarr as $bin)
3563
		$stfbrarr[] = dechex(bindec($bin));
3564
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3565

    
3566
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3567
	$stflanarr = array();
3568
	$stflanbinarr = array();
3569
	$stflanbinarr = str_split($stflanbin, 16);
3570
	foreach($stflanbinarr as $bin)
3571
		$stflanarr[] = dechex(bindec($bin));
3572
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3573
	$stflanarr[7] = 1;
3574
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3575

    
3576
	/* setup the stf interface */
3577
	if (!is_module_loaded("if_stf"))
3578
		mwexec("/sbin/kldload if_stf.ko");
3579
	$stfiface = "{$interface}_stf";
3580
	if (does_interface_exist($stfiface))
3581
		pfSense_interface_destroy($stfiface);
3582
	$tmpstfiface = pfSense_interface_create("stf");
3583
	pfSense_interface_rename($tmpstfiface, $stfiface);
3584
	pfSense_interface_flags($stfiface, IFF_LINK2);
3585
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3586

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

    
3590
	/* write out a default router file */
3591
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3592
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3593

    
3594
	$ip4gateway = get_interface_gateway($interface);
3595
	if (is_ipaddrv4($ip4gateway))
3596
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3597

    
3598
	if (!$g['booting'])
3599
		link_interface_to_track6($interface, "update");
3600

    
3601
	return 0;
3602
}
3603

    
3604
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3605
	global $config, $g;
3606

    
3607
	if (!is_array($wancfg))
3608
		return;
3609

    
3610
	$wanif = get_real_interface($interface, "inet6");
3611
	$dhcp6cconf = "";
3612
	$dhcp6cconf .= "interface {$wanif} {\n";
3613

    
3614
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3615
	if($wancfg['ipaddrv6'] == "slaac") {
3616
		$dhcp6cconf .= "	information-only;\n";
3617
		$dhcp6cconf .= "	request domain-name-servers;\n";
3618
		$dhcp6cconf .= "	request domain-name;\n";
3619
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3620
		$dhcp6cconf .= "};\n";
3621
	} else {
3622
		/* skip address request if this is set */
3623
		if(!isset($wancfg['dhcp6prefixonly']))
3624
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3625
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3626
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3627

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

    
3632
		$dhcp6cconf .= "};\n";
3633

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

    
3637
		if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3638
			/* Setup the prefix delegation */
3639
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3640
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3641
			if (isset($wancfg['dhcp6-ia-pd-send-hint']))
3642
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3643
			$iflist = link_interface_to_track6($interface);
3644
			foreach ($iflist as $friendly => $ifcfg) {
3645
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3646
					if ($g['debug'])
3647
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3648
					$realif = get_real_interface($friendly);
3649
					$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3650
					$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3651
					$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3652
					$dhcp6cconf .= "	};\n";
3653
				}
3654
			}
3655
			unset($preflen, $iflist, $ifcfg);
3656
			$dhcp6cconf .= "};\n";
3657
		}
3658
	}
3659

    
3660
	// DHCP6 Config File Advanced
3661
	if ($wancfg['adv_dhcp6_config_advanced']) { $dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif); }
3662

    
3663
	// DHCP6 Config File Override
3664
	if ($wancfg['adv_dhcp6_config_file_override']) { $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif); }
3665

    
3666
	/* wide-dhcp6c works for now. */
3667
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3668
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3669
		unset($dhcp6cconf);
3670
		return 1;
3671
	}
3672
	unset($dhcp6cconf);
3673

    
3674
	$dhcp6cscript = "#!/bin/sh\n";
3675
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3676
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3677
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3678
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3679
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3680
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3681
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3682
		unset($dhcp6cscript);
3683
		return 1;
3684
	}
3685
	unset($dhcp6cscript);
3686
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3687

    
3688
	$rtsoldscript = "#!/bin/sh\n";
3689
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3690
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3691
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3692
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Recieved RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
3693
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3694
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3695
	$rtsoldscript .= "\t/bin/sleep 1\n";
3696
	$rtsoldscript .= "fi\n";
3697
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3698
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3699
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3700
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3701
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3702
		unset($rtsoldscript);
3703
		return 1;
3704
	}
3705
	unset($rtsoldscript);
3706
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3707

    
3708
	/* accept router advertisements for this interface */
3709
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3710
	log_error("Accept router advertisements on interface {$wanif} ");
3711
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3712

    
3713
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3714
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3715
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3716
		sleep(2);
3717
	}
3718
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3719

    
3720
	/* NOTE: will be called from rtsold invoked script
3721
	 * link_interface_to_track6($interface, "update");
3722
	 */
3723

    
3724
	return 0;
3725
}
3726

    
3727
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3728
	global $g;
3729

    
3730
	$send_options = "";
3731
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3732
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_send_options']);
3733
		foreach ($options as $option) {
3734
			$send_options .= "\tsend " . trim($option) . ";\n";
3735
		}
3736
	}
3737

    
3738
	$request_options = "";
3739
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3740
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_request_options']);
3741
		foreach ($options as $option) {
3742
			$request_options .= "\trequest " . trim($option) . ";\n";
3743
		}
3744
	}
3745

    
3746
	$information_only = "";
3747
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') 
3748
		$information_only = "\tinformation-only;\n";
3749

    
3750
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3751
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '')
3752
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3753

    
3754
	$interface_statement  = "interface";
3755
	$interface_statement .= " {$wanif}";
3756
	$interface_statement .= " {\n";
3757
	$interface_statement .= "$send_options";
3758
	$interface_statement .= "$request_options";
3759
	$interface_statement .= "$information_only";
3760
	$interface_statement .= "$script";
3761
	$interface_statement .= "};\n";
3762

    
3763
	$id_assoc_statement_address = "";
3764
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3765
		$id_assoc_statement_address .= "id-assoc";
3766
		$id_assoc_statement_address .= " na";
3767
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) 
3768
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3769
		$id_assoc_statement_address .= " { ";
3770

    
3771
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') && 
3772
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) || 
3773
			 ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity')) ) {
3774
			$id_assoc_statement_address .= "\n\taddress";
3775
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3776
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3777
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) || 
3778
							($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity') ) 
3779
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3780
			$id_assoc_statement_address .= ";\n";
3781
		}
3782

    
3783
		$id_assoc_statement_address  .= "};\n";
3784
	}
3785

    
3786
	$id_assoc_statement_prefix = "";
3787
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3788
		$id_assoc_statement_prefix .= "id-assoc";
3789
		$id_assoc_statement_prefix .= " pd";
3790
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) 
3791
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3792
		$id_assoc_statement_prefix .= " { ";
3793

    
3794
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') && 
3795
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) || 
3796
			 ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity')) ) {
3797
			$id_assoc_statement_prefix .= "\n\tprefix";
3798
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3799
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3800
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) || 
3801
						  ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity') ) 
3802
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3803
			$id_assoc_statement_prefix .= ";";
3804
		}
3805

    
3806
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3807
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3808
			$id_assoc_statement_prefix .= " {$wanif}";
3809
			$id_assoc_statement_prefix .= " {\n";
3810
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3811
			if ( ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) && 
3812
				 ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128) ) 
3813
				 $id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3814
			$id_assoc_statement_prefix .= "\t};";
3815
		}
3816

    
3817
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') || 
3818
			 (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) ) { 
3819
			$id_assoc_statement_prefix .= "\n";
3820
		}
3821

    
3822
		$id_assoc_statement_prefix  .= "};\n";
3823
	}
3824

    
3825
	$authentication_statement = "";
3826
	if ( ($wancfg['adv_dhcp6_authentication_statement_authname'] != '') && 
3827
		 ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed') ) {
3828
		$authentication_statement .= "authentication";
3829
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
3830
		$authentication_statement .= " {\n";
3831
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
3832
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) 
3833
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
3834
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') 
3835
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
3836
		$authentication_statement .= "};\n";
3837
	}
3838

    
3839
	$key_info_statement = "";
3840
	if ( ($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') && 
3841
		 ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') && 
3842
		 (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) && 
3843
		 ($wancfg['adv_dhcp6_key_info_statement_secret'] != '') ) {
3844
		$key_info_statement .= "keyinfo";
3845
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
3846
		$key_info_statement .= " {\n";
3847
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
3848
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
3849
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
3850
		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'])) 
3851
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
3852
		$key_info_statement .= "};\n";
3853
	}
3854

    
3855
	$dhcp6cconf  = $interface_statement;
3856
	$dhcp6cconf .= $id_assoc_statement_address;
3857
	$dhcp6cconf .= $id_assoc_statement_prefix;
3858
	$dhcp6cconf .= $authentication_statement;
3859
	$dhcp6cconf .= $key_info_statement;
3860

    
3861
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3862

    
3863
	return $dhcp6cconf;
3864
}
3865

    
3866

    
3867
function DHCP6_Config_File_Override($wancfg, $wanif) {
3868

    
3869
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
3870
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3871

    
3872
	return $dhcp6cconf;
3873
}
3874

    
3875

    
3876
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
3877

    
3878
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3879

    
3880
	return $dhcp6cconf;
3881
}
3882

    
3883

    
3884
function interface_dhcp_configure($interface = "wan") {
3885
	global $config, $g;
3886

    
3887
	$wancfg = $config['interfaces'][$interface];
3888
	$wanif = $wancfg['if'];
3889
	if (empty($wancfg))
3890
		$wancfg = array();
3891

    
3892
	/* generate dhclient_wan.conf */
3893
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3894
	if (!$fd) {
3895
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3896
		return 1;
3897
	}
3898

    
3899
	if ($wancfg['dhcphostname']) {
3900
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3901
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3902
	} else {
3903
		$dhclientconf_hostname = "";
3904
	}
3905

    
3906
	$wanif = get_real_interface($interface);
3907
	if (empty($wanif)) {
3908
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3909
		return 0;
3910
	}
3911
	$dhclientconf = "";
3912

    
3913
	$dhclientconf .= <<<EOD
3914
interface "{$wanif}" {
3915
timeout 60;
3916
retry 15;
3917
select-timeout 0;
3918
initial-interval 1;
3919
	{$dhclientconf_hostname}
3920
	script "/sbin/dhclient-script";
3921
EOD;
3922

    
3923
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3924
	$dhclientconf .= <<<EOD
3925

    
3926
	reject {$wancfg['dhcprejectfrom']};
3927
EOD;
3928
}
3929
	$dhclientconf .= <<<EOD
3930

    
3931
}
3932

    
3933
EOD;
3934

    
3935
	// DHCP Config File Advanced
3936
	if ($wancfg['adv_dhcp_config_advanced']) { $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif); }
3937

    
3938
if(is_ipaddr($wancfg['alias-address'])) {
3939
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3940
	$dhclientconf .= <<<EOD
3941
alias {
3942
	interface  "{$wanif}";
3943
	fixed-address {$wancfg['alias-address']};
3944
	option subnet-mask {$subnetmask};
3945
}
3946

    
3947
EOD;
3948
}
3949

    
3950
	// DHCP Config File Override
3951
	if ($wancfg['adv_dhcp_config_file_override']) { $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif); }
3952

    
3953
	fwrite($fd, $dhclientconf);
3954
	fclose($fd);
3955

    
3956
	/* bring wan interface up before starting dhclient */
3957
	if($wanif)
3958
		interfaces_bring_up($wanif);
3959
	else
3960
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3961

    
3962
	/* Make sure dhclient is not running */
3963
	kill_dhclient_process($wanif);
3964

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

    
3968
	return 0;
3969
}
3970

    
3971
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3972

    
3973
	$hostname = "";
3974
	if ($wancfg['dhcphostname'] != '') {
3975
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3976
	}
3977

    
3978
	/* DHCP Protocol Timings */
3979
	$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");
3980
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
3981
		$pt_variable = "{$Protocol_Timing}";
3982
		${$pt_variable} = "";
3983
		if ($wancfg[$Protocol_Timing] != "") {
3984
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
3985
		}
3986
	}
3987

    
3988
	$send_options = "";
3989
	if ($wancfg['adv_dhcp_send_options'] != '') {
3990
		$options = split(",", $wancfg['adv_dhcp_send_options']);
3991
		foreach ($options as $option) {
3992
			$send_options .= "\tsend " . trim($option) . ";\n";
3993
		}
3994
	}
3995

    
3996
	$request_options = "";
3997
	if ($wancfg['adv_dhcp_request_options'] != '') {
3998
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
3999
	}
4000

    
4001
	$required_options = "";
4002
	if ($wancfg['adv_dhcp_required_options'] != '') {
4003
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4004
	}
4005

    
4006
	$option_modifiers = "";
4007
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4008
		$modifiers = split(",", $wancfg['adv_dhcp_option_modifiers']);
4009
		foreach ($modifiers as $modifier) {
4010
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4011
		}
4012
	}
4013

    
4014
 	$dhclientconf  = "interface \"{$wanif}\" {\n";
4015
 	$dhclientconf .= "\n";
4016
 	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4017
 	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4018
 	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4019
 	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4020
 	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4021
 	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4022
 	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4023
 	$dhclientconf .= "\n";
4024
 	$dhclientconf .= "# DHCP Protocol Options\n";
4025
 	$dhclientconf .= "{$hostname}";
4026
 	$dhclientconf .= "{$send_options}";
4027
 	$dhclientconf .= "{$request_options}";
4028
 	$dhclientconf .= "{$required_options}";
4029
 	$dhclientconf .= "{$option_modifiers}";
4030
 	$dhclientconf .= "\n";
4031
 	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4032
 	$dhclientconf .= "}\n";
4033

    
4034
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4035

    
4036
	return $dhclientconf;
4037
}
4038

    
4039

    
4040
function DHCP_Config_File_Override($wancfg, $wanif) {
4041

    
4042
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4043
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4044

    
4045
	return $dhclientconf;
4046
}
4047

    
4048

    
4049
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4050

    
4051
	/* Apply Interface Substitutions */
4052
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4053

    
4054
	/* Apply Hostname Substitutions */
4055
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4056

    
4057
	/* Arrays of MAC Address Types, Cases, Delimiters */
4058
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4059
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4060
	$various_mac_cases      = array("U", "L");
4061
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4062

    
4063
	/* Apply MAC Address Substitutions */
4064
	foreach ($various_mac_types as $various_mac_type) {
4065
		foreach ($various_mac_cases as $various_mac_case) {
4066
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4067

    
4068
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4069
				if ($res !== false) {
4070

    
4071
					/* Get MAC Address as ASCII String With Colon (:) Celimiters */
4072
					if ("$various_mac_case" == "U") $dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4073
					if ("$various_mac_case" == "L") $dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4074

    
4075
					if ("$various_mac_type" == "mac_addr_hex") {
4076
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4077
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4078
						$dhcpclientconf_mac_hex = "";
4079
						$delimiter = "";
4080
						for($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4081
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4082
							$delimiter = ":";
4083
						}
4084
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4085
					}
4086

    
4087
					/* MAC Address Delimiter Substitutions */
4088
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4089

    
4090
					/* Apply MAC Address Substitutions */
4091
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4092
				}
4093
			}
4094
		}
4095
	}
4096

    
4097
	return $dhclientconf;
4098
}
4099

    
4100
function interfaces_group_setup() {
4101
	global $config;
4102

    
4103
	if (!is_array($config['ifgroups']['ifgroupentry']))
4104
		return;
4105

    
4106
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
4107
		interface_group_setup($groupar);
4108

    
4109
	return;
4110
}
4111

    
4112
function interface_group_setup(&$groupname /* The parameter is an array */) {
4113
	global $config;
4114

    
4115
	if (!is_array($groupname))
4116
		return;
4117
	$members = explode(" ", $groupname['members']);
4118
	foreach($members as $ifs) {
4119
		$realif = get_real_interface($ifs);
4120
		if ($realif)
4121
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4122
	}
4123

    
4124
	return;
4125
}
4126

    
4127
function is_interface_group($if) {
4128
	global $config;
4129

    
4130
	if (is_array($config['ifgroups']['ifgroupentry']))
4131
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4132
			if ($groupentry['ifname'] === $if)
4133
				return true;
4134
		}
4135

    
4136
	return false;
4137
}
4138

    
4139
function interface_group_add_member($interface, $groupname) {
4140
	$interface = get_real_interface($interface);
4141
	mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4142
}
4143

    
4144
/* COMPAT Function */
4145
function convert_friendly_interface_to_real_interface_name($interface) {
4146
	return get_real_interface($interface);
4147
}
4148

    
4149
/* COMPAT Function */
4150
function get_real_wan_interface($interface = "wan") {
4151
	return get_real_interface($interface);
4152
}
4153

    
4154
/* COMPAT Function */
4155
function get_current_wan_address($interface = "wan") {
4156
	return get_interface_ip($interface);
4157
}
4158

    
4159
/*
4160
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4161
 */
4162
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
4163
	global $config;
4164

    
4165
	if (stripos($interface, "_vip")) {
4166
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
4167
			if ($vip['mode'] == "carp")  {
4168
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4169
				return $vip['interface'];
4170
			}
4171
		}
4172
	}
4173

    
4174
	/* XXX: For speed reasons reference directly the interface array */
4175
	$ifdescrs = &$config['interfaces'];
4176
	//$ifdescrs = get_configured_interface_list(false, true);
4177

    
4178
	foreach ($ifdescrs as $if => $ifname) {
4179
		if ($if == $interface || $ifname['if'] == $interface)
4180
			return $if;
4181

    
4182
		if (get_real_interface($if) == $interface)
4183
			return $if;
4184

    
4185
		$int = get_parent_interface($if, true);
4186
		if (is_array($int)) {
4187
			foreach ($int as $iface) {
4188
				if ($iface == $interface)
4189
					return $if;
4190
			}
4191
		}
4192
	}
4193

    
4194
	if ($interface == "enc0")
4195
		return 'IPsec';
4196

    
4197
	return NULL;
4198
}
4199

    
4200
/* attempt to resolve interface to friendly descr */
4201
function convert_friendly_interface_to_friendly_descr($interface) {
4202
	global $config;
4203

    
4204
	switch ($interface) {
4205
	case "l2tp":
4206
		$ifdesc = "L2TP";
4207
		break;
4208
	case "pptp":
4209
		$ifdesc = "PPTP";
4210
		break;
4211
	case "pppoe":
4212
		$ifdesc = "PPPoE";
4213
		break;
4214
	case "openvpn":
4215
		$ifdesc = "OpenVPN";
4216
		break;
4217
	case "enc0":
4218
	case "ipsec":
4219
	case "IPsec":
4220
		$ifdesc = "IPsec";
4221
		break;
4222
	default:
4223
		if (isset($config['interfaces'][$interface])) {
4224
			if (empty($config['interfaces'][$interface]['descr']))
4225
				$ifdesc = strtoupper($interface);
4226
			else
4227
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4228
			break;
4229
		} else if (stristr($interface, "_vip")) {
4230
			if (is_array($config['virtualip']['vip'])) {
4231
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
4232
					if ($vip['mode'] == "carp")  {
4233
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4234
							return "{$vip['subnet']} - {$vip['descr']}";
4235
					}
4236
				}
4237
			}
4238
		} else {
4239
			/* if list */
4240
			$ifdescrs = get_configured_interface_with_descr(false, true);
4241
			foreach ($ifdescrs as $if => $ifname) {
4242
				if ($if == $interface || $ifname == $interface)
4243
					return $ifname;
4244
			}
4245
		}
4246
		break;
4247
	}
4248

    
4249
	return $ifdesc;
4250
}
4251

    
4252
function convert_real_interface_to_friendly_descr($interface) {
4253

    
4254
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4255

    
4256
	if (!empty($ifdesc))
4257
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4258

    
4259
	return $interface;
4260
}
4261

    
4262
/*
4263
 *  get_parent_interface($interface):
4264
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4265
 *				or virtual interface (i.e. vlan)
4266
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4267
 *			-- returns $interface passed in if $interface parent is not found
4268
 *			-- returns empty array if an invalid interface is passed
4269
 *	(Only handles ppps and vlans now.)
4270
 */
4271
function get_parent_interface($interface, $avoidrecurse = false) {
4272
	global $config;
4273

    
4274
	$parents = array();
4275
	//Check that we got a valid interface passed
4276
	$realif = get_real_interface($interface);
4277
	if ($realif == NULL)
4278
		return $parents;
4279

    
4280
	// If we got a real interface, find it's friendly assigned name
4281
	if ($interface == $realif && $avoidrecurse == false)
4282
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4283

    
4284
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4285
		$ifcfg = $config['interfaces'][$interface];
4286
		switch ($ifcfg['ipaddr']) {
4287
			case "ppp":
4288
			case "pppoe":
4289
			case "pptp":
4290
			case "l2tp":
4291
				if (empty($parents))
4292
					if (is_array($config['ppps']['ppp']))
4293
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4294
							if ($ifcfg['if'] == $ppp['if']) {
4295
								$ports = explode(',', $ppp['ports']);
4296
								foreach ($ports as $pid => $parent_if)
4297
									$parents[$pid] = get_real_interface($parent_if);
4298
								break;
4299
							}
4300
						}
4301
				break;
4302
			case "dhcp":
4303
			case "static":
4304
			default:
4305
				// Handle _vlans
4306
				if (stristr($realif,"_vlan"))
4307
					if (is_array($config['vlans']['vlan']))
4308
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
4309
							if ($ifcfg['if'] == $vlan['vlanif']){
4310
								$parents[0] = $vlan['if'];
4311
								break;
4312
							}
4313
				break;
4314
		}
4315
	}
4316

    
4317
	if (empty($parents))
4318
		$parents[0] = $realif;
4319

    
4320
	return $parents;
4321
}
4322

    
4323
function interface_is_wireless_clone($wlif) {
4324
	if(!stristr($wlif, "_wlan")) {
4325
		return false;
4326
	} else {
4327
		return true;
4328
	}
4329
}
4330

    
4331
function interface_get_wireless_base($wlif) {
4332
	if(!stristr($wlif, "_wlan")) {
4333
		return $wlif;
4334
	} else {
4335
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4336
	}
4337
}
4338

    
4339
function interface_get_wireless_clone($wlif) {
4340
	if(!stristr($wlif, "_wlan")) {
4341
		return $wlif . "_wlan0";
4342
	} else {
4343
		return $wlif;
4344
	}
4345
}
4346

    
4347
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4348
	global $config, $g;
4349

    
4350
	$wanif = NULL;
4351

    
4352
	switch ($interface) {
4353
	case "l2tp":
4354
		$wanif = "l2tp";
4355
		break;
4356
	case "pptp":
4357
		$wanif = "pptp";
4358
		break;
4359
	case "pppoe":
4360
		$wanif = "pppoe";
4361
		break;
4362
	case "openvpn":
4363
		$wanif = "openvpn";
4364
		break;
4365
	case "ipsec":
4366
	case "enc0":
4367
		$wanif = "enc0";
4368
		break;
4369
	case "ppp":
4370
		$wanif = "ppp";
4371
		break;
4372
	default:
4373
		// If a real interface was alread passed simply
4374
		// pass the real interface back.  This encourages
4375
		// the usage of this function in more cases so that
4376
		// we can combine logic for more flexibility.
4377
		if(does_interface_exist($interface, $flush)) {
4378
			$wanif = $interface;
4379
			break;
4380
		}
4381

    
4382
		if (empty($config['interfaces'][$interface]))
4383
			break;
4384

    
4385
		$cfg = &$config['interfaces'][$interface];
4386

    
4387
		if ($family == "inet6") {
4388
			switch ($cfg['ipaddrv6']) {
4389
			case "6rd":
4390
			case "6to4":
4391
				$wanif = "{$interface}_stf";
4392
				break;
4393
			case 'pppoe':
4394
			case 'ppp':
4395
			case 'l2tp':
4396
			case 'pptp':
4397
				if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4398
					$wanif = interface_get_wireless_clone($cfg['if']);
4399
				else
4400
					$wanif = $cfg['if'];
4401
				break;
4402
			default:
4403
				switch ($cfg['ipaddr']) {
4404
				case 'pppoe':
4405
				case 'ppp':
4406
				case 'l2tp':
4407
				case 'pptp':
4408
					if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false)
4409
						$wanif = $cfg['if'];
4410
					else {
4411
						$parents = get_parent_interface($interface);
4412
						if (!empty($parents[0]))
4413
							$wanif = $parents[0];
4414
						else
4415
							$wanif = $cfg['if'];
4416
					}
4417
					break;
4418
				default:
4419
					if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4420
						$wanif = interface_get_wireless_clone($cfg['if']);
4421
					else
4422
						$wanif = $cfg['if'];
4423
					break;
4424
				}
4425
				break;
4426
			}
4427
		} else {
4428
			// Wireless cloned NIC support (FreeBSD 8+)
4429
			// interface name format: $parentnic_wlanparentnic#
4430
			// example: ath0_wlan0
4431
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4432
				$wanif = interface_get_wireless_clone($cfg['if']);
4433
			else
4434
				$wanif = $cfg['if'];
4435
		}
4436
		break;
4437
	}
4438

    
4439
	return $wanif;
4440
}
4441

    
4442
/* Guess the physical interface by providing a IP address */
4443
function guess_interface_from_ip($ipaddress) {
4444
	if(! is_ipaddr($ipaddress)) {
4445
		return false;
4446
	}
4447
	if(is_ipaddrv4($ipaddress)) {
4448
		/* create a route table we can search */
4449
		exec("/usr/bin/netstat -rnWf inet", $output, $ret);
4450
		foreach($output as $line) {
4451
			if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
4452
				$fields = preg_split("/[ ]+/", $line);
4453
				if(ip_in_subnet($ipaddress, $fields[0])) {
4454
					return $fields[5];
4455
				}
4456
			}
4457
		}
4458
	}
4459
	/* FIXME: This works from cursory testing, regexp might need fine tuning */
4460
	if(is_ipaddrv6($ipaddress)) {
4461
		/* create a route table we can search */
4462
		exec("/usr/bin/netstat -rnWf inet6", $output, $ret);
4463
		foreach($output as $line) {
4464
			if(preg_match("/[0-9a-f]+[:]+[0-9a-f]+[:]+[\/][0-9]+/", $line)) {
4465
				$fields = preg_split("/[ ]+/", $line);
4466
				if(ip_in_subnet($ipaddress, $fields[0])) {
4467
					return $fields[5];
4468
				}
4469
			}
4470
		}
4471
	}
4472
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
4473
	if(empty($ret)) {
4474
		return false;
4475
	}
4476
	return $ret;
4477
}
4478

    
4479
/*
4480
 * find_ip_interface($ip): return the interface where an ip is defined
4481
 *   (or if $bits is specified, where an IP within the subnet is defined)
4482
 */
4483
function find_ip_interface($ip, $bits = null) {
4484
	if (!is_ipaddr($ip))
4485
		return false;
4486

    
4487
	$isv6ip = is_ipaddrv6($ip);
4488

    
4489
	/* if list */
4490
	$ifdescrs = get_configured_interface_list();
4491

    
4492
	foreach ($ifdescrs as $ifdescr => $ifname) {
4493
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4494
		if (is_null($ifip))
4495
			continue;
4496
		if (is_null($bits)) {
4497
			if ($ip == $ifip) {
4498
				$int = get_real_interface($ifname);
4499
				return $int;
4500
			}
4501
		}
4502
		else {
4503
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4504
				$int = get_real_interface($ifname);
4505
				return $int;
4506
			}
4507
		}
4508
	}
4509

    
4510
	return false;
4511
}
4512

    
4513
/*
4514
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4515
 *   (or if $bits is specified, where an IP within the subnet is found)
4516
 */
4517
function find_virtual_ip_alias($ip, $bits = null) {
4518
	global $config;
4519

    
4520
	if (!is_array($config['virtualip']['vip'])) {
4521
		return false;
4522
	}
4523
	if (!is_ipaddr($ip))
4524
		return false;
4525

    
4526
	$isv6ip = is_ipaddrv6($ip);
4527

    
4528
	foreach ($config['virtualip']['vip'] as $vip) {
4529
		if ($vip['mode'] === "ipalias") {
4530
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4531
				continue;
4532
			if (is_null($bits)) {
4533
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4534
					return $vip;
4535
				}
4536
			}
4537
			else {
4538
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4539
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4540
					return $vip;
4541
				}
4542
			}
4543
		}
4544
	}
4545
	return false;
4546
}
4547

    
4548
/*
4549
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4550
 */
4551
function find_number_of_created_carp_interfaces() {
4552
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4553
}
4554

    
4555
/*
4556
 * find_carp_interface($ip): return the carp interface where an ip is defined
4557
 */
4558
function find_carp_interface($ip) {
4559
	global $config;
4560
	if (is_array($config['virtualip']['vip'])) {
4561
		foreach ($config['virtualip']['vip'] as $vip) {
4562
			if ($vip['mode'] == "carp") {
4563
				if(is_ipaddrv4($ip)) {
4564
					$carp_ip = get_interface_ip($vip['interface']);
4565
				}
4566
				if(is_ipaddrv6($ip)) {
4567
					$carp_ip = get_interface_ipv6($vip['interface']);
4568
				}
4569
				exec("/sbin/ifconfig", $output, $return);
4570
				foreach($output as $line) {
4571
					$elements = preg_split("/[ ]+/i", $line);
4572
					if(strstr($elements[0], "vip"))
4573
						$curif = str_replace(":", "", $elements[0]);
4574
					if(stristr($line, $ip)) {
4575
						$if = $curif;
4576
						continue;
4577
					}
4578
				}
4579

    
4580
				if ($if)
4581
					return $if;
4582
			}
4583
		}
4584
	}
4585
}
4586

    
4587
function link_carp_interface_to_parent($interface) {
4588
	global $config;
4589

    
4590
	if (empty($interface))
4591
		return;
4592

    
4593
	$carp_ip = get_interface_ip($interface);
4594
	$carp_ipv6 = get_interface_ipv6($interface);
4595

    
4596
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4597
		return;
4598

    
4599
	/* if list */
4600
	$ifdescrs = get_configured_interface_list();
4601
	foreach ($ifdescrs as $ifdescr => $ifname) {
4602
		/* check IPv4 */
4603
		if(is_ipaddrv4($carp_ip)) {
4604
			$interfaceip = get_interface_ip($ifname);
4605
			$subnet_bits = get_interface_subnet($ifname);
4606
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4607
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4608
				return $ifname;
4609
		}
4610
		/* Check IPv6 */
4611
		if(is_ipaddrv6($carp_ipv6)) {
4612
			$interfaceipv6 = get_interface_ipv6($ifname);
4613
			$prefixlen = get_interface_subnetv6($ifname);
4614
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4615
				return $ifname;
4616
		}
4617
	}
4618
	return "";
4619
}
4620

    
4621

    
4622
/****f* interfaces/link_ip_to_carp_interface
4623
 * NAME
4624
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4625
 * INPUTS
4626
 *   $ip
4627
 * RESULT
4628
 *   $carp_ints
4629
 ******/
4630
function link_ip_to_carp_interface($ip) {
4631
	global $config;
4632

    
4633
	if (!is_ipaddr($ip))
4634
		return;
4635

    
4636
	$carp_ints = "";
4637
	if (is_array($config['virtualip']['vip'])) {
4638
		$first = 0;
4639
		$carp_int = array();
4640
		foreach ($config['virtualip']['vip'] as $vip) {
4641
			if ($vip['mode'] == "carp") {
4642
				$carp_ip = $vip['subnet'];
4643
				$carp_sn = $vip['subnet_bits'];
4644
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4645
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4646
					$carp_int[] = get_real_interface($vip['interface']);
4647
				}
4648
			}
4649
		}
4650
		if (!empty($carp_int))
4651
			$carp_ints = implode(" ", array_unique($carp_int));
4652
	}
4653

    
4654
	return $carp_ints;
4655
}
4656

    
4657
function link_interface_to_track6($int, $action = "") {
4658
	global $config;
4659

    
4660
	if (empty($int))
4661
		return;
4662

    
4663
	if (is_array($config['interfaces'])) {
4664
		$list = array();
4665
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4666
			if (!isset($ifcfg['enable']))
4667
				continue;
4668
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4669
				if ($action == "update")
4670
					interface_track6_configure($ifname, $ifcfg);
4671
				else if ($action == "")
4672
					$list[$ifname] = $ifcfg;
4673
			}
4674
		}
4675
		return $list;
4676
	}
4677
}
4678

    
4679
function link_interface_to_vlans($int, $action = "") {
4680
	global $config;
4681

    
4682
	if (empty($int))
4683
		return;
4684

    
4685
	if (is_array($config['vlans']['vlan'])) {
4686
		$ifaces = array();
4687
		foreach ($config['vlans']['vlan'] as $vlan) {
4688
			if ($int == $vlan['if']) {
4689
				if ($action == "update") {
4690
					interfaces_bring_up($int);
4691
				} else if ($action == "")
4692
					$ifaces[$vlan['tag']] = $vlan;
4693
			}
4694
		}
4695
		if (!empty($ifaces))
4696
			return $ifaces;
4697
	}
4698
}
4699

    
4700
function link_interface_to_vips($int, $action = "") {
4701
	global $config;
4702

    
4703
	if (is_array($config['virtualip']['vip'])) {
4704
		$result = array();
4705
		foreach ($config['virtualip']['vip'] as $vip) {
4706
			if ($int == $vip['interface']) {
4707
				if ($action == "update")
4708
					interfaces_vips_configure($int);
4709
				else
4710
					$result[] = $vip;
4711
			}
4712
		}
4713
		return $result;
4714
	}
4715
}
4716

    
4717
/****f* interfaces/link_interface_to_bridge
4718
 * NAME
4719
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4720
 * INPUTS
4721
 *   $ip
4722
 * RESULT
4723
 *   bridge[0-99]
4724
 ******/
4725
function link_interface_to_bridge($int) {
4726
	global $config;
4727

    
4728
	if (is_array($config['bridges']['bridged'])) {
4729
		foreach ($config['bridges']['bridged'] as $bridge) {
4730
			if (in_array($int, explode(',', $bridge['members'])))
4731
				return "{$bridge['bridgeif']}";
4732
		}
4733
	}
4734
}
4735

    
4736
function link_interface_to_group($int) {
4737
	global $config;
4738

    
4739
	$result = array();
4740

    
4741
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4742
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4743
			if (in_array($int, explode(" ", $group['members'])))
4744
				$result[$group['ifname']] = $int;
4745
		}
4746
	}
4747

    
4748
	return $result;
4749
}
4750

    
4751
function link_interface_to_gre($interface) {
4752
	global $config;
4753

    
4754
	$result = array();
4755

    
4756
	if (is_array($config['gres']['gre'])) {
4757
		foreach ($config['gres']['gre'] as $gre)
4758
			if($gre['if'] == $interface)
4759
				$result[] = $gre;
4760
	}
4761

    
4762
	return $result;
4763
}
4764

    
4765
function link_interface_to_gif($interface) {
4766
	global $config;
4767

    
4768
	$result = array();
4769

    
4770
	if (is_array($config['gifs']['gif'])) {
4771
		foreach ($config['gifs']['gif'] as $gif)
4772
			if($gif['if'] == $interface)
4773
				$result[] = $gif;
4774
	}
4775

    
4776
	return $result;
4777
}
4778

    
4779
/*
4780
 * find_interface_ip($interface): return the interface ip (first found)
4781
 */
4782
function find_interface_ip($interface, $flush = false) {
4783
	global $interface_ip_arr_cache;
4784
	global $interface_sn_arr_cache;
4785

    
4786
	$interface = str_replace("\n", "", $interface);
4787

    
4788
	if (!does_interface_exist($interface))
4789
		return;
4790

    
4791
	/* Setup IP cache */
4792
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4793
		$ifinfo = pfSense_get_interface_addresses($interface);
4794
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4795
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4796
	}
4797

    
4798
	return $interface_ip_arr_cache[$interface];
4799
}
4800

    
4801
/*
4802
 * find_interface_ipv6($interface): return the interface ip (first found)
4803
 */
4804
function find_interface_ipv6($interface, $flush = false) {
4805
	global $interface_ipv6_arr_cache;
4806
	global $interface_snv6_arr_cache;
4807
	global $config;
4808

    
4809
	$interface = trim($interface);
4810
	$interface = get_real_interface($interface);
4811

    
4812
	if (!does_interface_exist($interface))
4813
		return;
4814

    
4815
	/* Setup IP cache */
4816
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4817
		$ifinfo = pfSense_get_interface_addresses($interface);
4818
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4819
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4820
	}
4821

    
4822
	return $interface_ipv6_arr_cache[$interface];
4823
}
4824

    
4825
/*
4826
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4827
 */
4828
function find_interface_ipv6_ll($interface, $flush = false) {
4829
	global $interface_llv6_arr_cache;
4830
	global $config;
4831

    
4832
	$interface = str_replace("\n", "", $interface);
4833

    
4834
	if (!does_interface_exist($interface))
4835
		return;
4836

    
4837
	/* Setup IP cache */
4838
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4839
		$ifinfo = pfSense_getall_interface_addresses($interface);
4840
		foreach($ifinfo as $line) {
4841
			if (strstr($line, ":")) {
4842
				$parts = explode("/", $line);
4843
				if(is_linklocal($parts[0])) {
4844
					$ifinfo['linklocal'] = $parts[0];
4845
				}
4846
			}
4847
		}
4848
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4849
	}
4850
	return $interface_llv6_arr_cache[$interface];
4851
}
4852

    
4853
function find_interface_subnet($interface, $flush = false) {
4854
	global $interface_sn_arr_cache;
4855
	global $interface_ip_arr_cache;
4856

    
4857
	$interface = str_replace("\n", "", $interface);
4858
	if (does_interface_exist($interface) == false)
4859
		return;
4860

    
4861
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4862
		$ifinfo = pfSense_get_interface_addresses($interface);
4863
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4864
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4865
	}
4866

    
4867
	return $interface_sn_arr_cache[$interface];
4868
}
4869

    
4870
function find_interface_subnetv6($interface, $flush = false) {
4871
	global $interface_snv6_arr_cache;
4872
	global $interface_ipv6_arr_cache;
4873

    
4874
	$interface = str_replace("\n", "", $interface);
4875
	if (does_interface_exist($interface) == false)
4876
		return;
4877

    
4878
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4879
		$ifinfo = pfSense_get_interface_addresses($interface);
4880
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4881
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4882
	}
4883

    
4884
	return $interface_snv6_arr_cache[$interface];
4885
}
4886

    
4887
function ip_in_interface_alias_subnet($interface, $ipalias) {
4888
	global $config;
4889

    
4890
	if (empty($interface) || !is_ipaddr($ipalias))
4891
		return false;
4892
	if (is_array($config['virtualip']['vip'])) {
4893
		foreach ($config['virtualip']['vip'] as $vip) {
4894
			switch ($vip['mode']) {
4895
			case "ipalias":
4896
				if ($vip['interface'] <> $interface)
4897
					break;
4898
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4899
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4900
					return true;
4901
				break;
4902
			}
4903
		}
4904
	}
4905

    
4906
	return false;
4907
}
4908

    
4909
function get_interface_ip($interface = "wan") {
4910
	$realif = get_failover_interface($interface);
4911
	if (!$realif) {
4912
		if (strstr($interface, "_vip"))
4913
			return get_configured_carp_interface_list($interface);
4914
		else
4915
			return null;
4916
	}
4917

    
4918
	$curip = find_interface_ip($realif);
4919
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4920
		return $curip;
4921
	else
4922
		return null;
4923
}
4924

    
4925
function get_interface_ipv6($interface = "wan", $flush = false) {
4926
	global $config;
4927

    
4928
	$realif = get_failover_interface($interface, "inet6");
4929
	if (!$realif) {
4930
		if (strstr($interface, "_vip"))
4931
			return get_configured_carp_interface_list($interface, "inet6");
4932
		else
4933
			return null;
4934
	}
4935

    
4936
	/*
4937
	 * NOTE: On the case when only the prefix is requested,
4938
	 * the communication on WAN will be done over link-local.
4939
	 */
4940
	if (is_array($config['interfaces'][$interface])) {
4941
		switch ($config['interfaces'][$interface]['ipaddr']) {
4942
		case 'pppoe':
4943
		case 'l2tp':
4944
		case 'pptp':
4945
		case 'ppp':
4946
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4947
				$realif = get_real_interface($interface, "inet6", true);
4948
			break;
4949
		}
4950
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4951
			$curip = find_interface_ipv6_ll($realif, $flush);
4952
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4953
				return $curip;
4954
		}
4955
	}
4956

    
4957
	$curip = find_interface_ipv6($realif, $flush);
4958
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4959
		return $curip;
4960
	else
4961
		return null;
4962
}
4963

    
4964
function get_interface_linklocal($interface = "wan") {
4965

    
4966
	$realif = get_failover_interface($interface, "inet6");
4967
	if (!$realif) {
4968
		if (strstr($interface, "_vip")) {
4969
			list($interface, $vhid) = explode("_vip", $interface);
4970
			$realif = get_real_interface($interface);
4971
		} else
4972
			return null;
4973
	}
4974

    
4975
	$curip = find_interface_ipv6_ll($realif);
4976
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4977
		return $curip;
4978
	else
4979
		return null;
4980
}
4981

    
4982
function get_interface_subnet($interface = "wan") {
4983
	$realif = get_real_interface($interface);
4984
	if (!$realif) {
4985
		if (strstr($interface, "_vip")) {
4986
			list($interface, $vhid) = explode("_vip", $interface);
4987
			$realif = get_real_interface($interface);
4988
		} else
4989
			return null;
4990
	}
4991

    
4992
	$cursn = find_interface_subnet($realif);
4993
	if (!empty($cursn))
4994
		return $cursn;
4995

    
4996
	return null;
4997
}
4998

    
4999
function get_interface_subnetv6($interface = "wan") {
5000
	global $config;
5001

    
5002
	$realif = get_real_interface($interface, "inet6");
5003
	if (!$realif) {
5004
		if (strstr($interface, "_vip")) {
5005
			list($interface, $vhid) = explode("_vip", $interface);
5006
			$realif = get_real_interface($interface);
5007
		} else
5008
			return null;
5009
	}
5010

    
5011
	$cursn = find_interface_subnetv6($realif);
5012
	if (!empty($cursn))
5013
		return $cursn;
5014

    
5015
	return null;
5016
}
5017

    
5018
/* return outside interfaces with a gateway */
5019
function get_interfaces_with_gateway() {
5020
	global $config;
5021

    
5022
	$ints = array();
5023

    
5024
	/* loop interfaces, check config for outbound */
5025
	foreach($config['interfaces'] as $ifdescr => $ifname) {
5026
		switch ($ifname['ipaddr']) {
5027
			case "dhcp":
5028
			case "ppp";
5029
			case "pppoe":
5030
			case "pptp":
5031
			case "l2tp":
5032
			case "ppp";
5033
				$ints[$ifdescr] = $ifdescr;
5034
			break;
5035
			default:
5036
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
5037
				    !empty($ifname['gateway']))
5038
					$ints[$ifdescr] = $ifdescr;
5039
			break;
5040
		}
5041
	}
5042
	return $ints;
5043
}
5044

    
5045
/* return true if interface has a gateway */
5046
function interface_has_gateway($friendly) {
5047
	global $config;
5048

    
5049
	if (!empty($config['interfaces'][$friendly])) {
5050
		$ifname = &$config['interfaces'][$friendly];
5051
		switch ($ifname['ipaddr']) {
5052
			case "dhcp":
5053
			case "pppoe":
5054
			case "pptp":
5055
			case "l2tp":
5056
			case "ppp";
5057
				return true;
5058
			break;
5059
			default:
5060
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
5061
					return true;
5062
				$tunnelif = substr($ifname['if'], 0, 3);
5063
				if ($tunnelif == "gif" || $tunnelif == "gre")
5064
					return true;
5065
				if (!empty($ifname['gateway']))
5066
					return true;
5067
			break;
5068
		}
5069
	}
5070

    
5071
	return false;
5072
}
5073

    
5074
/* return true if interface has a gateway */
5075
function interface_has_gatewayv6($friendly) {
5076
	global $config;
5077

    
5078
	if (!empty($config['interfaces'][$friendly])) {
5079
		$ifname = &$config['interfaces'][$friendly];
5080
		switch ($ifname['ipaddrv6']) {
5081
			case "slaac":
5082
			case "dhcp6":
5083
			case "6to4":
5084
			case "6rd":
5085
				return true;
5086
				break;
5087
			default:
5088
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
5089
					return true;
5090
				$tunnelif = substr($ifname['if'], 0, 3);
5091
				if ($tunnelif == "gif" || $tunnelif == "gre")
5092
					return true;
5093
				if (!empty($ifname['gatewayv6']))
5094
					return true;
5095
				break;
5096
		}
5097
	}
5098

    
5099
	return false;
5100
}
5101

    
5102
/****f* interfaces/is_altq_capable
5103
 * NAME
5104
 *   is_altq_capable - Test if interface is capable of using ALTQ
5105
 * INPUTS
5106
 *   $int            - string containing interface name
5107
 * RESULT
5108
 *   boolean         - true or false
5109
 ******/
5110

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

    
5124
	$int_family = remove_ifindex($int);
5125

    
5126
	if (in_array($int_family, $capable))
5127
		return true;
5128
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
5129
		return true;
5130
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
5131
		return true;
5132
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
5133
		return true;
5134
	else
5135
		return false;
5136
}
5137

    
5138
/****f* interfaces/is_interface_wireless
5139
 * NAME
5140
 *   is_interface_wireless - Returns if an interface is wireless
5141
 * RESULT
5142
 *   $tmp       - Returns if an interface is wireless
5143
 ******/
5144
function is_interface_wireless($interface) {
5145
	global $config, $g;
5146

    
5147
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5148
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
5149
		if (preg_match($g['wireless_regex'], $interface)) {
5150
			if (isset($config['interfaces'][$friendly]))
5151
				$config['interfaces'][$friendly]['wireless'] = array();
5152
			return true;
5153
		}
5154
		return false;
5155
	} else
5156
		return true;
5157
}
5158

    
5159
function get_wireless_modes($interface) {
5160
	/* return wireless modes and channels */
5161
	$wireless_modes = array();
5162

    
5163
	$cloned_interface = get_real_interface($interface);
5164

    
5165
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5166
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5167
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5168
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5169

    
5170
		$interface_channels = "";
5171
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5172
		$interface_channel_count = count($interface_channels);
5173

    
5174
		$c = 0;
5175
		while ($c < $interface_channel_count) {
5176
			$channel_line = explode(",", $interface_channels["$c"]);
5177
			$wireless_mode = trim($channel_line[0]);
5178
			$wireless_channel = trim($channel_line[1]);
5179
			if(trim($wireless_mode) != "") {
5180
				/* if we only have 11g also set 11b channels */
5181
				if($wireless_mode == "11g") {
5182
					if(!isset($wireless_modes["11b"]))
5183
						$wireless_modes["11b"] = array();
5184
				} else if($wireless_mode == "11g ht") {
5185
					if(!isset($wireless_modes["11b"]))
5186
						$wireless_modes["11b"] = array();
5187
					if(!isset($wireless_modes["11g"]))
5188
						$wireless_modes["11g"] = array();
5189
					$wireless_mode = "11ng";
5190
				} else if($wireless_mode == "11a ht") {
5191
					if(!isset($wireless_modes["11a"]))
5192
						$wireless_modes["11a"] = array();
5193
					$wireless_mode = "11na";
5194
				}
5195
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5196
			}
5197
			$c++;
5198
		}
5199
	}
5200
	return($wireless_modes);
5201
}
5202

    
5203
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5204
function get_wireless_channel_info($interface) {
5205
	$wireless_channels = array();
5206

    
5207
	$cloned_interface = get_real_interface($interface);
5208

    
5209
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5210
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5211
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5212
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5213

    
5214
		$interface_channels = "";
5215
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5216

    
5217
		foreach ($interface_channels as $channel_line) {
5218
			$channel_line = explode(",", $channel_line);
5219
			if(!isset($wireless_channels[$channel_line[0]]))
5220
				$wireless_channels[$channel_line[0]] = $channel_line;
5221
		}
5222
	}
5223
	return($wireless_channels);
5224
}
5225

    
5226
/****f* interfaces/get_interface_mtu
5227
 * NAME
5228
 *   get_interface_mtu - Return the mtu of an interface
5229
 * RESULT
5230
 *   $tmp       - Returns the mtu of an interface
5231
 ******/
5232
function get_interface_mtu($interface) {
5233
	$mtu = pfSense_get_interface_addresses($interface);
5234
	return $mtu['mtu'];
5235
}
5236

    
5237
function get_interface_mac($interface) {
5238

    
5239
	$macinfo = pfSense_get_interface_addresses($interface);
5240
	return $macinfo["macaddr"];
5241
}
5242

    
5243
/****f* pfsense-utils/generate_random_mac_address
5244
 * NAME
5245
 *   generate_random_mac - generates a random mac address
5246
 * INPUTS
5247
 *   none
5248
 * RESULT
5249
 *   $mac - a random mac address
5250
 ******/
5251
function generate_random_mac_address() {
5252
	$mac = "02";
5253
	for($x=0; $x<5; $x++)
5254
		$mac .= ":" . dechex(rand(16, 255));
5255
	return $mac;
5256
}
5257

    
5258
/****f* interfaces/is_jumbo_capable
5259
 * NAME
5260
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5261
 * INPUTS
5262
 *   $int             - string containing interface name
5263
 * RESULT
5264
 *   boolean          - true or false
5265
 ******/
5266
function is_jumbo_capable($iface) {
5267
	$iface = trim($iface);
5268
	$capable = pfSense_get_interface_addresses($iface);
5269

    
5270
	if (isset($capable['caps']['vlanmtu']))
5271
		return true;
5272

    
5273
	return false;
5274
}
5275

    
5276
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5277
	global $g;
5278

    
5279
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5280

    
5281
	if(!empty($iface) && !empty($pppif)){
5282
		$cron_cmd = <<<EOD
5283
#!/bin/sh
5284
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5285
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5286

    
5287
EOD;
5288

    
5289
		@file_put_contents($cron_file, $cron_cmd);
5290
		chmod($cron_file, 0755);
5291
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5292
	} else
5293
		unlink_if_exists($cron_file);
5294
}
5295

    
5296
function get_interface_default_mtu($type = "ethernet") {
5297
	switch ($type) {
5298
	case "gre":
5299
		return 1476;
5300
		break;
5301
	case "gif":
5302
		return 1280;
5303
		break;
5304
	case "tun":
5305
	case "vlan":
5306
	case "tap":
5307
	case "ethernet":
5308
	default:
5309
		return 1500;
5310
		break;
5311
	}
5312

    
5313
	/* Never reached */
5314
	return 1500;
5315
}
5316

    
5317
function get_vip_descr($ipaddress) {
5318
	global $config;
5319

    
5320
	foreach ($config['virtualip']['vip'] as $vip) {
5321
		if ($vip['subnet'] == $ipaddress) {
5322
			return ($vip['descr']);
5323
		}
5324
	}
5325
	return "";
5326
}
5327

    
5328
function interfaces_staticarp_configure($if) {
5329
	global $config, $g;
5330
	if(isset($config['system']['developerspew'])) {
5331
		$mt = microtime();
5332
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5333
	}
5334

    
5335
	$ifcfg = $config['interfaces'][$if];
5336

    
5337
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5338
		return 0;
5339

    
5340
	/* Enable staticarp, if enabled */
5341
	if(isset($config['dhcpd'][$if]['staticarp'])) {
5342
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
5343
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5344
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5345

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

    
5349
			}
5350

    
5351
		}
5352
	} else {
5353
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
5354
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5355
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5356
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5357
				if (isset($arpent['arp_table_static_entry'])) {
5358
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5359
				}
5360
			}
5361
		}
5362
	}
5363

    
5364
	return 0;
5365
}
5366

    
5367
function get_failover_interface($interface, $family = "all") {
5368
	global $config;
5369

    
5370
	/* shortcut to get_real_interface if we find it in the config */
5371
	if (is_array($config['interfaces'][$interface])) {
5372
		return get_real_interface($interface, $family);
5373
	}
5374

    
5375
	/* compare against gateway groups */
5376
	$a_groups = return_gateway_groups_array();
5377
	if (is_array($a_groups[$interface])) {
5378
		/* we found a gateway group, fetch the interface or vip */
5379
		if ($a_groups[$interface][0]['vip'] <> "")
5380
			return $a_groups[$interface][0]['vip'];
5381
		else
5382
			return $a_groups[$interface][0]['int'];
5383
	}
5384
	/* fall through to get_real_interface */
5385
	/* XXX: Really needed? */
5386
	return get_real_interface($interface, $family);
5387
}
5388

    
5389
function remove_ifindex($ifname) {
5390
	return preg_replace("/[0-9]+$/", "", $ifname);
5391
}
5392

    
5393
?>
(26-26/68)