Projet

Général

Profil

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

univnautes / etc / inc / interfaces.inc @ 672e28f3

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

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

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

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

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

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

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

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

    
42
*/
43

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

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

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

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

    
68
	return $interface_arr_cache;
69
}
70

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

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

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

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

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

    
98

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

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

    
120
	return false;
121
}
122

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
266
	interfaces_bring_up($vlanif);
267

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

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

    
274
	return $vlanif;
275
}
276

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

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

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

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

    
297
	$vlanif = interface_vlan_configure($vlan);
298

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

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

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

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

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

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

    
350
	return $vlanif;
351
}
352

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

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

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

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

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

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

    
393
	return $vlanif;
394
}
395

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

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

    
402
	$iflist = get_configured_interface_list();
403

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

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

    
423
}
424

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

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

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

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

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

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

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

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

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

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

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

    
546
	$checklist = get_configured_interface_list();
547

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
798
	$checklist = get_interface_list();
799

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

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

    
813
	interfaces_bring_up($laggif);
814

    
815
	return $laggif;
816
}
817

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

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

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

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

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

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

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

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

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

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

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

    
894
	interfaces_bring_up($greif);
895

    
896
	return $greif;
897
}
898

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

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

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

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

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

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

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

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

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

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

    
995

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

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

    
1008
	interfaces_bring_up($gifif);
1009

    
1010
	return $gifif;
1011
}
1012

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

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

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

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

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

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

    
1031
	interfaces_qinq_configure();
1032

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

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

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

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

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

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

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

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

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

    
1089
		interface_configure($if, $reload);
1090

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

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

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

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

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

    
1110
		interface_configure($if, $reload);
1111

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

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

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

    
1125
		interface_configure($if, $reload);
1126

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

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

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

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

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

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

    
1151
	return 0;
1152
}
1153

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1354
	return;
1355
}
1356

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

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

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

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

    
1384
	return false;
1385
}
1386

    
1387
function interfaces_ptpid_next() {
1388

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

    
1393
	return $ptpid;
1394
}
1395

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

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

    
1407
	return NULL;
1408
}
1409

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

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

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

    
1419
	$itemhash = getMPDCRONSettings($pppif);
1420

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

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

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

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

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

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

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

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

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

    
1569
				if(!is_ipaddr($localips[$pid])){
1570
					log_error("Could not get a Local IP address for PPTP/L2TP link on {$port} in interfaces_ppps_configure. Using 0.0.0.0 ip!");
1571
					$localips[$pid] = "0.0.0.0";
1572
				}
1573
				if(!is_ipaddr($gateways[$pid])){
1574
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $dhcp_gateway, $gway));
1575
					return 0;
1576
				}
1577
				pfSense_ngctl_attach(".", $port);
1578
				break;
1579
			case "ppp":
1580
				if (!file_exists("{$port}")) {
1581
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1582
					return 0;
1583
				}
1584
				break;
1585
			default:
1586
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1587
				break;
1588
		}
1589
	}
1590

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1679
EOD;
1680

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

    
1685
EOD;
1686

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

    
1694
EOD;
1695

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

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

    
1706
EOD;
1707

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

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

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

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

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

    
1734
EOD;
1735

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

    
1740
EOD;
1741

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

    
1746
EOD;
1747

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

    
1753
EOD;
1754

    
1755

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

    
1760
EOD;
1761

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

    
1767
EOD;
1768

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

    
1773
EOD;
1774

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

    
1779
EOD;
1780

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

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

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

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

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

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

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

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

    
1838
EOD;
1839

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

    
1845
EOD;
1846
		}
1847

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

    
1851

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

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

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

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

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

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

    
1927
	return 1;
1928
}
1929

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

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

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

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

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

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

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

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

    
1970
		sleep(1);
1971

    
1972
		/* XXX: Handle an issue with pfsync(4) and carp(4). In a cluster carp will come up before pfsync(4) has updated and so will cause issues
1973
		 * for existing sessions.
1974
		 */
1975
		log_error("waiting for pfsync...");
1976
		$i = 0;
