Projet

Général

Profil

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

univnautes / etc / inc / interfaces.inc @ c650b2f7

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

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

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

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

    
1355
	return;
1356
}
1357

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

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

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

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

    
1385
	return false;
1386
}
1387

    
1388
function interfaces_ptpid_next() {
1389

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

    
1394
	return $ptpid;
1395
}
1396

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

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

    
1408
	return NULL;
1409
}
1410

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

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

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

    
1420
	$itemhash = getMPDCRONSettings($pppif);
1421

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1680
EOD;
1681

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

    
1686
EOD;
1687

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

    
1695
EOD;
1696

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

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

    
1707
EOD;
1708

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

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

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

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

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

    
1735
EOD;
1736

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

    
1741
EOD;
1742

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

    
1747
EOD;
1748

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

    
1754
EOD;
1755

    
1756

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

    
1761
EOD;
1762

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

    
1768
EOD;
1769

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

    
1774
EOD;
1775

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

    
1780
EOD;
1781

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

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

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

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

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

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

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

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

    
1839
EOD;
1840

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

    
1846
EOD;
1847
		}
1848

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

    
1852

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

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

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

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

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

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

    
1928
	return 1;
1929
}
1930

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

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

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

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

    
1954
	set_sysctl(array(
1955
		"net.inet.carp.preempt" => "1",
1956
		"net.inet.carp.log" => "1")
1957
	);
1958

    
1959
	if (!empty($pfsyncinterface))
1960
		$carp_sync_int = get_real_interface($pfsyncinterface);
1961
	else
1962
		unset($carp_sync_int);
1963

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

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

    
1973
		sleep(1);
1974

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

    
1990
	if($config['virtualip']['vip'])
1991
		set_single_sysctl("net.inet.carp.allow", "1");
1992
	else
1993
		set_single_sysctl("net.inet.carp.allow", "0");
1994

    
1995
	if ($g['booting']) {
1996
		unmute_kernel_msgs();
1997
		echo gettext("done.") . "\n";
1998
	}
1999
}
2000

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

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

    
2017
	$paa = array();
2018
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2019

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

    
2028
				if (!empty($interface) && $interface != $proxyif)
2029
					continue;
2030

    
2031
				if (!is_array($paa[$proxyif]))
2032
					$paa[$proxyif] = array();
2033

    
2034
				$paa[$proxyif][] = $vipent;
2035
			}
2036
		}
2037
	}
2038

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

    
2070
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2071
	global $g, $config;
2072

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

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

    
2124
function interface_ipalias_configure(&$vip) {
2125
	global $config;
2126

    
2127
	if ($vip['mode'] != "ipalias")
2128
		return;
2129

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

    
2133
	if ($vip['interface'] != 'lo0' && !isset($config['interfaces'][$vip['interface']]['enable']))
2134
		return;
2135

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

    
2143
function interface_reload_carps($cif) {
2144
	global $config;
2145

    
2146
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2147
	if (empty($carpifs))
2148
		return;
2149

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

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

    
2179
	if ($vip['mode'] != "carp")
2180
		return;
2181

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

    
2189
	if (is_ipaddrv4($vip['subnet'])) {
2190
		/* Ensure CARP IP really exists prior to loading up. */
2191
		$ww_subnet_ip = find_interface_ip($realif);
2192
		$ww_subnet_bits = find_interface_subnet($realif);
2193
		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'])) {
2194
			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", "");
2195
			return;
2196
		}
2197
	} else if (is_ipaddrv6($vip['subnet'])) {
2198
		/* Ensure CARP IP really exists prior to loading up. */
2199
		$ww_subnet_ip = find_interface_ipv6($realif);
2200
		$ww_subnet_bits = find_interface_subnetv6($realif);
2201
		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'])) {
2202
			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", "");
2203
			return;
2204
		}
2205
	}
2206

    
2207
	$vip_password = $vip['password'];
2208
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2209
	if ($vip['password'] != "")
2210
		$password = " pass {$vip_password}";
