Projet

Général

Profil

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

univnautes / etc / inc / interfaces.inc @ 2d5fd3c2

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
		kill_dhclient_process($realif);
1246
		unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1247
		if(does_interface_exist("$realif")) {
1248
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1249
			interface_ipalias_cleanup($interface);
1250
			if ($destroy == true)
1251
				pfSense_interface_flags($realif, -IFF_UP);
1252
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1253
		}
1254
		break;
1255
	default:
1256
		if(does_interface_exist("$realif")) {
1257
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1258
			interface_ipalias_cleanup($interface);
1259
			if ($destroy == true)
1260
				pfSense_interface_flags($realif, -IFF_UP);
1261
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1262
		}
1263
		break;
1264
	}
1265

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

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

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

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

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

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

    
1352
	return;
1353
}
1354

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

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

    
1374
function interfaces_ptpid_used($ptpid) {
1375
	global $config;
1376

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

    
1382
	return false;
1383
}
1384

    
1385
function interfaces_ptpid_next() {
1386

    
1387
	$ptpid = 0;
1388
	while(interfaces_ptpid_used($ptpid))
1389
		$ptpid++;
1390

    
1391
	return $ptpid;
1392
}
1393

    
1394
function getMPDCRONSettings($pppif) {
1395
	global $config;
1396

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

    
1405
	return NULL;
1406
}
1407

    
1408
function handle_pppoe_reset($post_array) {
1409
	global $config, $g;
1410

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

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

    
1417
	$itemhash = getMPDCRONSettings($pppif);
1418

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1677
EOD;
1678

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

    
1683
EOD;
1684

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

    
1692
EOD;
1693

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

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

    
1704
EOD;
1705

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

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

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

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

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

    
1732
EOD;
1733

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

    
1738
EOD;
1739

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

    
1744
EOD;
1745

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

    
1751
EOD;
1752

    
1753

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

    
1758
EOD;
1759

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

    
1765
EOD;
1766

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

    
1771
EOD;
1772

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

    
1777
EOD;
1778

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

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

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

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

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

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

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

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

    
1836
EOD;
1837

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

    
1843
EOD;
1844
		}
1845

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

    
1849

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

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

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

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

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

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

    
1925
	return 1;
1926
}
1927

    
1928
function interfaces_carp_setup() {
1929
	global $g, $config;
1930

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

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

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

    
1951
	set_sysctl(array(
1952
		"net.inet.carp.preempt" => "1",
1953
		"net.inet.carp.log" => "1")
1954
	);
1955

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

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

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

    
1970
		sleep(1);
1971

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2186
	if (is_ipaddrv4($vip['subnet'])) {
2187
		/* Ensure a IP on this interface exists prior to configuring CARP. */
2188
		$ww_subnet_ip = find_interface_ip($realif);
2189
		if (!is_ipaddrv4($ww_subnet_ip)) {
2190
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a required assigned ip address on the interface for the virtual IP address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2191
			return;
2192
		}
2193
	} else if (is_ipaddrv6($vip['subnet'])) {
2194
		/* Ensure a IP on this interface exists prior to configuring CARP. */
2195
		$ww_subnet_ip = find_interface_ipv6($realif);
2196
		if (!is_ipaddrv6($ww_subnet_ip)) {
2197
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a required assigned ip address on the interface for the virtual IPv6 address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2198
			return;
2199
		}
2200
	}
2201

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

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

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

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

    
2224
	return $realif;
2225
}
2226

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

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

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

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

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

    
2298
	if(!is_interface_wireless($ifcfg['if']))
2299
		return;
2300

    
2301
	$baseif = interface_get_wireless_base($ifcfg['if']);
2302

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

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

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

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

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

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

    
2373
	// Clone wireless nic if needed.
2374
	interface_wireless_clone($if, $wl);
2375

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2525
	kill_hostapd($if);
2526
	mwexec(kill_wpasupplicant("{$if}"));
2527

    
2528
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2529
	conf_mount_rw();
2530

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

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

    
2584
EOD;
2585

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

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

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

    
2603
auth_server_addr={$wlcfg['auth_server_addr']}
2604
auth_server_port={$auth_server_port}
2605
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2606

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

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

    
2618
EOD;
2619
					}
2620
				}
2621
			}
2622

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

    
2629
	/*
2630
	 *    all variables are set, lets start up everything
2631
	 */
2632

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

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

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

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

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

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

    
2679
	fclose($fd_set);
2680
	conf_mount_ro();
2681

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

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

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

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

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

    
2715
		$wlregcmd_args = implode(" ", $wlregcmd);
2716

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

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

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

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

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

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

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

    
2770

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

    
2775
	return 0;
2776

    
2777
}
2778

    
2779
function kill_hostapd($interface) {
2780
	global $g;
2781

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

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

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

    
2796
	return intval($pid);
2797
}
2798

    
2799
function kill_dhclient_process($interface) {
2800
	if (empty($interface) || !does_interface_exist($interface))
2801
		return;
2802

    
2803
	$i = 0;
2804
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2805
		/* 3rd time make it die for sure */
2806
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2807
		posix_kill($pid, $sig);
2808
		sleep(1);
2809
		$i++;
2810
	}
2811
	unset($i);
2812
}
2813

    
2814
function find_dhcp6c_process($interface) {
2815
	global $g;
2816

    
2817
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid"))
2818
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2819
	else
2820
		return(false);
2821

    
2822
	return intval($pid);
2823
}
2824

    
2825
function interface_vlan_mtu_configured($realhwif, $mtu) {
2826
	global $config;
2827

    
2828
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
2829
		foreach ($config['vlans']['vlan'] as $vlan) {
2830
			if ($vlan['if'] != $realhwif)
2831
				continue;
2832
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2833
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
2834
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2835
					$mtu = $portmtu;
2836
			}
2837
		}
2838
	}
2839

    
2840
	return $mtu;
2841
}
2842

    
2843
function interface_virtual_create($interface) {
2844
	global $config;
2845

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

    
2883
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2884
	global $config;
2885

    
2886
	if (!is_array($vlanifs))
2887
		return;
2888

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

    
2910
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2911
	global $config, $g;
2912
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2913
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2914

    
2915
	$wancfg = $config['interfaces'][$interface];
2916

    
2917
	if (!isset($wancfg['enable']))
2918
		return;
2919

    
2920
	$realif = get_real_interface($interface);
2921
	$realhwif_array = get_parent_interface($interface);
2922
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2923
	$realhwif = $realhwif_array[0];
2924

    
2925
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2926
		/* remove all IPv4 and IPv6 addresses */
2927
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2928
		if (is_array($tmpifaces)) {
2929
			foreach ($tmpifaces as $tmpiface) {
2930
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
2931
					if (!is_linklocal($tmpiface))
2932
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2933
				} else {
2934
					if (is_subnetv4($tmpiface)) {
2935
						$tmpip = explode('/', $tmpiface);
2936
						$tmpip = $tmpip[0];
2937
					} else
2938
						$tmpip = $tmpiface;
2939
					pfSense_interface_deladdress($realif, $tmpip);
2940
				}
2941
			}
2942
		}
2943

    
2944
		/* only bring down the interface when both v4 and v6 are set to NONE */
2945
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6']))
2946
			interface_bring_down($interface);
2947
	}
2948

    
2949
	$interface_to_check = $realif;
2950
	switch ($wancfg['ipaddr']) {
2951
	case 'pppoe':
2952
	case 'l2tp':
2953
	case 'pptp':
2954
	case 'ppp':
2955
		$interface_to_check = $realhwif;
2956
		break;
2957
	}
2958

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

    
2963
	/* Disable Accepting router advertisements unless specifically requested */
2964
	if ($g['debug'])
2965
		log_error("Deny router advertisements for interface {$interface}");
2966
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2967

    
2968
	/* wireless configuration? */
2969
	if (is_array($wancfg['wireless']))