1977
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1978
			$i++;
1979
			sleep(1);
1980
		}
1981
		log_error("pfsync done in $i seconds.");
1982
		log_error("Configuring CARP settings finalize...");
1983
	} else {
1984
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
1985
	}
1986

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2226
	return $realif;
2227
}
2228

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2586
EOD;
2587

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

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

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

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

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

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

    
2620
EOD;
2621
					}
2622
				}
2623
			}
2624

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2772

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

    
2777
	return 0;
2778

    
2779
}
2780

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

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

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

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

    
2798
	return intval($pid);
2799
}
2800

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

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

    
2809
	return intval($pid);
2810
}
2811

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

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

    
2827
	return $mtu;
2828
}
2829

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2983
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2984
			/*   this is not a valid mac address.  generate a
2985
			 *   temporary mac address so the machine can get online.
2986
			 */
2987
			echo gettext("Generating new MAC address.");
2988
			$random_mac = generate_random_mac_address();
2989
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2990
				" link " . escapeshellarg($random_mac));
2991
			$wancfg['spoofmac'] = $random_mac;
2992
			write_config();
2993
			file_notice("MAC Address altered", sprintf(gettext('The INVALID MAC address (ff:ff:ff:ff:ff:ff) on interface %1$s has been automatically replaced with %2$s'), $realif, $random_mac), "Interfaces");
2994
		}
2995
	}
2996

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3126
	interface_netgraph_needed($interface);
3127

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

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

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

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

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

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

    
3156
		if ($reloadall == true) {
3157

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3242
		services_dhcpd_configure("inet6");
3243
	}
3244

    
3245
	return 0;
3246
}
3247

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

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

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

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

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

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

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

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

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

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

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

    
3306
	return 0;
3307
}
3308

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

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

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

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

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

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

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

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

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

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

    
3363
	return 0;
3364
}
3365

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

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

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

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

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

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

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

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

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

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

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

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

    
3425
	/* write out a default router file */
3426
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3427
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3428

    
3429
	$ip4gateway = get_interface_gateway($interface);
3430
	if (is_ipaddrv4($ip4gateway))
3431
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3432

    
3433
	/* configure dependent interfaces */
3434
	if (!$g['booting'])
3435
		link_interface_to_track6($interface, "update");
3436

    
3437
	return 0;
3438
}
3439

    
3440
function interface_6to4_configure($interface = "wan", $wancfg){
3441
	global $config, $g;
3442

    
3443
	/* because this is a tunnel interface we can only function
3444
	 *	with a public IPv4 address on the interface */
3445

    
3446
	if (!is_array($wancfg))
3447
		return;
3448

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

    
3456
	/* create the long prefix notation for math, save the prefix length */
3457
	$stfprefixlen = 16;
3458
	$stfprefix = Net_IPv6::uncompress("2002::");
3459
	$stfarr = explode(":", $stfprefix);
3460
	$v4prefixlen = "0";
3461

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

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

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

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

    
3486
	/* for the local subnet too. */
3487
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3488
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3489

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

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

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

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

    
3522
	/* write out a default router file */
3523
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3524
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3525

    
3526
	$ip4gateway = get_interface_gateway($interface);
3527
	if (is_ipaddrv4($ip4gateway))
3528
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3529

    
3530
	if (!$g['booting'])
3531
		link_interface_to_track6($interface, "update");
3532

    
3533
	return 0;
3534
}
3535

    
3536
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3537
	global $config, $g;
3538

    
3539
	if (!is_array($wancfg))
3540
		return;
3541

    
3542
	$wanif = get_real_interface($interface, "inet6");
3543
	$dhcp6cconf = "";
3544
	$dhcp6cconf .= "interface {$wanif} {\n";
3545

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

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

    
3564
		$dhcp6cconf .= "};\n";
3565

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

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

    
3592
	// DHCP6 Config File Advanced
3593
	if ($wancfg['adv_dhcp6_config_advanced']) { $dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif); }
3594

    
3595
	// DHCP6 Config File Override
3596
	if ($wancfg['adv_dhcp6_config_file_override']) { $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif); }