2211

    
2212
	$advbase = "";
2213
	if (!empty($vip['advbase']))
2214
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2215

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

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

    
2229
	return $realif;
2230
}
2231

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

    
2273
	if($needs_clone == true) {
2274
		/* remove previous instance if it exists */
2275
		if(does_interface_exist($realif))
2276
			pfSense_interface_destroy($realif);
2277

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

    
2296
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2297
	global $config, $g;
2298

    
2299
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2300
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2301
				 'regdomain', 'regcountry', 'reglocation');
2302

    
2303
	if(!is_interface_wireless($ifcfg['if']))
2304
		return;
2305

    
2306
	$baseif = interface_get_wireless_base($ifcfg['if']);
2307

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

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

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

    
2365
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2366
	global $config, $g;
2367

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

    
2375
	// Remove script file
2376
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2377

    
2378
	// Clone wireless nic if needed.
2379
	interface_wireless_clone($if, $wl);
2380

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

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

    
2388
	/* set values for /path/program */
2389
	$hostapd = "/usr/sbin/hostapd";
2390
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2391
	$ifconfig = "/sbin/ifconfig";
2392
	$sysctl = "/sbin/sysctl";
2393
	$killall = "/usr/bin/killall";
2394

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

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

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

    
2410
	/* Set ssid */
2411
	if($wlcfg['ssid'])
2412
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2413

    
2414
	/* Set 802.11g protection mode */
2415
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2416

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

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

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

    
2434
	/* Set rxantenna value */
2435
	if(isset($wlcfg['rxantenna']))
2436
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2437

    
2438
	/* set Distance value */
2439
	if($wlcfg['distance'])
2440
		$distance = escapeshellarg($wlcfg['distance']);
2441

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

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

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

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

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

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

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

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

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

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

    
2530
	kill_hostapd($if);
2531
	mwexec(kill_wpasupplicant("{$if}"));
2532

    
2533
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2534
	conf_mount_rw();
2535

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

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

    
2589
EOD;
2590

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

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

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

    
2608
auth_server_addr={$wlcfg['auth_server_addr']}
2609
auth_server_port={$auth_server_port}
2610
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2611

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

    
2618
					$wpa .= <<<EOD
2619
auth_server_addr={$wlcfg['auth_server_addr2']}
2620
auth_server_port={$auth_server_port2}
2621
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2622

    
2623
EOD;
2624
					}
2625
				}
2626
			}
2627

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

    
2634
	/*
2635
	 *    all variables are set, lets start up everything
2636
	 */
2637

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

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

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

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

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

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

    
2684
	fclose($fd_set);
2685
	conf_mount_ro();
2686

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

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

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

    
2712
		/* set country */
2713
		if($wlcfg['regcountry'])
2714
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2715

    
2716
		/* set location */
2717
		if($wlcfg['reglocation'])
2718
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2719

    
2720
		$wlregcmd_args = implode(" ", $wlregcmd);
2721

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

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

    
2743
		/* apply the regulatory settings */
2744
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2745

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

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

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

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

    
2775

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

    
2780
	return 0;
2781

    
2782
}
2783

    
2784
function kill_hostapd($interface) {
2785
	global $g;
2786

    
2787
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2788
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2789
}
2790

    
2791
function kill_wpasupplicant($interface) {
2792
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2793
}
2794

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

    
2801
	return intval($pid);
2802
}
2803

    
2804
function find_dhcp6c_process($interface) {
2805
	global $g;
2806

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

    
2812
	return intval($pid);
2813
}
2814

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

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

    
2830
	return $mtu;