2970
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2971

    
2972
	$mac = get_interface_mac($realhwif);
2973
	/*
2974
	 * Don't try to reapply the spoofed MAC if it's already applied.
2975
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2976
	 * the interface config again, which attempts to spoof the MAC again,
2977
	 * which cycles the link again...
2978
	 */
2979
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
2980
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2981
			" link " . escapeshellarg($wancfg['spoofmac']));
2982

    
2983
		/*
2984
		 * All vlans need to spoof their parent mac address, too.  see
2985
		 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2986
		 */
2987
		if (is_array($config['vlans']['vlan'])) {
2988
			foreach ($config['vlans']['vlan'] as $vlan) {
2989
				if ($vlan['if'] == $realhwif)
2990
					mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2991
					" link " . escapeshellarg($wancfg['spoofmac']));
2992
			}
2993
		}
2994
	}  else {
2995

    
2996
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2997
			/*   this is not a valid mac address.  generate a
2998
			 *   temporary mac address so the machine can get online.
2999
			 */
3000
			echo gettext("Generating new MAC address.");
3001
			$random_mac = generate_random_mac_address();
3002
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3003
				" link " . escapeshellarg($random_mac));
3004
			$wancfg['spoofmac'] = $random_mac;
3005
			write_config();
3006
			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");
3007
		}
3008
	}
3009

    
3010
	/* media */
3011
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3012
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3013
		if ($wancfg['media'])
3014
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3015
		if ($wancfg['mediaopt'])
3016
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3017
		mwexec($cmd);
3018
	}
3019
	$options = pfSense_get_interface_addresses($realhwif);
3020

    
3021
	/* skip vlans for checksumming and polling */
3022
	if (!stristr($realif, "_vlan") && is_array($options)) {
3023
		$flags_on = 0;
3024
		$flags_off = 0;
3025
		if(isset($config['system']['disablechecksumoffloading'])) {
3026
			if (isset($options['encaps']['txcsum']))
3027
				$flags_off |= IFCAP_TXCSUM;
3028
			if (isset($options['encaps']['rxcsum']))
3029
				$flags_off |= IFCAP_RXCSUM;
3030
		} else {
3031
			if (isset($options['caps']['txcsum']))
3032
				$flags_on |= IFCAP_TXCSUM;
3033
			if (isset($options['caps']['rxcsum']))
3034
				$flags_on |= IFCAP_RXCSUM;
3035
		}
3036

    
3037
		if(isset($config['system']['disablesegmentationoffloading']))
3038
			$flags_off |= IFCAP_TSO;
3039
		else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6']))
3040
			$flags_on |= IFCAP_TSO;
3041

    
3042
		if(isset($config['system']['disablelargereceiveoffloading']))
3043
			$flags_off |= IFCAP_LRO;
3044
		else if (isset($options['caps']['lro']))
3045
			$flags_on |= IFCAP_LRO;
3046

    
3047
		/* if the NIC supports polling *AND* it is enabled in the GUI */
3048
		if (!isset($config['system']['polling']))
3049
			$flags_off |= IFCAP_POLLING;
3050
		else if (isset($options['caps']['polling']))
3051
			$flags_on |= IFCAP_POLLING;
3052

    
3053
		pfSense_interface_capabilities($realhwif, -$flags_off);
3054
		pfSense_interface_capabilities($realhwif, $flags_on);
3055
	}
3056

    
3057
	/* invalidate interface/ip/sn cache */
3058
	get_interface_arr(true);
3059
	unset($interface_ip_arr_cache[$realif]);
3060
	unset($interface_sn_arr_cache[$realif]);
3061
	unset($interface_ipv6_arr_cache[$realif]);
3062
	unset($interface_snv6_arr_cache[$realif]);
3063

    
3064
	$tunnelif = substr($realif, 0, 3);
3065
	switch ($wancfg['ipaddr']) {
3066
	case 'dhcp':
3067
		interface_dhcp_configure($interface);
3068
		break;
3069
	case 'pppoe':
3070
	case 'l2tp':
3071
	case 'pptp':
3072
	case 'ppp':
3073
		interface_ppps_configure($interface);
3074
		break;
3075
	default:
3076
		/* XXX: Kludge for now related to #3280 */
3077
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3078
			if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "")
3079
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3080
		}
3081
		break;
3082
	}
3083

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

    
3110
	if (!empty($wancfg['mtu'])) {
3111
		if (stristr($realif, "_vlan")) {
3112
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3113
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
3114
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3115
			else
3116
				$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
3117

    
3118
			if ($wancfg['mtu'] > $parentmtu) {
3119
				if (get_interface_mtu($realhwif) != $wancfg['mtu'])
3120
					pfSense_interface_mtu($realhwif, $wancfg['mtu']);
3121

    
3122
				/* All vlans need to use the same mtu value as their parent. */
3123
				interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $wancfg['mtu']);
3124
			} else
3125
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3126
		} else {
3127
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3128
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3129

    
3130
			/* This case is needed when the parent of vlans is being configured */
3131
			interface_vlan_adapt_mtu(link_interface_to_vlans($realif), $wancfg['mtu']);
3132
		}
3133
		/* XXX: What about gre/gif/lagg/.. ? */
3134
	}
3135

    
3136
	if (does_interface_exist($wancfg['if']))
3137
		interfaces_bring_up($wancfg['if']);
3138

    
3139
	interface_netgraph_needed($interface);
3140

    
3141
	if (!$g['booting']) {
3142
		link_interface_to_vips($interface, "update");
3143

    
3144
		unset($gre);
3145
		$gre = link_interface_to_gre($interface);
3146
		if (!empty($gre))
3147
			array_walk($gre, 'interface_gre_configure');
3148

    
3149
		unset($gif);
3150
		$gif = link_interface_to_gif($interface);
3151
		if (!empty($gif))
3152
			array_walk($gif, 'interface_gif_configure');
3153

    
3154
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3155
			unset($bridgetmp);
3156
			$bridgetmp = link_interface_to_bridge($interface);
3157
			if (!empty($bridgetmp))
3158
				interface_bridge_add_member($bridgetmp, $realif);
3159
		}
3160

    
3161
		$grouptmp = link_interface_to_group($interface);
3162
		if (!empty($grouptmp))
3163
			array_walk($grouptmp, 'interface_group_add_member');
3164

    
3165
		if ($interface == "lan")
3166
			/* make new hosts file */
3167
			system_hosts_generate();
3168

    
3169
		if ($reloadall == true) {
3170

    
3171
			/* reconfigure static routes (kernel may have deleted them) */
3172
			system_routing_configure($interface);
3173

    
3174
			/* reload ipsec tunnels */
3175
			vpn_ipsec_configure();
3176

    
3177
			/* restart dnsmasq or unbound */
3178
			if (isset($config['dnsmasq']['enable']))
3179
				services_dnsmasq_configure();
3180
			elseif (isset($config['unbound']['enable']))
3181
				services_unbound_configure();
3182

    
3183
			/* update dyndns */
3184
			send_event("service reload dyndns {$interface}");
3185

    
3186
			/* XXX: which CPZONE? Needed? */
3187
			/* reload captive portal */
3188
			captiveportal_init_rules();
3189
		}
3190
	}
3191

    
3192
	interfaces_staticarp_configure($interface);
3193
	return 0;
3194
}
3195

    
3196
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3197
	global $config, $g;
3198

    
3199
	if (!is_array($wancfg))
3200
		return;
3201

    
3202
	if (!isset($wancfg['enable']))
3203
		return;
3204

    
3205
	/* If the interface is not configured via another, exit */
3206
	if (empty($wancfg['track6-interface']))
3207
		return;
3208

    
3209
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3210
	$realif = get_real_interface($interface);
3211
	$linklocal = find_interface_ipv6_ll($realif);
3212
	if (!empty($linklocal))
3213
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3214
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3215
	/* XXX: Probably should remove? */
