Projet

Général

Profil

Télécharger (160 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / etc / inc / interfaces.inc @ ed10564b

1
<?php
2
/*
3
	interfaces.inc
4
	Copyright (C) 2004-2008 Scott Ullrich
5
	Copyright (C) 2008-2009 Ermal Lu?i
6
	All rights reserved.
7

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

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

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

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

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

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

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

    
42
*/
43

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

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

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

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

    
68
	return $interface_arr_cache;
69
}
70

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

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

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

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

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

    
98

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

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

    
120
	return false;
121
}
122

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
266
	interfaces_bring_up($vlanif);
267

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

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

    
274
	return $vlanif;
275
}
276

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

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

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

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

    
297
	$vlanif = interface_vlan_configure($vlan);
298

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

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

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

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

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

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

    
350
	return $vlanif;
351
}
352

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

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

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

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

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

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

    
393
	return $vlanif;
394
}
395

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

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

    
402
	$iflist = get_configured_interface_list();
403

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

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

    
423
}
424

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

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

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

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

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

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

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

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

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

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

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

    
546
	$checklist = get_configured_interface_list();
547

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
750
	/* Calculate smaller mtu and enforce it */
751
	$smallermtu = 0;
752
	foreach ($members as $member) {
753
		$opts = pfSense_get_interface_addresses($member);
754
		$mtu = $opts['mtu'];
755
		if (!isset($opts['caps']['txcsum']))
756
			$commontx = false;
757
		if (!isset($opts['caps']['rxcsum']))
758
			$commonrx = false;
759
		if (!isset($opts['caps']['tso4']))
760
			$commontso4 = false;
761
		if (!isset($opts['caps']['tso6']))
762
			$commontso6 = false;
763
		if (!isset($opts['caps']['lro']))
764
			$commonlro = false;
765
		if ($smallermtu == 0 && !empty($mtu))
766
			$smallermtu = $mtu;
767
		else if (!empty($mtu) && $mtu < $smallermtu)
768
			$smallermtu = $mtu;
769
	}
770

    
771
	/* Just in case anything is not working well */
772
	if ($smallermtu == 0)
773
		$smallermtu = 1500;
774

    
775
	$flags_on = 0;
776
	$flags_off = 0;
777
	if (isset($config['system']['disablechecksumoffloading']) || ($commonrx === false))
778
		$flags_off |= IFCAP_RXCSUM;
779
	else
780
		$flags_on |= IFCAP_RXCSUM;
781
	if (isset($config['system']['disablechecksumoffloading']) || ($commontx === false))
782
		$flags_off |= IFCAP_TXCSUM;
783
	else
784
		$flags_on |= IFCAP_TXCSUM;
785
	if (isset($config['system']['disablesegmentationoffloading']) || ($commontso4 === false))
786
		$flags_off |= IFCAP_TSO4;
787
	else
788
		$flags_on |= IFCAP_TSO4;
789
	if (isset($config['system']['disablesegmentationoffloading']) || ($commontso6 === false))
790
		$flags_off |= IFCAP_TSO6;
791
	else
792
		$flags_on |= IFCAP_TSO6;
793
	if (isset($config['system']['disablelargereceiveoffloading']) || ($commonlro === false))
794
		$flags_off |= IFCAP_LRO;
795
	else
796
		$flags_on |= IFCAP_LRO;
797

    
798
	$checklist = get_interface_list();
799

    
800
	foreach ($members as $member) {
801
		if (!array_key_exists($member, $checklist))
802
			continue;
803
		/* make sure the parent interface is up */
804
		pfSense_interface_mtu($member, $smallermtu);
805
		pfSense_interface_capabilities($member, -$flags_off);
806
		pfSense_interface_capabilities($member, $flags_on);
807
		interfaces_bring_up($member);
808
		mwexec("/sbin/ifconfig {$laggif} laggport {$member}");
809
	}
810

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

    
813
	interfaces_bring_up($laggif);
814

    
815
	return $laggif;
816
}
817

    
818
function interfaces_gre_configure($checkparent = 0, $realif = "") {
819
	global $config;
820

    
821
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
822
		foreach ($config['gres']['gre'] as $i => $gre) {
823
			if (empty($gre['greif']))
824
				$gre['greif'] = "gre{$i}";
825
			if (!empty($realif) && $realif != $gre['greif'])
826
				continue;
827

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

    
846
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
847
function interface_gre_configure(&$gre, $grekey = "") {
848
	global $config, $g;
849

    
850
	if (!is_array($gre))
851
		return -1;
852

    
853
	$realif = get_real_interface($gre['if']);
854
	$realifip = get_interface_ip($gre['if']);
855

    
856
	/* make sure the parent interface is up */
857
	interfaces_bring_up($realif);
858

    
859
	if ($g['booting'] || !(empty($gre['greif']))) {
860
		pfSense_interface_destroy($gre['greif']);
861
		pfSense_interface_create($gre['greif']);
862
		$greif = $gre['greif'];
863
	} else
864
		$greif = pfSense_interface_create("gre");
865

    
866
	/* Do not change the order here for more see gre(4) NOTES section. */
867
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
868
	if((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
869
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
870
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
871
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
872
	} else {
873
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
874
	}
875
	if (isset($gre['link0']))
876
		pfSense_interface_flags($greif, IFF_LINK0);
877
	if (isset($gre['link1']))
878
		pfSense_interface_flags($greif, IFF_LINK1);
879
	if (isset($gre['link2']))
880
		pfSense_interface_flags($greif, IFF_LINK2);
881

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

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

    
894
	interfaces_bring_up($greif);
895

    
896
	return $greif;
897
}
898

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

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

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

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

    
931
	if (!is_array($gif))
932
		return -1;
933

    
934
	$realif = get_real_interface($gif['if']);
935
	$ipaddr = $gif['ipaddr'];
936

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

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

    
963
	/* Do not change the order here for more see gif(4) NOTES section. */
964
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
965
	if((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
966
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
967
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
968
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
969
	} else {
970
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
971
	}
972
	if (isset($gif['link0']))
973
		pfSense_interface_flags($gifif, IFF_LINK0);
974
	if (isset($gif['link1']))
975
		pfSense_interface_flags($gifif, IFF_LINK1);
976
	if($gifif)
977
		interfaces_bring_up($gifif);
978
	else
979
		log_error(gettext("could not bring gifif up -- variable not defined"));
980

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

    
995

    
996
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
997
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
998
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
999
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1000

    
1001
	if (is_ipaddrv4($realifgw)) {
1002
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1003
	}
1004
	if (is_ipaddrv6($realifgw)) {
1005
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1006
	}
1007

    
1008
	interfaces_bring_up($gifif);
1009

    
1010
	return $gifif;
1011
}
1012

    
1013
function interfaces_configure() {
1014
	global $config, $g;
1015

    
1016
	if ($g['platform'] == 'jail')
1017
		return;
1018

    
1019
	/* Set up our loopback interface */
1020
	interfaces_loopback_configure();
1021

    
1022
	/* create the unconfigured wireless clones */
1023
	interfaces_create_wireless_clones();
1024

    
1025
	/* set up LAGG virtual interfaces */
1026
	interfaces_lagg_configure();
1027

    
1028
	/* set up VLAN virtual interfaces */
1029
	interfaces_vlan_configure();
1030

    
1031
	interfaces_qinq_configure();
1032

    
1033
	$iflist = get_configured_interface_with_descr();
1034
	$delayed_list = array();
1035
	$bridge_list = array();
1036
	$track6_list = array();
1037

    
1038
	/* This is needed to speedup interfaces on bootup. */
1039
	$reload = false;
1040
	if (!$g['booting'])
1041
		$reload = true;
1042

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

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

    
1068
	/*
1069
	 * NOTE: The following function parameter consists of
1070
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1071
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1072
	 */
1073

    
1074
	/* set up GRE virtual interfaces */
1075
	interfaces_gre_configure(1);
1076

    
1077
	/* set up GIF virtual interfaces */
1078
	interfaces_gif_configure(1);
1079

    
1080
	/* set up BRIDGe virtual interfaces */
1081
	interfaces_bridge_configure(1);
1082

    
1083
	foreach ($track6_list as $if => $ifname) {
1084
		if ($g['booting'])
1085
			printf(gettext("Configuring %s interface..."), $ifname);
1086
		if ($g['debug'])
1087
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1088

    
1089
		interface_configure($if, $reload);
1090

    
1091
		if ($g['booting'])
1092
			echo gettext("done.") . "\n";
1093
	}
1094

    
1095
	/* bring up vip interfaces */
1096
	interfaces_vips_configure();
1097

    
1098
	/* set up GRE virtual interfaces */
1099
	interfaces_gre_configure(2);
1100

    
1101
	/* set up GIF virtual interfaces */
1102
	interfaces_gif_configure(2);
1103

    
1104
	foreach ($delayed_list as $if => $ifname) {
1105
		if ($g['booting'])
1106
			printf(gettext("Configuring %s interface..."), $ifname);
1107
		if ($g['debug'])
1108
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1109

    
1110
		interface_configure($if, $reload);
1111

    
1112
		if ($g['booting'])
1113
			echo gettext("done.") . "\n";
1114
	}
1115

    
1116
	/* set up BRIDGe virtual interfaces */
1117
	interfaces_bridge_configure(2);
1118

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

    
1125
		interface_configure($if, $reload);
1126

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

    
1131
	/* configure interface groups */
1132
	interfaces_group_setup();
1133

    
1134
	if (!$g['booting']) {
1135
		/* reconfigure static routes (kernel may have deleted them) */
1136
		system_routing_configure();
1137

    
1138
		/* reload IPsec tunnels */
1139
		vpn_ipsec_configure();
1140

    
1141
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1142
		services_dhcpd_configure();
1143

    
1144
		/* restart dnsmasq or unbound */
1145
		if (isset($config['dnsmasq']['enable']))
1146
			services_dnsmasq_configure();
1147
		elseif (isset($config['unbound']['enable']))
1148
			services_unbound_configure();
1149
	}
1150

    
1151
	return 0;
1152
}
1153

    
1154
function interface_reconfigure($interface = "wan", $reloadall = false) {
1155
	interface_bring_down($interface);
1156
	interface_configure($interface, $reloadall);
1157
}
1158

    
1159
function interface_vip_bring_down($vip) {
1160
	global $g;
1161

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

    
1184
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1185
	global $config, $g;
1186

    
1187
	if (!isset($config['interfaces'][$interface]))
1188
		return;
1189

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

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

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

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

    
1318
	if (!empty($track6) && is_array($track6)) {
1319
		if (!function_exists('services_dhcp_configure'))
1320
			require_once('services.inc');
1321
		/* Bring down radvd and dhcp6 on these interfaces */
1322
		services_dhcpd_configure('inet6', $track6);
1323
	}
1324

    
1325
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1326
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1327
//	log_error("Checking for old router states: {$g['tmp_path']}/{$realif}_router = {$old_router}");
1328
	if (!empty($old_router)) {
1329
		log_error("Clearing states to old gateway {$old_router}.");
1330
		mwexec("/sbin/pfctl -i " . escapeshellarg($realif) . " -Fs -G {$old_router}");
1331
	}
1332

    
1333
	/* remove interface up file if it exists */
1334
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1335
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1336
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1337
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1338
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1339
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1340
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1341

    
1342
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1343
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1344
	if (is_array($ifcfg['wireless'])) {
1345
		kill_hostapd($realif);
1346
		mwexec(kill_wpasupplicant($realif));
1347
	}
1348

    
1349
	if ($destroy == true) {
1350
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif))
1351
			pfSense_interface_destroy($realif);
1352
	}
1353

    
1354
	return;
1355
}
1356

    
1357
function interfaces_carp_set_maintenancemode($carp_maintenancemode){
1358
	global $config;
1359
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1360
		unset($config["virtualip_carp_maintenancemode"]);
1361
		write_config("Leave CARP maintenance mode");
1362
	} else
1363
	if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1364
		$config["virtualip_carp_maintenancemode"] = true;
1365
		write_config("Enter CARP maintenance mode");
1366
	}
1367

    
1368
	$viparr = &$config['virtualip']['vip'];
1369
	foreach ($viparr as $vip) {
1370
		if ($vip['mode'] == "carp") {
1371
			interface_carp_configure($vip);
1372
		}
1373
	}
1374
}
1375

    
1376
function interfaces_ptpid_used($ptpid) {
1377
	global $config;
1378

    
1379
	if (is_array($config['ppps']['ppp']))
1380
		foreach ($config['ppps']['ppp'] as & $settings)
1381
			if ($ptpid == $settings['ptpid'])
1382
				return true;
1383

    
1384
	return false;
1385
}
1386

    
1387
function interfaces_ptpid_next() {
1388

    
1389
	$ptpid = 0;
1390
	while(interfaces_ptpid_used($ptpid))
1391
		$ptpid++;
1392

    
1393
	return $ptpid;
1394
}
1395

    
1396
function getMPDCRONSettings($pppif) {
1397
	global $config;
1398

    
1399
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1400
	if (is_array($config['cron']['item'])) {
1401
		foreach ($config['cron']['item'] as $i => $item) {
1402
			if (stripos($item['command'], $cron_cmd_file) !== false)
1403
				return array("ID" => $i, "ITEM" => $item);
1404
		}
1405
	}
1406

    
1407
	return NULL;
1408
}
1409

    
1410
function handle_pppoe_reset($post_array) {
1411
	global $config, $g;
1412

    
1413
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1414
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1415

    
1416
	if (!is_array($config['cron']['item']))
1417
		$config['cron']['item'] = array();
1418

    
1419
	$itemhash = getMPDCRONSettings($pppif);
1420

    
1421
	// reset cron items if necessary and return
1422
	if (empty($post_array['pppoe-reset-type'])) {
1423
		if (isset($itemhash))
1424
			unset($config['cron']['item'][$itemhash['ID']]);
1425
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1426
		return;
1427
	}
1428

    
1429
	if (empty($itemhash))
1430
		$itemhash = array();
1431
	$item = array();
1432
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1433
		$item['minute'] = $post_array['pppoe_resetminute'];
1434
		$item['hour'] = $post_array['pppoe_resethour'];
1435
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1436
			$date = explode("/", $post_array['pppoe_resetdate']);
1437
			$item['mday'] = $date[1];
1438
			$item['month'] = $date[0];
1439
		} else {
1440
			$item['mday'] = "*";
1441
			$item['month'] = "*";
1442
		}
1443
		$item['wday'] = "*";
1444
		$item['who'] = "root";
1445
		$item['command'] = $cron_cmd_file;
1446
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1447
		switch ($post_array['pppoe_pr_preset_val']) {
1448
		case "monthly":
1449
			$item['minute'] = "0";
1450
			$item['hour'] = "0";
1451
			$item['mday'] = "1";
1452
			$item['month'] = "*";
1453
			$item['wday'] = "*";
1454
			break;
1455
		case "weekly":
1456
			$item['minute'] = "0";
1457
			$item['hour'] = "0";
1458
			$item['mday'] = "*";
1459
			$item['month'] = "*";
1460
			$item['wday'] = "0";
1461
			break;
1462
		case "daily":
1463
			$item['minute'] = "0";
1464
			$item['hour'] = "0";
1465
			$item['mday'] = "*";
1466
			$item['month'] = "*";
1467
			$item['wday'] = "*";
1468
			break;
1469
		case "hourly":
1470
			$item['minute'] = "0";
1471
			$item['hour'] = "*";
1472
			$item['mday'] = "*";
1473
			$item['month'] = "*";
1474
			$item['wday'] = "*";
1475
			break;
1476
		} // end switch
1477
		$item['who'] = "root";
1478
		$item['command'] = $cron_cmd_file;
1479
	}
1480
	if (empty($item))
1481
		return;
1482
	if (isset($itemhash['ID']))
1483
		$config['cron']['item'][$itemhash['ID']] = $item;
1484
	else
1485
		$config['cron']['item'][] = $item;
1486
}
1487

    
1488
/*
1489
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1490
 * It writes the mpd config file to /var/etc every time the link is opened.
1491
 */