3597

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

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

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

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

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

    
3651
	/* NOTE: will be called from rtsold invoked script
3652
	 * link_interface_to_track6($interface, "update");
3653
	 */
3654

    
3655
	return 0;
3656
}
3657

    
3658
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3659
	global $g;
3660

    
3661
	$send_options = "";
3662
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3663
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_send_options']);
3664
		foreach ($options as $option) {
3665
			$send_options .= "\tsend " . trim($option) . ";\n";
3666
		}
3667
	}
3668

    
3669
	$request_options = "";
3670
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3671
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_request_options']);
3672
		foreach ($options as $option) {
3673
			$request_options .= "\trequest " . trim($option) . ";\n";
3674
		}
3675
	}
3676

    
3677
	$information_only = "";
3678
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') 
3679
		$information_only = "\tinformation-only;\n";
3680

    
3681
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3682
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '')
3683
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3684

    
3685
	$interface_statement  = "interface";
3686
	$interface_statement .= " {$wanif}";
3687
	$interface_statement .= " {\n";
3688
	$interface_statement .= "$send_options";
3689
	$interface_statement .= "$request_options";
3690
	$interface_statement .= "$information_only";
3691
	$interface_statement .= "$script";
3692
	$interface_statement .= "};\n";
3693

    
3694
	$id_assoc_statement_address = "";
3695
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3696
		$id_assoc_statement_address .= "id-assoc";
3697
		$id_assoc_statement_address .= " na";
3698
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) 
3699
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3700
		$id_assoc_statement_address .= " { ";
3701

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

    
3714
		$id_assoc_statement_address  .= "};\n";
3715
	}
3716

    
3717
	$id_assoc_statement_prefix = "";
3718
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3719
		$id_assoc_statement_prefix .= "id-assoc";
3720
		$id_assoc_statement_prefix .= " pd";
3721
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) 
3722
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3723
		$id_assoc_statement_prefix .= " { ";
3724

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

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

    
3748
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') || 
3749
			 (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) ) { 
3750
			$id_assoc_statement_prefix .= "\n";
3751
		}
3752

    
3753
		$id_assoc_statement_prefix  .= "};\n";
3754
	}
3755

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

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

    
3786
	$dhcp6cconf  = $interface_statement;
3787
	$dhcp6cconf .= $id_assoc_statement_address;
3788
	$dhcp6cconf .= $id_assoc_statement_prefix;
3789
	$dhcp6cconf .= $authentication_statement;
3790
	$dhcp6cconf .= $key_info_statement;
3791

    
3792
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3793

    
3794
	return $dhcp6cconf;
3795
}
3796

    
3797

    
3798
function DHCP6_Config_File_Override($wancfg, $wanif) {
3799

    
3800
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
3801
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3802

    
3803
	return $dhcp6cconf;
3804
}
3805

    
3806

    
3807
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
3808

    
3809
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3810

    
3811
	return $dhcp6cconf;
3812
}
3813

    
3814

    
3815
function interface_dhcp_configure($interface = "wan") {
3816
	global $config, $g;
3817

    
3818
	$wancfg = $config['interfaces'][$interface];
3819
	$wanif = $wancfg['if'];
3820
	if (empty($wancfg))
3821
		$wancfg = array();
3822

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

    
3830
	if ($wancfg['dhcphostname']) {
3831
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3832
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3833
	} else {
3834
		$dhclientconf_hostname = "";
3835
	}
3836

    
3837
	$wanif = get_real_interface($interface);
3838
	if (empty($wanif)) {
3839
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3840
		return 0;
3841
	}
3842
	$dhclientconf = "";
3843

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

    
3854
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3855
	$dhclientconf .= <<<EOD
3856

    
3857
	reject {$wancfg['dhcprejectfrom']};
3858
EOD;
3859
}
3860
	$dhclientconf .= <<<EOD
3861

    
3862
}
3863

    
3864
EOD;
3865

    
3866
	// DHCP Config File Advanced
3867
	if ($wancfg['adv_dhcp_config_advanced']) { $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif); }