3216
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3217

    
3218
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3219
	if (!isset($trackcfg['enable'])) {
3220
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3221
		return;
3222
	}
3223

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

    
3251
	if (!$g['booting'] && $linkupevent == false) {
3252
		if (!function_exists('services_dhcpd_configure'))
3253
			require_once("services.inc");
3254

    
3255
		services_dhcpd_configure("inet6");
3256
	}
3257

    
3258
	return 0;
3259
}
3260

    
3261
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3262
	global $config, $g;
3263
	global $interface_ipv6_arr_cache;
3264
	global $interface_snv6_arr_cache;
3265

    
3266
	if (!is_array($lancfg))
3267
		return;
3268

    
3269
	/* If the interface is not configured via another, exit */
3270
	if (empty($lancfg['track6-interface']))
3271
		return;
3272

    
3273
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3274
	if (empty($wancfg)) {
3275
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3276
		return;
3277
	}
3278

    
3279
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3280
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3281
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3282
		return;
3283
	}
3284
	$hexwanv4 = return_hex_ipv4($ip4address);
3285

    
3286
	/* create the long prefix notation for math, save the prefix length */
3287
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3288
	$rd6prefixlen = $rd6prefix[1];
3289
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3290

    
3291
	/* binary presentation of the prefix for all 128 bits. */
3292
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3293

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

    
3299
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3300
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3301
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3302
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3303
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3304
	/* fill the rest out with zeros */
3305
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3306

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

    
3310
	$lanif = get_real_interface($interface);
3311
	$oip = find_interface_ipv6($lanif);
3312
	if (is_ipaddrv6($oip))
3313
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3314
	unset($interface_ipv6_arr_cache[$lanif]);
3315
	unset($interface_snv6_arr_cache[$lanif]);
3316
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3317
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3318

    
3319
	return 0;
3320
}
3321

    
3322
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3323
	global $config, $g;
3324
	global $interface_ipv6_arr_cache;
3325
	global $interface_snv6_arr_cache;
3326

    
3327
	if (!is_array($lancfg))
3328
		return;
3329

    
3330
	/* If the interface is not configured via another, exit */
3331
	if (empty($lancfg['track6-interface']))
3332
		return;
3333

    
3334
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3335
	if (empty($wancfg)) {
3336
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3337
		return;
3338
	}
3339

    
3340
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3341
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3342
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3343
		return;
3344
	}
3345
	$hexwanv4 = return_hex_ipv4($ip4address);
3346

    
3347
	/* create the long prefix notation for math, save the prefix length */
3348
	$sixto4prefix = "2002::";
3349
	$sixto4prefixlen = 16;
3350
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3351

    
3352
	/* binary presentation of the prefix for all 128 bits. */
3353
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3354

    
3355
	/* just save the left prefix length bits */
3356
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3357
	/* add the v4 address */
3358
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3359
	/* add the custom prefix id */
3360
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3361
	/* fill the rest out with zeros */
3362
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3363

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

    
3367
	$lanif = get_real_interface($interface);
3368
	$oip = find_interface_ipv6($lanif);
3369
	if (is_ipaddrv6($oip))
3370
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3371
	unset($interface_ipv6_arr_cache[$lanif]);
3372
	unset($interface_snv6_arr_cache[$lanif]);
3373
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3374
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3375

    
3376
	return 0;
3377
}
3378

    
3379
function interface_6rd_configure($interface = "wan", $wancfg) {
3380
	global $config, $g;
3381

    
3382
	/* because this is a tunnel interface we can only function
3383
	 *	with a public IPv4 address on the interface */
3384

    
3385
	if (!is_array($wancfg))
3386
		return;
3387

    
3388
	if (!is_module_loaded('if_stf.ko'))
3389
		mwexec('/sbin/kldload if_stf.ko');
3390

    
3391
	$wanif = get_real_interface($interface);
3392
	$ip4address = find_interface_ip($wanif);
3393
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3394
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3395
		return false;
3396
	}
3397
	$hexwanv4 = return_hex_ipv4($ip4address);
3398

    
3399
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3400
		$wancfg['prefix-6rd-v4plen'] = 0;
3401

    
3402
	/* create the long prefix notation for math, save the prefix length */
3403
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3404
	$rd6prefixlen = $rd6prefix[1];
3405
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3406

    
3407
	/* binary presentation of the prefix for all 128 bits. */
3408
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3409

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

    
3417
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3418
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3419

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

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

    
3442
	/* write out a default router file */
3443
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3444
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3445

    
3446
	$ip4gateway = get_interface_gateway($interface);
3447
	if (is_ipaddrv4($ip4gateway))
3448
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3449

    
3450
	/* configure dependent interfaces */
3451
	if (!$g['booting'])
3452
		link_interface_to_track6($interface, "update");
3453

    
3454
	return 0;
3455
}
3456

    
3457
function interface_6to4_configure($interface = "wan", $wancfg){
3458
	global $config, $g;
3459

    
3460
	/* because this is a tunnel interface we can only function
3461
	 *	with a public IPv4 address on the interface */
3462

    
3463
	if (!is_array($wancfg))
3464
		return;
3465

    
3466
	$wanif = get_real_interface($interface);
3467
	$ip4address = find_interface_ip($wanif);
3468
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3469
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3470
		return false;
3471
	}
3472

    
3473
	/* create the long prefix notation for math, save the prefix length */
3474
	$stfprefixlen = 16;
3475
	$stfprefix = Net_IPv6::uncompress("2002::");
3476
	$stfarr = explode(":", $stfprefix);
3477
	$v4prefixlen = "0";
3478

    
3479
	/* we need the hex form of the interface IPv4 address */
3480
	$ip4arr = explode(".", $ip4address);
3481
	$hexwanv4 = "";
3482
	foreach($ip4arr as $octet)
3483
		$hexwanv4 .= sprintf("%02x", $octet);
3484

    
3485
	/* we need the hex form of the broker IPv4 address */
3486
	$ip4arr = explode(".", "192.88.99.1");
3487
	$hexbrv4 = "";
3488
	foreach($ip4arr as $octet)
3489
		$hexbrv4 .= sprintf("%02x", $octet);
3490

    
3491
	/* binary presentation of the prefix for all 128 bits. */
3492
	$stfprefixbin = "";
3493
	foreach($stfarr as $element) {
3494
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3495
	}
3496
	/* just save the left prefix length bits */
3497
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3498

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

    
3503
	/* for the local subnet too. */
3504
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3505
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3506

    
3507
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3508
	$stfbrarr = array();
3509
	$stfbrbinarr = array();
3510
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3511
	foreach($stfbrbinarr as $bin)
3512
		$stfbrarr[] = dechex(bindec($bin));
3513
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3514

    
3515
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3516
	$stflanarr = array();
3517
	$stflanbinarr = array();
3518
	$stflanbinarr = str_split($stflanbin, 16);
3519
	foreach($stflanbinarr as $bin)
3520
		$stflanarr[] = dechex(bindec($bin));
3521
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3522
	$stflanarr[7] = 1;
3523
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3524

    
3525
	/* setup the stf interface */
3526
	if (!is_module_loaded("if_stf"))
3527
		mwexec("/sbin/kldload if_stf.ko");
3528
	$stfiface = "{$interface}_stf";
3529
	if (does_interface_exist($stfiface))
3530
		pfSense_interface_destroy($stfiface);
3531
	$tmpstfiface = pfSense_interface_create("stf");
3532
	pfSense_interface_rename($tmpstfiface, $stfiface);
3533
	pfSense_interface_flags($stfiface, IFF_LINK2);
3534
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3535

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

    
3539
	/* write out a default router file */
3540
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3541
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3542

    
3543
	$ip4gateway = get_interface_gateway($interface);
3544
	if (is_ipaddrv4($ip4gateway))
3545
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3546

    
3547
	if (!$g['booting'])