1492
function interface_ppps_configure($interface) {
1493
	global $config, $g;
1494

    
1495
	/* Return for unassigned interfaces. This is a minimum requirement. */
1496
	if (empty($config['interfaces'][$interface]))
1497
		return 0;
1498
	$ifcfg = $config['interfaces'][$interface];
1499
	if (!isset($ifcfg['enable']))
1500
		return 0;
1501

    
1502
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1503
	if(!is_dir("/var/spool/lock")) {
1504
		mkdir("/var/spool/lock", 0777, true);
1505
	}
1506
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1507
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1508
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1509

    
1510
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1511
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1512
			if ($ifcfg['if'] == $ppp['if'])
1513
				break;
1514
		}
1515
	}
1516
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1517
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1518
		return 0;
1519
	}
1520
	$pppif = $ifcfg['if'];
1521
	if ($ppp['type'] == "ppp")
1522
		$type = "modem";
1523
	else
1524
		$type = $ppp['type'];
1525
	$upper_type = strtoupper($ppp['type']);
1526

    
1527
	if($g['booting']) {
1528
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1529
		echo "starting {$pppif} link...";
1530
		// Do not re-configure the interface if we are booting and it's already been started
1531
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1532
			return 0;
1533
	}
1534

    
1535
	$ports = explode(',',$ppp['ports']);
1536
	if ($type != "modem") {
1537
		foreach ($ports as $pid => $port) {
1538
			$ports[$pid] = get_real_interface($port);
1539
			if (empty($ports[$pid]))
1540
				return 0;
1541
		}
1542
	}
1543
	$localips = explode(',',$ppp['localip']);
1544
	$gateways = explode(',',$ppp['gateway']);
1545
	$subnets = explode(',',$ppp['subnet']);
1546

    
1547
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1548
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1549
	 */
1550
	foreach($ports as $pid => $port){
1551
		switch ($ppp['type']) {
1552
			case "pppoe":
1553
				/* Bring the parent interface up */
1554
				interfaces_bring_up($port);
1555
				pfSense_ngctl_attach(".", $port);
1556
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1557
				mwexec("ngctl msg {$port}: setautosrc 1");
1558
				break;
1559
			case "pptp":
1560
			case "l2tp":
1561
				/* configure interface */
1562
				if(is_ipaddr($localips[$pid])){
1563
					// Manually configure interface IP/subnet
1564
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1565
					interfaces_bring_up($port);
1566
				} else if (empty($localips[$pid]))
1567
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1568

    
1569
				if(!is_ipaddr($localips[$pid])){
1570
					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!");
1571
					$localips[$pid] = "0.0.0.0";
1572
				}
1573
				if(!is_ipaddr($gateways[$pid])){
1574
					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));
1575
					return 0;
1576
				}
1577
				pfSense_ngctl_attach(".", $port);
1578
				break;
1579
			case "ppp":
1580
				if (!file_exists("{$port}")) {
1581
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1582
					return 0;
1583
				}
1584
				break;
1585
			default:
1586
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1587
				break;
1588
		}
1589
	}
1590

    
1591
	if (is_array($ports) && count($ports) > 1)
1592
		$multilink = "enable";
1593
	else
1594
		$multilink = "disable";
1595

    
1596
	if ($type == "modem"){
1597
		if (is_ipaddr($ppp['localip']))
1598
			$localip = $ppp['localip'];
1599
		else
1600
			$localip = '0.0.0.0';
1601

    
1602
		if (is_ipaddr($ppp['gateway']))
1603
			$gateway = $ppp['gateway'];
1604
		else
1605
			$gateway = "10.64.64.{$pppid}";
1606
		$ranges = "{$localip}/0 {$gateway}/0";
1607

    
1608
		if (empty($ppp['apnum']))
1609
			$ppp['apnum'] = 1;
1610
	} else
1611
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1612

    
1613
	if (isset($ppp['ondemand']))
1614
		$ondemand = "enable";
1615
	else
1616
		$ondemand = "disable";
1617
	if (!isset($ppp['idletimeout']))
1618
		$ppp['idletimeout'] = 0;
1619

    
1620
	if (empty($ppp['username']) && $type == "modem"){
1621
		$ppp['username'] = "user";
1622
		$ppp['password'] = "none";
1623
	}
1624
	if (empty($ppp['password']) && $type == "modem")
1625
		$passwd = "none";
1626
	else
1627
		$passwd = base64_decode($ppp['password']);
1628

    
1629
	$bandwidths = explode(',',$ppp['bandwidth']);
1630
	$defaultmtu = "1492";
1631
	if (!empty($ifcfg['mtu']))
1632
		$defaultmtu = intval($ifcfg['mtu']);
1633
	$mtus = explode(',',$ppp['mtu']);
1634
	$mrus = explode(',',$ppp['mru']);
1635

    
1636
	if (isset($ppp['mrru']))
1637
		$mrrus = explode(',',$ppp['mrru']);
1638

    
1639
	// Construct the mpd.conf file
1640
	$mpdconf = <<<EOD
1641
startup:
1642
	# configure the console
1643
	set console close
1644
	# configure the web server
1645
	set web close
1646

    
1647
default:
1648
{$ppp['type']}client:
1649
	create bundle static {$interface}
1650
	set bundle enable ipv6cp
1651
	set iface name {$pppif}
1652

    
1653
EOD;
1654
	$setdefaultgw = false;
1655
	$founddefaultgw = false;
1656
	if (is_array($config['gateways']['gateway_item'])) {
1657
		foreach($config['gateways']['gateway_item'] as $gateway) {
1658
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1659
				$setdefaultgw = true;
1660
				break;
1661
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1662
				$founddefaultgw = true;
1663
				break;
1664
			}
1665
		}
1666
	}
1667

    
1668
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1669
		$setdefaultgw = true;
1670
		$mpdconf .= <<<EOD
1671
	set iface route default
1672

    
1673
EOD;
1674
	}
1675
	$mpdconf .= <<<EOD
1676
	set iface {$ondemand} on-demand
1677
	set iface idle {$ppp['idletimeout']}
1678

    
1679
EOD;
1680

    
1681
	if (isset($ppp['ondemand']))
1682
		$mpdconf .= <<<EOD
1683
	set iface addrs 10.10.1.1 10.10.1.2
1684

    
1685
EOD;
1686

    
1687
	if (isset($ppp['tcpmssfix']))
1688
		$tcpmss = "disable";
1689
	else
1690
		$tcpmss = "enable";
1691
		$mpdconf .= <<<EOD
1692
	set iface {$tcpmss} tcpmssfix
1693

    
1694
EOD;
1695

    
1696
	$mpdconf .= <<<EOD
1697
	set iface up-script /usr/local/sbin/ppp-linkup
1698
	set iface down-script /usr/local/sbin/ppp-linkdown
1699
	set ipcp ranges {$ranges}
1700

    
1701
EOD;
1702
	if (isset($ppp['vjcomp']))
1703
		$mpdconf .= <<<EOD
1704
	set ipcp no vjcomp
1705

    
1706
EOD;
1707

    
1708
	if (isset($config['system']['dnsallowoverride']))
1709
		$mpdconf .= <<<EOD
1710
	set ipcp enable req-pri-dns
1711
	set ipcp enable req-sec-dns
1712

    
1713
EOD;
1714
	if (!isset($ppp['verbose_log']))
1715
		$mpdconf .= <<<EOD
1716
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1717

    
1718
EOD;
1719
	foreach($ports as $pid => $port){
1720
		$port = get_real_interface($port);
1721
		$mpdconf .= <<<EOD
1722

    
1723
	create link static {$interface}_link{$pid} {$type}
1724
	set link action bundle {$interface}
1725
	set link {$multilink} multilink
1726
	set link keep-alive 10 60
1727
	set link max-redial 0
1728

    
1729
EOD;
1730
		if (isset($ppp['shortseq']))
1731
			$mpdconf .= <<<EOD
1732
	set link no shortseq
1733

    
1734
EOD;
1735

    
1736
		if (isset($ppp['acfcomp']))
1737
			$mpdconf .= <<<EOD
1738
	set link no acfcomp
1739

    
1740
EOD;
1741

    
1742
		if (isset($ppp['protocomp']))
1743
			$mpdconf .= <<<EOD
1744
	set link no protocomp
1745

    
1746
EOD;
1747

    
1748
		$mpdconf .= <<<EOD
1749
	set link disable chap pap
1750
	set link accept chap pap eap
1751
	set link disable incoming
1752

    
1753
EOD;
1754

    
1755

    
1756
		if (!empty($bandwidths[$pid]))
1757
			$mpdconf .= <<<EOD
1758
	set link bandwidth {$bandwidths[$pid]}
1759

    
1760
EOD;
1761

    
1762
		if (empty($mtus[$pid]))
1763
			$mtus[$pid] = $defaultmtu;
1764
			$mpdconf .= <<<EOD
1765
	set link mtu {$mtus[$pid]}
1766

    
1767
EOD;
1768

    
1769
		if (!empty($mrus[$pid]))
1770
			$mpdconf .= <<<EOD
1771
	set link mru {$mrus[$pid]}
1772

    
1773
EOD;
1774

    
1775
		if (!empty($mrrus[$pid]))
1776
			$mpdconf .= <<<EOD
1777
	set link mrru {$mrrus[$pid]}
1778

    
1779
EOD;
1780

    
1781
		$mpdconf .= <<<EOD
1782
	set auth authname "{$ppp['username']}"
1783
	set auth password {$passwd}
1784

    
1785
EOD;
1786
		if ($type == "modem") {
1787
			$mpdconf .= <<<EOD
1788
	set modem device {$ppp['ports']}
1789
	set modem script DialPeer
1790
	set modem idle-script Ringback
1791
	set modem watch -cd
1792
	set modem var \$DialPrefix "DT"
1793
	set modem var \$Telephone "{$ppp['phone']}"
1794

    
1795
EOD;
1796
		}
1797
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1798
			$mpdconf .= <<<EOD
1799
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1800

    
1801
EOD;
1802
		}
1803
		if (isset($ppp['initstr']) && $type == "modem") {
1804
			$initstr = base64_decode($ppp['initstr']);
1805
			$mpdconf .= <<<EOD
1806
	set modem var \$InitString "{$initstr}"
1807

    
1808
EOD;
1809
		}
1810
		if (isset($ppp['simpin']) && $type == "modem") {
1811
			if($ppp['pin-wait'] == "")
1812
				$ppp['pin-wait'] = 0;
1813
			$mpdconf .= <<<EOD
1814
	set modem var \$SimPin "{$ppp['simpin']}"
1815
	set modem var \$PinWait "{$ppp['pin-wait']}"
1816

    
1817
EOD;
1818
		}
1819
		if (isset($ppp['apn']) && $type == "modem") {
1820
			$mpdconf .= <<<EOD
1821
	set modem var \$APN "{$ppp['apn']}"
1822
	set modem var \$APNum "{$ppp['apnum']}"
1823

    
1824
EOD;
1825
		}
1826
		if ($type == "pppoe") {
1827
			// Send a null service name if none is set.
1828
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1829
			$mpdconf .= <<<EOD
1830
	set pppoe service "{$provider}"
1831

    
1832
EOD;
1833
		}
1834
		if ($type == "pppoe")
1835
			$mpdconf .= <<<EOD
1836
	set pppoe iface {$port}
1837

    
1838
EOD;
1839

    
1840
		if ($type == "pptp" || $type == "l2tp") {
1841
			$mpdconf .= <<<EOD
1842
	set {$type} self {$localips[$pid]}
1843
	set {$type} peer {$gateways[$pid]}
1844

    
1845
EOD;
1846
		}
1847

    
1848
		$mpdconf .= "\topen\n";
1849
	} //end foreach($port)
1850

    
1851

    
1852
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1853
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1854
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1855
	else {
1856
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1857
		if (!$fd) {
1858
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1859
			return 0;
1860
		}
1861
		// Write out mpd_ppp.conf
1862
		fwrite($fd, $mpdconf);
1863
		fclose($fd);
1864
		unset($mpdconf);
1865
	}
1866

    
1867
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1868
	if (isset($ppp['uptime'])) {
1869
		if (!file_exists("/conf/{$pppif}.log")) {
1870
			conf_mount_rw();
1871
			file_put_contents("/conf/{$pppif}.log", '');
1872
			conf_mount_ro();
1873
		}
1874
	} else {
1875
		if (file_exists("/conf/{$pppif}.log")) {
1876
			conf_mount_rw();
1877
			@unlink("/conf/{$pppif}.log");
1878
			conf_mount_ro();
1879
		}
1880
	}
1881

    
1882
	/* clean up old lock files */
1883
	foreach($ports as $port) {
1884
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1885
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1886
	}
1887

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

    
1892
	// Check for PPPoE periodic reset request
1893
	if ($type == "pppoe") {
1894
		if (!empty($ppp['pppoe-reset-type']))
1895
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1896
		else
1897
			interface_setup_pppoe_reset_file($ppp['if']);
1898
	}
1899
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1900
	$i = 0;
1901
	while($i < 10) {
1902
		exec("/sbin/ifconfig " . escapeshellarg($ppp['if']) . " 2>&1", $out, $ret);
1903
		if($ret == 0)
1904
			break;
1905
		sleep(1);
1906
		$i++;
1907
	}
1908

    
1909
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
1910
	/* We should be able to launch the right version for each modem */
1911
	/* We can also guess the mondev from the manufacturer */
1912
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
1913
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
1914
	foreach($ports as $port) {
1915
		if(preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1916
			$mondev  = substr(basename($port), 0, -1);
1917
			$devlist = glob("/dev/{$mondev}?");
1918
			$mondev = basename(end($devlist));
1919
		}
1920
		if(preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1921
			$mondev  = substr(basename($port), 0, -1) . "1";
1922
		}
1923
		log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
1924
		mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
1925
	}
1926

    
1927
	return 1;
1928
}
1929

    
1930
function interfaces_carp_setup() {
1931
	global $g, $config;
1932

    
1933
	if (isset($config['system']['developerspew'])) {
1934
		$mt = microtime();
1935
		echo "interfaces_carp_setup() being called $mt\n";
1936
	}
1937

    
1938
	if ($g['booting']) {
1939
		echo gettext("Configuring CARP settings...");
1940
		mute_kernel_msgs();
1941
	}
1942

    
1943
	/* suck in configuration items */
1944
	if ($config['hasync']) {
1945
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1946
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1947
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1948
	} else {
1949
		unset($pfsyncinterface);
1950
		unset($pfsyncenabled);
1951
	}
1952

    
1953
	mwexec("/sbin/sysctl net.inet.carp.preempt=1", true);
1954
	mwexec("/sbin/sysctl net.inet.carp.log=1", true);
1955

    
1956
	if (!empty($pfsyncinterface))
1957
		$carp_sync_int = get_real_interface($pfsyncinterface);
1958
	else
1959
		unset($carp_sync_int);
1960

    
1961
	/* setup pfsync interface */
1962
	if ($carp_sync_int and $pfsyncenabled) {
1963
		if (is_ipaddr($pfsyncpeerip))
1964
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1965
		else
1966
			$syncpeer = "-syncpeer";
1967

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

    
1970
		sleep(1);
1971

    
1972
		/* 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
1973
		 * for existing sessions.
1974
		 */
1975
		log_error("waiting for pfsync...");
1976
		$i = 0;
1977
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1978
			$i++;
1979
			sleep(1);
1980
		}
1981
		log_error("pfsync done in $i seconds.");
1982
		log_error("Configuring CARP settings finalize...");
1983
	} else {
1984
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
1985
	}
1986

    
1987
	if($config['virtualip']['vip'])
1988
		mwexec("/sbin/sysctl net.inet.carp.allow=1", true);
1989
	else
1990
		mwexec("/sbin/sysctl net.inet.carp.allow=0", true);
1991

    
1992
	if ($g['booting']) {
1993
		unmute_kernel_msgs();
1994
		echo gettext("done.") . "\n";
1995
	}