3868

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

    
3878
EOD;
3879
}
3880

    
3881
	// DHCP Config File Override
3882
	if ($wancfg['adv_dhcp_config_file_override']) { $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif); }
3883

    
3884
	fwrite($fd, $dhclientconf);
3885
	fclose($fd);
3886

    
3887
	/* bring wan interface up before starting dhclient */
3888
	if($wanif)
3889
		interfaces_bring_up($wanif);
3890
	else
3891
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3892

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

    
3896
	return 0;
3897
}
3898

    
3899
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3900

    
3901
	$hostname = "";
3902
	if ($wancfg['dhcphostname'] != '') {
3903
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3904
	}
3905

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

    
3916
	$send_options = "";
3917
	if ($wancfg['adv_dhcp_send_options'] != '') {
3918
		$options = split(",", $wancfg['adv_dhcp_send_options']);
3919
		foreach ($options as $option) {
3920
			$send_options .= "\tsend " . trim($option) . ";\n";
3921
		}
3922
	}
3923

    
3924
	$request_options = "";
3925
	if ($wancfg['adv_dhcp_request_options'] != '') {
3926
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
3927
	}
3928

    
3929
	$required_options = "";
3930
	if ($wancfg['adv_dhcp_required_options'] != '') {
3931
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
3932
	}
3933

    
3934
	$option_modifiers = "";
3935
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
3936
		$modifiers = split(",", $wancfg['adv_dhcp_option_modifiers']);
3937
		foreach ($modifiers as $modifier) {
3938
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
3939
		}
3940
	}
3941

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

    
3962
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3963

    
3964
	return $dhclientconf;
3965
}
3966

    
3967

    
3968
function DHCP_Config_File_Override($wancfg, $wanif) {
3969

    
3970
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
3971
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3972

    
3973
	return $dhclientconf;
3974
}
3975

    
3976

    
3977
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
3978

    
3979
	/* Apply Interface Substitutions */
3980
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
3981

    
3982
	/* Apply Hostname Substitutions */
3983
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
3984

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

    
3991
	/* Apply MAC Address Substitutions */
3992
	foreach ($various_mac_types as $various_mac_type) {
3993
		foreach ($various_mac_cases as $various_mac_case) {
3994
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
3995

    
3996
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
3997
				if ($res !== false) {
3998

    
3999
					/* Get MAC Address as ASCII String With Colon (:) Celimiters */
4000
					if ("$various_mac_case" == "U") $dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4001
					if ("$various_mac_case" == "L") $dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4002

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

    
4015
					/* MAC Address Delimiter Substitutions */
4016
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4017

    
4018
					/* Apply MAC Address Substitutions */
4019
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4020
				}
4021
			}
4022
		}
4023
	}
4024

    
4025
	return $dhclientconf;
4026
}
4027

    
4028
function interfaces_group_setup() {
4029
	global $config;
4030

    
4031
	if (!is_array($config['ifgroups']['ifgroupentry']))
4032
		return;
4033

    
4034
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
4035
		interface_group_setup($groupar);
4036

    
4037
	return;
4038
}
4039

    
4040
function interface_group_setup(&$groupname /* The parameter is an array */) {
4041
	global $config;
4042

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

    
4052
	return;
4053
}
4054

    
4055
function is_interface_group($if) {
4056
	global $config;
4057

    
4058
	if (is_array($config['ifgroups']['ifgroupentry']))
4059
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4060
			if ($groupentry['ifname'] === $if)
4061
				return true;
4062
		}
4063

    
4064
	return false;
4065
}
4066

    
4067
function interface_group_add_member($interface, $groupname) {
4068
	$interface = get_real_interface($interface);
4069
	mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4070
}
4071

    
4072
/* COMPAT Function */
4073
function convert_friendly_interface_to_real_interface_name($interface) {
4074
	return get_real_interface($interface);
4075
}
4076

    
4077
/* COMPAT Function */
4078
function get_real_wan_interface($interface = "wan") {
4079
	return get_real_interface($interface);
4080
}
4081

    
4082
/* COMPAT Function */
4083
function get_current_wan_address($interface = "wan") {
4084
	return get_interface_ip($interface);
4085
}
4086

    
4087
/*
4088
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4089
 */
