Projet

Général

Profil

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

univnautes / etc / inc / interfaces.inc @ ff3da5db

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

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

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

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

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

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

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

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

    
42
*/
43

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

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

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

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

    
68
	return $interface_arr_cache;
69
}
70

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

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

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

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

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

    
98

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

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

    
120
	return false;
121
}
122

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
266
	interfaces_bring_up($vlanif);
267

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

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

    
274
	return $vlanif;
275
}
276

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

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

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

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

    
297
	$vlanif = interface_vlan_configure($vlan);
298

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

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

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

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

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

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

    
350
	return $vlanif;
351
}
352

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

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

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

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

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

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

    
393
	return $vlanif;
394
}
395

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

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

    
402
	$iflist = get_configured_interface_list();
403

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

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

    
423
}
424

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

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

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

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

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

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

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

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

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

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

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

    
546
	$checklist = get_configured_interface_list();
547

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
798
	$checklist = get_interface_list();
799

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

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

    
813
	interfaces_bring_up($laggif);
814

    
815
	return $laggif;
816
}
817

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

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

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

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

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

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

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

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

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

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

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

    
894
	interfaces_bring_up($greif);
895

    
896
	return $greif;
897
}
898

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

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

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

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

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

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

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

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

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

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

    
995

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

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

    
1008
	interfaces_bring_up($gifif);
1009

    
1010
	return $gifif;
1011
}
1012

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

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

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

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

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

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

    
1031
	interfaces_qinq_configure();
1032

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

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

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

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

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

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

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

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

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

    
1089
		interface_configure($if, $reload);
1090

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

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

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

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

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

    
1110
		interface_configure($if, $reload);
1111

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

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

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

    
1125
		interface_configure($if, $reload);
1126

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

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

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

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

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

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

    
1151
	return 0;
1152
}
1153

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1355
	return;
1356
}
1357

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

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

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

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

    
1385
	return false;
1386
}
1387

    
1388
function interfaces_ptpid_next() {
1389

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

    
1394
	return $ptpid;
1395
}
1396

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

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

    
1408
	return NULL;
1409
}
1410

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

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

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

    
1420
	$itemhash = getMPDCRONSettings($pppif);
1421

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1680
EOD;
1681

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

    
1686
EOD;
1687

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

    
1695
EOD;
1696

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

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

    
1707
EOD;
1708

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

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

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

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

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

    
1735
EOD;
1736

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

    
1741
EOD;
1742

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

    
1747
EOD;
1748

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

    
1754
EOD;
1755

    
1756

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

    
1761
EOD;
1762

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

    
1768
EOD;
1769

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

    
1774
EOD;
1775

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

    
1780
EOD;
1781

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

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

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

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

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

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

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

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

    
1839
EOD;
1840

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

    
1846
EOD;
1847
		}
1848

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

    
1852

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

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

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

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

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

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

    
1928
	return 1;
1929
}
1930

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

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

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

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

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

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

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

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

    
1971
		sleep(1);
1972

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2227
	return $realif;
2228
}
2229

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2587
EOD;
2588

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

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

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

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

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

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

    
2621
EOD;
2622
					}
2623
				}
2624
			}
2625

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2773

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

    
2778
	return 0;
2779

    
2780
}
2781

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

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

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

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

    
2799
	return intval($pid);
2800
}
2801

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

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

    
2810
	return intval($pid);
2811
}
2812

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

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

    
2828
	return $mtu;
2829
}
2830

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3127
	interface_netgraph_needed($interface);
3128

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

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

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

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

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

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

    
3157
		if ($reloadall == true) {
3158

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3243
		services_dhcpd_configure("inet6");
3244
	}
3245

    
3246
	return 0;
3247
}
3248

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

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

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

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

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

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

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

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

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

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

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

    
3307
	return 0;
3308
}
3309

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

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

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

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

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

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

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

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

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

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

    
3364
	return 0;
3365
}
3366

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3442
	return 0;
3443
}
3444

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3538
	return 0;
3539
}
3540

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3660
	return 0;
3661
}
3662

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3799
	return $dhcp6cconf;
3800
}
3801

    
3802

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

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

    
3808
	return $dhcp6cconf;
3809
}
3810

    
3811

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

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

    
3816
	return $dhcp6cconf;
3817
}
3818

    
3819

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

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

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

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

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

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

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

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

    
3867
}
3868

    
3869
EOD;
3870

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

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

    
3883
EOD;
3884
}
3885

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

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

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

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

    
3901
	return 0;
3902
}
3903

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

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

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

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

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

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

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

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

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

    
3969
	return $dhclientconf;
3970
}
3971

    
3972

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

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

    
3978
	return $dhclientconf;
3979
}
3980

    
3981

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

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

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

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

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

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

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

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

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

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

    
4030
	return $dhclientconf;
4031
}
4032

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

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

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

    
4042
	return;
4043
}
4044

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

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

    
4057
	return;
4058
}
4059

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

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

    
4069
	return false;
4070
}
4071

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

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

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

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

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

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

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

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

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

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

    
4121
	return NULL;
4122
}
4123

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

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

    
4172
	return $ifdesc;
4173
}
4174

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

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

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

    
4185
	return $interface;
4186
}
4187

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

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

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

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

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

    
4246
	return $parents;
4247
}
4248

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

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

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

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

    
4276
	$wanif = NULL;
4277

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

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

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

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

    
4365
	return $wanif;
4366
}
4367

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

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

    
4413
	$isv6ip = is_ipaddrv6($ip);
4414

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

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

    
4436
	return false;
4437
}
4438

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

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

    
4452
	$isv6ip = is_ipaddrv6($ip);
4453

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

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

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

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

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

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

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

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

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

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

    
4553

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

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

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

    
4586
	return $carp_ints;
4587
}
4588

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

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

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

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

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

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

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

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

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

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

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

    
4671
	$result = array();
4672

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

    
4680
	return $result;
4681
}
4682

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

    
4686
	$result = array();
4687

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

    
4694
	return $result;
4695
}
4696

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

    
4700
	$result = array();
4701

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

    
4708
	return $result;
4709
}
4710

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4838
	return false;
4839
}
4840

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

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

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

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

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

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

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

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

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

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

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

    
4928
	return null;
4929
}
4930

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

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

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

    
4947
	return null;
4948
}
4949

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

    
4954
	$ints = array();
4955

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

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

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

    
5003
	return false;
5004
}
5005

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

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

    
5031
	return false;
5032
}
5033

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

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

    
5056
	$int_family = remove_ifindex($int);
5057

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

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

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

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

    
5095
	$cloned_interface = get_real_interface($interface);
5096

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

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

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

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

    
5139
	$cloned_interface = get_real_interface($interface);
5140

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

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

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

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

    
5169
function get_interface_mac($interface) {
5170

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

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

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

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

    
5205
	return false;
5206
}
5207

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

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

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

    
5219
EOD;
5220

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

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

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

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

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

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

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

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

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

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

    
5281
			}
5282

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

    
5296
	return 0;
5297
}
5298

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

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

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

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

    
5325
?>
(26-26/68)