1996
}
1997

    
1998
function interface_proxyarp_configure($interface = "") {
1999
	global $config, $g;
2000
	if(isset($config['system']['developerspew'])) {
2001
		$mt = microtime();
2002
		echo "interface_proxyarp_configure() being called $mt\n";
2003
	}
2004

    
2005
	/* kill any running choparp */
2006
	if (empty($interface))
2007
		killbyname("choparp");
2008
	else {
2009
		$vipif = get_real_interface($interface);
2010
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
2011
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2012
	}
2013

    
2014
	$paa = array();
2015
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2016

    
2017
		/* group by interface */
2018
		foreach ($config['virtualip']['vip'] as $vipent) {
2019
			if ($vipent['mode'] === "proxyarp") {
2020
				if ($vipent['interface'])
2021
					$proxyif = $vipent['interface'];
2022
				else
2023
					$proxyif = "wan";
2024

    
2025
				if (!empty($interface) && $interface != $proxyif)
2026
					continue;
2027

    
2028
				if (!is_array($paa[$proxyif]))
2029
					$paa[$proxyif] = array();
2030

    
2031
				$paa[$proxyif][] = $vipent;
2032
			}
2033
		}
2034
	}
2035

    
2036
	if (!empty($interface)) {
2037
		if (is_array($paa[$interface])) {
2038
			$paaifip = get_interface_ip($interface);
2039
			if (!is_ipaddr($paaifip))
2040
				return;
2041
			$args = get_real_interface($interface) . " auto";
2042
			foreach ($paa[$interface] as $paent) {
2043
				if (isset($paent['subnet']))
2044
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2045
				else if (isset($paent['range']))
2046
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2047
			}
2048
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2049
		}
2050
	} else if (count($paa) > 0) {
2051
		foreach ($paa as $paif => $paents)  {
2052
			$paaifip = get_interface_ip($paif);
2053
			if (!is_ipaddr($paaifip))
2054
				continue;
2055
			$args = get_real_interface($paif) . " auto";
2056
			foreach ($paents as $paent) {
2057
				if (isset($paent['subnet']))
2058
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2059
				else if (isset($paent['range']))
2060
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2061
			}
2062
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2063
		}
2064
	}
2065
}
2066

    
2067
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2068
	global $g, $config;
2069

    
2070
	if (is_array($config['virtualip']['vip'])) {
2071
		foreach ($config['virtualip']['vip'] as $vip) {
2072
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2073
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2074
					interface_vip_bring_down($vip);
2075
				else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2076
					interface_vip_bring_down($vip);
2077
			}
2078
		}
2079
	}
2080
}
2081

    
2082
function interfaces_vips_configure($interface = "") {
2083
	global $g, $config;
2084
	if(isset($config['system']['developerspew'])) {
2085
		$mt = microtime();
2086
		echo "interfaces_vips_configure() being called $mt\n";
2087
	}
2088
	$paa = array();
2089
	if(is_array($config['virtualip']['vip'])) {
2090
		$carp_setuped = false;
2091
		$anyproxyarp = false;
2092
		foreach ($config['virtualip']['vip'] as $vip) {
2093
			switch ($vip['mode']) {
2094
			case "proxyarp":
2095
				/* nothing it is handled on interface_proxyarp_configure() */
2096
				if ($interface <> "" && $vip['interface'] <> $interface)
2097
					continue;
2098
				$anyproxyarp = true;
2099
				break;
2100
			case "ipalias":
2101
				if ($interface <> "" && $vip['interface'] <> $interface)
2102
					continue;
2103
				interface_ipalias_configure($vip);
2104
				break;
2105
			case "carp":
2106
				if ($interface <> "" && $vip['interface'] <> $interface)
2107
					continue;
2108
				if ($carp_setuped == false)
2109
					$carp_setuped = true;
2110
				interface_carp_configure($vip);
2111
				break;
2112
			}
2113
		}
2114
		if ($carp_setuped == true)
2115
			interfaces_carp_setup();
2116
		if ($anyproxyarp == true)
2117
			interface_proxyarp_configure();
2118
	}
2119
}
2120

    
2121
function interface_ipalias_configure(&$vip) {
2122
	global $config;
2123

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

    
2127
	if ($vip['interface'] != 'lo0' && !isset($config['interfaces'][$vip['interface']]))
2128
		return;
2129

    
2130
	if ($vip['interface'] != 'lo0' && !isset($config['interfaces'][$vip['interface']]['enable']))
2131
		return;
2132

    
2133
	$if = get_real_interface($vip['interface']);
2134
	$af = "inet";
2135
	if(is_ipaddrv6($vip['subnet']))
2136
		$af = "inet6";
2137
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
2138
}
2139

    
2140
function interface_reload_carps($cif) {
2141
	global $config;
2142

    
2143
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2144
	if (empty($carpifs))
2145
		return;
2146

    
2147
	$carps = explode(" ", $carpifs);
2148
	if(is_array($config['virtualip']['vip'])) {
2149
		$viparr = &$config['virtualip']['vip'];
2150
		foreach ($viparr as $vip) {
2151
			if (in_array($vip['carpif'], $carps)) {
2152
				switch ($vip['mode']) {
2153
				case "carp":
2154
					interface_vip_bring_down($vip);
2155
					sleep(1);
2156
					interface_carp_configure($vip);
2157
					break;
2158
				case "ipalias":
2159
					interface_vip_bring_down($vip);
2160
					sleep(1);
2161
					interface_ipalias_configure($vip);
2162
					break;
2163
				}
2164
			}
2165
		}
2166
	}
2167
}
2168

    
2169
function interface_carp_configure(&$vip) {
2170
	global $config, $g;
2171
	if(isset($config['system']['developerspew'])) {
2172
		$mt = microtime();
2173
		echo "interface_carp_configure() being called $mt\n";
2174
	}
2175

    
2176
	if ($vip['mode'] != "carp")
2177
		return;
2178

    
2179
	/* NOTE: Maybe its useless nowdays */
2180
	$realif = get_real_interface($vip['interface']);
2181
	if (!does_interface_exist($realif)) {
2182
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2183
		return;
2184
	}
2185

    
2186
	if (is_ipaddrv4($vip['subnet'])) {
2187
		/* Ensure CARP IP really exists prior to loading up. */
2188
		$ww_subnet_ip = find_interface_ip($realif);
2189
		$ww_subnet_bits = find_interface_subnet($realif);
2190
		if (!ip_in_subnet($vip['subnet'], gen_subnet($ww_subnet_ip, $ww_subnet_bits) . "/" . $ww_subnet_bits) && !ip_in_interface_alias_subnet($vip['interface'], $vip['subnet'])) {
2191
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a matching real interface subnet for the virtual IP address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2192
			return;
2193
		}
2194
	} else if (is_ipaddrv6($vip['subnet'])) {
2195
		/* Ensure CARP IP really exists prior to loading up. */
2196
		$ww_subnet_ip = find_interface_ipv6($realif);
2197
		$ww_subnet_bits = find_interface_subnetv6($realif);
2198
		if (!ip_in_subnet($vip['subnet'], gen_subnetv6($ww_subnet_ip, $ww_subnet_bits) . "/" . $ww_subnet_bits) && !ip_in_interface_alias_subnet($vip['interface'], $vip['subnet'])) {
2199
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a matching real interface subnet for the virtual IPv6 address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2200
			return;
2201
		}
2202
	}
2203

    
2204
	$vip_password = $vip['password'];
2205
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2206
	if ($vip['password'] != "")
2207
		$password = " pass {$vip_password}";
2208

    
2209
	$advbase = "";
2210
	if (!empty($vip['advbase']))
2211
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2212

    
2213
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2214
	if ($carp_maintenancemode)
2215
		$advskew = "advskew 254";
2216
	else
2217
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2218
	
2219
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) . " {$advskew} {$advbase} {$password}");
2220

    
2221
	if (is_ipaddrv4($vip['subnet']))
2222
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2223
	else if (is_ipaddrv6($vip['subnet']))
2224
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " vhid " . escapeshellarg($vip['vhid']));
2225

    
2226
	return $realif;
2227
}
2228

    
2229
function interface_wireless_clone($realif, $wlcfg) {
2230
	global $config, $g;
2231
	/*   Check to see if interface has been cloned as of yet.
2232
	 *   If it has not been cloned then go ahead and clone it.
2233
	 */
2234
	$needs_clone = false;
2235
	if(is_array($wlcfg['wireless']))
2236
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2237
	else
2238
		$wlcfg_mode = $wlcfg['mode'];
2239
	switch($wlcfg_mode) {
2240
	case "hostap":
2241
		$mode = "wlanmode hostap";
2242
		break;
2243
	case "adhoc":
2244
		$mode = "wlanmode adhoc";
2245
		break;
2246
	default:
2247
		$mode = "";
2248
		break;
2249
	}
2250
	$baseif = interface_get_wireless_base($wlcfg['if']);
2251
	if(does_interface_exist($realif)) {
2252
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2253
		$ifconfig_str = implode($output);
2254
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
2255
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2256
			$needs_clone = true;
2257
		}
2258
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
2259
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2260
			$needs_clone = true;
2261
		}
2262
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2263
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2264
			$needs_clone = true;
2265
		}
2266
	} else {
2267
		$needs_clone = true;
2268
	}
2269

    
2270
	if($needs_clone == true) {
2271
		/* remove previous instance if it exists */
2272
		if(does_interface_exist($realif))
2273
			pfSense_interface_destroy($realif);
2274

    
2275
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2276
		// Create the new wlan interface. FreeBSD returns the new interface name.
2277
		// example:  wlan2
2278
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2279
		if($ret <> 0) {
2280
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2281
			return false;
2282
		}
2283
		$newif = trim($out[0]);
2284
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2285
		pfSense_interface_rename($newif, $realif);
2286
		// FIXME: not sure what ngctl is for. Doesn't work.
2287
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
2288
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2289
	}
2290
	return true;
2291
}
2292

    
2293
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2294
	global $config, $g;
2295

    
2296
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2297
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2298
				 'regdomain', 'regcountry', 'reglocation');
2299

    
2300
	if(!is_interface_wireless($ifcfg['if']))
2301
		return;
2302

    
2303
	$baseif = interface_get_wireless_base($ifcfg['if']);
2304

    
2305
	// Sync shared settings for assigned clones
2306
	$iflist = get_configured_interface_list(false, true);
2307
	foreach ($iflist as $if) {
2308
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2309
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2310
				foreach ($shared_settings as $setting) {
2311
					if ($sync_changes) {
2312
						if (isset($ifcfg['wireless'][$setting]))
2313
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2314
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2315
							unset($config['interfaces'][$if]['wireless'][$setting]);
2316
					} else {
2317
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2318
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2319
						else if (isset($ifcfg['wireless'][$setting]))
2320
							unset($ifcfg['wireless'][$setting]);
2321
					}
2322
				}
2323
				if (!$sync_changes)
2324
					break;
2325
			}
2326
		}
2327
	}
2328

    
2329
	// Read or write settings at shared area
2330
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2331
		foreach ($shared_settings as $setting) {
2332
			if ($sync_changes) {
2333
				if (isset($ifcfg['wireless'][$setting]))
2334
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2335
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2336
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2337
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2338
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2339
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2340
				else if (isset($ifcfg['wireless'][$setting]))
2341
					unset($ifcfg['wireless'][$setting]);
2342
			}
2343
		}
2344
	}
2345

    
2346
	// Sync the mode on the clone creation page with the configured mode on the interface
2347
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2348
		foreach ($config['wireless']['clone'] as &$clone) {
2349
			if ($clone['cloneif'] == $ifcfg['if']) {
2350
				if ($sync_changes) {
2351
					$clone['mode'] = $ifcfg['wireless']['mode'];
2352
				} else {
2353
					$ifcfg['wireless']['mode'] = $clone['mode'];
2354
				}
2355
				break;
2356
			}
2357
		}
2358
		unset($clone);
2359
	}
2360
}
2361

    
2362
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2363
	global $config, $g;
2364

    
2365
	/*    open up a shell script that will be used to output the commands.
2366
	 *    since wireless is changing a lot, these series of commands are fragile
2367
	 *    and will sometimes need to be verified by a operator by executing the command
2368
	 *    and returning the output of the command to the developers for inspection.  please
2369
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2370
	 */
2371

    
2372
	// Remove script file
2373
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2374

    
2375
	// Clone wireless nic if needed.
2376
	interface_wireless_clone($if, $wl);
2377

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

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

    
2385
	/* set values for /path/program */
2386
	$hostapd = "/usr/sbin/hostapd";
2387
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2388
	$ifconfig = "/sbin/ifconfig";
2389
	$sysctl = "/sbin/sysctl";
2390
	$killall = "/usr/bin/killall";
2391

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

    
2394
	$wlcmd = array();
2395
	$wl_sysctl = array();
2396
	/* Make sure it's up */
2397
	$wlcmd[] = "up";
2398
	/* Set a/b/g standard */
2399
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2400
	$wlcmd[] = "mode " . escapeshellarg($standard);
2401

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

    
2407
	/* Set ssid */
2408
	if($wlcfg['ssid'])
2409
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2410

    
2411
	/* Set 802.11g protection mode */
2412
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2413

    
2414
	/* set wireless channel value */
2415
	if(isset($wlcfg['channel'])) {
2416
		if($wlcfg['channel'] == "0") {
2417
			$wlcmd[] = "channel any";
2418
		} else {
2419
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2420
		}
2421
	}
2422

    
2423
	/* Set antenna diversity value */
2424
	if(isset($wlcfg['diversity']))
2425
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2426

    
2427
	/* Set txantenna value */
2428
	if(isset($wlcfg['txantenna']))
2429
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2430

    
2431
	/* Set rxantenna value */
2432
	if(isset($wlcfg['rxantenna']))
2433
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2434

    
2435
	/* set Distance value */
2436
	if($wlcfg['distance'])
2437
		$distance = escapeshellarg($wlcfg['distance']);
2438

    
2439
	/* Set wireless hostap mode */
2440
	if ($wlcfg['mode'] == "hostap") {
2441
		$wlcmd[] = "mediaopt hostap";
2442
	} else {
2443
		$wlcmd[] = "-mediaopt hostap";
2444
	}
2445

    
2446
	/* Set wireless adhoc mode */
2447
	if ($wlcfg['mode'] == "adhoc") {
2448
		$wlcmd[] = "mediaopt adhoc";
2449
	} else {
2450
		$wlcmd[] = "-mediaopt adhoc";
2451
	}
2452

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

    
2455
	/* handle hide ssid option */
2456
	if(isset($wlcfg['hidessid']['enable'])) {
2457
		$wlcmd[] = "hidessid";
2458
	} else {
2459
		$wlcmd[] = "-hidessid";
2460
	}
2461

    
2462
	/* handle pureg (802.11g) only option */
2463
	if(isset($wlcfg['pureg']['enable'])) {
2464
		$wlcmd[] = "mode 11g pureg";
2465
	} else {
2466
		$wlcmd[] = "-pureg";
2467
	}
2468

    
2469
	/* handle puren (802.11n) only option */
2470
	if(isset($wlcfg['puren']['enable'])) {
2471
		$wlcmd[] = "puren";
2472
	} else {
2473
		$wlcmd[] = "-puren";
2474
	}
2475

    
2476
	/* enable apbridge option */
2477
	if(isset($wlcfg['apbridge']['enable'])) {
2478
		$wlcmd[] = "apbridge";
2479
	} else {
2480
		$wlcmd[] = "-apbridge";
2481
	}
2482

    
2483
	/* handle turbo option */
2484
	if(isset($wlcfg['turbo']['enable'])) {
2485
		$wlcmd[] = "mediaopt turbo";
2486
	} else {
2487
		$wlcmd[] = "-mediaopt turbo";
2488
	}
2489

    
2490
	/* handle txpower setting */
2491
	/* if($wlcfg['txpower'] <> "")
2492
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2493
	*/
2494
	/* handle wme option */
2495
	if(isset($wlcfg['wme']['enable'])) {
2496
		$wlcmd[] = "wme";
2497
	} else {
2498
		$wlcmd[] = "-wme";
2499
	}
2500

    
2501
	/* set up wep if enabled */
2502
	$wepset = "";
2503
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2504
		switch($wlcfg['wpa']['auth_algs']) {
2505
			case "1":
2506
				$wepset .= "authmode open wepmode on ";
2507
				break;
2508
			case "2":
2509
				$wepset .= "authmode shared wepmode on ";
2510
				break;
2511
			case "3":
2512
				$wepset .= "authmode mixed wepmode on ";
2513
		}
2514
		$i = 1;
2515
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2516
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2517
			if (isset($wepkey['txkey'])) {
2518
				$wlcmd[] = "weptxkey {$i} ";
2519
			}
2520
			$i++;
2521
		}
2522
		$wlcmd[] = $wepset;