4090
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
4091
	global $config;
4092

    
4093
	/* XXX: For speed reasons reference directly the interface array */
4094
	$ifdescrs = &$config['interfaces'];
4095
	//$ifdescrs = get_configured_interface_list(false, true);
4096

    
4097
	foreach ($ifdescrs as $if => $ifname) {
4098
		if ($if == $interface || $ifname['if'] == $interface)
4099
			return $if;
4100

    
4101
		if (get_real_interface($if) == $interface)
4102
			return $if;
4103

    
4104
		$int = get_parent_interface($if, true);
4105
		if (is_array($int)) {
4106
			foreach ($int as $iface) {
4107
				if ($iface == $interface)
4108
					return $if;
4109
			}
4110
		}
4111
	}
4112

    
4113
	if ($interface == "enc0")
4114
		return 'IPsec';
4115

    
4116
	return NULL;
4117
}
4118

    
4119
/* attempt to resolve interface to friendly descr */
4120
function convert_friendly_interface_to_friendly_descr($interface) {
4121
	global $config;
4122

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

    
4167
	return $ifdesc;
4168
}
4169

    
4170
function convert_real_interface_to_friendly_descr($interface) {
4171
	global $config;
4172

    
4173
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4174

    
4175
	if ($ifdesc) {
4176
		$iflist = get_configured_interface_with_descr(false, true);
4177
		return $iflist[$ifdesc];
4178
	}
4179

    
4180
	return $interface;
4181
}
4182

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

    
4195
	$parents = array();
4196
	//Check that we got a valid interface passed
4197
	$realif = get_real_interface($interface);
4198
	if ($realif == NULL)
4199
		return $parents;
4200

    
4201
	// If we got a real interface, find it's friendly assigned name
4202
	if ($interface == $realif && $avoidrecurse == false)
4203
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4204

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

    
4238
	if (empty($parents))
4239
		$parents[0] = $realif;
4240

    
4241
	return $parents;
4242
}
4243

    
4244
function interface_is_wireless_clone($wlif) {
4245
	if(!stristr($wlif, "_wlan")) {
4246
		return false;
4247
	} else {
4248
		return true;
4249
	}
4250
}
4251

    
4252
function interface_get_wireless_base($wlif) {
4253
	if(!stristr($wlif, "_wlan")) {
4254
		return $wlif;
4255
	} else {
4256
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4257
	}
4258
}
4259

    
4260
function interface_get_wireless_clone($wlif) {
4261
	if(!stristr($wlif, "_wlan")) {
4262
		return $wlif . "_wlan0";
4263
	} else {
4264
		return $wlif;
4265
	}
4266
}
4267

    
4268
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4269
	global $config, $g;
4270

    
4271
	$wanif = NULL;
4272

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

    
4303
		if (empty($config['interfaces'][$interface]))
4304
			break;
4305

    
4306
		$cfg = &$config['interfaces'][$interface];
4307

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

    
4360
	return $wanif;
4361
}
4362

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

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

    
4408
	$isv6ip = is_ipaddrv6($ip);
4409

    
4410
	/* if list */
4411
	$ifdescrs = get_configured_interface_list();
4412

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

    
4431
	return false;
4432
}
4433

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

    
4441
	if (!is_array($config['virtualip']['vip'])) {
4442
		return false;
4443
	}
4444
	if (!is_ipaddr($ip))
4445
		return false;
4446

    
4447
	$isv6ip = is_ipaddrv6($ip);
4448

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

    
4469
/*
4470
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4471
 */
4472
function find_number_of_created_carp_interfaces() {
4473
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4474
}
4475

    
4476
function get_all_carp_interfaces() {
4477
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
4478
	$ints = explode(" ", $ints);
4479
	return $ints;
4480
}
4481

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

    
4507
				if ($if)
4508
					return $if;
4509
			}
4510
		}
4511
	}
