Projet

Général

Profil

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

univnautes / etc / inc / interfaces.inc @ 572f6ccc

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
	case "IPsec":
4146
		$ifdesc = "IPsec";
4147
		break;
4148
	default:
4149
		if (isset($config['interfaces'][$interface])) {
4150
			if (empty($config['interfaces'][$interface]['descr']))
4151
				$ifdesc = strtoupper($interface);
4152
			else
4153
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4154
			break;
4155
		} else if (stristr($interface, "_vip")) {
4156
			if (is_array($config['virtualip']['vip'])) {
4157
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
4158
					if ($vip['mode'] == "carp")  {
4159
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4160
							return "{$vip['subnet']} - {$vip['descr']}";
4161
					}
4162
				}
4163
			}
4164
		} else {
4165
			/* if list */
4166
			$ifdescrs = get_configured_interface_with_descr(false, true);
4167
			foreach ($ifdescrs as $if => $ifname) {
4168
				if ($if == $interface || $ifname == $interface)
4169
					return $ifname;
4170
			}
4171
		}
4172
		break;
4173
	}
4174

    
4175
	return $ifdesc;
4176
}
4177

    
4178
function convert_real_interface_to_friendly_descr($interface) {
4179

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

    
4182
	if (!empty($ifdesc))
4183
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4184

    
4185
	return $interface;
4186
}
4187

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

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

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

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

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

    
4246
	return $parents;
4247
}
4248

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

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

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

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

    
4276
	$wanif = NULL;
4277

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

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

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

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

    
4365
	return $wanif;
4366
}
4367

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

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

    
4413
	$isv6ip = is_ipaddrv6($ip);
4414

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

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

    
4436
	return false;
4437
}
4438

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

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

    
4452
	$isv6ip = is_ipaddrv6($ip);
4453

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

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

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

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

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

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

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

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

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

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

    
4553

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

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

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

    
4586
	return $carp_ints;
4587
}
4588

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

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

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

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

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

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

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

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

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

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

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

    
4671
	$result = array();
4672

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

    
4680
	return $result;
4681
}
4682

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

    
4686
	$result = array();
4687

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

    
4694
	return $result;
4695
}
4696

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

    
4700
	$result = array();
4701

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

    
4708
	return $result;
4709
}
4710

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4799
	return $interface_sn_arr_cache[$interface];
4800
}
4801

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

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

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

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

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

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

    
4838
	return false;
4839
}
4840

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

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

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

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

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

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

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

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

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

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

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

    
4928
	return null;
4929
}
4930

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

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

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

    
4947
	return null;
4948
}
4949

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

    
4954
	$ints = array();
4955

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

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

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

    
5003
	return false;
5004
}
5005

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

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

    
5031
	return false;
5032
}
5033

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

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

    
5056
	$int_family = remove_ifindex($int);
5057

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

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

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

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

    
5095
	$cloned_interface = get_real_interface($interface);
5096

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

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

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

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

    
5139
	$cloned_interface = get_real_interface($interface);
5140

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

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

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

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

    
5169
function get_interface_mac($interface) {
5170

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

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

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

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

    
5205
	return false;
5206
}
5207

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

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

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

    
5219
EOD;
5220

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

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

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

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

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

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

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

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

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

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

    
5281
			}
5282

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

    
5296
	return 0;
5297
}
5298

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

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

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

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

    
5325
?>
(26-26/68)