2523
	} else {
2524
		$wlcmd[] = "authmode open wepmode off ";
2525
	}
2526

    
2527
	kill_hostapd($if);
2528
	mwexec(kill_wpasupplicant("{$if}"));
2529

    
2530
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2531
	conf_mount_rw();
2532

    
2533
	switch ($wlcfg['mode']) {
2534
	case 'bss':
2535
		if (isset($wlcfg['wpa']['enable'])) {
2536
			$wpa .= <<<EOD
2537
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2538
ctrl_interface_group=0
2539
ap_scan=1
2540
#fast_reauth=1
2541
network={
2542
ssid="{$wlcfg['ssid']}"
2543
scan_ssid=1
2544
priority=5
2545
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2546
psk="{$wlcfg['wpa']['passphrase']}"
2547
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2548
group={$wlcfg['wpa']['wpa_pairwise']}
2549
}
2550
EOD;
2551

    
2552
			@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2553
			unset($wpa);
2554
		}
2555
		break;
2556
	case 'hostap':
2557
		if (!empty($wlcfg['wpa']['passphrase']))
2558
			$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2559
		else
2560
			$wpa_passphrase = "";
2561
		if (isset($wlcfg['wpa']['enable'])) {
2562
			$wpa .= <<<EOD
2563
interface={$if}
2564
driver=bsd
2565
logger_syslog=-1
2566
logger_syslog_level=0
2567
logger_stdout=-1
2568
logger_stdout_level=0
2569
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2570
ctrl_interface={$g['varrun_path']}/hostapd
2571
ctrl_interface_group=wheel
2572
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2573
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2574
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2575
ssid={$wlcfg['ssid']}
2576
debug={$wlcfg['wpa']['debug_mode']}
2577
auth_algs={$wlcfg['wpa']['auth_algs']}
2578
wpa={$wlcfg['wpa']['wpa_mode']}
2579
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2580
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2581
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2582
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2583
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2584
{$wpa_passphrase}
2585

    
2586
EOD;
2587

    
2588
			if (isset($wlcfg['wpa']['rsn_preauth'])) {
2589
				$wpa .= <<<EOD
2590
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2591
rsn_preauth=1
2592
rsn_preauth_interfaces={$if}
2593

    
2594
EOD;
2595
			}
2596
			if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2597
				$wpa .= "ieee8021x=1\n";
2598

    
2599
			if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2600
				$auth_server_port = "1812";
2601
				if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port']))
2602
					$auth_server_port = intval($wlcfg['auth_server_port']);
2603
				$wpa .= <<<EOD
2604

    
2605
auth_server_addr={$wlcfg['auth_server_addr']}
2606
auth_server_port={$auth_server_port}
2607
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2608

    
2609
EOD;
2610
				if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2611
					$auth_server_port2 = "1812";
2612
					if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2']))
2613
						$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2614

    
2615
					$wpa .= <<<EOD
2616
auth_server_addr={$wlcfg['auth_server_addr2']}
2617
auth_server_port={$auth_server_port2}
2618
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2619

    
2620
EOD;
2621
					}
2622
				}
2623
			}
2624

    
2625
			@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2626
			unset($wpa);
2627
		}
2628
		break;
2629
	}
2630

    
2631
	/*
2632
	 *    all variables are set, lets start up everything
2633
	 */
2634

    
2635
	$baseif = interface_get_wireless_base($if);
2636
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2637
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2638

    
2639
	/* set sysctls for the wireless interface */
2640
	if (!empty($wl_sysctl)) {
2641
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2642
		foreach ($wl_sysctl as $wl_sysctl_line) {
2643
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2644
		}
2645
	}
2646

    
2647
	/* set ack timers according to users preference (if he/she has any) */
2648
	if($distance) {
2649
		fwrite($fd_set, "# Enable ATH distance settings\n");
2650
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2651
	}
2652

    
2653
	if (isset($wlcfg['wpa']['enable'])) {
2654
		if ($wlcfg['mode'] == "bss") {
2655
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2656
		}
2657
		if ($wlcfg['mode'] == "hostap") {
2658
			/* add line to script to restore old mac to make hostapd happy */
2659
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2660
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2661
				if (is_macaddr($if_oldmac))
2662
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2663
						" link " . escapeshellarg($if_oldmac) . "\n");
2664
			}
2665

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

    
2668
			/* add line to script to restore spoofed mac after running hostapd */
2669
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2670
				if ($wl['spoofmac'])
2671
					$if_curmac = $wl['spoofmac'];
2672
				else
2673
					$if_curmac = get_interface_mac($if);
2674
				if (is_macaddr($if_curmac))
2675
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2676
						" link " . escapeshellarg($if_curmac) . "\n");
2677
			}
2678
		}
2679
	}
2680

    
2681
	fclose($fd_set);
2682
	conf_mount_ro();
2683

    
2684
	/* Making sure regulatory settings have actually changed
2685
	 * before applying, because changing them requires bringing
2686
	 * down all wireless networks on the interface. */
2687
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2688
	$ifconfig_str = implode($output);
2689
	unset($output);
2690
	$reg_changing = false;
2691

    
2692
	/* special case for the debug country code */
2693
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2694
		$reg_changing = true;
2695
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2696
		$reg_changing = true;
2697
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2698
		$reg_changing = true;
2699
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2700
		$reg_changing = true;
2701
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2702
		$reg_changing = true;
2703

    
2704
	if ($reg_changing) {
2705
		/* set regulatory domain */
2706
		if($wlcfg['regdomain'])
2707
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2708

    
2709
		/* set country */
2710
		if($wlcfg['regcountry'])
2711
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2712

    
2713
		/* set location */
2714
		if($wlcfg['reglocation'])
2715
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2716

    
2717
		$wlregcmd_args = implode(" ", $wlregcmd);
2718

    
2719
		/* build a complete list of the wireless clones for this interface */
2720
		$clone_list = array();
2721
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2722
			$clone_list[] = interface_get_wireless_clone($baseif);
2723
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2724
			foreach ($config['wireless']['clone'] as $clone) {
2725
				if ($clone['if'] == $baseif)
2726
					$clone_list[] = $clone['cloneif'];
2727
			}
2728
		}
2729

    
2730
		/* find which clones are up and bring them down */
2731
		$clones_up = array();
2732
		foreach ($clone_list as $clone_if) {
2733
			$clone_status = pfSense_get_interface_addresses($clone_if);
2734
			if ($clone_status['status'] == 'up') {
2735
				$clones_up[] = $clone_if;
2736
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2737
			}
2738
		}
2739

    
2740
		/* apply the regulatory settings */
2741
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2742

    
2743
		/* bring the clones back up that were previously up */
2744
		foreach ($clones_up as $clone_if) {
2745
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2746

    
2747
			/*
2748
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2749
			 * is in infrastructure mode, and WPA is enabled.
2750
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2751
			 */
2752
			if ($clone_if != $if) {
2753
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2754
				if ( !empty($friendly_if)
2755
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2756
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2757
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2758
				}
2759
			}
2760
		}
2761
	}
2762

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

    
2767
	/* configure wireless */
2768
	$wlcmd_args = implode(" ", $wlcmd);
2769
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2770
	unset($wlcmd_args, $wlcmd);
2771

    
2772

    
2773
	sleep(1);
2774
	/* execute hostapd and wpa_supplicant if required in shell */
2775
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2776

    
2777
	return 0;
2778

    
2779
}
2780

    
2781
function kill_hostapd($interface) {
2782
	global $g;
2783

    
2784
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2785
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2786
}
2787

    
2788
function kill_wpasupplicant($interface) {
2789
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2790
}
2791

    
2792
function find_dhclient_process($interface) {
2793
	if ($interface)
2794
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2795
	else
2796
		$pid = 0;
2797

    
2798
	return intval($pid);
2799
}
2800

    
2801
function find_dhcp6c_process($interface) {
2802
	global $g;
2803

    
2804
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid"))
2805
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2806
	else
2807
		return(false);
2808

    
2809
	return intval($pid);
2810
}
2811

    
2812
function interface_vlan_mtu_configured($realhwif, $mtu) {
2813
	global $config;
2814

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

    
2827
	return $mtu;
2828
}
2829

    
2830
function interface_virtual_create($interface) {
2831
	global $config;
2832

    
2833
	if (strstr($interface, "_vlan")) {
2834
		interfaces_vlan_configure($vlan);
2835
	} else if (substr($interface, 0, 3) == "gre") {
2836
		interfaces_gre_configure(0, $interface);
2837
	} else if (substr($interface, 0, 3) == "gif") {
2838
		interfaces_gif_configure(0, $interface);
2839
	} else if (substr($interface, 0, 5) == "ovpns") {
2840
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
2841
			foreach ($config['openvpn']['openvpn-server'] as $server) {
2842
				if ($interface == "ovpns{$server['vpnid']}") {
2843
					if (!function_exists('openvpn_resync'))
2844
						require_once('openvpn.inc');
2845
					log_error("OpenVPN: Resync server {$server['description']}");
2846
					openvpn_resync('server', $server);
2847
				}
2848
			}
2849
			unset($server);
2850
		}
2851
	} else if (substr($interface, 0, 5) == "ovpnc") {
2852
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
2853
			foreach ($config['openvpn']['openvpn-client'] as $client) {
2854
				if ($interface == "ovpnc{$client['vpnid']}") {
2855
					if (!function_exists('openvpn_resync'))
2856
						require_once('openvpn.inc');
2857
					log_error("OpenVPN: Resync server {$client['description']}");
2858
					openvpn_resync('client', $client);
2859
				}
2860
			}
2861
			unset($client);
2862
		}
2863
	} else if (substr($interface, 0, 4) == "lagg") {
2864
		interfaces_lagg_configure($interface);
2865
	} else if (substr($interface, 0, 6) == "bridge") {
2866
		interfaces_bridge_configure(0, $interface);
2867
	}
2868
}
2869

    
2870
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2871
	global $config;
2872

    
2873
	if (!is_array($vlanifs))
2874
		return;
2875

    
2876
	/* All vlans need to use the same mtu value as their parent. */
2877
	foreach ($vlanifs as $vlan) {
2878
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2879
		if (!empty($assignedport)) {
2880
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
2881
				/*
2882
				* XXX: This is really never going to happen just keep the code for safety and readbility.
2883
				* It never happens since interface_vlan_mtu_configured finds the biggest mtu on vlans.
2884
				* Also if it has a lower mtu configured just respect user choice.
2885
				*/
2886
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2887
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2888
			} else {
2889
				if (get_interface_mtu($vlan['vlanif']) != $mtu)
2890
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2891
			}
2892
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2893
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
2894
	}
2895
}
2896

    
2897
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2898
	global $config, $g;
2899
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2900
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2901

    
2902
	$wancfg = $config['interfaces'][$interface];
2903

    
2904
	if (!isset($wancfg['enable']))
2905
		return;
2906

    
2907
	$realif = get_real_interface($interface);
2908
	$realhwif_array = get_parent_interface($interface);
2909
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2910
	$realhwif = $realhwif_array[0];
2911

    
2912
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2913
		/* remove all IPv4 and IPv6 addresses */
2914
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2915
		if (is_array($tmpifaces)) {
2916
			foreach ($tmpifaces as $tmpiface) {
2917
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
2918
					if (!is_linklocal($tmpiface))
2919
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2920
				} else {
2921
					if (is_subnetv4($tmpiface)) {
2922
						$tmpip = explode('/', $tmpiface);
2923
						$tmpip = $tmpip[0];
2924
					} else
2925
						$tmpip = $tmpiface;
2926
					pfSense_interface_deladdress($realif, $tmpip);
2927
				}
2928
			}
2929
		}
2930

    
2931
		/* only bring down the interface when both v4 and v6 are set to NONE */
2932
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6']))
2933
			interface_bring_down($interface);
2934
	}
2935

    
2936
	$interface_to_check = $realif;
2937
	switch ($wancfg['ipaddr']) {
2938
	case 'pppoe':
2939
	case 'l2tp':
2940
	case 'pptp':
2941
	case 'ppp':
2942
		$interface_to_check = $realhwif;
2943
		break;
2944
	}
2945

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

    
2950
	/* Disable Accepting router advertisements unless specifically requested */
2951
	if ($g['debug'])
2952
		log_error("Deny router advertisements for interface {$interface}");
2953
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2954

    
2955
	/* wireless configuration? */
2956
	if (is_array($wancfg['wireless']))
2957
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2958

    
2959
	$mac = get_interface_mac($realhwif);
2960
	/*
2961
	 * Don't try to reapply the spoofed MAC if it's already applied.
2962
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2963
	 * the interface config again, which attempts to spoof the MAC again,
2964
	 * which cycles the link again...
2965
	 */
2966
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
2967
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2968
			" link " . escapeshellarg($wancfg['spoofmac']));
2969

    
2970
		/*
2971
		 * All vlans need to spoof their parent mac address, too.  see
2972
		 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2973
		 */
2974
		if (is_array($config['vlans']['vlan'])) {
2975
			foreach ($config['vlans']['vlan'] as $vlan) {
2976
				if ($vlan['if'] == $realhwif)
2977
					mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2978
					" link " . escapeshellarg($wancfg['spoofmac']));
2979
			}
2980
		}
2981
	}  else {
2982

    
2983
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2984
			/*   this is not a valid mac address.  generate a
2985
			 *   temporary mac address so the machine can get online.
2986
			 */
2987
			echo gettext("Generating new MAC address.");
2988
			$random_mac = generate_random_mac_address();
2989
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2990
				" link " . escapeshellarg($random_mac));
2991
			$wancfg['spoofmac'] = $random_mac;
2992
			write_config();
2993
			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");
2994
		}
2995
	}
2996

    
2997
	/* media */
2998
	if ($wancfg['media'] || $wancfg['mediaopt']) {
2999
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3000
		if ($wancfg['media'])
3001
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3002
		if ($wancfg['mediaopt'])
3003
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3004
		mwexec($cmd);
3005
	}
3006
	$options = pfSense_get_interface_addresses($realhwif);
3007

    
3008
	/* skip vlans for checksumming and polling */
3009
	if (!stristr($realif, "_vlan") && is_array($options)) {
3010
		$flags_on = 0;
3011
		$flags_off = 0;
3012
		if(isset($config['system']['disablechecksumoffloading'])) {
3013
			if (isset($options['encaps']['txcsum']))
3014
				$flags_off |= IFCAP_TXCSUM;
3015
			if (isset($options['encaps']['rxcsum']))
3016
				$flags_off |= IFCAP_RXCSUM;
3017
		} else {
3018
			if (isset($options['caps']['txcsum']))
3019
				$flags_on |= IFCAP_TXCSUM;
3020
			if (isset($options['caps']['rxcsum']))
3021
				$flags_on |= IFCAP_RXCSUM;
3022
		}
3023

    
3024
		if(isset($config['system']['disablesegmentationoffloading']))
3025
			$flags_off |= IFCAP_TSO;
3026
		else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6']))
3027
			$flags_on |= IFCAP_TSO;
3028

    
3029
		if(isset($config['system']['disablelargereceiveoffloading']))
3030
			$flags_off |= IFCAP_LRO;
3031
		else if (isset($options['caps']['lro']))
3032
			$flags_on |= IFCAP_LRO;
3033

    
3034
		/* if the NIC supports polling *AND* it is enabled in the GUI */
3035
		if (!isset($config['system']['polling']))
3036
			$flags_off |= IFCAP_POLLING;
3037
		else if (isset($options['caps']['polling']))
3038
			$flags_on |= IFCAP_POLLING;
3039

    
3040
		pfSense_interface_capabilities($realhwif, -$flags_off);
3041
		pfSense_interface_capabilities($realhwif, $flags_on);
3042
	}
3043

    
3044
	/* invalidate interface/ip/sn cache */
3045
	get_interface_arr(true);
3046
	unset($interface_ip_arr_cache[$realif]);
3047
	unset($interface_sn_arr_cache[$realif]);
3048
	unset($interface_ipv6_arr_cache[$realif]);
3049
	unset($interface_snv6_arr_cache[$realif]);
3050

    
3051
	$tunnelif = substr($realif, 0, 3);