4512
}
4513

    
4514
function link_carp_interface_to_parent($interface) {
4515
	global $config;
4516

    
4517
	if (empty($interface))
4518
		return;
4519

    
4520
	$carp_ip = get_interface_ip($interface);
4521
	$carp_ipv6 = get_interface_ipv6($interface);
4522

    
4523
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4524
		return;
4525

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

    
4548

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

    
4560
	if (!is_ipaddr($ip))
4561
		return;
4562

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

    
4581
	return $carp_ints;
4582
}
4583

    
4584
function link_interface_to_track6($int, $action = "") {
4585
	global $config;
4586

    
4587
	if (empty($int))
4588
		return;
4589

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

    
4606
function link_interface_to_vlans($int, $action = "") {
4607
	global $config;
4608

    
4609
	if (empty($int))
4610
		return;
4611

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

    
4627
function link_interface_to_vips($int, $action = "") {
4628
	global $config;
4629

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

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

    
4655
	if (is_array($config['bridges']['bridged'])) {
4656
		foreach ($config['bridges']['bridged'] as $bridge) {
4657
			if (in_array($int, explode(',', $bridge['members'])))
4658
				return "{$bridge['bridgeif']}";
4659
		}
4660
	}
4661
}
4662

    
4663
function link_interface_to_group($int) {
4664
	global $config;
4665

    
4666
	$result = array();
4667

    
4668
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4669
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4670
			if (in_array($int, explode(" ", $group['members'])))
4671
				$result[$group['ifname']] = $int;
4672
		}
4673
	}
4674

    
4675
	return $result;
4676
}
4677

    
4678
function link_interface_to_gre($interface) {
4679
	global $config;
4680

    
4681
	$result = array();
4682

    
4683
	if (is_array($config['gres']['gre'])) {
4684
		foreach ($config['gres']['gre'] as $gre)
4685
			if($gre['if'] == $interface)
4686
				$result[] = $gre;
4687
	}
4688

    
4689
	return $result;
4690
}
4691

    
4692
function link_interface_to_gif($interface) {
4693
	global $config;
4694

    
4695
	$result = array();
4696

    
4697
	if (is_array($config['gifs']['gif'])) {
4698
		foreach ($config['gifs']['gif'] as $gif)
4699
			if($gif['if'] == $interface)
4700
				$result[] = $gif;
4701
	}
4702

    
4703
	return $result;
4704
}
4705

    
4706
/*
4707
 * find_interface_ip($interface): return the interface ip (first found)
4708
 */
4709
function find_interface_ip($interface, $flush = false) {
4710
	global $interface_ip_arr_cache;
4711
	global $interface_sn_arr_cache;
4712

    
4713
	$interface = str_replace("\n", "", $interface);
4714

    
4715
	if (!does_interface_exist($interface))
4716
		return;
4717

    
4718
	/* Setup IP cache */
4719
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4720
		$ifinfo = pfSense_get_interface_addresses($interface);
4721
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4722
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4723
	}
4724

    
4725
	return $interface_ip_arr_cache[$interface];
4726
}
4727

    
4728
/*
4729
 * find_interface_ipv6($interface): return the interface ip (first found)
4730
 */
4731
function find_interface_ipv6($interface, $flush = false) {
4732
	global $interface_ipv6_arr_cache;
4733
	global $interface_snv6_arr_cache;
4734
	global $config;
4735

    
4736
	$interface = trim($interface);
4737
	$interface = get_real_interface($interface);
4738

    
4739
	if (!does_interface_exist($interface))
4740
		return;
4741

    
4742
	/* Setup IP cache */
4743
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4744
		$ifinfo = pfSense_get_interface_addresses($interface);
4745
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4746
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4747
	}
4748

    
4749
	return $interface_ipv6_arr_cache[$interface];
4750
}
4751

    
4752
/*
4753
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4754
 */