2831
}
2832

    
2833
function interface_virtual_create($interface) {
2834
	global $config;
2835

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

    
2873
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2874
	global $config;
2875

    
2876
	if (!is_array($vlanifs))
2877
		return;
2878

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

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

    
2905
	$wancfg = $config['interfaces'][$interface];
2906

    
2907
	if (!isset($wancfg['enable']))
2908
		return;
2909

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

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

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

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

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

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

    
2958
	/* wireless configuration? */
2959
	if (is_array($wancfg['wireless']))
2960
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2961

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

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

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

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

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

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

    
3032
		if(isset($config['system']['disablelargereceiveoffloading']))
3033
			$flags_off |= IFCAP_LRO;
3034
		else if (isset($options['caps']['lro']))
3035
			$flags_on |= IFCAP_LRO;
3036

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

    
3043
		pfSense_interface_capabilities($realhwif, -$flags_off);
3044
		pfSense_interface_capabilities($realhwif, $flags_on);
3045
	}
3046

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

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

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

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

    
3108
			if ($wancfg['mtu'] > $parentmtu) {
3109
				if (get_interface_mtu($realhwif) != $wancfg['mtu'])
3110
					pfSense_interface_mtu($realhwif, $wancfg['mtu']);
3111

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

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

    
3126
	if (does_interface_exist($wancfg['if']))
3127
		interfaces_bring_up($wancfg['if']);
3128

    
3129
	interface_netgraph_needed($interface);
3130

    
3131
	if (!$g['booting']) {
3132
		link_interface_to_vips($interface, "update");
3133

    
3134
		unset($gre);
3135
		$gre = link_interface_to_gre($interface);
3136
		if (!empty($gre))
3137
			array_walk($gre, 'interface_gre_configure');
3138

    
3139
		unset($gif);
3140
		$gif = link_interface_to_gif($interface);
3141
		if (!empty($gif))
3142
			array_walk($gif, 'interface_gif_configure');
3143

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

    
3151
		$grouptmp = link_interface_to_group($interface);
3152
		if (!empty($grouptmp))
3153
			array_walk($grouptmp, 'interface_group_add_member');
3154

    
3155
		if ($interface == "lan")
3156
			/* make new hosts file */
3157
			system_hosts_generate();
3158

    
3159
		if ($reloadall == true) {
3160

    
3161
			/* reconfigure static routes (kernel may have deleted them) */
3162
			system_routing_configure($interface);
3163

    
3164
			/* reload ipsec tunnels */
3165
			vpn_ipsec_configure();
3166

    
3167
			/* restart dnsmasq or unbound */
3168
			if (isset($config['dnsmasq']['enable']))
3169
				services_dnsmasq_configure();
3170
			elseif (isset($config['unbound']['enable']))
3171
				services_unbound_configure();
3172

    
3173
			/* update dyndns */
3174
			send_event("service reload dyndns {$interface}");
3175

    
3176
			/* XXX: which CPZONE? Needed? */
3177
			/* reload captive portal */
3178
			captiveportal_init_rules();
3179
		}
3180
	}
3181

    
3182
	interfaces_staticarp_configure($interface);
3183
	return 0;
3184
}
3185

    
3186
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3187
	global $config, $g;
3188

    
3189
	if (!is_array($wancfg))
3190
		return;
3191

    
3192
	if (!isset($wancfg['enable']))
3193
		return;
3194

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

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

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

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

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

    
3245
		services_dhcpd_configure("inet6");
3246
	}
3247

    
3248
	return 0;
3249
}
3250

    
3251
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3252
	global $config, $g;
3253
	global $interface_ipv6_arr_cache;
3254
	global $interface_snv6_arr_cache;
3255

    
3256
	if (!is_array($lancfg))
3257
		return;
3258

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

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

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

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

    
3281
	/* binary presentation of the prefix for all 128 bits. */
3282
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3283

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

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

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

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

    
3309
	return 0;
3310
}
3311

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

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

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

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

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

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

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

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

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

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

    
3366
	return 0;