3052
	switch ($wancfg['ipaddr']) {
3053
	case 'dhcp':
3054
		interface_dhcp_configure($interface);
3055
		break;
3056
	case 'pppoe':
3057
	case 'l2tp':
3058
	case 'pptp':
3059
	case 'ppp':
3060
		interface_ppps_configure($interface);
3061
		break;
3062
	default:
3063
		/* XXX: Kludge for now related to #3280 */
3064
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3065
			if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "")
3066
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3067
		}
3068
		break;
3069
	}
3070

    
3071
	switch ($wancfg['ipaddrv6']) {
3072
	case 'slaac':
3073
	case 'dhcp6':
3074
		interface_dhcpv6_configure($interface, $wancfg);
3075
		break;
3076
	case '6rd':
3077
		interface_6rd_configure($interface, $wancfg);
3078
		break;
3079
	case '6to4':
3080
		interface_6to4_configure($interface, $wancfg);
3081
		break;
3082
	case 'track6':
3083
		interface_track6_configure($interface, $wancfg, $linkupevent);
3084
		break;
3085
	default:
3086
		/* XXX: Kludge for now related to #3280 */
3087
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3088
			if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3089
				//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3090
				// FIXME: Add IPv6 Support to the pfSense module
3091
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3092
			}
3093
		}
3094
		break;
3095
	}
3096

    
3097
	if (!empty($wancfg['mtu'])) {
3098
		if (stristr($realif, "_vlan")) {
3099
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3100
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
3101
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3102
			else
3103
				$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
3104

    
3105
			if ($wancfg['mtu'] > $parentmtu) {
3106
				if (get_interface_mtu($realhwif) != $wancfg['mtu'])
3107
					pfSense_interface_mtu($realhwif, $wancfg['mtu']);
3108

    
3109
				/* All vlans need to use the same mtu value as their parent. */
3110
				interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $wancfg['mtu']);
3111
			} else
3112
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3113
		} else {
3114
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3115
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3116

    
3117
			/* This case is needed when the parent of vlans is being configured */
3118
			interface_vlan_adapt_mtu(link_interface_to_vlans($realif), $wancfg['mtu']);
3119
		}
3120
		/* XXX: What about gre/gif/lagg/.. ? */
3121
	}
3122

    
3123
	if (does_interface_exist($wancfg['if']))
3124
		interfaces_bring_up($wancfg['if']);
3125

    
3126
	interface_netgraph_needed($interface);
3127

    
3128
	if (!$g['booting']) {
3129
		link_interface_to_vips($interface, "update");
3130

    
3131
		unset($gre);
3132
		$gre = link_interface_to_gre($interface);
3133
		if (!empty($gre))
3134
			array_walk($gre, 'interface_gre_configure');
3135

    
3136
		unset($gif);
3137
		$gif = link_interface_to_gif($interface);
3138
		if (!empty($gif))
3139
			array_walk($gif, 'interface_gif_configure');
3140

    
3141
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3142
			unset($bridgetmp);
3143
			$bridgetmp = link_interface_to_bridge($interface);
3144
			if (!empty($bridgetmp))
3145
				interface_bridge_add_member($bridgetmp, $realif);
3146
		}
3147

    
3148
		$grouptmp = link_interface_to_group($interface);
3149
		if (!empty($grouptmp))
3150
			array_walk($grouptmp, 'interface_group_add_member');
3151

    
3152
		if ($interface == "lan")
3153
			/* make new hosts file */
3154
			system_hosts_generate();
3155

    
3156
		if ($reloadall == true) {
3157

    
3158
			/* reconfigure static routes (kernel may have deleted them) */
3159
			system_routing_configure($interface);
3160

    
3161
			/* reload ipsec tunnels */
3162
			vpn_ipsec_configure();
3163

    
3164
			/* restart dnsmasq or unbound */
3165
			if (isset($config['dnsmasq']['enable']))
3166
				services_dnsmasq_configure();
3167
			elseif (isset($config['unbound']['enable']))
3168
				services_unbound_configure();
3169

    
3170
			/* update dyndns */
3171
			send_event("service reload dyndns {$interface}");
3172

    
3173
			/* XXX: which CPZONE? Needed? */
3174
			/* reload captive portal */
3175
			captiveportal_init_rules();
3176
		}
3177
	}
3178

    
3179
	interfaces_staticarp_configure($interface);
3180
	return 0;
3181
}
3182

    
3183
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3184
	global $config, $g;
3185

    
3186
	if (!is_array($wancfg))
3187
		return;
3188

    
3189
	if (!isset($wancfg['enable']))
3190
		return;
3191

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

    
3196
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3197
	$realif = get_real_interface($interface);
3198
	$linklocal = find_interface_ipv6_ll($realif);
3199
	if (!empty($linklocal))
3200
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3201
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3202
	/* XXX: Probably should remove? */
3203
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3204

    
3205
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3206
	if (!isset($trackcfg['enable'])) {
3207
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3208
		return;
3209
	}
3210

    
3211
	switch($trackcfg['ipaddrv6']) {
3212
	case "6to4":
3213
		if ($g['debug'])
3214
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3215
		interface_track6_6to4_configure($interface, $wancfg);
3216
		break;
3217
	case "6rd":
3218
		if ($g['debug'])
3219
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3220
		interface_track6_6rd_configure($interface, $wancfg);
3221
		break;
3222
	case "dhcp6":
3223
		if ($linkupevent == true) {
3224
			/* 
3225
			 * NOTE: Usually come here from rc.linkup calling so just call directly intead of generating event
3226
			 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3227
			 *
3228
			 * XXX: Probably DHCPv6 client should handle this autmagically itself?
3229
			 */
3230
			$parentrealif = get_real_interface($wancfg['track6-interface']);
3231
			$pidv6 = find_dhcp6c_process($parentrealif);
3232
			if($pidv6)
3233
				posix_kill($pidv6, SIGHUP);
3234
		}
3235
		break;
3236
	}
3237

    
3238
	if (!$g['booting'] && $linkupevent == false) {
3239
		if (!function_exists('services_dhcpd_configure'))
3240
			require_once("services.inc");
3241

    
3242
		services_dhcpd_configure("inet6");
3243
	}
3244

    
3245
	return 0;
3246
}
3247

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

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

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

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

    
3266
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3267
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3268
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3269
		return;
3270
	}
3271
	$hexwanv4 = return_hex_ipv4($ip4address);
3272

    
3273
	/* create the long prefix notation for math, save the prefix length */
3274
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3275
	$rd6prefixlen = $rd6prefix[1];
3276
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3277

    
3278
	/* binary presentation of the prefix for all 128 bits. */
3279
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3280

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

    
3286
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3287
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3288
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3289
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3290
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3291
	/* fill the rest out with zeros */
3292
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3293

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

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

    
3306
	return 0;
3307
}
3308

    
3309
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3310
	global $config, $g;
3311
	global $interface_ipv6_arr_cache;
3312
	global $interface_snv6_arr_cache;
3313

    
3314
	if (!is_array($lancfg))
3315
		return;
3316

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

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

    
3327
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3328
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3329
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3330
		return;
3331
	}
3332
	$hexwanv4 = return_hex_ipv4($ip4address);
3333

    
3334
	/* create the long prefix notation for math, save the prefix length */
3335
	$sixto4prefix = "2002::";
3336
	$sixto4prefixlen = 16;
3337
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3338

    
3339
	/* binary presentation of the prefix for all 128 bits. */
3340
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3341

    
3342
	/* just save the left prefix length bits */
3343
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3344
	/* add the v4 address */
3345
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3346
	/* add the custom prefix id */
3347
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3348
	/* fill the rest out with zeros */
3349
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3350

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

    
3354
	$lanif = get_real_interface($interface);
3355
	$oip = find_interface_ipv6($lanif);
3356
	if (is_ipaddrv6($oip))
3357
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3358
	unset($interface_ipv6_arr_cache[$lanif]);
3359
	unset($interface_snv6_arr_cache[$lanif]);
3360
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3361
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3362

    
3363
	return 0;
3364
}
3365

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

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

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

    
3375
	if (!is_module_loaded('if_stf.ko'))
3376
		mwexec('/sbin/kldload if_stf.ko');
3377

    
3378
	$wanif = get_real_interface($interface);
3379
	$ip4address = find_interface_ip($wanif);
3380
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3381
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3382
		return false;
3383
	}
3384
	$hexwanv4 = return_hex_ipv4($ip4address);
3385

    
3386
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3387
		$wancfg['prefix-6rd-v4plen'] = 0;
3388

    
3389
	/* create the long prefix notation for math, save the prefix length */
3390
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3391
	$rd6prefixlen = $rd6prefix[1];
3392
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3393

    
3394
	/* binary presentation of the prefix for all 128 bits. */
3395
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3396

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

    
3404
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3405
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3406

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

    
3409
	/* XXX: need to extend to support variable prefix size for v4 */
3410
	if (!is_module_loaded("if_stf"))
3411
		mwexec("/sbin/kldload if_stf.ko");
3412
	$stfiface = "{$interface}_stf";
3413
	if (does_interface_exist($stfiface))
3414
		pfSense_interface_destroy($stfiface);
3415
	$tmpstfiface = pfSense_interface_create("stf");
3416
	pfSense_interface_rename($tmpstfiface, $stfiface);
3417
	pfSense_interface_flags($stfiface, IFF_LINK2);
3418
	if ($wancfg['prefix-6rd-v4plen'] > 0)
3419
		$rd6prefixlen += intval($wancfg['prefix-6rd-v4plen']);
3420
	else
3421
		$rd6prefixlen += 32;
3422
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3423
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3424
	if ($wancfg['prefix-6rd-v4plen'] > 0 && $wancfg['prefix-6rd-v4plen'] < 32)
3425
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/{$wancfg['prefix-6rd-v4plen']}");
3426
	if ($g['debug'])
3427
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3428

    
3429
	/* write out a default router file */
3430
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3431
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3432

    
3433
	$ip4gateway = get_interface_gateway($interface);
3434
	if (is_ipaddrv4($ip4gateway))
3435
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3436

    
3437
	/* configure dependent interfaces */
3438
	if (!$g['booting'])
3439
		link_interface_to_track6($interface, "update");
3440

    
3441
	return 0;
3442
}
3443

    
3444
function interface_6to4_configure($interface = "wan", $wancfg){
3445
	global $config, $g;
3446

    
3447
	/* because this is a tunnel interface we can only function
3448
	 *	with a public IPv4 address on the interface */
3449

    
3450
	if (!is_array($wancfg))
3451
		return;
3452

    
3453
	$wanif = get_real_interface($interface);
3454
	$ip4address = find_interface_ip($wanif);
3455
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3456
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3457
		return false;
3458
	}
3459

    
3460
	/* create the long prefix notation for math, save the prefix length */
3461
	$stfprefixlen = 16;
3462
	$stfprefix = Net_IPv6::uncompress("2002::");
3463
	$stfarr = explode(":", $stfprefix);
3464
	$v4prefixlen = "0";
3465

    
3466
	/* we need the hex form of the interface IPv4 address */
3467
	$ip4arr = explode(".", $ip4address);
3468
	$hexwanv4 = "";
3469
	foreach($ip4arr as $octet)
3470
		$hexwanv4 .= sprintf("%02x", $octet);
3471

    
3472
	/* we need the hex form of the broker IPv4 address */
3473
	$ip4arr = explode(".", "192.88.99.1");
3474
	$hexbrv4 = "";
3475
	foreach($ip4arr as $octet)
3476
		$hexbrv4 .= sprintf("%02x", $octet);
3477

    
3478
	/* binary presentation of the prefix for all 128 bits. */
3479
	$stfprefixbin = "";
3480
	foreach($stfarr as $element) {
3481
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3482
	}
3483
	/* just save the left prefix length bits */
3484
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3485

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

    
3490
	/* for the local subnet too. */
3491
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3492
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3493

    
3494
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3495
	$stfbrarr = array();
3496
	$stfbrbinarr = array();
3497
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3498
	foreach($stfbrbinarr as $bin)
3499
		$stfbrarr[] = dechex(bindec($bin));
3500
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3501

    
3502
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3503
	$stflanarr = array();
3504
	$stflanbinarr = array();
3505
	$stflanbinarr = str_split($stflanbin, 16);
3506
	foreach($stflanbinarr as $bin)
3507
		$stflanarr[] = dechex(bindec($bin));
3508
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3509
	$stflanarr[7] = 1;
3510
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3511

    
3512
	/* setup the stf interface */
3513
	if (!is_module_loaded("if_stf"))
3514
		mwexec("/sbin/kldload if_stf.ko");
3515
	$stfiface = "{$interface}_stf";
3516
	if (does_interface_exist($stfiface))
3517
		pfSense_interface_destroy($stfiface);
3518
	$tmpstfiface = pfSense_interface_create("stf");
3519
	pfSense_interface_rename($tmpstfiface, $stfiface);
3520
	pfSense_interface_flags($stfiface, IFF_LINK2);
3521
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3522

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

    
3526
	/* write out a default router file */
3527
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3528
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3529

    
3530
	$ip4gateway = get_interface_gateway($interface);
3531
	if (is_ipaddrv4($ip4gateway))
3532
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3533

    
3534
	if (!$g['booting'])
3535
		link_interface_to_track6($interface, "update");
3536

    
3537
	return 0;
3538
}
3539

    
3540
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3541
	global $config, $g;
3542

    
3543
	if (!is_array($wancfg))
3544
		return;
3545

    
3546
	$wanif = get_real_interface($interface, "inet6");
3547
	$dhcp6cconf = "";
3548
	$dhcp6cconf .= "interface {$wanif} {\n";
3549

    
3550
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3551
	if($wancfg['ipaddrv6'] == "slaac") {
3552
		$dhcp6cconf .= "	information-only;\n";
3553
		$dhcp6cconf .= "	request domain-name-servers;\n";
3554
		$dhcp6cconf .= "	request domain-name;\n";
3555
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3556
		$dhcp6cconf .= "};\n";
3557
	} else {
3558
		/* skip address request if this is set */
3559
		if(!isset($wancfg['dhcp6prefixonly']))
3560
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3561
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3562
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3563

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

    
3568
		$dhcp6cconf .= "};\n";
3569

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

    
3573
		if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3574
			/* Setup the prefix delegation */
3575
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3576
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3577
			if (isset($wancfg['dhcp6-ia-pd-send-hint']))
3578
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3579
			$iflist = link_interface_to_track6($interface);
3580
			foreach ($iflist as $friendly => $ifcfg) {
3581
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3582
					if ($g['debug'])
3583
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3584
					$realif = get_real_interface($friendly);
3585
					$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3586
					$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3587
					$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3588
					$dhcp6cconf .= "	};\n";
3589
				}
3590
			}
3591
			unset($preflen, $iflist, $ifcfg);
3592
			$dhcp6cconf .= "};\n";
3593
		}
3594
	}
3595

    
3596
	// DHCP6 Config File Advanced
3597
	if ($wancfg['adv_dhcp6_config_advanced']) { $dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif); }
3598

    
3599
	// DHCP6 Config File Override
3600
	if ($wancfg['adv_dhcp6_config_file_override']) { $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif); }
3601

    
3602
	/* wide-dhcp6c works for now. */
3603
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3604
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3605
		unset($dhcp6cconf);
3606
		return 1;
3607
	}
3608
	unset($dhcp6cconf);
3609

    
3610
	$dhcp6cscript = "#!/bin/sh\n";
3611
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3612
	$dhcp6cscript .= "\$dmips = \${new_domain_name_servers}\n";
3613
	$dhcp6cscript .= "\$dmnames = \${new_domain_name}\n";
3614
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\$dmnames&dmips=\$dmips\"\n";
3615
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3616
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3617
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3618
		unset($dhcp6cscript);
3619
		return 1;
3620
	}
3621
	unset($dhcp6cscript);
3622
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3623

    
3624
	$rtsoldscript = "#!/bin/sh\n";
3625
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3626
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3627
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3628
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3629
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3630
	$rtsoldscript .= "\t/bin/sleep 1\n";
3631
	$rtsoldscript .= "fi\n";
3632
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3633
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3634
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3635
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3636
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3637
		unset($rtsoldscript);
3638
		return 1;
3639
	}
3640
	unset($rtsoldscript);
3641
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3642

    
3643
	/* accept router advertisements for this interface */
3644
	mwexec("/sbin/sysctl -w net.inet6.ip6.accept_rtadv=1");
3645
	log_error("Accept router advertisements on interface {$wanif} ");