4755
function find_interface_ipv6_ll($interface, $flush = false) {
4756
	global $interface_llv6_arr_cache;
4757
	global $config;
4758

    
4759
	$interface = str_replace("\n", "", $interface);
4760

    
4761
	if (!does_interface_exist($interface))
4762
		return;
4763

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

    
4780
function find_interface_subnet($interface, $flush = false) {
4781
	global $interface_sn_arr_cache;
4782
	global $interface_ip_arr_cache;
4783

    
4784
	$interface = str_replace("\n", "", $interface);
4785
	if (does_interface_exist($interface) == false)
4786
		return;
4787

    
4788
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4789
		$ifinfo = pfSense_get_interface_addresses($interface);
4790
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4791
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4792
	}
4793

    
4794
	return $interface_sn_arr_cache[$interface];
4795
}
4796

    
4797
function find_interface_subnetv6($interface, $flush = false) {
4798
	global $interface_snv6_arr_cache;
4799
	global $interface_ipv6_arr_cache;
4800

    
4801
	$interface = str_replace("\n", "", $interface);
4802
	if (does_interface_exist($interface) == false)
4803
		return;
4804

    
4805
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4806
		$ifinfo = pfSense_get_interface_addresses($interface);
4807
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4808
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4809
	}
4810

    
4811
	return $interface_snv6_arr_cache[$interface];
4812
}
4813

    
4814
function ip_in_interface_alias_subnet($interface, $ipalias) {
4815
	global $config;
4816

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

    
4833
	return false;
4834
}
4835

    
4836
function get_interface_ip($interface = "wan") {
4837
	$realif = get_failover_interface($interface);
4838
	if (!$realif) {
4839
		if (strstr($interface, "_vip"))
4840
			return get_configured_carp_interface_list($interface);
4841
		else
4842
			return null;
4843
	}
4844

    
4845
	$curip = find_interface_ip($realif);
4846
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4847
		return $curip;
4848
	else
4849
		return null;
4850
}
4851

    
4852
function get_interface_ipv6($interface = "wan", $flush = false) {
4853
	global $config;
4854

    
4855
	$realif = get_failover_interface($interface, "inet6");
4856
	if (!$realif) {
4857
		if (strstr($interface, "_vip"))
4858
			return get_configured_carp_interface_list($interface, "inet6");
4859
		else
4860
			return null;
4861
	}
4862

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

    
4884
	$curip = find_interface_ipv6($realif, $flush);
4885
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4886
		return $curip;
4887
	else
4888
		return null;
4889
}
4890

    
4891
function get_interface_linklocal($interface = "wan") {
4892

    
4893
	$realif = get_failover_interface($interface, "inet6");
4894
	if (!$realif) {
4895
		if (strstr($interface, "_vip")) {
4896
			list($interface, $vhid) = explode("_vip", $interface);
4897
			$realif = get_real_interface($interface);
4898
		} else
4899
			return null;
4900
	}
4901

    
4902
	$curip = find_interface_ipv6_ll($realif);
4903
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4904
		return $curip;
4905
	else
4906
		return null;
4907
}
4908

    
4909
function get_interface_subnet($interface = "wan") {
4910
	$realif = get_real_interface($interface);
4911
	if (!$realif) {
4912
		if (strstr($interface, "_vip")) {
4913
			list($interface, $vhid) = explode("_vip", $interface);
4914
			$realif = get_real_interface($interface);
4915
		} else
4916
			return null;
4917
	}
4918

    
4919
	$cursn = find_interface_subnet($realif);
4920
	if (!empty($cursn))
4921
		return $cursn;
4922

    
4923
	return null;
4924
}
4925

    
4926
function get_interface_subnetv6($interface = "wan") {
4927
	global $config;
4928

    
4929
	$realif = get_real_interface($interface, "inet6");
4930
	if (!$realif) {
4931
		if (strstr($interface, "_vip")) {
4932
			list($interface, $vhid) = explode("_vip", $interface);
4933
			$realif = get_real_interface($interface);
4934
		} else
4935
			return null;
4936
	}
4937

    
4938
	$cursn = find_interface_subnetv6($realif);
4939
	if (!empty($cursn))
4940
		return $cursn;
4941

    
4942
	return null;
4943
}
4944

    
4945
/* return outside interfaces with a gateway */
4946
function get_interfaces_with_gateway() {
4947
	global $config;
4948

    
4949
	$ints = array();
4950

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

    
4972
/* return true if interface has a gateway */
4973
function interface_has_gateway($friendly) {
4974
	global $config;
4975

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

    
4998
	return false;
4999
}
5000

    
5001
/* return true if interface has a gateway */
5002
function interface_has_gatewayv6($friendly) {
5003
	global $config;
5004

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

    
5026
	return false;
5027
}
5028

    
5029
/****f* interfaces/is_altq_capable
5030
 * NAME
5031
 *   is_altq_capable - Test if interface is capable of using ALTQ
5032
 * INPUTS
5033
 *   $int            - string containing interface name
5034
 * RESULT
5035
 *   boolean         - true or false
5036
 ******/
5037

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

    
5051
	$int_family = remove_ifindex($int);
5052

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

    
5065
/****f* interfaces/is_interface_wireless
5066
 * NAME
5067
 *   is_interface_wireless - Returns if an interface is wireless
5068
 * RESULT
5069
 *   $tmp       - Returns if an interface is wireless
5070
 ******/
5071
function is_interface_wireless($interface) {
5072
	global $config, $g;
5073

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

    
5086
function get_wireless_modes($interface) {
5087
	/* return wireless modes and channels */
5088
	$wireless_modes = array();
5089

    
5090
	$cloned_interface = get_real_interface($interface);
5091

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

    
5097
		$interface_channels = "";
5098
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5099
		$interface_channel_count = count($interface_channels);
5100

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

    
5130
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5131
function get_wireless_channel_info($interface) {
5132
	$wireless_channels = array();
5133

    
5134
	$cloned_interface = get_real_interface($interface);
5135

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

    
5141
		$interface_channels = "";
5142
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5143

    
5144
		foreach ($interface_channels as $channel_line) {
5145
			$channel_line = explode(",", $channel_line);
5146
			if(!isset($wireless_channels[$channel_line[0]]))
5147
				$wireless_channels[$channel_line[0]] = $channel_line;
5148
		}
5149
	}
5150
	return($wireless_channels);
5151
}
5152

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

    
5164
function get_interface_mac($interface) {
5165

    
5166
	$macinfo = pfSense_get_interface_addresses($interface);
5167
	return $macinfo["macaddr"];
5168
}
5169

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

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

    
5197
	if (isset($capable['caps']['vlanmtu']))
5198
		return true;
5199

    
5200
	return false;
5201
}
5202

    
5203
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5204
	global $g;
5205

    
5206
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5207

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

    
5214
EOD;
5215

    
5216
		@file_put_contents($cron_file, $cron_cmd);
5217
		chmod($cron_file, 0755);
5218
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5219
	} else