3367
}
3368

    
3369
function interface_6rd_configure($interface = "wan", $wancfg) {
3370
	global $config, $g;
3371

    
3372
	/* because this is a tunnel interface we can only function
3373
	 *	with a public IPv4 address on the interface */
3374

    
3375
	if (!is_array($wancfg))
3376
		return;
3377

    
3378
	if (!is_module_loaded('if_stf.ko'))
3379
		mwexec('/sbin/kldload if_stf.ko');
3380

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

    
3389
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3390
		$wancfg['prefix-6rd-v4plen'] = 0;
3391

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

    
3397
	/* binary presentation of the prefix for all 128 bits. */
3398
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3399

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

    
3407
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3408
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3409

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

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

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

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

    
3440
	/* configure dependent interfaces */
3441
	if (!$g['booting'])
3442
		link_interface_to_track6($interface, "update");
3443

    
3444
	return 0;
3445
}
3446

    
3447
function interface_6to4_configure($interface = "wan", $wancfg){
3448
	global $config, $g;
3449

    
3450
	/* because this is a tunnel interface we can only function
3451
	 *	with a public IPv4 address on the interface */
3452

    
3453
	if (!is_array($wancfg))
3454
		return;
3455

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

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

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

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

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

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

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

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

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

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

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

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

    
3533
	$ip4gateway = get_interface_gateway($interface);
3534
	if (is_ipaddrv4($ip4gateway))
3535
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3536

    
3537
	if (!$g['booting'])
3538
		link_interface_to_track6($interface, "update");
3539

    
3540
	return 0;
3541
}
3542

    
3543
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3544
	global $config, $g;
3545

    
3546
	if (!is_array($wancfg))
3547
		return;
3548

    
3549
	$wanif = get_real_interface($interface, "inet6");
3550
	$dhcp6cconf = "";
3551
	$dhcp6cconf .= "interface {$wanif} {\n";
3552

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

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

    
3571
		$dhcp6cconf .= "};\n";
3572

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

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

    
3599
	// DHCP6 Config File Advanced
3600
	if ($wancfg['adv_dhcp6_config_advanced']) { $dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif); }
3601

    
3602
	// DHCP6 Config File Override
3603
	if ($wancfg['adv_dhcp6_config_file_override']) { $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif); }
3604

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

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

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

    
3646
	/* accept router advertisements for this interface */
3647
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3648
	log_error("Accept router advertisements on interface {$wanif} ");
3649
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3650

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

    
3658
	/* NOTE: will be called from rtsold invoked script
3659
	 * link_interface_to_track6($interface, "update");
3660
	 */
3661

    
3662
	return 0;
3663
}
3664

    
3665
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3666
	global $g;
3667

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

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

    
3684
	$information_only = "";
3685
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') 
3686
		$information_only = "\tinformation-only;\n";
3687

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

    
3692
	$interface_statement  = "interface";
3693
	$interface_statement .= " {$wanif}";
3694
	$interface_statement .= " {\n";
3695
	$interface_statement .= "$send_options";
3696
	$interface_statement .= "$request_options";
3697
	$interface_statement .= "$information_only";
3698
	$interface_statement .= "$script";
3699
	$interface_statement .= "};\n";
3700

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

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

    
3721
		$id_assoc_statement_address  .= "};\n";
3722
	}
3723

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

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

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

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

    
3760
		$id_assoc_statement_prefix  .= "};\n";
3761
	}
3762

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

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

    
3793
	$dhcp6cconf  = $interface_statement;
3794
	$dhcp6cconf .= $id_assoc_statement_address;
3795
	$dhcp6cconf .= $id_assoc_statement_prefix;
3796
	$dhcp6cconf .= $authentication_statement;
3797
	$dhcp6cconf .= $key_info_statement;
3798

    
3799
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3800

    
3801
	return $dhcp6cconf;
3802
}
3803

    
3804

    
3805
function DHCP6_Config_File_Override($wancfg, $wanif) {
3806

    
3807
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
3808
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3809

    
3810
	return $dhcp6cconf;
3811
}
3812

    
3813

    
3814
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
3815

    
3816
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3817

    
3818
	return $dhcp6cconf;