3646
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3647

    
3648
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3649
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3650
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3651
		sleep(2);
3652
	}
3653
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3654

    
3655
	/* NOTE: will be called from rtsold invoked script
3656
	 * link_interface_to_track6($interface, "update");
3657
	 */
3658

    
3659
	return 0;
3660
}
3661

    
3662
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3663
	global $g;
3664

    
3665
	$send_options = "";
3666
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3667
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_send_options']);
3668
		foreach ($options as $option) {
3669
			$send_options .= "\tsend " . trim($option) . ";\n";
3670
		}
3671
	}
3672

    
3673
	$request_options = "";
3674
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3675
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_request_options']);
3676
		foreach ($options as $option) {
3677
			$request_options .= "\trequest " . trim($option) . ";\n";
3678
		}
3679
	}
3680

    
3681
	$information_only = "";
3682
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') 
3683
		$information_only = "\tinformation-only;\n";
3684

    
3685
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3686
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '')
3687
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3688

    
3689
	$interface_statement  = "interface";
3690
	$interface_statement .= " {$wanif}";
3691
	$interface_statement .= " {\n";
3692
	$interface_statement .= "$send_options";
3693
	$interface_statement .= "$request_options";
3694
	$interface_statement .= "$information_only";
3695
	$interface_statement .= "$script";
3696
	$interface_statement .= "};\n";
3697

    
3698
	$id_assoc_statement_address = "";
3699
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3700
		$id_assoc_statement_address .= "id-assoc";
3701
		$id_assoc_statement_address .= " na";
3702
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) 
3703
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3704
		$id_assoc_statement_address .= " { ";
3705

    
3706
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') && 
3707
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) || 
3708
			 ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity')) ) {
3709
			$id_assoc_statement_address .= "\n\taddress";
3710
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3711
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3712
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) || 
3713
							($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity') ) 
3714
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3715
			$id_assoc_statement_address .= ";\n";
3716
		}
3717

    
3718
		$id_assoc_statement_address  .= "};\n";
3719
	}
3720

    
3721
	$id_assoc_statement_prefix = "";
3722
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3723
		$id_assoc_statement_prefix .= "id-assoc";
3724
		$id_assoc_statement_prefix .= " pd";
3725
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) 
3726
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3727
		$id_assoc_statement_prefix .= " { ";
3728

    
3729
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') && 
3730
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) || 
3731
			 ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity')) ) {
3732
			$id_assoc_statement_prefix .= "\n\tprefix";
3733
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3734
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3735
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) || 
3736
						  ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity') ) 
3737
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3738
			$id_assoc_statement_prefix .= ";";
3739
		}
3740

    
3741
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3742
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3743
			$id_assoc_statement_prefix .= " {$wanif}";
3744
			$id_assoc_statement_prefix .= " {\n";
3745
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3746
			if ( ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) && 
3747
				 ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128) ) 
3748
				 $id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3749
			$id_assoc_statement_prefix .= "\t};";
3750
		}
3751

    
3752
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') || 
3753
			 (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) ) { 
3754
			$id_assoc_statement_prefix .= "\n";
3755
		}
3756

    
3757
		$id_assoc_statement_prefix  .= "};\n";
3758
	}
3759

    
3760
	$authentication_statement = "";
3761
	if ( ($wancfg['adv_dhcp6_authentication_statement_authname'] != '') && 
3762
		 ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed') ) {
3763
		$authentication_statement .= "authentication";
3764
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
3765
		$authentication_statement .= " {\n";
3766
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
3767
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) 
3768
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
3769
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') 
3770
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
3771
		$authentication_statement .= "};\n";
3772
	}
3773

    
3774
	$key_info_statement = "";
3775
	if ( ($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') && 
3776
		 ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') && 
3777
		 (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) && 
3778
		 ($wancfg['adv_dhcp6_key_info_statement_secret'] != '') ) {
3779
		$key_info_statement .= "keyinfo";
3780
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
3781
		$key_info_statement .= " {\n";
3782
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
3783
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
3784
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
3785
		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'])) 
3786
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
3787
		$key_info_statement .= "};\n";
3788
	}
3789

    
3790
	$dhcp6cconf  = $interface_statement;
3791
	$dhcp6cconf .= $id_assoc_statement_address;
3792
	$dhcp6cconf .= $id_assoc_statement_prefix;
3793
	$dhcp6cconf .= $authentication_statement;
3794
	$dhcp6cconf .= $key_info_statement;
3795

    
3796
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3797

    
3798
	return $dhcp6cconf;
3799
}
3800

    
3801

    
3802
function DHCP6_Config_File_Override($wancfg, $wanif) {
3803

    
3804
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
3805
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3806

    
3807
	return $dhcp6cconf;
3808
}
3809

    
3810

    
3811
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
3812

    
3813
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3814

    
3815
	return $dhcp6cconf;
3816
}
3817

    
3818

    
3819
function interface_dhcp_configure($interface = "wan") {
3820
	global $config, $g;
3821

    
3822
	$wancfg = $config['interfaces'][$interface];
3823
	$wanif = $wancfg['if'];
3824
	if (empty($wancfg))
3825
		$wancfg = array();
3826

    
3827
	/* generate dhclient_wan.conf */
3828
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3829
	if (!$fd) {
3830
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3831
		return 1;
3832
	}
3833

    
3834
	if ($wancfg['dhcphostname']) {
3835
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3836
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3837
	} else {
3838
		$dhclientconf_hostname = "";
3839
	}
3840

    
3841
	$wanif = get_real_interface($interface);
3842
	if (empty($wanif)) {
3843
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3844
		return 0;
3845
	}
3846
	$dhclientconf = "";
3847

    
3848
	$dhclientconf .= <<<EOD
3849
interface "{$wanif}" {
3850
timeout 60;
3851
retry 15;
3852
select-timeout 0;
3853
initial-interval 1;
3854
	{$dhclientconf_hostname}
3855
	script "/sbin/dhclient-script";
3856
EOD;
3857

    
3858
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3859
	$dhclientconf .= <<<EOD
3860

    
3861
	reject {$wancfg['dhcprejectfrom']};
3862
EOD;
3863
}
3864
	$dhclientconf .= <<<EOD
3865

    
3866
}
3867

    
3868
EOD;
3869

    
3870
	// DHCP Config File Advanced
3871
	if ($wancfg['adv_dhcp_config_advanced']) { $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif); }
3872

    
3873
if(is_ipaddr($wancfg['alias-address'])) {
3874
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3875
	$dhclientconf .= <<<EOD
3876
alias {
3877
	interface  "{$wanif}";
3878
	fixed-address {$wancfg['alias-address']};
3879
	option subnet-mask {$subnetmask};
3880
}
3881

    
3882
EOD;
3883
}
3884

    
3885
	// DHCP Config File Override
3886
	if ($wancfg['adv_dhcp_config_file_override']) { $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif); }
3887

    
3888
	fwrite($fd, $dhclientconf);
3889
	fclose($fd);
3890

    
3891
	/* bring wan interface up before starting dhclient */
3892
	if($wanif)
3893
		interfaces_bring_up($wanif);
3894
	else
3895
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3896

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

    
3900
	return 0;
3901
}
3902

    
3903
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3904

    
3905
	$hostname = "";
3906
	if ($wancfg['dhcphostname'] != '') {
3907
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3908
	}
3909

    
3910
	/* DHCP Protocol Timings */
3911
	$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");
3912
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
3913
		$pt_variable = "{$Protocol_Timing}";
3914
		${$pt_variable} = "";
3915
		if ($wancfg[$Protocol_Timing] != "") {
3916
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
3917
		}
3918
	}
3919

    
3920
	$send_options = "";
3921
	if ($wancfg['adv_dhcp_send_options'] != '') {
3922
		$options = split(",", $wancfg['adv_dhcp_send_options']);
3923
		foreach ($options as $option) {
3924
			$send_options .= "\tsend " . trim($option) . ";\n";
3925
		}
3926
	}
3927

    
3928
	$request_options = "";
3929
	if ($wancfg['adv_dhcp_request_options'] != '') {
3930
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
3931
	}
3932

    
3933
	$required_options = "";
3934
	if ($wancfg['adv_dhcp_required_options'] != '') {
3935
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
3936
	}
3937

    
3938
	$option_modifiers = "";
3939
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
3940
		$modifiers = split(",", $wancfg['adv_dhcp_option_modifiers']);
3941
		foreach ($modifiers as $modifier) {
3942
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
3943
		}
3944
	}
3945

    
3946
 	$dhclientconf  = "interface \"{$wanif}\" {\n";
3947
 	$dhclientconf .= "\n";
3948
 	$dhclientconf .= "# DHCP Protocol Timing Values\n";
3949
 	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
3950
 	$dhclientconf .= "{$adv_dhcp_pt_retry}";
3951
 	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
3952
 	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
3953
 	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
3954
 	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
3955
 	$dhclientconf .= "\n";
3956
 	$dhclientconf .= "# DHCP Protocol Options\n";
3957
 	$dhclientconf .= "{$hostname}";
3958
 	$dhclientconf .= "{$send_options}";
3959
 	$dhclientconf .= "{$request_options}";
3960
 	$dhclientconf .= "{$required_options}";
3961
 	$dhclientconf .= "{$option_modifiers}";
3962
 	$dhclientconf .= "\n";
3963
 	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
3964
 	$dhclientconf .= "}\n";
3965

    
3966
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3967

    
3968
	return $dhclientconf;
3969
}
3970

    
3971

    
3972
function DHCP_Config_File_Override($wancfg, $wanif) {
3973

    
3974
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
3975
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3976

    
3977
	return $dhclientconf;
3978
}
3979

    
3980

    
3981
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
3982

    
3983
	/* Apply Interface Substitutions */
3984
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
3985

    
3986
	/* Apply Hostname Substitutions */
3987
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
3988

    
3989
	/* Arrays of MAC Address Types, Cases, Delimiters */
3990
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
3991
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
3992
	$various_mac_cases      = array("U", "L");
3993
	$various_mac_delimiters = array("", " ", ":", "-", ".");
3994

    
3995
	/* Apply MAC Address Substitutions */
3996
	foreach ($various_mac_types as $various_mac_type) {
3997
		foreach ($various_mac_cases as $various_mac_case) {
3998
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
3999

    
4000
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4001
				if ($res !== false) {
4002

    
4003
					/* Get MAC Address as ASCII String With Colon (:) Celimiters */
4004
					if ("$various_mac_case" == "U") $dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4005
					if ("$various_mac_case" == "L") $dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4006

    
4007
					if ("$various_mac_type" == "mac_addr_hex") {
4008
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4009
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4010
						$dhcpclientconf_mac_hex = "";
4011
						$delimiter = "";
4012
						for($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4013
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4014
							$delimiter = ":";
4015
						}
4016
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4017
					}
4018

    
4019
					/* MAC Address Delimiter Substitutions */
4020
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4021

    
4022
					/* Apply MAC Address Substitutions */
4023
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4024
				}
4025
			}
4026
		}
4027
	}
4028

    
4029
	return $dhclientconf;
4030
}
4031

    
4032
function interfaces_group_setup() {
4033
	global $config;
4034

    
4035
	if (!is_array($config['ifgroups']['ifgroupentry']))
4036
		return;
4037

    
4038
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
4039
		interface_group_setup($groupar);
4040

    
4041
	return;
4042
}
4043

    
4044
function interface_group_setup(&$groupname /* The parameter is an array */) {
4045
	global $config;
4046

    
4047
	if (!is_array($groupname))
4048
		return;
4049
	$members = explode(" ", $groupname['members']);
4050
	foreach($members as $ifs) {
4051
		$realif = get_real_interface($ifs);
4052
		if ($realif)
4053
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4054
	}
4055

    
4056
	return;
4057
}
4058

    
4059
function is_interface_group($if) {
4060
	global $config;
4061

    
4062
	if (is_array($config['ifgroups']['ifgroupentry']))
4063
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4064
			if ($groupentry['ifname'] === $if)
4065
				return true;
4066
		}
4067

    
4068
	return false;
4069
}
4070

    
4071
function interface_group_add_member($interface, $groupname) {
4072
	$interface = get_real_interface($interface);
4073
	mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4074
}
4075

    
4076
/* COMPAT Function */
4077
function convert_friendly_interface_to_real_interface_name($interface) {
4078
	return get_real_interface($interface);
4079
}
4080

    
4081
/* COMPAT Function */
4082
function get_real_wan_interface($interface = "wan") {
4083
	return get_real_interface($interface);
4084
}
4085

    
4086
/* COMPAT Function */
4087
function get_current_wan_address($interface = "wan") {
4088
	return get_interface_ip($interface);
4089
}
4090

    
4091
/*
4092
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4093
 */
4094
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
4095
	global $config;
4096

    
4097
	/* XXX: For speed reasons reference directly the interface array */
4098
	$ifdescrs = &$config['interfaces'];
4099
	//$ifdescrs = get_configured_interface_list(false, true);
4100

    
4101
	foreach ($ifdescrs as $if => $ifname) {
4102
		if ($if == $interface || $ifname['if'] == $interface)
4103
			return $if;
4104

    
4105
		if (get_real_interface($if) == $interface)
4106
			return $if;
4107

    
4108
		$int = get_parent_interface($if, true);
4109
		if (is_array($int)) {
4110
			foreach ($int as $iface) {
4111
				if ($iface == $interface)
4112
					return $if;
4113
			}
4114
		}
4115
	}
4116

    
4117
	if ($interface == "enc0")
4118
		return 'IPsec';
4119

    
4120
	return NULL;
4121
}
4122

    
4123
/* attempt to resolve interface to friendly descr */
4124
function convert_friendly_interface_to_friendly_descr($interface) {
4125
	global $config;
4126

    
4127
	switch ($interface) {
4128
	case "l2tp":
4129
		$ifdesc = "L2TP";
4130
		break;
4131
	case "pptp":
4132
		$ifdesc = "PPTP";
4133
		break;
4134
	case "pppoe":
4135
		$ifdesc = "PPPoE";
4136
		break;
4137
	case "openvpn":
4138
		$ifdesc = "OpenVPN";
4139
		break;
4140
	case "enc0":
4141
	case "ipsec":
4142
		$ifdesc = "IPsec";
4143
		break;
4144
	default:
4145
		if (isset($config['interfaces'][$interface])) {
4146
			if (empty($config['interfaces'][$interface]['descr']))
4147
				$ifdesc = strtoupper($interface);
4148
			else
4149
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4150
			break;
4151
		} else if (stristr($interface, "_vip")) {
4152
			if (is_array($config['virtualip']['vip'])) {
4153
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
4154
					if ($vip['mode'] == "carp")  {
4155
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4156
							return "{$vip['subnet']} - {$vip['descr']}";
4157
					}
4158
				}
4159
			}
4160
		} else {
4161
			/* if list */
4162
			$ifdescrs = get_configured_interface_with_descr(false, true);
4163
			foreach ($ifdescrs as $if => $ifname) {
4164
				if ($if == $interface || $ifname == $interface)
4165
					return $ifname;
4166
			}
4167
		}
4168
		break;
4169
	}
4170

    
4171
	return $ifdesc;
4172
}
4173

    
4174
function convert_real_interface_to_friendly_descr($interface) {
4175
	global $config;
4176

    
4177
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4178

    
4179
	if ($ifdesc) {
4180
		$iflist = get_configured_interface_with_descr(false, true);
4181
		return $iflist[$ifdesc];
4182
	}
4183

    
4184
	return $interface;
4185
}
4186

    
4187
/*
4188
 *  get_parent_interface($interface):
4189
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4190
 *				or virtual interface (i.e. vlan)
4191
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4192
 *			-- returns $interface passed in if $interface parent is not found
4193
 *			-- returns empty array if an invalid interface is passed
4194
 *	(Only handles ppps and vlans now.)
4195
 */