3548
		link_interface_to_track6($interface, "update");
3549

    
3550
	return 0;
3551
}
3552

    
3553
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3554
	global $config, $g;
3555

    
3556
	if (!is_array($wancfg))
3557
		return;
3558

    
3559
	$wanif = get_real_interface($interface, "inet6");
3560
	$dhcp6cconf = "";
3561
	$dhcp6cconf .= "interface {$wanif} {\n";
3562

    
3563
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3564
	if($wancfg['ipaddrv6'] == "slaac") {
3565
		$dhcp6cconf .= "	information-only;\n";
3566
		$dhcp6cconf .= "	request domain-name-servers;\n";
3567
		$dhcp6cconf .= "	request domain-name;\n";
3568
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3569
		$dhcp6cconf .= "};\n";
3570
	} else {
3571
		/* skip address request if this is set */
3572
		if(!isset($wancfg['dhcp6prefixonly']))
3573
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3574
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3575
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3576

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

    
3581
		$dhcp6cconf .= "};\n";
3582

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

    
3586
		if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3587
			/* Setup the prefix delegation */
3588
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3589
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3590
			if (isset($wancfg['dhcp6-ia-pd-send-hint']))
3591
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3592
			$iflist = link_interface_to_track6($interface);
3593
			foreach ($iflist as $friendly => $ifcfg) {
3594
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3595
					if ($g['debug'])
3596
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3597
					$realif = get_real_interface($friendly);
3598
					$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3599
					$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3600
					$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3601
					$dhcp6cconf .= "	};\n";
3602
				}
3603
			}
3604
			unset($preflen, $iflist, $ifcfg);
3605
			$dhcp6cconf .= "};\n";
3606
		}
3607
	}
3608

    
3609
	// DHCP6 Config File Advanced
3610
	if ($wancfg['adv_dhcp6_config_advanced']) { $dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif); }
3611

    
3612
	// DHCP6 Config File Override
3613
	if ($wancfg['adv_dhcp6_config_file_override']) { $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif); }
3614

    
3615
	/* wide-dhcp6c works for now. */
3616
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3617
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3618
		unset($dhcp6cconf);
3619
		return 1;
3620
	}
3621
	unset($dhcp6cconf);
3622

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

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

    
3656
	/* accept router advertisements for this interface */
3657
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3658
	log_error("Accept router advertisements on interface {$wanif} ");
3659
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3660

    
3661
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3662
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3663
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3664
		sleep(2);
3665
	}
3666
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3667

    
3668
	/* NOTE: will be called from rtsold invoked script
3669
	 * link_interface_to_track6($interface, "update");
3670
	 */
3671

    
3672
	return 0;
3673
}
3674

    
3675
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3676
	global $g;
3677

    
3678
	$send_options = "";
3679
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3680
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_send_options']);
3681
		foreach ($options as $option) {
3682
			$send_options .= "\tsend " . trim($option) . ";\n";
3683
		}
3684
	}
3685

    
3686
	$request_options = "";
3687
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3688
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_request_options']);
3689
		foreach ($options as $option) {
3690
			$request_options .= "\trequest " . trim($option) . ";\n";
3691
		}
3692
	}
3693

    
3694
	$information_only = "";
3695
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') 
3696
		$information_only = "\tinformation-only;\n";
3697

    
3698
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3699
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '')
3700
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3701

    
3702
	$interface_statement  = "interface";
3703
	$interface_statement .= " {$wanif}";
3704
	$interface_statement .= " {\n";
3705
	$interface_statement .= "$send_options";
3706
	$interface_statement .= "$request_options";
3707
	$interface_statement .= "$information_only";
3708
	$interface_statement .= "$script";
3709
	$interface_statement .= "};\n";
3710

    
3711
	$id_assoc_statement_address = "";
3712
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3713
		$id_assoc_statement_address .= "id-assoc";
3714
		$id_assoc_statement_address .= " na";
3715
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) 
3716
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3717
		$id_assoc_statement_address .= " { ";
3718

    
3719
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') && 
3720
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) || 
3721
			 ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity')) ) {
3722
			$id_assoc_statement_address .= "\n\taddress";
3723
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3724
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3725
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) || 
3726
							($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity') ) 
3727
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3728
			$id_assoc_statement_address .= ";\n";
3729
		}
3730

    
3731
		$id_assoc_statement_address  .= "};\n";
3732
	}
3733

    
3734
	$id_assoc_statement_prefix = "";
3735
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3736
		$id_assoc_statement_prefix .= "id-assoc";
3737
		$id_assoc_statement_prefix .= " pd";
3738
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) 
3739
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3740
		$id_assoc_statement_prefix .= " { ";
3741

    
3742
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') && 
3743
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) || 
3744
			 ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity')) ) {
3745
			$id_assoc_statement_prefix .= "\n\tprefix";
3746
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3747
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3748
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) || 
3749
						  ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity') ) 
3750
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3751
			$id_assoc_statement_prefix .= ";";
3752
		}
3753

    
3754
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3755
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3756
			$id_assoc_statement_prefix .= " {$wanif}";
3757
			$id_assoc_statement_prefix .= " {\n";
3758
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3759
			if ( ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) && 
3760
				 ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128) ) 
3761
				 $id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3762
			$id_assoc_statement_prefix .= "\t};";
3763
		}
3764

    
3765
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') || 
3766
			 (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) ) { 
3767
			$id_assoc_statement_prefix .= "\n";
3768
		}
3769

    
3770
		$id_assoc_statement_prefix  .= "};\n";
3771
	}
3772

    
3773
	$authentication_statement = "";
3774
	if ( ($wancfg['adv_dhcp6_authentication_statement_authname'] != '') && 
3775
		 ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed') ) {
3776
		$authentication_statement .= "authentication";
3777
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
3778
		$authentication_statement .= " {\n";
3779
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
3780
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) 
3781
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
3782
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') 
3783
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
3784
		$authentication_statement .= "};\n";
3785
	}
3786

    
3787
	$key_info_statement = "";
3788
	if ( ($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') && 
3789
		 ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') && 
3790
		 (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) && 
3791
		 ($wancfg['adv_dhcp6_key_info_statement_secret'] != '') ) {
3792
		$key_info_statement .= "keyinfo";
3793
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
3794
		$key_info_statement .= " {\n";
3795
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
3796
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
3797
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
3798
		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'])) 
3799
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
3800
		$key_info_statement .= "};\n";
3801
	}
3802

    
3803
	$dhcp6cconf  = $interface_statement;
3804
	$dhcp6cconf .= $id_assoc_statement_address;
3805
	$dhcp6cconf .= $id_assoc_statement_prefix;
3806
	$dhcp6cconf .= $authentication_statement;
3807
	$dhcp6cconf .= $key_info_statement;
3808

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

    
3811
	return $dhcp6cconf;
3812
}
3813

    
3814

    
3815
function DHCP6_Config_File_Override($wancfg, $wanif) {
3816

    
3817
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
3818
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3819

    
3820
	return $dhcp6cconf;
3821
}
3822

    
3823

    
3824
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
3825

    
3826
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3827

    
3828
	return $dhcp6cconf;