3819
}
3820

    
3821

    
3822
function interface_dhcp_configure($interface = "wan") {
3823
	global $config, $g;
3824

    
3825
	$wancfg = $config['interfaces'][$interface];
3826
	$wanif = $wancfg['if'];
3827
	if (empty($wancfg))
3828
		$wancfg = array();
3829

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

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

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

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

    
3861
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3862
	$dhclientconf .= <<<EOD
3863

    
3864
	reject {$wancfg['dhcprejectfrom']};
3865
EOD;
3866
}
3867
	$dhclientconf .= <<<EOD
3868

    
3869
}
3870

    
3871
EOD;
3872

    
3873
	// DHCP Config File Advanced
3874
	if ($wancfg['adv_dhcp_config_advanced']) { $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif); }
3875

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

    
3885
EOD;
3886
}
3887

    
3888
	// DHCP Config File Override
3889
	if ($wancfg['adv_dhcp_config_file_override']) { $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif); }
3890

    
3891
	fwrite($fd, $dhclientconf);
3892
	fclose($fd);
3893

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

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

    
3903
	return 0;
3904
}
3905

    
3906
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3907

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

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

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

    
3931
	$request_options = "";
3932
	if ($wancfg['adv_dhcp_request_options'] != '') {
3933
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
3934
	}
3935

    
3936
	$required_options = "";
3937
	if ($wancfg['adv_dhcp_required_options'] != '') {
3938
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
3939
	}
3940

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

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

    
3969
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3970

    
3971
	return $dhclientconf;
3972
}
3973

    
3974

    
3975
function DHCP_Config_File_Override($wancfg, $wanif) {
3976

    
3977
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
3978
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3979

    
3980
	return $dhclientconf;
3981
}
3982

    
3983

    
3984
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
3985

    
3986
	/* Apply Interface Substitutions */
3987
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
3988

    
3989
	/* Apply Hostname Substitutions */
3990
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
3991

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

    
3998
	/* Apply MAC Address Substitutions */
3999
	foreach ($various_mac_types as $various_mac_type) {
4000
		foreach ($various_mac_cases as $various_mac_case) {
4001
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4002

    
4003
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4004
				if ($res !== false) {
4005

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

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

    
4022
					/* MAC Address Delimiter Substitutions */
4023
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4024

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

    
4032
	return $dhclientconf;
4033
}
4034

    
4035
function interfaces_group_setup() {
4036
	global $config;
4037

    
4038
	if (!is_array($config['ifgroups']['ifgroupentry']))
4039
		return;
4040

    
4041
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
4042
		interface_group_setup($groupar);
4043

    
4044
	return;
4045
}
4046

    
4047
function interface_group_setup(&$groupname /* The parameter is an array */) {
4048
	global $config;
4049

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

    
4059
	return;
4060
}
4061

    
4062
function is_interface_group($if) {
4063
	global $config;
4064

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

    
4071
	return false;
4072
}
4073

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

    
4079
/* COMPAT Function */
4080
function convert_friendly_interface_to_real_interface_name($interface) {
4081
	return get_real_interface($interface);
4082
}
4083

    
4084
/* COMPAT Function */
4085
function get_real_wan_interface($interface = "wan") {
4086
	return get_real_interface($interface);
4087
}
4088

    
4089
/* COMPAT Function */
4090
function get_current_wan_address($interface = "wan") {
4091
	return get_interface_ip($interface);
4092
}
4093

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

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

    
4104
	foreach ($ifdescrs as $if => $ifname) {
4105
		if ($if == $interface || $ifname['if'] == $interface)
4106
			return $if;
4107

    
4108
		if (get_real_interface($if) == $interface)
4109
			return $if;
4110

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

    
4120
	if ($interface == "enc0")
4121
		return 'IPsec';
4122

    
4123
	return NULL;
4124
}
4125

    
4126
/* attempt to resolve interface to friendly descr */
4127
function convert_friendly_interface_to_friendly_descr($interface) {
4128
	global $config;
4129

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

    
4174
	return $ifdesc;
4175
}
4176

    
4177
function convert_real_interface_to_friendly_descr($interface) {
4178
	global $config;
4179

    
4180
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4181

    
4182
	if ($ifdesc) {
4183
		$iflist = get_configured_interface_with_descr(false, true);
4184
		return $iflist[$ifdesc];
4185
	}
4186

    
4187
	return $interface;
4188
}
4189

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

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

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

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

    
4245
	if (empty($parents))
4246
		$parents[0] = $realif;
4247

    
4248
	return $parents;
4249
}
4250

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

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

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

    
4275
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4276
	global $config, $g;
4277

    
4278
	$wanif = NULL;
4279

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

    
4310
		if (empty($config['interfaces'][$interface]))
4311
			break;
4312

    
4313
		$cfg = &$config['interfaces'][$interface];
4314

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

    
4367
	return $wanif;
4368
}
4369

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

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

    
4415
	$isv6ip = is_ipaddrv6($ip);