4196
function get_parent_interface($interface, $avoidrecurse = false) {
4197
	global $config;
4198

    
4199
	$parents = array();
4200
	//Check that we got a valid interface passed
4201
	$realif = get_real_interface($interface);
4202
	if ($realif == NULL)
4203
		return $parents;
4204

    
4205
	// If we got a real interface, find it's friendly assigned name
4206
	if ($interface == $realif && $avoidrecurse == false)
4207
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4208

    
4209
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4210
		$ifcfg = $config['interfaces'][$interface];
4211
		switch ($ifcfg['ipaddr']) {
4212
			case "ppp":
4213
			case "pppoe":
4214
			case "pptp":
4215
			case "l2tp":
4216
				if (empty($parents))
4217
					if (is_array($config['ppps']['ppp']))
4218
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4219
							if ($ifcfg['if'] == $ppp['if']) {
4220
								$ports = explode(',', $ppp['ports']);
4221
								foreach ($ports as $pid => $parent_if)
4222
									$parents[$pid] = get_real_interface($parent_if);
4223
								break;
4224
							}
4225
						}
4226
				break;
4227
			case "dhcp":
4228
			case "static":
4229
			default:
4230
				// Handle _vlans
4231
				if (stristr($realif,"_vlan"))
4232
					if (is_array($config['vlans']['vlan']))
4233
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
4234
							if ($ifcfg['if'] == $vlan['vlanif']){
4235
								$parents[0] = $vlan['if'];
4236
								break;
4237
							}
4238
				break;
4239
		}
4240
	}
4241

    
4242
	if (empty($parents))
4243
		$parents[0] = $realif;
4244

    
4245
	return $parents;
4246
}
4247

    
4248
function interface_is_wireless_clone($wlif) {
4249
	if(!stristr($wlif, "_wlan")) {
4250
		return false;
4251
	} else {
4252
		return true;
4253
	}
4254
}
4255

    
4256
function interface_get_wireless_base($wlif) {
4257
	if(!stristr($wlif, "_wlan")) {
4258
		return $wlif;
4259
	} else {
4260
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4261
	}
4262
}
4263

    
4264
function interface_get_wireless_clone($wlif) {
4265
	if(!stristr($wlif, "_wlan")) {
4266
		return $wlif . "_wlan0";
4267
	} else {
4268
		return $wlif;
4269
	}
4270
}
4271

    
4272
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4273
	global $config, $g;
4274

    
4275
	$wanif = NULL;
4276

    
4277
	switch ($interface) {
4278
	case "l2tp":
4279
		$wanif = "l2tp";
4280
		break;
4281
	case "pptp":
4282
		$wanif = "pptp";
4283
		break;
4284
	case "pppoe":
4285
		$wanif = "pppoe";
4286
		break;
4287
	case "openvpn":
4288
		$wanif = "openvpn";
4289
		break;
4290
	case "ipsec":
4291
	case "enc0":
4292
		$wanif = "enc0";
4293
		break;
4294
	case "ppp":
4295
		$wanif = "ppp";
4296
		break;
4297
	default:
4298
		// If a real interface was alread passed simply
4299
		// pass the real interface back.  This encourages
4300
		// the usage of this function in more cases so that
4301
		// we can combine logic for more flexibility.
4302
		if(does_interface_exist($interface, $flush)) {
4303
			$wanif = $interface;
4304
			break;
4305
		}
4306

    
4307
		if (empty($config['interfaces'][$interface]))
4308
			break;
4309

    
4310
		$cfg = &$config['interfaces'][$interface];
4311

    
4312
		if ($family == "inet6") {
4313
			switch ($cfg['ipaddrv6']) {
4314
			case "6rd":
4315
			case "6to4":
4316
				$wanif = "{$interface}_stf";
4317
				break;
4318
			case 'pppoe':
4319
			case 'ppp':
4320
			case 'l2tp':
4321
			case 'pptp':
4322
				if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4323
					$wanif = interface_get_wireless_clone($cfg['if']);
4324
				else
4325
					$wanif = $cfg['if'];
4326
				break;
4327
			default:
4328
				switch ($cfg['ipaddr']) {
4329
				case 'pppoe':
4330
				case 'ppp':
4331
				case 'l2tp':
4332
				case 'pptp':
4333
					if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false)
4334
						$wanif = $cfg['if'];
4335
					else {
4336
						$parents = get_parent_interface($interface);
4337
						if (!empty($parents[0]))
4338
							$wanif = $parents[0];
4339
						else
4340
							$wanif = $cfg['if'];
4341
					}
4342
					break;
4343
				default:
4344
					if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4345
						$wanif = interface_get_wireless_clone($cfg['if']);
4346
					else
4347
						$wanif = $cfg['if'];
4348
					break;
4349
				}
4350
				break;
4351
			}
4352
		} else {
4353
			// Wireless cloned NIC support (FreeBSD 8+)
4354
			// interface name format: $parentnic_wlanparentnic#
4355
			// example: ath0_wlan0
4356
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4357
				$wanif = interface_get_wireless_clone($cfg['if']);
4358
			else
4359
				$wanif = $cfg['if'];
4360
		}
4361
		break;
4362
	}
4363

    
4364
	return $wanif;
4365
}
4366

    
4367
/* Guess the physical interface by providing a IP address */
4368
function guess_interface_from_ip($ipaddress) {
4369
	if(! is_ipaddr($ipaddress)) {
4370
		return false;
4371
	}
4372
	if(is_ipaddrv4($ipaddress)) {
4373
		/* create a route table we can search */
4374
		exec("netstat -rnWf inet", $output, $ret);
4375
		foreach($output as $line) {
4376
			if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
4377
				$fields = preg_split("/[ ]+/", $line);
4378
				if(ip_in_subnet($ipaddress, $fields[0])) {
4379
					return $fields[6];
4380
				}
4381
			}
4382
		}
4383
	}
4384
	/* FIXME: This works from cursory testing, regexp might need fine tuning */
4385
	if(is_ipaddrv6($ipaddress)) {
4386
		/* create a route table we can search */
4387
		exec("netstat -rnWf inet6", $output, $ret);
4388
		foreach($output as $line) {
4389
			if(preg_match("/[0-9a-f]+[:]+[0-9a-f]+[:]+[\/][0-9]+/", $line)) {
4390
				$fields = preg_split("/[ ]+/", $line);
4391
				if(ip_in_subnet($ipaddress, $fields[0])) {
4392
					return $fields[6];
4393
				}
4394
			}
4395
		}
4396
	}
4397
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
4398
	if(empty($ret)) {
4399
		return false;
4400
	}
4401
	return $ret;
4402
}
4403

    
4404
/*
4405
 * find_ip_interface($ip): return the interface where an ip is defined
4406
 *   (or if $bits is specified, where an IP within the subnet is defined)
4407
 */
4408
function find_ip_interface($ip, $bits = null) {
4409
	if (!is_ipaddr($ip))
4410
		return false;
4411

    
4412
	$isv6ip = is_ipaddrv6($ip);
4413

    
4414
	/* if list */
4415
	$ifdescrs = get_configured_interface_list();
4416

    
4417
	foreach ($ifdescrs as $ifdescr => $ifname) {
4418
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4419
		if (is_null($ifip))
4420
			continue;
4421
		if (is_null($bits)) {
4422
			if ($ip == $ifip) {
4423
				$int = get_real_interface($ifname);
4424
				return $int;
4425
			}
4426
		}
4427
		else {
4428
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4429
				$int = get_real_interface($ifname);
4430
				return $int;
4431
			}
4432
		}
4433
	}
4434

    
4435
	return false;
4436
}
4437

    
4438
/*
4439
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4440
 *   (or if $bits is specified, where an IP within the subnet is found)
4441
 */
4442
function find_virtual_ip_alias($ip, $bits = null) {
4443
	global $config;
4444

    
4445
	if (!is_array($config['virtualip']['vip'])) {
4446
		return false;
4447
	}
4448
	if (!is_ipaddr($ip))
4449
		return false;
4450

    
4451
	$isv6ip = is_ipaddrv6($ip);
4452

    
4453
	foreach ($config['virtualip']['vip'] as $vip) {
4454
		if ($vip['mode'] === "ipalias") {
4455
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4456
				continue;
4457
			if (is_null($bits)) {
4458
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4459
					return $vip;
4460
				}
4461
			}
4462
			else {
4463
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4464
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4465
					return $vip;
4466
				}
4467
			}
4468
		}
4469
	}
4470
	return false;
4471
}
4472

    
4473
/*
4474
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4475
 */
4476
function find_number_of_created_carp_interfaces() {
4477
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4478
}
4479

    
4480
function get_all_carp_interfaces() {
4481
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
4482
	$ints = explode(" ", $ints);
4483
	return $ints;
4484
}
4485

    
4486
/*
4487
 * find_carp_interface($ip): return the carp interface where an ip is defined
4488
 */
4489
function find_carp_interface($ip) {
4490
	global $config;
4491
	if (is_array($config['virtualip']['vip'])) {
4492
		foreach ($config['virtualip']['vip'] as $vip) {
4493
			if ($vip['mode'] == "carp") {
4494
				if(is_ipaddrv4($ip)) {
4495
					$carp_ip = get_interface_ip($vip['interface']);
4496
				}
4497
				if(is_ipaddrv6($ip)) {
4498
					$carp_ip = get_interface_ipv6($vip['interface']);
4499
				}
4500
				exec("/sbin/ifconfig", $output, $return);
4501
				foreach($output as $line) {
4502
					$elements = preg_split("/[ ]+/i", $line);
4503
					if(strstr($elements[0], "vip"))
4504
						$curif = str_replace(":", "", $elements[0]);
4505
					if(stristr($line, $ip)) {
4506
						$if = $curif;
4507
						continue;
4508
					}
4509
				}
4510

    
4511
				if ($if)
4512
					return $if;
4513
			}
4514
		}
4515
	}
4516
}
4517

    
4518
function link_carp_interface_to_parent($interface) {
4519
	global $config;
4520

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

    
4524
	$carp_ip = get_interface_ip($interface);
4525
	$carp_ipv6 = get_interface_ipv6($interface);
4526

    
4527
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4528
		return;
4529

    
4530
	/* if list */
4531
	$ifdescrs = get_configured_interface_list();
4532
	foreach ($ifdescrs as $ifdescr => $ifname) {
4533
		/* check IPv4 */
4534
		if(is_ipaddrv4($carp_ip)) {
4535
			$interfaceip = get_interface_ip($ifname);
4536
			$subnet_bits = get_interface_subnet($ifname);
4537
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4538
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4539
				return $ifname;
4540
		}
4541
		/* Check IPv6 */
4542
		if(is_ipaddrv6($carp_ipv6)) {
4543
			$interfaceipv6 = get_interface_ipv6($ifname);
4544
			$prefixlen = get_interface_subnetv6($ifname);
4545
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4546
				return $ifname;
4547
		}
4548
	}
4549
	return "";
4550
}
4551

    
4552

    
4553
/****f* interfaces/link_ip_to_carp_interface
4554
 * NAME
4555
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4556
 * INPUTS
4557
 *   $ip
4558
 * RESULT
4559
 *   $carp_ints
4560
 ******/
4561
function link_ip_to_carp_interface($ip) {
4562
	global $config;
4563

    
4564
	if (!is_ipaddr($ip))
4565
		return;
4566

    
4567
	$carp_ints = "";
4568
	if (is_array($config['virtualip']['vip'])) {
4569
		$first = 0;
4570
		$carp_int = array();
4571
		foreach ($config['virtualip']['vip'] as $vip) {
4572
			if ($vip['mode'] == "carp") {
4573
				$carp_ip = $vip['subnet'];
4574
				$carp_sn = $vip['subnet_bits'];
4575
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4576
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4577
					$carp_int[] = get_real_interface($vip['interface']);
4578
				}
4579
			}
4580
		}
4581
		if (!empty($carp_int))
4582
			$carp_ints = implode(" ", array_unique($carp_int));
4583
	}
4584

    
4585
	return $carp_ints;
4586
}
4587

    
4588
function link_interface_to_track6($int, $action = "") {
4589
	global $config;
4590

    
4591
	if (empty($int))
4592
		return;
4593

    
4594
	if (is_array($config['interfaces'])) {
4595
		$list = array();
4596
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4597
			if (!isset($ifcfg['enable']))
4598
				continue;
4599
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4600
				if ($action == "update")
4601
					interface_track6_configure($ifname, $ifcfg);
4602
				else if ($action == "")
4603
					$list[$ifname] = $ifcfg;
4604
			}
4605
		}
4606
		return $list;
4607
	}
4608
}
4609

    
4610
function link_interface_to_vlans($int, $action = "") {
4611
	global $config;
4612

    
4613
	if (empty($int))
4614
		return;
4615

    
4616
	if (is_array($config['vlans']['vlan'])) {
4617
		$ifaces = array();
4618
		foreach ($config['vlans']['vlan'] as $vlan) {
4619
			if ($int == $vlan['if']) {
4620
				if ($action == "update") {
4621
					interfaces_bring_up($int);
4622
				} else if ($action == "")
4623
					$ifaces[$vlan['tag']] = $vlan;
4624
			}
4625
		}
4626
		if (!empty($ifaces))
4627
			return $ifaces;
4628
	}
4629
}
4630

    
4631
function link_interface_to_vips($int, $action = "") {
4632
	global $config;
4633

    
4634
	if (is_array($config['virtualip']['vip'])) {
4635
		$result = array();
4636
		foreach ($config['virtualip']['vip'] as $vip) {
4637
			if ($int == $vip['interface']) {
4638
				if ($action == "update")
4639
					interfaces_vips_configure($int);
4640
				else
4641
					$result[] = $vip;
4642
			}
4643
		}
4644
		return $result;
4645
	}
4646
}
4647

    
4648
/****f* interfaces/link_interface_to_bridge
4649
 * NAME
4650
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4651
 * INPUTS
4652
 *   $ip
4653
 * RESULT
4654
 *   bridge[0-99]
4655
 ******/
4656
function link_interface_to_bridge($int) {
4657
	global $config;
4658

    
4659
	if (is_array($config['bridges']['bridged'])) {
4660
		foreach ($config['bridges']['bridged'] as $bridge) {
4661
			if (in_array($int, explode(',', $bridge['members'])))
4662
				return "{$bridge['bridgeif']}";
4663
		}
4664
	}
4665
}
4666

    
4667
function link_interface_to_group($int) {
4668
	global $config;
4669

    
4670
	$result = array();
4671

    
4672
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4673
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4674
			if (in_array($int, explode(" ", $group['members'])))
4675
				$result[$group['ifname']] = $int;
4676
		}
4677
	}
4678

    
4679
	return $result;
4680
}
4681

    
4682
function link_interface_to_gre($interface) {
4683
	global $config;
4684

    
4685
	$result = array();
4686

    
4687
	if (is_array($config['gres']['gre'])) {
4688
		foreach ($config['gres']['gre'] as $gre)
4689
			if($gre['if'] == $interface)
4690
				$result[] = $gre;
4691
	}
4692

    
4693
	return $result;
4694
}
4695

    
4696
function link_interface_to_gif($interface) {
4697
	global $config;
4698

    
4699
	$result = array();
4700

    
4701
	if (is_array($config['gifs']['gif'])) {
4702
		foreach ($config['gifs']['gif'] as $gif)
4703
			if($gif['if'] == $interface)
4704
				$result[] = $gif;
4705
	}
4706

    
4707
	return $result;
4708
}
4709

    
4710
/*
4711
 * find_interface_ip($interface): return the interface ip (first found)
4712
 */
4713
function find_interface_ip($interface, $flush = false) {
4714
	global $interface_ip_arr_cache;
4715
	global $interface_sn_arr_cache;
4716

    
4717
	$interface = str_replace("\n", "", $interface);
4718

    
4719
	if (!does_interface_exist($interface))
4720
		return;
4721

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

    
4729
	return $interface_ip_arr_cache[$interface];
4730
}
4731

    
4732
/*
4733
 * find_interface_ipv6($interface): return the interface ip (first found)
4734
 */
4735
function find_interface_ipv6($interface, $flush = false) {
4736
	global $interface_ipv6_arr_cache;
4737
	global $interface_snv6_arr_cache;
4738
	global $config;
4739

    
4740
	$interface = trim($interface);
4741
	$interface = get_real_interface($interface);
4742

    
4743
	if (!does_interface_exist($interface))
4744
		return;
4745

    
4746
	/* Setup IP cache */
4747
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4748
		$ifinfo = pfSense_get_interface_addresses($interface);
4749
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4750
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4751
	}
4752

    
4753
	return $interface_ipv6_arr_cache[$interface];
4754
}
4755

    
4756
/*
4757
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4758
 */