3829
}
3830

    
3831

    
3832
function interface_dhcp_configure($interface = "wan") {
3833
	global $config, $g;
3834

    
3835
	$wancfg = $config['interfaces'][$interface];
3836
	$wanif = $wancfg['if'];
3837
	if (empty($wancfg))
3838
		$wancfg = array();
3839

    
3840
	/* generate dhclient_wan.conf */
3841
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3842
	if (!$fd) {
3843
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3844
		return 1;
3845
	}
3846

    
3847
	if ($wancfg['dhcphostname']) {
3848
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3849
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3850
	} else {
3851
		$dhclientconf_hostname = "";
3852
	}
3853

    
3854
	$wanif = get_real_interface($interface);
3855
	if (empty($wanif)) {
3856
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3857
		return 0;
3858
	}
3859
	$dhclientconf = "";
3860

    
3861
	$dhclientconf .= <<<EOD
3862
interface "{$wanif}" {
3863
timeout 60;
3864
retry 15;
3865
select-timeout 0;
3866
initial-interval 1;
3867
	{$dhclientconf_hostname}
3868
	script "/sbin/dhclient-script";
3869
EOD;
3870

    
3871
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3872
	$dhclientconf .= <<<EOD
3873

    
3874
	reject {$wancfg['dhcprejectfrom']};
3875
EOD;
3876
}
3877
	$dhclientconf .= <<<EOD
3878

    
3879
}
3880

    
3881
EOD;
3882

    
3883
	// DHCP Config File Advanced
3884
	if ($wancfg['adv_dhcp_config_advanced']) { $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif); }
3885

    
3886
if(is_ipaddr($wancfg['alias-address'])) {
3887
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3888
	$dhclientconf .= <<<EOD
3889
alias {
3890
	interface  "{$wanif}";
3891
	fixed-address {$wancfg['alias-address']};
3892
	option subnet-mask {$subnetmask};
3893
}
3894

    
3895
EOD;
3896
}
3897

    
3898
	// DHCP Config File Override
3899
	if ($wancfg['adv_dhcp_config_file_override']) { $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif); }
3900

    
3901
	fwrite($fd, $dhclientconf);
3902
	fclose($fd);
3903

    
3904
	/* bring wan interface up before starting dhclient */
3905
	if($wanif)
3906
		interfaces_bring_up($wanif);
3907
	else
3908
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3909

    
3910
	/* Make sure dhclient is not running */
3911
	kill_dhclient_process($wanif);
3912

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

    
3916
	return 0;
3917
}
3918

    
3919
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3920

    
3921
	$hostname = "";
3922
	if ($wancfg['dhcphostname'] != '') {
3923
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3924
	}
3925

    
3926
	/* DHCP Protocol Timings */
3927
	$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");
3928
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
3929
		$pt_variable = "{$Protocol_Timing}";
3930
		${$pt_variable} = "";
3931
		if ($wancfg[$Protocol_Timing] != "") {
3932
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
3933
		}
3934
	}
3935

    
3936
	$send_options = "";
3937
	if ($wancfg['adv_dhcp_send_options'] != '') {
3938
		$options = split(",", $wancfg['adv_dhcp_send_options']);
3939
		foreach ($options as $option) {
3940
			$send_options .= "\tsend " . trim($option) . ";\n";
3941
		}
3942
	}
3943

    
3944
	$request_options = "";
3945
	if ($wancfg['adv_dhcp_request_options'] != '') {
3946
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
3947
	}
3948

    
3949
	$required_options = "";
3950
	if ($wancfg['adv_dhcp_required_options'] != '') {
3951
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
3952
	}
3953

    
3954
	$option_modifiers = "";
3955
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
3956
		$modifiers = split(",", $wancfg['adv_dhcp_option_modifiers']);
3957
		foreach ($modifiers as $modifier) {
3958
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
3959
		}
3960
	}
3961

    
3962
 	$dhclientconf  = "interface \"{$wanif}\" {\n";
3963
 	$dhclientconf .= "\n";
3964
 	$dhclientconf .= "# DHCP Protocol Timing Values\n";
3965
 	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
3966
 	$dhclientconf .= "{$adv_dhcp_pt_retry}";
3967
 	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
3968
 	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
3969
 	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
3970
 	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
3971
 	$dhclientconf .= "\n";
3972
 	$dhclientconf .= "# DHCP Protocol Options\n";
3973
 	$dhclientconf .= "{$hostname}";
3974
 	$dhclientconf .= "{$send_options}";
3975
 	$dhclientconf .= "{$request_options}";
3976
 	$dhclientconf .= "{$required_options}";
3977
 	$dhclientconf .= "{$option_modifiers}";
3978
 	$dhclientconf .= "\n";
3979
 	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
3980
 	$dhclientconf .= "}\n";
3981

    
3982
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3983

    
3984
	return $dhclientconf;
3985
}
3986

    
3987

    
3988
function DHCP_Config_File_Override($wancfg, $wanif) {
3989

    
3990
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
3991
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
3992

    
3993
	return $dhclientconf;
3994
}
3995

    
3996

    
3997
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
3998

    
3999
	/* Apply Interface Substitutions */
4000
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4001

    
4002
	/* Apply Hostname Substitutions */
4003
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4004

    
4005
	/* Arrays of MAC Address Types, Cases, Delimiters */
4006
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4007
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4008
	$various_mac_cases      = array("U", "L");
4009
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4010

    
4011
	/* Apply MAC Address Substitutions */
4012
	foreach ($various_mac_types as $various_mac_type) {
4013
		foreach ($various_mac_cases as $various_mac_case) {
4014
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4015

    
4016
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4017
				if ($res !== false) {
4018

    
4019
					/* Get MAC Address as ASCII String With Colon (:) Celimiters */
4020
					if ("$various_mac_case" == "U") $dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4021
					if ("$various_mac_case" == "L") $dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4022

    
4023
					if ("$various_mac_type" == "mac_addr_hex") {
4024
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4025
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4026
						$dhcpclientconf_mac_hex = "";
4027
						$delimiter = "";
4028
						for($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4029
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4030
							$delimiter = ":";
4031
						}
4032
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4033
					}
4034

    
4035
					/* MAC Address Delimiter Substitutions */
4036
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4037

    
4038
					/* Apply MAC Address Substitutions */
4039
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4040
				}
4041
			}
4042
		}
4043
	}
4044

    
4045
	return $dhclientconf;
4046
}
4047

    
4048
function interfaces_group_setup() {
4049
	global $config;
4050

    
4051
	if (!is_array($config['ifgroups']['ifgroupentry']))
4052
		return;
4053

    
4054
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
4055
		interface_group_setup($groupar);
4056

    
4057
	return;
4058
}
4059

    
4060
function interface_group_setup(&$groupname /* The parameter is an array */) {
4061
	global $config;
4062

    
4063
	if (!is_array($groupname))
4064
		return;
4065
	$members = explode(" ", $groupname['members']);
4066
	foreach($members as $ifs) {
4067
		$realif = get_real_interface($ifs);
4068
		if ($realif)
4069
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4070
	}
4071

    
4072
	return;
4073
}
4074

    
4075
function is_interface_group($if) {
4076
	global $config;
4077

    
4078
	if (is_array($config['ifgroups']['ifgroupentry']))
4079
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4080
			if ($groupentry['ifname'] === $if)
4081
				return true;
4082
		}
4083

    
4084
	return false;
4085
}
4086

    
4087
function interface_group_add_member($interface, $groupname) {
4088
	$interface = get_real_interface($interface);
4089
	mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4090
}
4091

    
4092
/* COMPAT Function */
4093
function convert_friendly_interface_to_real_interface_name($interface) {
4094
	return get_real_interface($interface);
4095
}
4096

    
4097
/* COMPAT Function */
4098
function get_real_wan_interface($interface = "wan") {
4099
	return get_real_interface($interface);
4100
}
4101

    
4102
/* COMPAT Function */
4103
function get_current_wan_address($interface = "wan") {
4104
	return get_interface_ip($interface);
4105
}
4106

    
4107
/*
4108
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4109
 */
4110
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
4111
	global $config;
4112

    
4113
	/* XXX: For speed reasons reference directly the interface array */
4114
	$ifdescrs = &$config['interfaces'];
4115
	//$ifdescrs = get_configured_interface_list(false, true);
4116

    
4117
	foreach ($ifdescrs as $if => $ifname) {
4118
		if ($if == $interface || $ifname['if'] == $interface)
4119
			return $if;
4120

    
4121
		if (get_real_interface($if) == $interface)
4122
			return $if;
4123

    
4124
		$int = get_parent_interface($if, true);
4125
		if (is_array($int)) {
4126
			foreach ($int as $iface) {
4127
				if ($iface == $interface)
4128
					return $if;
4129
			}
4130
		}
4131
	}