4416

    
4417
	/* if list */
4418
	$ifdescrs = get_configured_interface_list();
4419

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

    
4438
	return false;
4439
}
4440

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

    
4448
	if (!is_array($config['virtualip']['vip'])) {
4449
		return false;
4450
	}
4451
	if (!is_ipaddr($ip))
4452
		return false;
4453

    
4454
	$isv6ip = is_ipaddrv6($ip);
4455

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

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

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

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

    
4514
				if ($if)
4515
					return $if;
4516
			}
4517
		}
4518
	}
4519
}
4520

    
4521
function link_carp_interface_to_parent($interface) {
4522
	global $config;
4523

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

    
4527
	$carp_ip = get_interface_ip($interface);
4528
	$carp_ipv6 = get_interface_ipv6($interface);
4529

    
4530
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4531
		return;
4532

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

    
4555

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

    
4567
	if (!is_ipaddr($ip))
4568
		return;
4569

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

    
4588
	return $carp_ints;
4589
}
4590

    
4591
function link_interface_to_track6($int, $action = "") {
4592
	global $config;
4593

    
4594
	if (empty($int))
4595
		return;
4596

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

    
4613
function link_interface_to_vlans($int, $action = "") {
4614
	global $config;
4615

    
4616
	if (empty($int))
4617
		return;
4618

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

    
4634
function link_interface_to_vips($int, $action = "") {
4635
	global $config;
4636

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

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

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

    
4670
function link_interface_to_group($int) {
4671
	global $config;
4672

    
4673
	$result = array();
4674

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

    
4682
	return $result;
4683
}
4684

    
4685
function link_interface_to_gre($interface) {
4686
	global $config;
4687

    
4688
	$result = array();
4689

    
4690
	if (is_array($config['gres']['gre'])) {
4691
		foreach ($config['gres']['gre'] as $gre)
4692
			if($gre['if'] == $interface)
4693
				$result[] = $gre;
4694
	}
4695

    
4696
	return $result;
4697
}
4698

    
4699
function link_interface_to_gif($interface) {
4700
	global $config;
4701

    
4702
	$result = array();
4703

    
4704
	if (is_array($config['gifs']['gif'])) {
4705
		foreach ($config['gifs']['gif'] as $gif)
4706
			if($gif['if'] == $interface)
4707
				$result[] = $gif;
4708
	}
4709

    
4710
	return $result;
4711
}
4712

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

    
4720
	$interface = str_replace("\n", "", $interface);
4721

    
4722
	if (!does_interface_exist($interface))
4723
		return;
4724

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

    
4732
	return $interface_ip_arr_cache[$interface];
4733
}
4734

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

    
4743
	$interface = trim($interface);
4744
	$interface = get_real_interface($interface);
4745

    
4746
	if (!does_interface_exist($interface))
4747
		return;
4748

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

    
4756
	return $interface_ipv6_arr_cache[$interface];
4757
}
4758

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

    
4766
	$interface = str_replace("\n", "", $interface);
4767

    
4768
	if (!does_interface_exist($interface))
4769
		return;
4770

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

    
4787
function find_interface_subnet($interface, $flush = false) {
4788
	global $interface_sn_arr_cache;
4789
	global $interface_ip_arr_cache;
4790

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

    
4795
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4796
		$ifinfo = pfSense_get_interface_addresses($interface);
4797
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4798
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4799
	}
4800

    
4801
	return $interface_sn_arr_cache[$interface];
4802
}
4803

    
4804
function find_interface_subnetv6($interface, $flush = false) {
4805
	global $interface_snv6_arr_cache;
4806
	global $interface_ipv6_arr_cache;
4807

    
4808
	$interface = str_replace("\n", "", $interface);
4809
	if (does_interface_exist($interface) == false)
4810
		return;
4811

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

    
4818
	return $interface_snv6_arr_cache[$interface];
4819
}
4820

    
4821
function ip_in_interface_alias_subnet($interface, $ipalias) {
4822
	global $config;
4823

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

    
4840
	return false;
4841
}
4842

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

    
4852
	$curip = find_interface_ip($realif);