4759
function find_interface_ipv6_ll($interface, $flush = false) {
4760
	global $interface_llv6_arr_cache;
4761
	global $config;
4762

    
4763
	$interface = str_replace("\n", "", $interface);
4764

    
4765
	if (!does_interface_exist($interface))
4766
		return;
4767

    
4768
	/* Setup IP cache */
4769
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4770
		$ifinfo = pfSense_getall_interface_addresses($interface);
4771
		foreach($ifinfo as $line) {
4772
			if (strstr($line, ":")) {
4773
				$parts = explode("/", $line);
4774
				if(is_linklocal($parts[0])) {
4775
					$ifinfo['linklocal'] = $parts[0];
4776
				}
4777
			}
4778
		}
4779
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4780
	}
4781
	return $interface_llv6_arr_cache[$interface];
4782
}
4783

    
4784
function find_interface_subnet($interface, $flush = false) {
4785
	global $interface_sn_arr_cache;
4786
	global $interface_ip_arr_cache;
4787

    
4788
	$interface = str_replace("\n", "", $interface);
4789
	if (does_interface_exist($interface) == false)
4790
		return;
4791

    
4792
	if (!isset($interface_sn_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_sn_arr_cache[$interface];
4799
}
4800

    
4801
function find_interface_subnetv6($interface, $flush = false) {
4802
	global $interface_snv6_arr_cache;
4803
	global $interface_ipv6_arr_cache;
4804

    
4805
	$interface = str_replace("\n", "", $interface);
4806
	if (does_interface_exist($interface) == false)
4807
		return;
4808

    
4809
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4810
		$ifinfo = pfSense_get_interface_addresses($interface);
4811
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4812
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4813
	}
4814

    
4815
	return $interface_snv6_arr_cache[$interface];
4816
}
4817

    
4818
function ip_in_interface_alias_subnet($interface, $ipalias) {
4819
	global $config;
4820

    
4821
	if (empty($interface) || !is_ipaddr($ipalias))
4822
		return false;
4823
	if (is_array($config['virtualip']['vip'])) {
4824
		foreach ($config['virtualip']['vip'] as $vip) {
4825
			switch ($vip['mode']) {
4826
			case "ipalias":
4827
				if ($vip['interface'] <> $interface)
4828
					break;
4829
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4830
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4831
					return true;
4832
				break;
4833
			}
4834
		}
4835
	}
4836

    
4837
	return false;
4838
}
4839

    
4840
function get_interface_ip($interface = "wan") {
4841
	$realif = get_failover_interface($interface);
4842
	if (!$realif) {
4843
		if (strstr($interface, "_vip"))
4844
			return get_configured_carp_interface_list($interface);
4845
		else
4846
			return null;
4847
	}
4848

    
4849
	$curip = find_interface_ip($realif);
4850
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4851
		return $curip;
4852
	else
4853
		return null;
4854
}
4855

    
4856
function get_interface_ipv6($interface = "wan", $flush = false) {
4857
	global $config;
4858

    
4859
	$realif = get_failover_interface($interface, "inet6");
4860
	if (!$realif) {
4861
		if (strstr($interface, "_vip"))
4862
			return get_configured_carp_interface_list($interface, "inet6");
4863
		else
4864
			return null;
4865
	}
4866

    
4867
	/*
4868
	 * NOTE: On the case when only the prefix is requested,
4869
	 * the communication on WAN will be done over link-local.
4870
	 */
4871
	if (is_array($config['interfaces'][$interface])) {
4872
		switch ($config['interfaces'][$interface]['ipaddr']) {
4873
		case 'pppoe':
4874
		case 'l2tp':
4875
		case 'pptp':
4876
		case 'ppp':
4877
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4878
				$realif = get_real_interface($interface, "inet6", true);
4879
			break;
4880
		}
4881
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4882
			$curip = find_interface_ipv6_ll($realif, $flush);
4883
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4884
				return $curip;
4885
		}
4886
	}
4887

    
4888
	$curip = find_interface_ipv6($realif, $flush);
4889
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4890
		return $curip;
4891
	else
4892
		return null;
4893
}
4894

    
4895
function get_interface_linklocal($interface = "wan") {
4896

    
4897
	$realif = get_failover_interface($interface, "inet6");
4898
	if (!$realif) {
4899
		if (strstr($interface, "_vip")) {
4900
			list($interface, $vhid) = explode("_vip", $interface);
4901
			$realif = get_real_interface($interface);
4902
		} else
4903
			return null;
4904
	}
4905

    
4906
	$curip = find_interface_ipv6_ll($realif);
4907
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4908
		return $curip;
4909
	else
4910
		return null;
4911
}
4912

    
4913
function get_interface_subnet($interface = "wan") {
4914
	$realif = get_real_interface($interface);
4915
	if (!$realif) {
4916
		if (strstr($interface, "_vip")) {
4917
			list($interface, $vhid) = explode("_vip", $interface);
4918
			$realif = get_real_interface($interface);
4919
		} else
4920
			return null;
4921
	}
4922

    
4923
	$cursn = find_interface_subnet($realif);
4924
	if (!empty($cursn))
4925
		return $cursn;
4926

    
4927
	return null;
4928
}
4929

    
4930
function get_interface_subnetv6($interface = "wan") {
4931
	global $config;
4932

    
4933
	$realif = get_real_interface($interface, "inet6");
4934
	if (!$realif) {
4935
		if (strstr($interface, "_vip")) {
4936
			list($interface, $vhid) = explode("_vip", $interface);
4937
			$realif = get_real_interface($interface);
4938
		} else
4939
			return null;
4940
	}
4941

    
4942
	$cursn = find_interface_subnetv6($realif);
4943
	if (!empty($cursn))
4944
		return $cursn;
4945

    
4946
	return null;
4947
}
4948

    
4949
/* return outside interfaces with a gateway */
4950
function get_interfaces_with_gateway() {
4951
	global $config;
4952

    
4953
	$ints = array();
4954

    
4955
	/* loop interfaces, check config for outbound */
4956
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4957
		switch ($ifname['ipaddr']) {
4958
			case "dhcp":
4959
			case "ppp";
4960
			case "pppoe":
4961
			case "pptp":
4962
			case "l2tp":
4963
			case "ppp";
4964
				$ints[$ifdescr] = $ifdescr;
4965
			break;
4966
			default:
4967
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
4968
				    !empty($ifname['gateway']))
4969
					$ints[$ifdescr] = $ifdescr;
4970
			break;
4971
		}
4972
	}
4973
	return $ints;
4974
}
4975

    
4976
/* return true if interface has a gateway */
4977
function interface_has_gateway($friendly) {
4978
	global $config;
4979

    
4980
	if (!empty($config['interfaces'][$friendly])) {
4981
		$ifname = &$config['interfaces'][$friendly];
4982
		switch ($ifname['ipaddr']) {
4983
			case "dhcp":
4984
			case "pppoe":
4985
			case "pptp":
4986
			case "l2tp":
4987
			case "ppp";
4988
				return true;
4989
			break;
4990
			default:
4991
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4992
					return true;
4993
				$tunnelif = substr($ifname['if'], 0, 3);
4994
				if ($tunnelif == "gif" || $tunnelif == "gre")
4995
					return true;
4996
				if (!empty($ifname['gateway']))
4997
					return true;
4998
			break;
4999
		}
5000
	}
5001

    
5002
	return false;
5003
}
5004

    
5005
/* return true if interface has a gateway */
5006
function interface_has_gatewayv6($friendly) {
5007
	global $config;
5008

    
5009
	if (!empty($config['interfaces'][$friendly])) {
5010
		$ifname = &$config['interfaces'][$friendly];
5011
		switch ($ifname['ipaddrv6']) {
5012
			case "slaac":
5013
			case "dhcp6":
5014
			case "6to4":
5015
			case "6rd":
5016
				return true;
5017
				break;
5018
			default:
5019
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
5020
					return true;
5021
				$tunnelif = substr($ifname['if'], 0, 3);
5022
				if ($tunnelif == "gif" || $tunnelif == "gre")
5023
					return true;
5024
				if (!empty($ifname['gatewayv6']))
5025
					return true;
5026
				break;
5027
		}
5028
	}
5029

    
5030
	return false;
5031
}
5032

    
5033
/****f* interfaces/is_altq_capable
5034
 * NAME
5035
 *   is_altq_capable - Test if interface is capable of using ALTQ
5036
 * INPUTS
5037
 *   $int            - string containing interface name
5038
 * RESULT
5039
 *   boolean         - true or false
5040
 ******/
5041

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

    
5055
	$int_family = remove_ifindex($int);
5056

    
5057
	if (in_array($int_family, $capable))
5058
		return true;
5059
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
5060
		return true;
5061
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
5062
		return true;
5063
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
5064
		return true;
5065
	else
5066
		return false;
5067
}
5068

    
5069
/****f* interfaces/is_interface_wireless
5070
 * NAME
5071
 *   is_interface_wireless - Returns if an interface is wireless
5072
 * RESULT
5073
 *   $tmp       - Returns if an interface is wireless
5074
 ******/
5075
function is_interface_wireless($interface) {
5076
	global $config, $g;
5077

    
5078
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5079
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
5080
		if (preg_match($g['wireless_regex'], $interface)) {
5081
			if (isset($config['interfaces'][$friendly]))
5082
				$config['interfaces'][$friendly]['wireless'] = array();
5083
			return true;
5084
		}
5085
		return false;
5086
	} else
5087
		return true;
5088
}
5089

    
5090
function get_wireless_modes($interface) {
5091
	/* return wireless modes and channels */
5092
	$wireless_modes = array();
5093

    
5094
	$cloned_interface = get_real_interface($interface);
5095

    
5096
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5097
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5098
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5099
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5100

    
5101
		$interface_channels = "";
5102
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5103
		$interface_channel_count = count($interface_channels);
5104

    
5105
		$c = 0;
5106
		while ($c < $interface_channel_count) {
5107
			$channel_line = explode(",", $interface_channels["$c"]);
5108
			$wireless_mode = trim($channel_line[0]);
5109
			$wireless_channel = trim($channel_line[1]);
5110
			if(trim($wireless_mode) != "") {
5111
				/* if we only have 11g also set 11b channels */
5112
				if($wireless_mode == "11g") {
5113
					if(!isset($wireless_modes["11b"]))
5114
						$wireless_modes["11b"] = array();
5115
				} else if($wireless_mode == "11g ht") {
5116
					if(!isset($wireless_modes["11b"]))
5117
						$wireless_modes["11b"] = array();
5118
					if(!isset($wireless_modes["11g"]))
5119
						$wireless_modes["11g"] = array();
5120
					$wireless_mode = "11ng";
5121
				} else if($wireless_mode == "11a ht") {
5122
					if(!isset($wireless_modes["11a"]))
5123
						$wireless_modes["11a"] = array();
5124
					$wireless_mode = "11na";
5125
				}
5126
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5127
			}
5128
			$c++;
5129
		}
5130
	}
5131
	return($wireless_modes);
5132
}
5133

    
5134
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5135
function get_wireless_channel_info($interface) {
5136
	$wireless_channels = array();
5137

    
5138
	$cloned_interface = get_real_interface($interface);
5139

    
5140
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5141
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5142
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5143
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5144

    
5145
		$interface_channels = "";
5146
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5147

    
5148
		foreach ($interface_channels as $channel_line) {
5149
			$channel_line = explode(",", $channel_line);
5150
			if(!isset($wireless_channels[$channel_line[0]]))
5151
				$wireless_channels[$channel_line[0]] = $channel_line;
5152
		}
5153
	}
5154
	return($wireless_channels);
5155
}
5156

    
5157
/****f* interfaces/get_interface_mtu
5158
 * NAME
5159
 *   get_interface_mtu - Return the mtu of an interface
5160
 * RESULT
5161
 *   $tmp       - Returns the mtu of an interface
5162
 ******/
5163
function get_interface_mtu($interface) {
5164
	$mtu = pfSense_get_interface_addresses($interface);
5165
	return $mtu['mtu'];
5166
}
5167

    
5168
function get_interface_mac($interface) {
5169

    
5170
	$macinfo = pfSense_get_interface_addresses($interface);
5171
	return $macinfo["macaddr"];
5172
}
5173

    
5174
/****f* pfsense-utils/generate_random_mac_address
5175
 * NAME
5176
 *   generate_random_mac - generates a random mac address
5177
 * INPUTS
5178
 *   none
5179
 * RESULT
5180
 *   $mac - a random mac address
5181
 ******/
5182
function generate_random_mac_address() {
5183
	$mac = "02";
5184
	for($x=0; $x<5; $x++)
5185
		$mac .= ":" . dechex(rand(16, 255));
5186
	return $mac;
5187
}
5188

    
5189
/****f* interfaces/is_jumbo_capable
5190
 * NAME
5191
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5192
 * INPUTS
5193
 *   $int             - string containing interface name
5194
 * RESULT
5195
 *   boolean          - true or false
5196
 ******/
5197
function is_jumbo_capable($iface) {
5198
	$iface = trim($iface);
5199
	$capable = pfSense_get_interface_addresses($iface);
5200

    
5201
	if (isset($capable['caps']['vlanmtu']))
5202
		return true;
5203

    
5204
	return false;
5205
}
5206

    
5207
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5208
	global $g;
5209

    
5210
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5211

    
5212
	if(!empty($iface) && !empty($pppif)){
5213
		$cron_cmd = <<<EOD
5214
#!/bin/sh
5215
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5216
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5217

    
5218
EOD;
5219

    
5220
		@file_put_contents($cron_file, $cron_cmd);
5221
		chmod($cron_file, 0755);
5222
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5223
	} else
5224
		unlink_if_exists($cron_file);
5225
}
5226

    
5227
function get_interface_default_mtu($type = "ethernet") {
5228
	switch ($type) {
5229
	case "gre":
5230
		return 1476;
5231
		break;
5232
	case "gif":
5233
		return 1280;
5234
		break;
5235
	case "tun":
5236
	case "vlan":
5237
	case "tap":
5238
	case "ethernet":
5239
	default:
5240
		return 1500;
5241
		break;
5242
	}
5243

    
5244
	/* Never reached */
5245
	return 1500;
5246
}
5247

    
5248
function get_vip_descr($ipaddress) {
5249
	global $config;
5250

    
5251
	foreach ($config['virtualip']['vip'] as $vip) {
5252
		if ($vip['subnet'] == $ipaddress) {
5253
			return ($vip['descr']);
5254
		}
5255
	}
5256
	return "";
5257
}
5258

    
5259
function interfaces_staticarp_configure($if) {
5260
	global $config, $g;
5261
	if(isset($config['system']['developerspew'])) {
5262
		$mt = microtime();
5263
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5264
	}
5265

    
5266
	$ifcfg = $config['interfaces'][$if];
5267

    
5268
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5269
		return 0;
5270

    
5271
	/* Enable staticarp, if enabled */
5272
	if(isset($config['dhcpd'][$if]['staticarp'])) {
5273
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
5274
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5275
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5276

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

    
5280
			}
5281

    
5282
		}
5283
	} else {
5284
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
5285
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5286
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5287
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5288
				if (isset($arpent['arp_table_static_entry'])) {
5289
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5290
				}
5291
			}
5292
		}
5293
	}
5294

    
5295
	return 0;
5296
}
5297

    
5298
function get_failover_interface($interface, $family = "all") {
5299
	global $config;
5300

    
5301
	/* shortcut to get_real_interface if we find it in the config */
5302
	if (is_array($config['interfaces'][$interface])) {
5303
		return get_real_interface($interface, $family);
5304
	}
5305

    
5306
	/* compare against gateway groups */
5307
	$a_groups = return_gateway_groups_array();
5308
	if (is_array($a_groups[$interface])) {
5309
		/* we found a gateway group, fetch the interface or vip */
5310
		if ($a_groups[$interface][0]['vip'] <> "")
5311
			return $a_groups[$interface][0]['vip'];
5312
		else
5313
			return $a_groups[$interface][0]['int'];
5314
	}
5315
	/* fall through to get_real_interface */
5316
	/* XXX: Really needed? */
5317
	return get_real_interface($interface, $family);
5318
}
5319

    
5320
function remove_ifindex($ifname) {
5321
	return preg_replace("/[0-9]+$/", "", $ifname);
5322
}
5323

    
5324
?>
(26-26/68)