4132

    
4133
	if ($interface == "enc0")
4134
		return 'IPsec';
4135

    
4136
	return NULL;
4137
}
4138

    
4139
/* attempt to resolve interface to friendly descr */
4140
function convert_friendly_interface_to_friendly_descr($interface) {
4141
	global $config;
4142

    
4143
	switch ($interface) {
4144
	case "l2tp":
4145
		$ifdesc = "L2TP";
4146
		break;
4147
	case "pptp":
4148
		$ifdesc = "PPTP";
4149
		break;
4150
	case "pppoe":
4151
		$ifdesc = "PPPoE";
4152
		break;
4153
	case "openvpn":
4154
		$ifdesc = "OpenVPN";
4155
		break;
4156
	case "enc0":
4157
	case "ipsec":
4158
	case "IPsec":
4159
		$ifdesc = "IPsec";
4160
		break;
4161
	default:
4162
		if (isset($config['interfaces'][$interface])) {
4163
			if (empty($config['interfaces'][$interface]['descr']))
4164
				$ifdesc = strtoupper($interface);
4165
			else
4166
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4167
			break;
4168
		} else if (stristr($interface, "_vip")) {
4169
			if (is_array($config['virtualip']['vip'])) {
4170
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
4171
					if ($vip['mode'] == "carp")  {
4172
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4173
							return "{$vip['subnet']} - {$vip['descr']}";
4174
					}
4175
				}
4176
			}
4177
		} else {
4178
			/* if list */
4179
			$ifdescrs = get_configured_interface_with_descr(false, true);
4180
			foreach ($ifdescrs as $if => $ifname) {
4181
				if ($if == $interface || $ifname == $interface)
4182
					return $ifname;
4183
			}
4184
		}
4185
		break;
4186
	}
4187

    
4188
	return $ifdesc;
4189
}
4190

    
4191
function convert_real_interface_to_friendly_descr($interface) {
4192

    
4193
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4194

    
4195
	if (!empty($ifdesc))
4196
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4197

    
4198
	return $interface;
4199
}
4200

    
4201
/*
4202
 *  get_parent_interface($interface):
4203
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4204
 *				or virtual interface (i.e. vlan)
4205
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4206
 *			-- returns $interface passed in if $interface parent is not found
4207
 *			-- returns empty array if an invalid interface is passed
4208
 *	(Only handles ppps and vlans now.)
4209
 */
4210
function get_parent_interface($interface, $avoidrecurse = false) {
4211
	global $config;
4212

    
4213
	$parents = array();
4214
	//Check that we got a valid interface passed
4215
	$realif = get_real_interface($interface);
4216
	if ($realif == NULL)
4217
		return $parents;
4218

    
4219
	// If we got a real interface, find it's friendly assigned name
4220
	if ($interface == $realif && $avoidrecurse == false)
4221
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4222

    
4223
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4224
		$ifcfg = $config['interfaces'][$interface];
4225
		switch ($ifcfg['ipaddr']) {
4226
			case "ppp":
4227
			case "pppoe":
4228
			case "pptp":
4229
			case "l2tp":
4230
				if (empty($parents))
4231
					if (is_array($config['ppps']['ppp']))
4232
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4233
							if ($ifcfg['if'] == $ppp['if']) {
4234
								$ports = explode(',', $ppp['ports']);
4235
								foreach ($ports as $pid => $parent_if)
4236
									$parents[$pid] = get_real_interface($parent_if);
4237
								break;
4238
							}
4239
						}
4240
				break;
4241
			case "dhcp":
4242
			case "static":
4243
			default:
4244
				// Handle _vlans
4245
				if (stristr($realif,"_vlan"))
4246
					if (is_array($config['vlans']['vlan']))
4247
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
4248
							if ($ifcfg['if'] == $vlan['vlanif']){
4249
								$parents[0] = $vlan['if'];
4250
								break;
4251
							}
4252
				break;
4253
		}
4254
	}
4255

    
4256
	if (empty($parents))
4257
		$parents[0] = $realif;
4258

    
4259
	return $parents;
4260
}
4261

    
4262
function interface_is_wireless_clone($wlif) {
4263
	if(!stristr($wlif, "_wlan")) {
4264
		return false;
4265
	} else {
4266
		return true;
4267
	}
4268
}
4269

    
4270
function interface_get_wireless_base($wlif) {
4271
	if(!stristr($wlif, "_wlan")) {
4272
		return $wlif;
4273
	} else {
4274
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4275
	}
4276
}
4277

    
4278
function interface_get_wireless_clone($wlif) {
4279
	if(!stristr($wlif, "_wlan")) {
4280
		return $wlif . "_wlan0";
4281
	} else {
4282
		return $wlif;
4283
	}
4284
}
4285

    
4286
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4287
	global $config, $g;
4288

    
4289
	$wanif = NULL;
4290

    
4291
	switch ($interface) {
4292
	case "l2tp":
4293
		$wanif = "l2tp";
4294
		break;
4295
	case "pptp":
4296
		$wanif = "pptp";
4297
		break;
4298
	case "pppoe":
4299
		$wanif = "pppoe";
4300
		break;
4301
	case "openvpn":
4302
		$wanif = "openvpn";
4303
		break;
4304
	case "ipsec":
4305
	case "enc0":
4306
		$wanif = "enc0";
4307
		break;
4308
	case "ppp":
4309
		$wanif = "ppp";
4310
		break;
4311
	default:
4312
		// If a real interface was alread passed simply
4313
		// pass the real interface back.  This encourages
4314
		// the usage of this function in more cases so that
4315
		// we can combine logic for more flexibility.
4316
		if(does_interface_exist($interface, $flush)) {
4317
			$wanif = $interface;
4318
			break;
4319
		}
4320

    
4321
		if (empty($config['interfaces'][$interface]))
4322
			break;
4323

    
4324
		$cfg = &$config['interfaces'][$interface];
4325

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

    
4378
	return $wanif;
4379
}
4380

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

    
4418
/*
4419
 * find_ip_interface($ip): return the interface where an ip is defined
4420
 *   (or if $bits is specified, where an IP within the subnet is defined)
4421
 */
4422
function find_ip_interface($ip, $bits = null) {
4423
	if (!is_ipaddr($ip))
4424
		return false;
4425

    
4426
	$isv6ip = is_ipaddrv6($ip);
4427

    
4428
	/* if list */
4429
	$ifdescrs = get_configured_interface_list();
4430

    
4431
	foreach ($ifdescrs as $ifdescr => $ifname) {
4432
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4433
		if (is_null($ifip))
4434
			continue;
4435
		if (is_null($bits)) {
4436
			if ($ip == $ifip) {
4437
				$int = get_real_interface($ifname);
4438
				return $int;
4439
			}
4440
		}
4441
		else {
4442
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4443
				$int = get_real_interface($ifname);
4444
				return $int;
4445
			}
4446
		}
4447
	}
4448

    
4449
	return false;
4450
}
4451

    
4452
/*
4453
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4454
 *   (or if $bits is specified, where an IP within the subnet is found)
4455
 */
4456
function find_virtual_ip_alias($ip, $bits = null) {
4457
	global $config;
4458

    
4459
	if (!is_array($config['virtualip']['vip'])) {
4460
		return false;
4461
	}
4462
	if (!is_ipaddr($ip))
4463
		return false;
4464

    
4465
	$isv6ip = is_ipaddrv6($ip);
4466

    
4467
	foreach ($config['virtualip']['vip'] as $vip) {
4468
		if ($vip['mode'] === "ipalias") {
4469
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4470
				continue;
4471
			if (is_null($bits)) {
4472
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4473
					return $vip;
4474
				}
4475
			}
4476
			else {
4477
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4478
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4479
					return $vip;
4480
				}
4481
			}
4482
		}