4853
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4854
		return $curip;
4855
	else
4856
		return null;
4857
}
4858

    
4859
function get_interface_ipv6($interface = "wan", $flush = false) {
4860
	global $config;
4861

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

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

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

    
4898
function get_interface_linklocal($interface = "wan") {
4899

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

    
4909
	$curip = find_interface_ipv6_ll($realif);
4910
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4911
		return $curip;
4912
	else
4913
		return null;
4914
}
4915

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

    
4926
	$cursn = find_interface_subnet($realif);
4927
	if (!empty($cursn))
4928
		return $cursn;
4929

    
4930
	return null;
4931
}
4932

    
4933
function get_interface_subnetv6($interface = "wan") {
4934
	global $config;
4935

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

    
4945
	$cursn = find_interface_subnetv6($realif);
4946
	if (!empty($cursn))
4947
		return $cursn;
4948

    
4949
	return null;
4950
}
4951

    
4952
/* return outside interfaces with a gateway */
4953
function get_interfaces_with_gateway() {
4954
	global $config;
4955

    
4956
	$ints = array();
4957

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

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

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

    
5005
	return false;
5006
}
5007

    
5008
/* return true if interface has a gateway */
5009
function interface_has_gatewayv6($friendly) {
5010
	global $config;
5011

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

    
5033
	return false;
5034
}
5035

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

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

    
5058
	$int_family = remove_ifindex($int);
5059

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

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

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

    
5093
function get_wireless_modes($interface) {
5094
	/* return wireless modes and channels */
5095
	$wireless_modes = array();
5096

    
5097
	$cloned_interface = get_real_interface($interface);
5098

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

    
5104
		$interface_channels = "";
5105
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5106
		$interface_channel_count = count($interface_channels);
5107

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

    
5137
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5138
function get_wireless_channel_info($interface) {
5139
	$wireless_channels = array();
5140

    
5141
	$cloned_interface = get_real_interface($interface);
5142

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

    
5148
		$interface_channels = "";
5149
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5150

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

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

    
5171
function get_interface_mac($interface) {
5172

    
5173
	$macinfo = pfSense_get_interface_addresses($interface);
5174
	return $macinfo["macaddr"];
5175
}
5176

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

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

    
5204
	if (isset($capable['caps']['vlanmtu']))
5205
		return true;
5206

    
5207
	return false;
5208
}
5209

    
5210
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5211
	global $g;
5212

    
5213
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5214

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

    
5221
EOD;
5222

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

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

    
5247
	/* Never reached */
5248
	return 1500;
5249
}
5250

    
5251
function get_vip_descr($ipaddress) {
5252
	global $config;
5253

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

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

    
5269
	$ifcfg = $config['interfaces'][$if];
5270

    
5271
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5272
		return 0;
5273

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

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

    
5283
			}
5284

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

    
5298
	return 0;
5299
}
5300

    
5301
function get_failover_interface($interface, $family = "all") {
5302
	global $config;
5303

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

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

    
5323
function remove_ifindex($ifname) {
5324
	return preg_replace("/[0-9]+$/", "", $ifname);
5325
}
5326

    
5327
?>
(26-26/68)