5220
		unlink_if_exists($cron_file);
5221
}
5222

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

    
5240
	/* Never reached */
5241
	return 1500;
5242
}
5243

    
5244
function get_vip_descr($ipaddress) {
5245
	global $config;
5246

    
5247
	foreach ($config['virtualip']['vip'] as $vip) {
5248
		if ($vip['subnet'] == $ipaddress) {
5249
			return ($vip['descr']);
5250
		}
5251
	}
5252
	return "";
5253
}
5254

    
5255
function interfaces_staticarp_configure($if) {
5256
	global $config, $g;
5257
	if(isset($config['system']['developerspew'])) {
5258
		$mt = microtime();
5259
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5260
	}
5261

    
5262
	$ifcfg = $config['interfaces'][$if];
5263

    
5264
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5265
		return 0;
5266

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

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

    
5276
			}
5277

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

    
5291
	return 0;
5292
}
5293

    
5294
function get_failover_interface($interface, $family = "all") {
5295
	global $config;
5296

    
5297
	/* shortcut to get_real_interface if we find it in the config */
5298
	if (is_array($config['interfaces'][$interface])) {
5299
		return get_real_interface($interface, $family);
5300
	}
5301

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

    
5316
function remove_ifindex($ifname) {
5317
	return preg_replace("/[0-9]+$/", "", $ifname);
5318
}
5319

    
5320
?>
(25-25/67)