4483
	}
4484
	return false;
4485
}
4486

    
4487
/*
4488
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4489
 */
4490
function find_number_of_created_carp_interfaces() {
4491
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4492
}
4493

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

    
4519
				if ($if)
4520
					return $if;
4521
			}
4522
		}
4523
	}
4524
}
4525

    
4526
function link_carp_interface_to_parent($interface) {
4527
	global $config;
4528

    
4529
	if (empty($interface))
4530
		return;
4531

    
4532
	$carp_ip = get_interface_ip($interface);
4533
	$carp_ipv6 = get_interface_ipv6($interface);
4534

    
4535
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4536
		return;
4537

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

    
4560

    
4561
/****f* interfaces/link_ip_to_carp_interface
4562
 * NAME
4563
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4564
 * INPUTS
4565
 *   $ip
4566
 * RESULT
4567
 *   $carp_ints
4568
 ******/
4569
function link_ip_to_carp_interface($ip) {
4570
	global $config;
4571

    
4572
	if (!is_ipaddr($ip))
4573
		return;
4574

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

    
4593
	return $carp_ints;
4594
}
4595

    
4596
function link_interface_to_track6($int, $action = "") {
4597
	global $config;
4598

    
4599
	if (empty($int))
4600
		return;
4601

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

    
4618
function link_interface_to_vlans($int, $action = "") {
4619
	global $config;
4620

    
4621
	if (empty($int))
4622
		return;
4623

    
4624
	if (is_array($config['vlans']['vlan'])) {
4625
		$ifaces = array();
4626
		foreach ($config['vlans']['vlan'] as $vlan) {
4627
			if ($int == $vlan['if']) {
4628
				if ($action == "update") {
4629
					interfaces_bring_up($int);
4630
				} else if ($action == "")
4631
					$ifaces[$vlan['tag']] = $vlan;
4632
			}
4633
		}
4634
		if (!empty($ifaces))
4635
			return $ifaces;
4636
	}
4637
}
4638

    
4639
function link_interface_to_vips($int, $action = "") {
4640
	global $config;
4641

    
4642
	if (is_array($config['virtualip']['vip'])) {
4643
		$result = array();
4644
		foreach ($config['virtualip']['vip'] as $vip) {
4645
			if ($int == $vip['interface']) {
4646
				if ($action == "update")
4647
					interfaces_vips_configure($int);
4648
				else
4649
					$result[] = $vip;
4650
			}
4651
		}
4652
		return $result;
4653
	}
4654
}
4655

    
4656
/****f* interfaces/link_interface_to_bridge
4657
 * NAME
4658
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4659
 * INPUTS
4660
 *   $ip
4661
 * RESULT
4662
 *   bridge[0-99]
4663
 ******/
4664
function link_interface_to_bridge($int) {
4665
	global $config;
4666

    
4667
	if (is_array($config['bridges']['bridged'])) {
4668
		foreach ($config['bridges']['bridged'] as $bridge) {
4669
			if (in_array($int, explode(',', $bridge['members'])))
4670
				return "{$bridge['bridgeif']}";
4671
		}
4672
	}
4673
}
4674

    
4675
function link_interface_to_group($int) {
4676
	global $config;
4677

    
4678
	$result = array();
4679

    
4680
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4681
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4682
			if (in_array($int, explode(" ", $group['members'])))
4683
				$result[$group['ifname']] = $int;
4684
		}
4685
	}
4686

    
4687
	return $result;
4688
}
4689

    
4690
function link_interface_to_gre($interface) {
4691
	global $config;
4692

    
4693
	$result = array();
4694

    
4695
	if (is_array($config['gres']['gre'])) {
4696
		foreach ($config['gres']['gre'] as $gre)
4697
			if($gre['if'] == $interface)
4698
				$result[] = $gre;
4699
	}
4700

    
4701
	return $result;
4702
}
4703

    
4704
function link_interface_to_gif($interface) {
4705
	global $config;
4706

    
4707
	$result = array();
4708

    
4709
	if (is_array($config['gifs']['gif'])) {
4710
		foreach ($config['gifs']['gif'] as $gif)
4711
			if($gif['if'] == $interface)
4712
				$result[] = $gif;
4713
	}
4714

    
4715
	return $result;
4716
}
4717

    
4718
/*
4719
 * find_interface_ip($interface): return the interface ip (first found)
4720
 */
4721
function find_interface_ip($interface, $flush = false) {
4722
	global $interface_ip_arr_cache;
4723
	global $interface_sn_arr_cache;
4724

    
4725
	$interface = str_replace("\n", "", $interface);
4726

    
4727
	if (!does_interface_exist($interface))
4728
		return;
4729

    
4730
	/* Setup IP cache */
4731
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4732
		$ifinfo = pfSense_get_interface_addresses($interface);
4733
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4734
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4735
	}
4736

    
4737
	return $interface_ip_arr_cache[$interface];
4738
}
4739

    
4740
/*
4741
 * find_interface_ipv6($interface): return the interface ip (first found)
4742
 */
4743
function find_interface_ipv6($interface, $flush = false) {
4744
	global $interface_ipv6_arr_cache;
4745
	global $interface_snv6_arr_cache;
4746
	global $config;
4747

    
4748
	$interface = trim($interface);
4749
	$interface = get_real_interface($interface);
4750

    
4751
	if (!does_interface_exist($interface))
4752
		return;
4753

    
4754
	/* Setup IP cache */
4755
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4756
		$ifinfo = pfSense_get_interface_addresses($interface);
4757
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4758
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4759
	}
4760

    
4761
	return $interface_ipv6_arr_cache[$interface];
4762
}
4763

    
4764
/*
4765
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4766
 */
4767
function find_interface_ipv6_ll($interface, $flush = false) {
4768
	global $interface_llv6_arr_cache;
4769
	global $config;
4770

    
4771
	$interface = str_replace("\n", "", $interface);
4772

    
4773
	if (!does_interface_exist($interface))
4774
		return;
4775

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

    
4792
function find_interface_subnet($interface, $flush = false) {
4793
	global $interface_sn_arr_cache;
4794
	global $interface_ip_arr_cache;
4795

    
4796
	$interface = str_replace("\n", "", $interface);
4797
	if (does_interface_exist($interface) == false)
4798
		return;
4799

    
4800
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4801
		$ifinfo = pfSense_get_interface_addresses($interface);
4802
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4803
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4804
	}
4805

    
4806
	return $interface_sn_arr_cache[$interface];
4807
}
4808

    
4809
function find_interface_subnetv6($interface, $flush = false) {
4810
	global $interface_snv6_arr_cache;
4811
	global $interface_ipv6_arr_cache;
4812

    
4813
	$interface = str_replace("\n", "", $interface);
4814
	if (does_interface_exist($interface) == false)
4815
		return;
4816

    
4817
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4818
		$ifinfo = pfSense_get_interface_addresses($interface);
4819
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4820
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4821
	}
4822

    
4823
	return $interface_snv6_arr_cache[$interface];
4824
}
4825

    
4826
function ip_in_interface_alias_subnet($interface, $ipalias) {
4827
	global $config;
4828

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

    
4845
	return false;
4846
}
4847

    
4848
function get_interface_ip($interface = "wan") {
4849
	$realif = get_failover_interface($interface);
4850
	if (!$realif) {
4851
		if (strstr($interface, "_vip"))
4852
			return get_configured_carp_interface_list($interface);
4853
		else
4854
			return null;
4855
	}
4856

    
4857
	$curip = find_interface_ip($realif);
4858
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4859
		return $curip;
4860
	else
4861
		return null;
4862
}
4863

    
4864
function get_interface_ipv6($interface = "wan", $flush = false) {
4865
	global $config;
4866

    
4867
	$realif = get_failover_interface($interface, "inet6");
4868
	if (!$realif) {
4869
		if (strstr($interface, "_vip"))
4870
			return get_configured_carp_interface_list($interface, "inet6");
4871
		else
4872
			return null;
4873
	}
4874

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

    
4896
	$curip = find_interface_ipv6($realif, $flush);
4897
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4898
		return $curip;
4899
	else
4900
		return null;
4901
}
4902

    
4903
function get_interface_linklocal($interface = "wan") {
4904

    
4905
	$realif = get_failover_interface($interface, "inet6");
4906
	if (!$realif) {
4907
		if (strstr($interface, "_vip")) {
4908
			list($interface, $vhid) = explode("_vip", $interface);
4909
			$realif = get_real_interface($interface);
4910
		} else
4911
			return null;
4912
	}
4913

    
4914
	$curip = find_interface_ipv6_ll($realif);
4915
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4916
		return $curip;
4917
	else
4918
		return null;
4919
}
4920

    
4921
function get_interface_subnet($interface = "wan") {
4922
	$realif = get_real_interface($interface);
4923
	if (!$realif) {
4924
		if (strstr($interface, "_vip")) {
4925
			list($interface, $vhid) = explode("_vip", $interface);
4926
			$realif = get_real_interface($interface);
4927
		} else
4928
			return null;
4929
	}
4930

    
4931
	$cursn = find_interface_subnet($realif);
4932
	if (!empty($cursn))
4933
		return $cursn;
4934

    
4935
	return null;
4936
}
4937

    
4938
function get_interface_subnetv6($interface = "wan") {
4939
	global $config;
4940

    
4941
	$realif = get_real_interface($interface, "inet6");
4942
	if (!$realif) {
4943
		if (strstr($interface, "_vip")) {
4944
			list($interface, $vhid) = explode("_vip", $interface);
4945
			$realif = get_real_interface($interface);
4946
		} else
4947
			return null;
4948
	}
4949

    
4950
	$cursn = find_interface_subnetv6($realif);
4951
	if (!empty($cursn))
4952
		return $cursn;
4953

    
4954
	return null;
4955
}
4956

    
4957
/* return outside interfaces with a gateway */
4958
function get_interfaces_with_gateway() {
4959
	global $config;
4960

    
4961
	$ints = array();
4962

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

    
4984
/* return true if interface has a gateway */
4985
function interface_has_gateway($friendly) {
4986
	global $config;
4987

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

    
5010
	return false;
5011
}
5012

    
5013
/* return true if interface has a gateway */
5014
function interface_has_gatewayv6($friendly) {
5015
	global $config;
5016

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

    
5038
	return false;
5039
}
5040

    
5041
/****f* interfaces/is_altq_capable
5042
 * NAME
5043
 *   is_altq_capable - Test if interface is capable of using ALTQ
5044
 * INPUTS
5045
 *   $int            - string containing interface name
5046
 * RESULT
5047
 *   boolean         - true or false
5048
 ******/
5049

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

    
5063
	$int_family = remove_ifindex($int);
5064

    
5065
	if (in_array($int_family, $capable))
5066
		return true;
5067
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
5068
		return true;
5069
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
5070
		return true;
5071
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
5072
		return true;
5073
	else
5074
		return false;
5075
}
5076

    
5077
/****f* interfaces/is_interface_wireless
5078
 * NAME
5079
 *   is_interface_wireless - Returns if an interface is wireless
5080
 * RESULT
5081
 *   $tmp       - Returns if an interface is wireless
5082
 ******/
5083
function is_interface_wireless($interface) {
5084
	global $config, $g;
5085

    
5086
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5087
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
5088
		if (preg_match($g['wireless_regex'], $interface)) {
5089
			if (isset($config['interfaces'][$friendly]))
5090
				$config['interfaces'][$friendly]['wireless'] = array();
5091
			return true;
5092
		}
5093
		return false;
5094
	} else
5095
		return true;
5096
}
5097

    
5098
function get_wireless_modes($interface) {
5099
	/* return wireless modes and channels */
5100
	$wireless_modes = array();
5101

    
5102
	$cloned_interface = get_real_interface($interface);
5103

    
5104
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5105
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5106
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5107
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5108

    
5109
		$interface_channels = "";
5110
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5111
		$interface_channel_count = count($interface_channels);
5112

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

    
5142
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5143
function get_wireless_channel_info($interface) {
5144
	$wireless_channels = array();
5145

    
5146
	$cloned_interface = get_real_interface($interface);
5147

    
5148
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5149
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5150
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5151
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5152

    
5153
		$interface_channels = "";
5154
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5155

    
5156
		foreach ($interface_channels as $channel_line) {
5157
			$channel_line = explode(",", $channel_line);
5158
			if(!isset($wireless_channels[$channel_line[0]]))
5159
				$wireless_channels[$channel_line[0]] = $channel_line;
5160
		}
5161
	}
5162
	return($wireless_channels);
5163
}
5164

    
5165
/****f* interfaces/get_interface_mtu
5166
 * NAME
5167
 *   get_interface_mtu - Return the mtu of an interface
5168
 * RESULT
5169
 *   $tmp       - Returns the mtu of an interface
5170
 ******/
5171
function get_interface_mtu($interface) {
5172
	$mtu = pfSense_get_interface_addresses($interface);
5173
	return $mtu['mtu'];
5174
}
5175

    
5176
function get_interface_mac($interface) {
5177

    
5178
	$macinfo = pfSense_get_interface_addresses($interface);
5179
	return $macinfo["macaddr"];
5180
}
5181

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

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

    
5209
	if (isset($capable['caps']['vlanmtu']))
5210
		return true;
5211

    
5212
	return false;
5213
}
5214

    
5215
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5216
	global $g;
5217

    
5218
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5219

    
5220
	if(!empty($iface) && !empty($pppif)){
5221
		$cron_cmd = <<<EOD
5222
#!/bin/sh
5223
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5224
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5225

    
5226
EOD;
5227

    
5228
		@file_put_contents($cron_file, $cron_cmd);
5229
		chmod($cron_file, 0755);
5230
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5231
	} else
5232
		unlink_if_exists($cron_file);
5233
}
5234

    
5235
function get_interface_default_mtu($type = "ethernet") {
5236
	switch ($type) {
5237
	case "gre":
5238
		return 1476;
5239
		break;
5240
	case "gif":
5241
		return 1280;
5242
		break;
5243
	case "tun":
5244
	case "vlan":
5245
	case "tap":
5246
	case "ethernet":
5247
	default:
5248
		return 1500;
5249
		break;
5250
	}
5251

    
5252
	/* Never reached */
5253
	return 1500;
5254
}
5255

    
5256
function get_vip_descr($ipaddress) {
5257
	global $config;
5258

    
5259
	foreach ($config['virtualip']['vip'] as $vip) {
5260
		if ($vip['subnet'] == $ipaddress) {
5261
			return ($vip['descr']);
5262
		}
5263
	}
5264
	return "";
5265
}
5266

    
5267
function interfaces_staticarp_configure($if) {
5268
	global $config, $g;
5269
	if(isset($config['system']['developerspew'])) {
5270
		$mt = microtime();
5271
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5272
	}
5273

    
5274
	$ifcfg = $config['interfaces'][$if];
5275

    
5276
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5277
		return 0;
5278

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

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

    
5288
			}
5289

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

    
5303
	return 0;
5304
}
5305

    
5306
function get_failover_interface($interface, $family = "all") {
5307
	global $config;
5308

    
5309
	/* shortcut to get_real_interface if we find it in the config */
5310
	if (is_array($config['interfaces'][$interface])) {
5311
		return get_real_interface($interface, $family);
5312
	}
5313

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

    
5328
function remove_ifindex($ifname) {
5329
	return preg_replace("/[0-9]+$/", "", $ifname);
5330
}
5331

    
5332
?>
(26-26/68)