Projet

Général

Profil

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

univnautes / etc / inc / interfaces.inc @ 71c26c22

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
	/* Check if MTU was defined for this lagg interface */
751
	$lagg_mtu = 0;
752
	if (is_array($config['interfaces'])) {
753
		foreach ($config['interfaces'] as $ifname => $ifdata) {
754
			if ($ifdata['if'] != $laggif)
755
				continue;
756

    
757
			if (isset($ifdata['mtu']) && !empty($ifdata['mtu'])) {
758
				$lagg_mtu = $ifdata['mtu'];
759
				break;
760
			}
761
		}
762
	}
763

    
764
	if ($lagg_mtu == 0) {
765
		/* Calculate smaller mtu and enforce it */
766
		$smallermtu = 0;
767
		foreach ($members as $member) {
768
			$opts = pfSense_get_interface_addresses($member);
769
			$mtu = $opts['mtu'];
770
			if (!isset($opts['caps']['txcsum']))
771
				$commontx = false;
772
			if (!isset($opts['caps']['rxcsum']))
773
				$commonrx = false;
774
			if (!isset($opts['caps']['tso4']))
775
				$commontso4 = false;
776
			if (!isset($opts['caps']['tso6']))
777
				$commontso6 = false;
778
			if (!isset($opts['caps']['lro']))
779
				$commonlro = false;
780
			if ($smallermtu == 0 && !empty($mtu))
781
				$smallermtu = $mtu;
782
			else if (!empty($mtu) && $mtu < $smallermtu)
783
				$smallermtu = $mtu;
784
		}
785
		$lagg_mtu = $smallermtu;
786
	}
787

    
788
	/* Just in case anything is not working well */
789
	if ($lagg_mtu == 0)
790
		$lagg_mtu = 1500;
791

    
792
	$flags_on = 0;
793
	$flags_off = 0;
794
	if (isset($config['system']['disablechecksumoffloading']) || ($commonrx === false))
795
		$flags_off |= IFCAP_RXCSUM;
796
	else
797
		$flags_on |= IFCAP_RXCSUM;
798
	if (isset($config['system']['disablechecksumoffloading']) || ($commontx === false))
799
		$flags_off |= IFCAP_TXCSUM;
800
	else
801
		$flags_on |= IFCAP_TXCSUM;
802
	if (isset($config['system']['disablesegmentationoffloading']) || ($commontso4 === false))
803
		$flags_off |= IFCAP_TSO4;
804
	else
805
		$flags_on |= IFCAP_TSO4;
806
	if (isset($config['system']['disablesegmentationoffloading']) || ($commontso6 === false))
807
		$flags_off |= IFCAP_TSO6;
808
	else
809
		$flags_on |= IFCAP_TSO6;
810
	if (isset($config['system']['disablelargereceiveoffloading']) || ($commonlro === false))
811
		$flags_off |= IFCAP_LRO;
812
	else
813
		$flags_on |= IFCAP_LRO;
814

    
815
	$checklist = get_interface_list();
816

    
817
	foreach ($members as $member) {
818
		if (!array_key_exists($member, $checklist))
819
			continue;
820
		/* make sure the parent interface is up */
821
		pfSense_interface_mtu($member, $lagg_mtu);
822
		pfSense_interface_capabilities($member, -$flags_off);
823
		pfSense_interface_capabilities($member, $flags_on);
824
		interfaces_bring_up($member);
825
		mwexec("/sbin/ifconfig {$laggif} laggport {$member}");
826
	}
827

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

    
830
	interfaces_bring_up($laggif);
831

    
832
	return $laggif;
833
}
834

    
835
function interfaces_gre_configure($checkparent = 0, $realif = "") {
836
	global $config;
837

    
838
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
839
		foreach ($config['gres']['gre'] as $i => $gre) {
840
			if (empty($gre['greif']))
841
				$gre['greif'] = "gre{$i}";
842
			if (!empty($realif) && $realif != $gre['greif'])
843
				continue;
844

    
845
			if ($checkparent == 1) {
846
				if (strstr($gre['if'], "_vip"))
847
					continue;
848
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6")
849
					continue;
850
			}
851
			else if ($checkparent == 2) {
852
				if (strstr($gre['if'], "_vip"))
853
					continue;
854
				if (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")
855
					continue;
856
			}
857
			/* XXX: Maybe we should report any errors?! */
858
			interface_gre_configure($gre);
859
		}
860
	}
861
}
862

    
863
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
864
function interface_gre_configure(&$gre, $grekey = "") {
865
	global $config, $g;
866

    
867
	if (!is_array($gre))
868
		return -1;
869

    
870
	$realif = get_real_interface($gre['if']);
871
	$realifip = get_interface_ip($gre['if']);
872

    
873
	/* make sure the parent interface is up */
874
	interfaces_bring_up($realif);
875

    
876
	if ($g['booting'] || !(empty($gre['greif']))) {
877
		pfSense_interface_destroy($gre['greif']);
878
		pfSense_interface_create($gre['greif']);
879
		$greif = $gre['greif'];
880
	} else
881
		$greif = pfSense_interface_create("gre");
882

    
883
	/* Do not change the order here for more see gre(4) NOTES section. */
884
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
885
	if((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
886
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
887
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
888
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
889
	} else {
890
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
891
	}
892
	if (isset($gre['link0']))
893
		pfSense_interface_flags($greif, IFF_LINK0);
894
	if (isset($gre['link1']))
895
		pfSense_interface_flags($greif, IFF_LINK1);
896
	if (isset($gre['link2']))
897
		pfSense_interface_flags($greif, IFF_LINK2);
898

    
899
	if($greif)
900
		interfaces_bring_up($greif);
901
	else
902
		log_error(gettext("Could not bring greif up -- variable not defined."));
903

    
904
	if (isset($gre['link1']) && $gre['link1'])
905
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
906
	if(is_ipaddrv4($gre['tunnel-remote-addr']))
907
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
908
	if(is_ipaddrv6($gre['tunnel-remote-addr']))
909
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
910

    
911
	interfaces_bring_up($greif);
912

    
913
	return $greif;
914
}
915

    
916
function interfaces_gif_configure($checkparent = 0, $realif = "") {
917
	global $config;
918

    
919
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
920
		foreach ($config['gifs']['gif'] as $i => $gif) {
921
			if (empty($gif['gifif']))
922
				$gre['gifif'] = "gif{$i}";
923
			if (!empty($realif) && $realif != $gif['gifif'])
924
				continue;
925

    
926
			if ($checkparent == 1) {
927
				if (strstr($gif['if'], "_vip"))
928
					continue;
929
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6")
930
					continue;
931
			}
932
			else if ($checkparent == 2) {
933
				if (strstr($gif['if'], "_vip"))
934
					continue;
935
				if (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")
936
					continue;
937
			}
938
			/* XXX: Maybe we should report any errors?! */
939
			interface_gif_configure($gif);
940
		}
941
	}
942
}
943

    
944
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
945
function interface_gif_configure(&$gif, $gifkey = "") {
946
	global $config, $g;
947

    
948
	if (!is_array($gif))
949
		return -1;
950

    
951
	$realif = get_real_interface($gif['if']);
952
	$ipaddr = $gif['ipaddr'];
953

    
954
	if (is_ipaddrv4($gif['remote-addr'])) {
955
		if (is_ipaddrv4($ipaddr))
956
			$realifip = $ipaddr;
957
		else
958
			$realifip = get_interface_ip($gif['if']);
959
		$realifgw = get_interface_gateway($gif['if']);
960
	} else if (is_ipaddrv6($gif['remote-addr'])) {
961
		if (is_ipaddrv6($ipaddr))
962
			$realifip = $ipaddr;
963
		else
964
			$realifip = get_interface_ipv6($gif['if']);
965
		$realifgw = get_interface_gateway_v6($gif['if']);
966
	}
967
	/* make sure the parent interface is up */
968
	if($realif)
969
		interfaces_bring_up($realif);
970
	else
971
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
972

    
973
	if ($g['booting'] || !(empty($gif['gifif']))) {
974
		pfSense_interface_destroy($gif['gifif']);
975
		pfSense_interface_create($gif['gifif']);
976
		$gifif = $gif['gifif'];
977
	} else
978
		$gifif = pfSense_interface_create("gif");
979

    
980
	/* Do not change the order here for more see gif(4) NOTES section. */
981
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
982
	if((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
983
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
984
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
985
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
986
	} else {
987
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
988
	}
989
	if (isset($gif['link0']))
990
		pfSense_interface_flags($gifif, IFF_LINK0);
991
	if (isset($gif['link1']))
992
		pfSense_interface_flags($gifif, IFF_LINK1);
993
	if($gifif)
994
		interfaces_bring_up($gifif);
995
	else
996
		log_error(gettext("could not bring gifif up -- variable not defined"));
997

    
998
	$iflist = get_configured_interface_list();
999
	foreach($iflist as $ifname) {
1000
		if($config['interfaces'][$ifname]['if'] == $gifif) {
1001
			if(get_interface_gateway($ifname)) {
1002
				system_routing_configure($ifname);
1003
				break;
1004
			}
1005
			if(get_interface_gateway_v6($ifname)) {
1006
				system_routing_configure($ifname);
1007
				break;
1008
			}
1009
		}
1010
	}
1011

    
1012

    
1013
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
1014
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1015
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
1016
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1017

    
1018
	if (is_ipaddrv4($realifgw)) {
1019
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1020
	}
1021
	if (is_ipaddrv6($realifgw)) {
1022
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1023
	}
1024

    
1025
	interfaces_bring_up($gifif);
1026

    
1027
	return $gifif;
1028
}
1029

    
1030
function interfaces_configure() {
1031
	global $config, $g;
1032

    
1033
	if ($g['platform'] == 'jail')
1034
		return;
1035

    
1036
	/* Set up our loopback interface */
1037
	interfaces_loopback_configure();
1038

    
1039
	/* create the unconfigured wireless clones */
1040
	interfaces_create_wireless_clones();
1041

    
1042
	/* set up LAGG virtual interfaces */
1043
	interfaces_lagg_configure();
1044

    
1045
	/* set up VLAN virtual interfaces */
1046
	interfaces_vlan_configure();
1047

    
1048
	interfaces_qinq_configure();
1049

    
1050
	$iflist = get_configured_interface_with_descr();
1051
	$delayed_list = array();
1052
	$bridge_list = array();
1053
	$track6_list = array();
1054

    
1055
	/* This is needed to speedup interfaces on bootup. */
1056
	$reload = false;
1057
	if (!$g['booting'])
1058
		$reload = true;
1059

    
1060
	foreach($iflist as $if => $ifname) {
1061
		$realif = $config['interfaces'][$if]['if'];
1062
		if (strstr($realif, "bridge"))
1063
			$bridge_list[$if] = $ifname;
1064
		else if (strstr($realif, "gre"))
1065
			$delayed_list[$if] = $ifname;
1066
		else if (strstr($realif, "gif"))
1067
			$delayed_list[$if] = $ifname;
1068
		else if (strstr($realif, "ovpn")) {
1069
			//echo "Delaying OpenVPN interface configuration...done.\n";
1070
			continue;
1071
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1072
			$track6_list[$if] = $ifname;
1073
		} else {
1074
			if ($g['booting'])
1075
				printf(gettext("Configuring %s interface..."), $ifname);
1076

    
1077
			if($g['debug'])
1078
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1079
			interface_configure($if, $reload);
1080
			if ($g['booting'])
1081
				echo gettext( "done.") . "\n";
1082
		}
1083
	}
1084

    
1085
	/*
1086
	 * NOTE: The following function parameter consists of
1087
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1088
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1089
	 */
1090

    
1091
	/* set up GRE virtual interfaces */
1092
	interfaces_gre_configure(1);
1093

    
1094
	/* set up GIF virtual interfaces */
1095
	interfaces_gif_configure(1);
1096

    
1097
	/* set up BRIDGe virtual interfaces */
1098
	interfaces_bridge_configure(1);
1099

    
1100
	foreach ($track6_list as $if => $ifname) {
1101
		if ($g['booting'])
1102
			printf(gettext("Configuring %s interface..."), $ifname);
1103
		if ($g['debug'])
1104
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1105

    
1106
		interface_configure($if, $reload);
1107

    
1108
		if ($g['booting'])
1109
			echo gettext("done.") . "\n";
1110
	}
1111

    
1112
	/* bring up vip interfaces */
1113
	interfaces_vips_configure();
1114

    
1115
	/* set up GRE virtual interfaces */
1116
	interfaces_gre_configure(2);
1117

    
1118
	/* set up GIF virtual interfaces */
1119
	interfaces_gif_configure(2);
1120

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

    
1127
		interface_configure($if, $reload);
1128

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

    
1133
	/* set up BRIDGe virtual interfaces */
1134
	interfaces_bridge_configure(2);
1135

    
1136
	foreach ($bridge_list as $if => $ifname) {
1137
		if ($g['booting'])
1138
			printf(gettext("Configuring %s interface..."), $ifname);
1139
		if($g['debug'])
1140
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1141

    
1142
		interface_configure($if, $reload);
1143

    
1144
		if ($g['booting'])
1145
			echo gettext("done.") . "\n";
1146
	}
1147

    
1148
	/* configure interface groups */
1149
	interfaces_group_setup();
1150

    
1151
	if (!$g['booting']) {
1152
		/* reconfigure static routes (kernel may have deleted them) */
1153
		system_routing_configure();
1154

    
1155
		/* reload IPsec tunnels */
1156
		vpn_ipsec_configure();
1157

    
1158
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1159
		services_dhcpd_configure();
1160

    
1161
		/* restart dnsmasq or unbound */
1162
		if (isset($config['dnsmasq']['enable']))
1163
			services_dnsmasq_configure();
1164
		elseif (isset($config['unbound']['enable']))
1165
			services_unbound_configure();
1166
	}
1167

    
1168
	return 0;
1169
}
1170

    
1171
function interface_reconfigure($interface = "wan", $reloadall = false) {
1172
	interface_bring_down($interface);
1173
	interface_configure($interface, $reloadall);
1174
}
1175

    
1176
function interface_vip_bring_down($vip) {
1177
	global $g;
1178

    
1179
	$vipif = get_real_interface($vip['interface']);
1180
	switch ($vip['mode']) {
1181
	case "proxyarp":
1182
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1183
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1184
		break;
1185
	case "ipalias":
1186
		if (does_interface_exist($vipif)) {
1187
			if (is_ipaddrv6($vip['subnet']))
1188
				mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1189
			else
1190
				pfSense_interface_deladdress($vipif, $vip['subnet']);
1191
		}
1192
		break;
1193
	case "carp":
1194
		/* XXX: Is enough to delete ip address? */
1195
		if (does_interface_exist($vipif))
1196
			pfSense_interface_deladdress($vipif, $vip['subnet']);
1197
		break;
1198
	}
1199
}
1200

    
1201
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1202
	global $config, $g;
1203

    
1204
	if (!isset($config['interfaces'][$interface]))
1205
		return;
1206

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

    
1210
	/*
1211
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1212
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1213
	 * Keep this in mind while doing changes here!
1214
	 */
1215
	if ($ifacecfg === false) {
1216
		$ifcfg = $config['interfaces'][$interface];
1217
		$ppps = $config['ppps']['ppp'];
1218
		$realif = get_real_interface($interface);
1219
		$realifv6 = get_real_interface($interface, "inet6", true);
1220
	} elseif (!is_array($ifacecfg)) {
1221
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1222
		$ifcfg = $config['interfaces'][$interface];
1223
		$ppps = $config['ppps']['ppp'];
1224
		$realif = get_real_interface($interface);
1225
		$realifv6 = get_real_interface($interface, "inet6", true);
1226
	} else {
1227
		$ifcfg = $ifacecfg['ifcfg'];
1228
		$ppps = $ifacecfg['ppps'];
1229
		if (isset($ifacecfg['ifcfg']['realif'])) {
1230
			$realif = $ifacecfg['ifcfg']['realif'];
1231
			/* XXX: Any better way? */
1232
			$realifv6 = $realif;
1233
		} else {
1234
			$realif = get_real_interface($interface);
1235
			$realifv6 = get_real_interface($interface, "inet6", true);
1236
		}
1237
	}
1238

    
1239
	switch ($ifcfg['ipaddr']) {
1240
	case "ppp":
1241
	case "pppoe":
1242
	case "pptp":
1243
	case "l2tp":
1244
		if (is_array($ppps) && count($ppps)) {
1245
			foreach ($ppps as $pppid => $ppp) {
1246
				if ($realif == $ppp['if']) {
1247
					if (isset($ppp['ondemand']) && !$destroy){
1248
						send_event("interface reconfigure {$interface}");
1249
						break;
1250
					}
1251
					if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1252
						killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1253
						sleep(2);
1254
					}
1255
					unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1256
					break;
1257
				}
1258
			}
1259
		}
1260
		break;
1261
	case "dhcp":
1262
		kill_dhclient_process($realif);
1263
		unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1264
		if(does_interface_exist("$realif")) {
1265
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1266
			interface_ipalias_cleanup($interface);
1267
			if ($destroy == true)
1268
				pfSense_interface_flags($realif, -IFF_UP);
1269
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1270
		}
1271
		break;
1272
	default:
1273
		if(does_interface_exist("$realif")) {
1274
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1275
			interface_ipalias_cleanup($interface);
1276
			if ($destroy == true)
1277
				pfSense_interface_flags($realif, -IFF_UP);
1278
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1279
		}
1280
		break;
1281
	}
1282

    
1283
	$track6 = array();
1284
	switch ($ifcfg['ipaddrv6']) {
1285
	case "slaac":
1286
	case "dhcp6":
1287
		$pidv6 = find_dhcp6c_process($realif);
1288
		if($pidv6)
1289
			posix_kill($pidv6, SIGTERM);
1290
		sleep(3);
1291
		unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1292
		if (does_interface_exist($realifv6)) {
1293
			$ip6 = find_interface_ipv6($realifv6);
1294
			if (is_ipaddrv6($ip6) && $ip6 != "::")
1295
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1296
			interface_ipalias_cleanup($interface, "inet6");
1297
			if ($destroy == true)
1298
				pfSense_interface_flags($realif, -IFF_UP);
1299
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1300
		}
1301
		$track6 = link_interface_to_track6($interface);
1302
		break;
1303
	case "6rd":
1304
	case "6to4":
1305
		$realif = "{$interface}_stf";
1306
		if(does_interface_exist("$realif")) {
1307
			$ip6 = get_interface_ipv6($interface);
1308
			if (is_ipaddrv6($ip6))
1309
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1310
			interface_ipalias_cleanup($interface, "inet6");
1311
			if ($destroy == true)
1312
				pfSense_interface_flags($realif, -IFF_UP);
1313
		}
1314
		$track6 = link_interface_to_track6($interface);
1315
		break;
1316
	default:
1317
		if(does_interface_exist("$realif")) {
1318
			$ip6 = get_interface_ipv6($interface);
1319
			if (is_ipaddrv6($ip6))
1320
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1321
			if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
1322
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1323
			interface_ipalias_cleanup($interface, "inet6");
1324
			if ($destroy == true)
1325
				pfSense_interface_flags($realif, -IFF_UP);
1326
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1327
		}
1328
		$track6 = link_interface_to_track6($interface);
1329
		break;
1330
	}
1331

    
1332
	if (!empty($track6) && is_array($track6)) {
1333
		if (!function_exists('services_dhcp_configure'))
1334
			require_once('services.inc');
1335
		/* Bring down radvd and dhcp6 on these interfaces */
1336
		services_dhcpd_configure('inet6', $track6);
1337
	}
1338

    
1339
	$old_router = '';
1340
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1341
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1342
//	log_error("Checking for old router states: {$g['tmp_path']}/{$realif}_router = {$old_router}");
1343
	if (!empty($old_router)) {
1344
		log_error("Clearing states to old gateway {$old_router}.");
1345
		mwexec("/sbin/pfctl -i " . escapeshellarg($realif) . " -Fs");
1346
	}
1347

    
1348
	/* remove interface up file if it exists */
1349
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1350
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1351
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1352
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1353
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1354
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1355
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1356

    
1357
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1358
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1359
	if (is_array($ifcfg['wireless'])) {
1360
		kill_hostapd($realif);
1361
		mwexec(kill_wpasupplicant($realif));
1362
	}
1363

    
1364
	if ($destroy == true) {
1365
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif))
1366
			pfSense_interface_destroy($realif);
1367
	}
1368

    
1369
	return;
1370
}
1371

    
1372
function interfaces_carp_set_maintenancemode($carp_maintenancemode){
1373
	global $config;
1374
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1375
		unset($config["virtualip_carp_maintenancemode"]);
1376
		write_config("Leave CARP maintenance mode");
1377
	} else
1378
	if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1379
		$config["virtualip_carp_maintenancemode"] = true;
1380
		write_config("Enter CARP maintenance mode");
1381
	}
1382

    
1383
	$viparr = &$config['virtualip']['vip'];
1384
	foreach ($viparr as $vip) {
1385
		if ($vip['mode'] == "carp") {
1386
			interface_carp_configure($vip);
1387
		}
1388
	}
1389
}
1390

    
1391
function interfaces_ptpid_used($ptpid) {
1392
	global $config;
1393

    
1394
	if (is_array($config['ppps']['ppp']))
1395
		foreach ($config['ppps']['ppp'] as & $settings)
1396
			if ($ptpid == $settings['ptpid'])
1397
				return true;
1398

    
1399
	return false;
1400
}
1401

    
1402
function interfaces_ptpid_next() {
1403

    
1404
	$ptpid = 0;
1405
	while(interfaces_ptpid_used($ptpid))
1406
		$ptpid++;
1407

    
1408
	return $ptpid;
1409
}
1410

    
1411
function getMPDCRONSettings($pppif) {
1412
	global $config;
1413

    
1414
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1415
	if (is_array($config['cron']['item'])) {
1416
		foreach ($config['cron']['item'] as $i => $item) {
1417
			if (stripos($item['command'], $cron_cmd_file) !== false)
1418
				return array("ID" => $i, "ITEM" => $item);
1419
		}
1420
	}
1421

    
1422
	return NULL;
1423
}
1424

    
1425
function handle_pppoe_reset($post_array) {
1426
	global $config, $g;
1427

    
1428
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1429
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1430

    
1431
	if (!is_array($config['cron']['item']))
1432
		$config['cron']['item'] = array();
1433

    
1434
	$itemhash = getMPDCRONSettings($pppif);
1435

    
1436
	// reset cron items if necessary and return
1437
	if (empty($post_array['pppoe-reset-type'])) {
1438
		if (isset($itemhash))
1439
			unset($config['cron']['item'][$itemhash['ID']]);
1440
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1441
		return;
1442
	}
1443

    
1444
	if (empty($itemhash))
1445
		$itemhash = array();
1446
	$item = array();
1447
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1448
		$item['minute'] = $post_array['pppoe_resetminute'];
1449
		$item['hour'] = $post_array['pppoe_resethour'];
1450
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1451
			$date = explode("/", $post_array['pppoe_resetdate']);
1452
			$item['mday'] = $date[1];
1453
			$item['month'] = $date[0];
1454
		} else {
1455
			$item['mday'] = "*";
1456
			$item['month'] = "*";
1457
		}
1458
		$item['wday'] = "*";
1459
		$item['who'] = "root";
1460
		$item['command'] = $cron_cmd_file;
1461
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1462
		switch ($post_array['pppoe_pr_preset_val']) {
1463
		case "monthly":
1464
			$item['minute'] = "0";
1465
			$item['hour'] = "0";
1466
			$item['mday'] = "1";
1467
			$item['month'] = "*";
1468
			$item['wday'] = "*";
1469
			break;
1470
		case "weekly":
1471
			$item['minute'] = "0";
1472
			$item['hour'] = "0";
1473
			$item['mday'] = "*";
1474
			$item['month'] = "*";
1475
			$item['wday'] = "0";
1476
			break;
1477
		case "daily":
1478
			$item['minute'] = "0";
1479
			$item['hour'] = "0";
1480
			$item['mday'] = "*";
1481
			$item['month'] = "*";
1482
			$item['wday'] = "*";
1483
			break;
1484
		case "hourly":
1485
			$item['minute'] = "0";
1486
			$item['hour'] = "*";
1487
			$item['mday'] = "*";
1488
			$item['month'] = "*";
1489
			$item['wday'] = "*";
1490
			break;
1491
		} // end switch
1492
		$item['who'] = "root";
1493
		$item['command'] = $cron_cmd_file;
1494
	}
1495
	if (empty($item))
1496
		return;
1497
	if (isset($itemhash['ID']))
1498
		$config['cron']['item'][$itemhash['ID']] = $item;
1499
	else
1500
		$config['cron']['item'][] = $item;
1501
}
1502

    
1503
/*
1504
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1505
 * It writes the mpd config file to /var/etc every time the link is opened.
1506
 */
1507
function interface_ppps_configure($interface) {
1508
	global $config, $g;
1509

    
1510
	/* Return for unassigned interfaces. This is a minimum requirement. */
1511
	if (empty($config['interfaces'][$interface]))
1512
		return 0;
1513
	$ifcfg = $config['interfaces'][$interface];
1514
	if (!isset($ifcfg['enable']))
1515
		return 0;
1516

    
1517
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1518
	if(!is_dir("/var/spool/lock")) {
1519
		mkdir("/var/spool/lock", 0777, true);
1520
	}
1521
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1522
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1523
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1524

    
1525
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1526
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1527
			if ($ifcfg['if'] == $ppp['if'])
1528
				break;
1529
		}
1530
	}
1531
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1532
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1533
		return 0;
1534
	}
1535
	$pppif = $ifcfg['if'];
1536
	if ($ppp['type'] == "ppp")
1537
		$type = "modem";
1538
	else
1539
		$type = $ppp['type'];
1540
	$upper_type = strtoupper($ppp['type']);
1541

    
1542
	if($g['booting']) {
1543
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1544
		echo "starting {$pppif} link...";
1545
		// Do not re-configure the interface if we are booting and it's already been started
1546
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1547
			return 0;
1548
	}
1549

    
1550
	$ports = explode(',',$ppp['ports']);
1551
	if ($type != "modem") {
1552
		foreach ($ports as $pid => $port) {
1553
			$ports[$pid] = get_real_interface($port);
1554
			if (empty($ports[$pid]))
1555
				return 0;
1556
		}
1557
	}
1558
	$localips = explode(',',$ppp['localip']);
1559
	$gateways = explode(',',$ppp['gateway']);
1560
	$subnets = explode(',',$ppp['subnet']);
1561

    
1562
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1563
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1564
	 */
1565
	foreach($ports as $pid => $port){
1566
		switch ($ppp['type']) {
1567
			case "pppoe":
1568
				/* Bring the parent interface up */
1569
				interfaces_bring_up($port);
1570
				pfSense_ngctl_attach(".", $port);
1571
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1572
				mwexec("ngctl msg {$port}: setautosrc 1");
1573
				break;
1574
			case "pptp":
1575
			case "l2tp":
1576
				/* configure interface */
1577
				if(is_ipaddr($localips[$pid])){
1578
					// Manually configure interface IP/subnet
1579
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1580
					interfaces_bring_up($port);
1581
				} else if (empty($localips[$pid]))
1582
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1583

    
1584
				if(!is_ipaddr($localips[$pid])){
1585
					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!");
1586
					$localips[$pid] = "0.0.0.0";
1587
				}
1588
				if(!is_ipaddr($gateways[$pid])){
1589
					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));
1590
					return 0;
1591
				}
1592
				pfSense_ngctl_attach(".", $port);
1593
				break;
1594
			case "ppp":
1595
				if (!file_exists("{$port}")) {
1596
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1597
					return 0;
1598
				}
1599
				break;
1600
			default:
1601
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1602
				break;
1603
		}
1604
	}
1605

    
1606
	if (is_array($ports) && count($ports) > 1)
1607
		$multilink = "enable";
1608
	else
1609
		$multilink = "disable";
1610

    
1611
	if ($type == "modem"){
1612
		if (is_ipaddr($ppp['localip']))
1613
			$localip = $ppp['localip'];
1614
		else
1615
			$localip = '0.0.0.0';
1616

    
1617
		if (is_ipaddr($ppp['gateway']))
1618
			$gateway = $ppp['gateway'];
1619
		else
1620
			$gateway = "10.64.64.{$pppid}";
1621
		$ranges = "{$localip}/0 {$gateway}/0";
1622

    
1623
		if (empty($ppp['apnum']))
1624
			$ppp['apnum'] = 1;
1625
	} else
1626
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1627

    
1628
	if (isset($ppp['ondemand']))
1629
		$ondemand = "enable";
1630
	else
1631
		$ondemand = "disable";
1632
	if (!isset($ppp['idletimeout']))
1633
		$ppp['idletimeout'] = 0;
1634

    
1635
	if (empty($ppp['username']) && $type == "modem"){
1636
		$ppp['username'] = "user";
1637
		$ppp['password'] = "none";
1638
	}
1639
	if (empty($ppp['password']) && $type == "modem")
1640
		$passwd = "none";
1641
	else
1642
		$passwd = base64_decode($ppp['password']);
1643

    
1644
	$bandwidths = explode(',',$ppp['bandwidth']);
1645
	$defaultmtu = "1492";
1646
	if (!empty($ifcfg['mtu']))
1647
		$defaultmtu = intval($ifcfg['mtu']);
1648
	$mtus = explode(',',$ppp['mtu']);
1649
	$mrus = explode(',',$ppp['mru']);
1650

    
1651
	if (isset($ppp['mrru']))
1652
		$mrrus = explode(',',$ppp['mrru']);
1653

    
1654
	// Construct the mpd.conf file
1655
	$mpdconf = <<<EOD
1656
startup:
1657
	# configure the console
1658
	set console close
1659
	# configure the web server
1660
	set web close
1661

    
1662
default:
1663
{$ppp['type']}client:
1664
	create bundle static {$interface}
1665
	set bundle enable ipv6cp
1666
	set iface name {$pppif}
1667

    
1668
EOD;
1669
	$setdefaultgw = false;
1670
	$founddefaultgw = false;
1671
	if (is_array($config['gateways']['gateway_item'])) {
1672
		foreach($config['gateways']['gateway_item'] as $gateway) {
1673
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1674
				$setdefaultgw = true;
1675
				break;
1676
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1677
				$founddefaultgw = true;
1678
				break;
1679
			}
1680
		}
1681
	}
1682

    
1683
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1684
		$setdefaultgw = true;
1685
		$mpdconf .= <<<EOD
1686
	set iface route default
1687

    
1688
EOD;
1689
	}
1690
	$mpdconf .= <<<EOD
1691
	set iface {$ondemand} on-demand
1692
	set iface idle {$ppp['idletimeout']}
1693

    
1694
EOD;
1695

    
1696
	if (isset($ppp['ondemand']))
1697
		$mpdconf .= <<<EOD
1698
	set iface addrs 10.10.1.1 10.10.1.2
1699

    
1700
EOD;
1701

    
1702
	if (isset($ppp['tcpmssfix']))
1703
		$tcpmss = "disable";
1704
	else
1705
		$tcpmss = "enable";
1706
		$mpdconf .= <<<EOD
1707
	set iface {$tcpmss} tcpmssfix
1708

    
1709
EOD;
1710

    
1711
	$mpdconf .= <<<EOD
1712
	set iface up-script /usr/local/sbin/ppp-linkup
1713
	set iface down-script /usr/local/sbin/ppp-linkdown
1714
	set ipcp ranges {$ranges}
1715

    
1716
EOD;
1717
	if (isset($ppp['vjcomp']))
1718
		$mpdconf .= <<<EOD
1719
	set ipcp no vjcomp
1720

    
1721
EOD;
1722

    
1723
	if (isset($config['system']['dnsallowoverride']))
1724
		$mpdconf .= <<<EOD
1725
	set ipcp enable req-pri-dns
1726
	set ipcp enable req-sec-dns
1727

    
1728
EOD;
1729
	if (!isset($ppp['verbose_log']))
1730
		$mpdconf .= <<<EOD
1731
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1732

    
1733
EOD;
1734
	foreach($ports as $pid => $port){
1735
		$port = get_real_interface($port);
1736
		$mpdconf .= <<<EOD
1737

    
1738
	create link static {$interface}_link{$pid} {$type}
1739
	set link action bundle {$interface}
1740
	set link {$multilink} multilink
1741
	set link keep-alive 10 60
1742
	set link max-redial 0
1743

    
1744
EOD;
1745
		if (isset($ppp['shortseq']))
1746
			$mpdconf .= <<<EOD
1747
	set link no shortseq
1748

    
1749
EOD;
1750

    
1751
		if (isset($ppp['acfcomp']))
1752
			$mpdconf .= <<<EOD
1753
	set link no acfcomp
1754

    
1755
EOD;
1756

    
1757
		if (isset($ppp['protocomp']))
1758
			$mpdconf .= <<<EOD
1759
	set link no protocomp
1760

    
1761
EOD;
1762

    
1763
		$mpdconf .= <<<EOD
1764
	set link disable chap pap
1765
	set link accept chap pap eap
1766
	set link disable incoming
1767

    
1768
EOD;
1769

    
1770

    
1771
		if (!empty($bandwidths[$pid]))
1772
			$mpdconf .= <<<EOD
1773
	set link bandwidth {$bandwidths[$pid]}
1774

    
1775
EOD;
1776

    
1777
		if (empty($mtus[$pid]))
1778
			$mtus[$pid] = $defaultmtu;
1779
			$mpdconf .= <<<EOD
1780
	set link mtu {$mtus[$pid]}
1781

    
1782
EOD;
1783

    
1784
		if (!empty($mrus[$pid]))
1785
			$mpdconf .= <<<EOD
1786
	set link mru {$mrus[$pid]}
1787

    
1788
EOD;
1789

    
1790
		if (!empty($mrrus[$pid]))
1791
			$mpdconf .= <<<EOD
1792
	set link mrru {$mrrus[$pid]}
1793

    
1794
EOD;
1795

    
1796
		$mpdconf .= <<<EOD
1797
	set auth authname "{$ppp['username']}"
1798
	set auth password {$passwd}
1799

    
1800
EOD;
1801
		if ($type == "modem") {
1802
			$mpdconf .= <<<EOD
1803
	set modem device {$ppp['ports']}
1804
	set modem script DialPeer
1805
	set modem idle-script Ringback
1806
	set modem watch -cd
1807
	set modem var \$DialPrefix "DT"
1808
	set modem var \$Telephone "{$ppp['phone']}"
1809

    
1810
EOD;
1811
		}
1812
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1813
			$mpdconf .= <<<EOD
1814
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1815

    
1816
EOD;
1817
		}
1818
		if (isset($ppp['initstr']) && $type == "modem") {
1819
			$initstr = base64_decode($ppp['initstr']);
1820
			$mpdconf .= <<<EOD
1821
	set modem var \$InitString "{$initstr}"
1822

    
1823
EOD;
1824
		}
1825
		if (isset($ppp['simpin']) && $type == "modem") {
1826
			if($ppp['pin-wait'] == "")
1827
				$ppp['pin-wait'] = 0;
1828
			$mpdconf .= <<<EOD
1829
	set modem var \$SimPin "{$ppp['simpin']}"
1830
	set modem var \$PinWait "{$ppp['pin-wait']}"
1831

    
1832
EOD;
1833
		}
1834
		if (isset($ppp['apn']) && $type == "modem") {
1835
			$mpdconf .= <<<EOD
1836
	set modem var \$APN "{$ppp['apn']}"
1837
	set modem var \$APNum "{$ppp['apnum']}"
1838

    
1839
EOD;
1840
		}
1841
		if ($type == "pppoe") {
1842
			// Send a null service name if none is set.
1843
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1844
			$mpdconf .= <<<EOD
1845
	set pppoe service "{$provider}"
1846

    
1847
EOD;
1848
		}
1849
		if ($type == "pppoe")
1850
			$mpdconf .= <<<EOD
1851
	set pppoe iface {$port}
1852

    
1853
EOD;
1854

    
1855
		if ($type == "pptp" || $type == "l2tp") {
1856
			$mpdconf .= <<<EOD
1857
	set {$type} self {$localips[$pid]}
1858
	set {$type} peer {$gateways[$pid]}
1859

    
1860
EOD;
1861
		}
1862

    
1863
		$mpdconf .= "\topen\n";
1864
	} //end foreach($port)
1865

    
1866

    
1867
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1868
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1869
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1870
	else {
1871
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1872
		if (!$fd) {
1873
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1874
			return 0;
1875
		}
1876
		// Write out mpd_ppp.conf
1877
		fwrite($fd, $mpdconf);
1878
		fclose($fd);
1879
		unset($mpdconf);
1880
	}
1881

    
1882
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1883
	if (isset($ppp['uptime'])) {
1884
		if (!file_exists("/conf/{$pppif}.log")) {
1885
			conf_mount_rw();
1886
			file_put_contents("/conf/{$pppif}.log", '');
1887
			conf_mount_ro();
1888
		}
1889
	} else {
1890
		if (file_exists("/conf/{$pppif}.log")) {
1891
			conf_mount_rw();
1892
			@unlink("/conf/{$pppif}.log");
1893
			conf_mount_ro();
1894
		}
1895
	}
1896

    
1897
	/* clean up old lock files */
1898
	foreach($ports as $port) {
1899
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1900
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1901
	}
1902

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

    
1907
	// Check for PPPoE periodic reset request
1908
	if ($type == "pppoe") {
1909
		if (!empty($ppp['pppoe-reset-type']))
1910
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1911
		else
1912
			interface_setup_pppoe_reset_file($ppp['if']);
1913
	}
1914
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1915
	$i = 0;
1916
	while($i < 10) {
1917
		exec("/sbin/ifconfig " . escapeshellarg($ppp['if']) . " 2>&1", $out, $ret);
1918
		if($ret == 0)
1919
			break;
1920
		sleep(1);
1921
		$i++;
1922
	}
1923

    
1924
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
1925
	/* We should be able to launch the right version for each modem */
1926
	/* We can also guess the mondev from the manufacturer */
1927
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
1928
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
1929
	foreach($ports as $port) {
1930
		if(preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1931
			$mondev  = substr(basename($port), 0, -1);
1932
			$devlist = glob("/dev/{$mondev}?");
1933
			$mondev = basename(end($devlist));
1934
		}
1935
		if(preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1936
			$mondev  = substr(basename($port), 0, -1) . "1";
1937
		}
1938
		log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
1939
		mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
1940
	}
1941

    
1942
	return 1;
1943
}
1944

    
1945
function interfaces_carp_setup() {
1946
	global $g, $config;
1947

    
1948
	if (isset($config['system']['developerspew'])) {
1949
		$mt = microtime();
1950
		echo "interfaces_carp_setup() being called $mt\n";
1951
	}
1952

    
1953
	if ($g['booting']) {
1954
		echo gettext("Configuring CARP settings...");
1955
		mute_kernel_msgs();
1956
	}
1957

    
1958
	/* suck in configuration items */
1959
	if ($config['hasync']) {
1960
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1961
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1962
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1963
	} else {
1964
		unset($pfsyncinterface);
1965
		unset($pfsyncenabled);
1966
	}
1967

    
1968
	set_sysctl(array(
1969
		"net.inet.carp.preempt" => "1",
1970
		"net.inet.carp.log" => "1")
1971
	);
1972

    
1973
	if (!empty($pfsyncinterface))
1974
		$carp_sync_int = get_real_interface($pfsyncinterface);
1975
	else
1976
		unset($carp_sync_int);
1977

    
1978
	/* setup pfsync interface */
1979
	if ($carp_sync_int and $pfsyncenabled) {
1980
		if (is_ipaddr($pfsyncpeerip))
1981
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1982
		else
1983
			$syncpeer = "-syncpeer";
1984

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

    
1987
		sleep(1);
1988

    
1989
		/* 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
1990
		 * for existing sessions.
1991
		 */
1992
		log_error("waiting for pfsync...");
1993
		$i = 0;
1994
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1995
			$i++;
1996
			sleep(1);
1997
		}
1998
		log_error("pfsync done in $i seconds.");
1999
		log_error("Configuring CARP settings finalize...");
2000
	} else {
2001
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2002
	}
2003

    
2004
	if($config['virtualip']['vip'])
2005
		set_single_sysctl("net.inet.carp.allow", "1");
2006
	else
2007
		set_single_sysctl("net.inet.carp.allow", "0");
2008

    
2009
	if ($g['booting']) {
2010
		unmute_kernel_msgs();
2011
		echo gettext("done.") . "\n";
2012
	}
2013
}
2014

    
2015
function interface_proxyarp_configure($interface = "") {
2016
	global $config, $g;
2017
	if(isset($config['system']['developerspew'])) {
2018
		$mt = microtime();
2019
		echo "interface_proxyarp_configure() being called $mt\n";
2020
	}
2021

    
2022
	/* kill any running choparp */
2023
	if (empty($interface))
2024
		killbyname("choparp");
2025
	else {
2026
		$vipif = get_real_interface($interface);
2027
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
2028
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2029
	}
2030

    
2031
	$paa = array();
2032
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2033

    
2034
		/* group by interface */
2035
		foreach ($config['virtualip']['vip'] as $vipent) {
2036
			if ($vipent['mode'] === "proxyarp") {
2037
				if ($vipent['interface'])
2038
					$proxyif = $vipent['interface'];
2039
				else
2040
					$proxyif = "wan";
2041

    
2042
				if (!empty($interface) && $interface != $proxyif)
2043
					continue;
2044

    
2045
				if (!is_array($paa[$proxyif]))
2046
					$paa[$proxyif] = array();
2047

    
2048
				$paa[$proxyif][] = $vipent;
2049
			}
2050
		}
2051
	}
2052

    
2053
	if (!empty($interface)) {
2054
		if (is_array($paa[$interface])) {
2055
			$paaifip = get_interface_ip($interface);
2056
			if (!is_ipaddr($paaifip))
2057
				return;
2058
			$args = get_real_interface($interface) . " auto";
2059
			foreach ($paa[$interface] as $paent) {
2060
				if (isset($paent['subnet']))
2061
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2062
				else if (isset($paent['range']))
2063
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2064
			}
2065
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2066
		}
2067
	} else if (count($paa) > 0) {
2068
		foreach ($paa as $paif => $paents)  {
2069
			$paaifip = get_interface_ip($paif);
2070
			if (!is_ipaddr($paaifip))
2071
				continue;
2072
			$args = get_real_interface($paif) . " auto";
2073
			foreach ($paents as $paent) {
2074
				if (isset($paent['subnet']))
2075
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2076
				else if (isset($paent['range']))
2077
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2078
			}
2079
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2080
		}
2081
	}
2082
}
2083

    
2084
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2085
	global $g, $config;
2086

    
2087
	if (is_array($config['virtualip']['vip'])) {
2088
		foreach ($config['virtualip']['vip'] as $vip) {
2089
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2090
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2091
					interface_vip_bring_down($vip);
2092
				else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2093
					interface_vip_bring_down($vip);
2094
			}
2095
		}
2096
	}
2097
}
2098

    
2099
function interfaces_vips_configure($interface = "") {
2100
	global $g, $config;
2101
	if(isset($config['system']['developerspew'])) {
2102
		$mt = microtime();
2103
		echo "interfaces_vips_configure() being called $mt\n";
2104
	}
2105
	$paa = array();
2106
	if(is_array($config['virtualip']['vip'])) {
2107
		$carp_setuped = false;
2108
		$anyproxyarp = false;
2109
		foreach ($config['virtualip']['vip'] as $vip) {
2110
			switch ($vip['mode']) {
2111
			case "proxyarp":
2112
				/* nothing it is handled on interface_proxyarp_configure() */
2113
				if ($interface <> "" && $vip['interface'] <> $interface)
2114
					continue;
2115
				$anyproxyarp = true;
2116
				break;
2117
			case "ipalias":
2118
				if ($interface <> "" && $vip['interface'] <> $interface)
2119
					continue;
2120
				interface_ipalias_configure($vip);
2121
				break;
2122
			case "carp":
2123
				if ($interface <> "" && $vip['interface'] <> $interface)
2124
					continue;
2125
				if ($carp_setuped == false)
2126
					$carp_setuped = true;
2127
				interface_carp_configure($vip);
2128
				break;
2129
			}
2130
		}
2131
		if ($carp_setuped == true)
2132
			interfaces_carp_setup();
2133
		if ($anyproxyarp == true)
2134
			interface_proxyarp_configure();
2135
	}
2136
}
2137

    
2138
function interface_ipalias_configure(&$vip) {
2139
	global $config;
2140

    
2141
	if ($vip['mode'] != "ipalias")
2142
		return;
2143

    
2144
	if ($vip['interface'] != 'lo0' && !isset($config['interfaces'][$vip['interface']]))
2145
		return;
2146

    
2147
	if ($vip['interface'] != 'lo0' && !isset($config['interfaces'][$vip['interface']]['enable']))
2148
		return;
2149

    
2150
	$if = get_real_interface($vip['interface']);
2151
	$af = "inet";
2152
	if(is_ipaddrv6($vip['subnet']))
2153
		$af = "inet6";
2154
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
2155
}
2156

    
2157
function interface_reload_carps($cif) {
2158
	global $config;
2159

    
2160
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2161
	if (empty($carpifs))
2162
		return;
2163

    
2164
	$carps = explode(" ", $carpifs);
2165
	if(is_array($config['virtualip']['vip'])) {
2166
		$viparr = &$config['virtualip']['vip'];
2167
		foreach ($viparr as $vip) {
2168
			if (in_array($vip['carpif'], $carps)) {
2169
				switch ($vip['mode']) {
2170
				case "carp":
2171
					interface_vip_bring_down($vip);
2172
					sleep(1);
2173
					interface_carp_configure($vip);
2174
					break;
2175
				case "ipalias":
2176
					interface_vip_bring_down($vip);
2177
					sleep(1);
2178
					interface_ipalias_configure($vip);
2179
					break;
2180
				}
2181
			}
2182
		}
2183
	}
2184
}
2185

    
2186
function interface_carp_configure(&$vip) {
2187
	global $config, $g;
2188
	if(isset($config['system']['developerspew'])) {
2189
		$mt = microtime();
2190
		echo "interface_carp_configure() being called $mt\n";
2191
	}
2192

    
2193
	if ($vip['mode'] != "carp")
2194
		return;
2195

    
2196
	/* NOTE: Maybe its useless nowdays */
2197
	$realif = get_real_interface($vip['interface']);
2198
	if (!does_interface_exist($realif)) {
2199
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2200
		return;
2201
	}
2202

    
2203
	if (is_ipaddrv4($vip['subnet'])) {
2204
		/* Ensure a IP on this interface exists prior to configuring CARP. */
2205
		$ww_subnet_ip = find_interface_ip($realif);
2206
		if (!is_ipaddrv4($ww_subnet_ip)) {
2207
			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", "");
2208
			return;
2209
		}
2210
	} else if (is_ipaddrv6($vip['subnet'])) {
2211
		/* Ensure a IP on this interface exists prior to configuring CARP. */
2212
		$ww_subnet_ip = find_interface_ipv6($realif);
2213
		if (!is_ipaddrv6($ww_subnet_ip)) {
2214
			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", "");
2215
			return;
2216
		}
2217
	}
2218

    
2219
	$vip_password = $vip['password'];
2220
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2221
	if ($vip['password'] != "")
2222
		$password = " pass {$vip_password}";
2223

    
2224
	$advbase = "";
2225
	if (!empty($vip['advbase']))
2226
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2227

    
2228
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2229
	if ($carp_maintenancemode)
2230
		$advskew = "advskew 254";
2231
	else
2232
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2233
	
2234
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) . " {$advskew} {$advbase} {$password}");
2235

    
2236
	if (is_ipaddrv4($vip['subnet']))
2237
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2238
	else if (is_ipaddrv6($vip['subnet']))
2239
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2240

    
2241
	return $realif;
2242
}
2243

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

    
2285
	if($needs_clone == true) {
2286
		/* remove previous instance if it exists */
2287
		if(does_interface_exist($realif))
2288
			pfSense_interface_destroy($realif);
2289

    
2290
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2291
		// Create the new wlan interface. FreeBSD returns the new interface name.
2292
		// example:  wlan2
2293
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2294
		if($ret <> 0) {
2295
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2296
			return false;
2297
		}
2298
		$newif = trim($out[0]);
2299
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2300
		pfSense_interface_rename($newif, $realif);
2301
		// FIXME: not sure what ngctl is for. Doesn't work.
2302
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
2303
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2304
	}
2305
	return true;
2306
}
2307

    
2308
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2309
	global $config, $g;
2310

    
2311
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2312
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2313
				 'regdomain', 'regcountry', 'reglocation');
2314

    
2315
	if(!is_interface_wireless($ifcfg['if']))
2316
		return;
2317

    
2318
	$baseif = interface_get_wireless_base($ifcfg['if']);
2319

    
2320
	// Sync shared settings for assigned clones
2321
	$iflist = get_configured_interface_list(false, true);
2322
	foreach ($iflist as $if) {
2323
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2324
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2325
				foreach ($shared_settings as $setting) {
2326
					if ($sync_changes) {
2327
						if (isset($ifcfg['wireless'][$setting]))
2328
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2329
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2330
							unset($config['interfaces'][$if]['wireless'][$setting]);
2331
					} else {
2332
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2333
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2334
						else if (isset($ifcfg['wireless'][$setting]))
2335
							unset($ifcfg['wireless'][$setting]);
2336
					}
2337
				}
2338
				if (!$sync_changes)
2339
					break;
2340
			}
2341
		}
2342
	}
2343

    
2344
	// Read or write settings at shared area
2345
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2346
		foreach ($shared_settings as $setting) {
2347
			if ($sync_changes) {
2348
				if (isset($ifcfg['wireless'][$setting]))
2349
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2350
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2351
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2352
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2353
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2354
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2355
				else if (isset($ifcfg['wireless'][$setting]))
2356
					unset($ifcfg['wireless'][$setting]);
2357
			}
2358
		}
2359
	}
2360

    
2361
	// Sync the mode on the clone creation page with the configured mode on the interface
2362
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2363
		foreach ($config['wireless']['clone'] as &$clone) {
2364
			if ($clone['cloneif'] == $ifcfg['if']) {
2365
				if ($sync_changes) {
2366
					$clone['mode'] = $ifcfg['wireless']['mode'];
2367
				} else {
2368
					$ifcfg['wireless']['mode'] = $clone['mode'];
2369
				}
2370
				break;
2371
			}
2372
		}
2373
		unset($clone);
2374
	}
2375
}
2376

    
2377
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2378
	global $config, $g;
2379

    
2380
	/*    open up a shell script that will be used to output the commands.
2381
	 *    since wireless is changing a lot, these series of commands are fragile
2382
	 *    and will sometimes need to be verified by a operator by executing the command
2383
	 *    and returning the output of the command to the developers for inspection.  please
2384
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2385
	 */
2386

    
2387
	// Remove script file
2388
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2389

    
2390
	// Clone wireless nic if needed.
2391
	interface_wireless_clone($if, $wl);
2392

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

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

    
2400
	/* set values for /path/program */
2401
	$hostapd = "/usr/sbin/hostapd";
2402
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2403
	$ifconfig = "/sbin/ifconfig";
2404
	$sysctl = "/sbin/sysctl";
2405
	$killall = "/usr/bin/killall";
2406

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

    
2409
	$wlcmd = array();
2410
	$wl_sysctl = array();
2411
	/* Make sure it's up */
2412
	$wlcmd[] = "up";
2413
	/* Set a/b/g standard */
2414
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2415
	$wlcmd[] = "mode " . escapeshellarg($standard);
2416

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

    
2422
	/* Set ssid */
2423
	if($wlcfg['ssid'])
2424
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2425

    
2426
	/* Set 802.11g protection mode */
2427
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2428

    
2429
	/* set wireless channel value */
2430
	if(isset($wlcfg['channel'])) {
2431
		if($wlcfg['channel'] == "0") {
2432
			$wlcmd[] = "channel any";
2433
		} else {
2434
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2435
		}
2436
	}
2437

    
2438
	/* Set antenna diversity value */
2439
	if(isset($wlcfg['diversity']))
2440
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2441

    
2442
	/* Set txantenna value */
2443
	if(isset($wlcfg['txantenna']))
2444
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2445

    
2446
	/* Set rxantenna value */
2447
	if(isset($wlcfg['rxantenna']))
2448
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2449

    
2450
	/* set Distance value */
2451
	if($wlcfg['distance'])
2452
		$distance = escapeshellarg($wlcfg['distance']);
2453

    
2454
	/* Set wireless hostap mode */
2455
	if ($wlcfg['mode'] == "hostap") {
2456
		$wlcmd[] = "mediaopt hostap";
2457
	} else {
2458
		$wlcmd[] = "-mediaopt hostap";
2459
	}
2460

    
2461
	/* Set wireless adhoc mode */
2462
	if ($wlcfg['mode'] == "adhoc") {
2463
		$wlcmd[] = "mediaopt adhoc";
2464
	} else {
2465
		$wlcmd[] = "-mediaopt adhoc";
2466
	}
2467

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

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

    
2477
	/* handle pureg (802.11g) only option */
2478
	if(isset($wlcfg['pureg']['enable'])) {
2479
		$wlcmd[] = "mode 11g pureg";
2480
	} else {
2481
		$wlcmd[] = "-pureg";
2482
	}
2483

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

    
2491
	/* enable apbridge option */
2492
	if(isset($wlcfg['apbridge']['enable'])) {
2493
		$wlcmd[] = "apbridge";
2494
	} else {
2495
		$wlcmd[] = "-apbridge";
2496
	}
2497

    
2498
	/* handle turbo option */
2499
	if(isset($wlcfg['turbo']['enable'])) {
2500
		$wlcmd[] = "mediaopt turbo";
2501
	} else {
2502
		$wlcmd[] = "-mediaopt turbo";
2503
	}
2504

    
2505
	/* handle txpower setting */
2506
	/* if($wlcfg['txpower'] <> "")
2507
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2508
	*/
2509
	/* handle wme option */
2510
	if(isset($wlcfg['wme']['enable'])) {
2511
		$wlcmd[] = "wme";
2512
	} else {
2513
		$wlcmd[] = "-wme";
2514
	}
2515

    
2516
	/* set up wep if enabled */
2517
	$wepset = "";
2518
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2519
		switch($wlcfg['wpa']['auth_algs']) {
2520
			case "1":
2521
				$wepset .= "authmode open wepmode on ";
2522
				break;
2523
			case "2":
2524
				$wepset .= "authmode shared wepmode on ";
2525
				break;
2526
			case "3":
2527
				$wepset .= "authmode mixed wepmode on ";
2528
		}
2529
		$i = 1;
2530
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2531
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2532
			if (isset($wepkey['txkey'])) {
2533
				$wlcmd[] = "weptxkey {$i} ";
2534
			}
2535
			$i++;
2536
		}
2537
		$wlcmd[] = $wepset;
2538
	} else {
2539
		$wlcmd[] = "authmode open wepmode off ";
2540
	}
2541

    
2542
	kill_hostapd($if);
2543
	mwexec(kill_wpasupplicant("{$if}"));
2544

    
2545
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2546
	conf_mount_rw();
2547

    
2548
	switch ($wlcfg['mode']) {
2549
	case 'bss':
2550
		if (isset($wlcfg['wpa']['enable'])) {
2551
			$wpa .= <<<EOD
2552
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2553
ctrl_interface_group=0
2554
ap_scan=1
2555
#fast_reauth=1
2556
network={
2557
ssid="{$wlcfg['ssid']}"
2558
scan_ssid=1
2559
priority=5
2560
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2561
psk="{$wlcfg['wpa']['passphrase']}"
2562
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2563
group={$wlcfg['wpa']['wpa_pairwise']}
2564
}
2565
EOD;
2566

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

    
2601
EOD;
2602

    
2603
			if (isset($wlcfg['wpa']['rsn_preauth'])) {
2604
				$wpa .= <<<EOD
2605
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2606
rsn_preauth=1
2607
rsn_preauth_interfaces={$if}
2608

    
2609
EOD;
2610
			}
2611
			if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2612
				$wpa .= "ieee8021x=1\n";
2613

    
2614
			if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2615
				$auth_server_port = "1812";
2616
				if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port']))
2617
					$auth_server_port = intval($wlcfg['auth_server_port']);
2618
				$wpa .= <<<EOD
2619

    
2620
auth_server_addr={$wlcfg['auth_server_addr']}
2621
auth_server_port={$auth_server_port}
2622
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2623

    
2624
EOD;
2625
				if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2626
					$auth_server_port2 = "1812";
2627
					if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2']))
2628
						$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2629

    
2630
					$wpa .= <<<EOD
2631
auth_server_addr={$wlcfg['auth_server_addr2']}
2632
auth_server_port={$auth_server_port2}
2633
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2634

    
2635
EOD;
2636
					}
2637
				}
2638
			}
2639

    
2640
			@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2641
			unset($wpa);
2642
		}
2643
		break;
2644
	}
2645

    
2646
	/*
2647
	 *    all variables are set, lets start up everything
2648
	 */
2649

    
2650
	$baseif = interface_get_wireless_base($if);
2651
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2652
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2653

    
2654
	/* set sysctls for the wireless interface */
2655
	if (!empty($wl_sysctl)) {
2656
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2657
		foreach ($wl_sysctl as $wl_sysctl_line) {
2658
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2659
		}
2660
	}
2661

    
2662
	/* set ack timers according to users preference (if he/she has any) */
2663
	if($distance) {
2664
		fwrite($fd_set, "# Enable ATH distance settings\n");
2665
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2666
	}
2667

    
2668
	if (isset($wlcfg['wpa']['enable'])) {
2669
		if ($wlcfg['mode'] == "bss") {
2670
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2671
		}
2672
		if ($wlcfg['mode'] == "hostap") {
2673
			/* add line to script to restore old mac to make hostapd happy */
2674
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2675
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2676
				if (is_macaddr($if_oldmac))
2677
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2678
						" link " . escapeshellarg($if_oldmac) . "\n");
2679
			}
2680

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

    
2683
			/* add line to script to restore spoofed mac after running hostapd */
2684
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2685
				if ($wl['spoofmac'])
2686
					$if_curmac = $wl['spoofmac'];
2687
				else
2688
					$if_curmac = get_interface_mac($if);
2689
				if (is_macaddr($if_curmac))
2690
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2691
						" link " . escapeshellarg($if_curmac) . "\n");
2692
			}
2693
		}
2694
	}
2695

    
2696
	fclose($fd_set);
2697
	conf_mount_ro();
2698

    
2699
	/* Making sure regulatory settings have actually changed
2700
	 * before applying, because changing them requires bringing
2701
	 * down all wireless networks on the interface. */
2702
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2703
	$ifconfig_str = implode($output);
2704
	unset($output);
2705
	$reg_changing = false;
2706

    
2707
	/* special case for the debug country code */
2708
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2709
		$reg_changing = true;
2710
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2711
		$reg_changing = true;
2712
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2713
		$reg_changing = true;
2714
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2715
		$reg_changing = true;
2716
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2717
		$reg_changing = true;
2718

    
2719
	if ($reg_changing) {
2720
		/* set regulatory domain */
2721
		if($wlcfg['regdomain'])
2722
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2723

    
2724
		/* set country */
2725
		if($wlcfg['regcountry'])
2726
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2727

    
2728
		/* set location */
2729
		if($wlcfg['reglocation'])
2730
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2731

    
2732
		$wlregcmd_args = implode(" ", $wlregcmd);
2733

    
2734
		/* build a complete list of the wireless clones for this interface */
2735
		$clone_list = array();
2736
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2737
			$clone_list[] = interface_get_wireless_clone($baseif);
2738
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2739
			foreach ($config['wireless']['clone'] as $clone) {
2740
				if ($clone['if'] == $baseif)
2741
					$clone_list[] = $clone['cloneif'];
2742
			}
2743
		}
2744

    
2745
		/* find which clones are up and bring them down */
2746
		$clones_up = array();
2747
		foreach ($clone_list as $clone_if) {
2748
			$clone_status = pfSense_get_interface_addresses($clone_if);
2749
			if ($clone_status['status'] == 'up') {
2750
				$clones_up[] = $clone_if;
2751
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2752
			}
2753
		}
2754

    
2755
		/* apply the regulatory settings */
2756
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2757

    
2758
		/* bring the clones back up that were previously up */
2759
		foreach ($clones_up as $clone_if) {
2760
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2761

    
2762
			/*
2763
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2764
			 * is in infrastructure mode, and WPA is enabled.
2765
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2766
			 */
2767
			if ($clone_if != $if) {
2768
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2769
				if ( !empty($friendly_if)
2770
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2771
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2772
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2773
				}
2774
			}
2775
		}
2776
	}
2777

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

    
2782
	/* configure wireless */
2783
	$wlcmd_args = implode(" ", $wlcmd);
2784
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2785
	unset($wlcmd_args, $wlcmd);
2786

    
2787

    
2788
	sleep(1);
2789
	/* execute hostapd and wpa_supplicant if required in shell */
2790
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2791

    
2792
	return 0;
2793

    
2794
}
2795

    
2796
function kill_hostapd($interface) {
2797
	global $g;
2798

    
2799
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2800
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2801
}
2802

    
2803
function kill_wpasupplicant($interface) {
2804
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2805
}
2806

    
2807
function find_dhclient_process($interface) {
2808
	if ($interface)
2809
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2810
	else
2811
		$pid = 0;
2812

    
2813
	return intval($pid);
2814
}
2815

    
2816
function kill_dhclient_process($interface) {
2817
	if (empty($interface) || !does_interface_exist($interface))
2818
		return;
2819

    
2820
	$i = 0;
2821
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2822
		/* 3rd time make it die for sure */
2823
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2824
		posix_kill($pid, $sig);
2825
		sleep(1);
2826
		$i++;
2827
	}
2828
	unset($i);
2829
}
2830

    
2831
function find_dhcp6c_process($interface) {
2832
	global $g;
2833

    
2834
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid"))
2835
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2836
	else
2837
		return(false);
2838

    
2839
	return intval($pid);
2840
}
2841

    
2842
function interface_vlan_mtu_configured($realhwif, $mtu) {
2843
	global $config;
2844

    
2845
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
2846
		foreach ($config['vlans']['vlan'] as $vlan) {
2847
			if ($vlan['if'] != $realhwif)
2848
				continue;
2849
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2850
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
2851
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2852
					$mtu = $portmtu;
2853
			}
2854
		}
2855
	}
2856

    
2857
	return $mtu;
2858
}
2859

    
2860
function interface_virtual_create($interface) {
2861
	global $config;
2862

    
2863
	if (strstr($interface, "_vlan")) {
2864
		interfaces_vlan_configure($vlan);
2865
	} else if (substr($interface, 0, 3) == "gre") {
2866
		interfaces_gre_configure(0, $interface);
2867
	} else if (substr($interface, 0, 3) == "gif") {
2868
		interfaces_gif_configure(0, $interface);
2869
	} else if (substr($interface, 0, 5) == "ovpns") {
2870
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
2871
			foreach ($config['openvpn']['openvpn-server'] as $server) {
2872
				if ($interface == "ovpns{$server['vpnid']}") {
2873
					if (!function_exists('openvpn_resync'))
2874
						require_once('openvpn.inc');
2875
					log_error("OpenVPN: Resync server {$server['description']}");
2876
					openvpn_resync('server', $server);
2877
				}
2878
			}
2879
			unset($server);
2880
		}
2881
	} else if (substr($interface, 0, 5) == "ovpnc") {
2882
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
2883
			foreach ($config['openvpn']['openvpn-client'] as $client) {
2884
				if ($interface == "ovpnc{$client['vpnid']}") {
2885
					if (!function_exists('openvpn_resync'))
2886
						require_once('openvpn.inc');
2887
					log_error("OpenVPN: Resync server {$client['description']}");
2888
					openvpn_resync('client', $client);
2889
				}
2890
			}
2891
			unset($client);
2892
		}
2893
	} else if (substr($interface, 0, 4) == "lagg") {
2894
		interfaces_lagg_configure($interface);
2895
	} else if (substr($interface, 0, 6) == "bridge") {
2896
		interfaces_bridge_configure(0, $interface);
2897
	}
2898
}
2899

    
2900
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2901
	global $config;
2902

    
2903
	if (!is_array($vlanifs))
2904
		return;
2905

    
2906
	/* All vlans need to use the same mtu value as their parent. */
2907
	foreach ($vlanifs as $vlan) {
2908
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2909
		if (!empty($assignedport)) {
2910
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
2911
				/*
2912
				* XXX: This is really never going to happen just keep the code for safety and readbility.
2913
				* It never happens since interface_vlan_mtu_configured finds the biggest mtu on vlans.
2914
				* Also if it has a lower mtu configured just respect user choice.
2915
				*/
2916
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2917
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2918
			} else {
2919
				if (get_interface_mtu($vlan['vlanif']) != $mtu)
2920
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2921
			}
2922
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2923
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
2924
	}
2925
}
2926

    
2927
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2928
	global $config, $g;
2929
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2930
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2931

    
2932
	$wancfg = $config['interfaces'][$interface];
2933

    
2934
	if (!isset($wancfg['enable']))
2935
		return;
2936

    
2937
	$realif = get_real_interface($interface);
2938
	$realhwif_array = get_parent_interface($interface);
2939
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2940
	$realhwif = $realhwif_array[0];
2941

    
2942
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2943
		/* remove all IPv4 and IPv6 addresses */
2944
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2945
		if (is_array($tmpifaces)) {
2946
			foreach ($tmpifaces as $tmpiface) {
2947
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
2948
					if (!is_linklocal($tmpiface))
2949
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2950
				} else {
2951
					if (is_subnetv4($tmpiface)) {
2952
						$tmpip = explode('/', $tmpiface);
2953
						$tmpip = $tmpip[0];
2954
					} else
2955
						$tmpip = $tmpiface;
2956
					pfSense_interface_deladdress($realif, $tmpip);
2957
				}
2958
			}
2959
		}
2960

    
2961
		/* only bring down the interface when both v4 and v6 are set to NONE */
2962
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6']))
2963
			interface_bring_down($interface);
2964
	}
2965

    
2966
	$interface_to_check = $realif;
2967
	switch ($wancfg['ipaddr']) {
2968
	case 'pppoe':
2969
	case 'l2tp':
2970
	case 'pptp':
2971
	case 'ppp':
2972
		$interface_to_check = $realhwif;
2973
		break;
2974
	}
2975

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

    
2980
	/* Disable Accepting router advertisements unless specifically requested */
2981
	if ($g['debug'])
2982
		log_error("Deny router advertisements for interface {$interface}");
2983
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2984

    
2985
	/* wireless configuration? */
2986
	if (is_array($wancfg['wireless']))
2987
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2988

    
2989
	$mac = get_interface_mac($realhwif);
2990
	/*
2991
	 * Don't try to reapply the spoofed MAC if it's already applied.
2992
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
2993
	 * the interface config again, which attempts to spoof the MAC again,
2994
	 * which cycles the link again...
2995
	 */
2996
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
2997
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2998
			" link " . escapeshellarg($wancfg['spoofmac']));
2999

    
3000
		/*
3001
		 * All vlans need to spoof their parent mac address, too.  see
3002
		 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
3003
		 */
3004
		if (is_array($config['vlans']['vlan'])) {
3005
			foreach ($config['vlans']['vlan'] as $vlan) {
3006
				if ($vlan['if'] == $realhwif)
3007
					mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
3008
					" link " . escapeshellarg($wancfg['spoofmac']));
3009
			}
3010
		}
3011
	}  else {
3012

    
3013
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3014
			/*   this is not a valid mac address.  generate a
3015
			 *   temporary mac address so the machine can get online.
3016
			 */
3017
			echo gettext("Generating new MAC address.");
3018
			$random_mac = generate_random_mac_address();
3019
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3020
				" link " . escapeshellarg($random_mac));
3021
			$wancfg['spoofmac'] = $random_mac;
3022
			write_config();
3023
			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");
3024
		}
3025
	}
3026

    
3027
	/* media */
3028
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3029
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3030
		if ($wancfg['media'])
3031
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3032
		if ($wancfg['mediaopt'])
3033
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3034
		mwexec($cmd);
3035
	}
3036
	$options = pfSense_get_interface_addresses($realhwif);
3037

    
3038
	/* skip vlans for checksumming and polling */
3039
	if (!stristr($realif, "_vlan") && is_array($options)) {
3040
		$flags_on = 0;
3041
		$flags_off = 0;
3042
		if(isset($config['system']['disablechecksumoffloading'])) {
3043
			if (isset($options['encaps']['txcsum']))
3044
				$flags_off |= IFCAP_TXCSUM;
3045
			if (isset($options['encaps']['rxcsum']))
3046
				$flags_off |= IFCAP_RXCSUM;
3047
		} else {
3048
			if (isset($options['caps']['txcsum']))
3049
				$flags_on |= IFCAP_TXCSUM;
3050
			if (isset($options['caps']['rxcsum']))
3051
				$flags_on |= IFCAP_RXCSUM;
3052
		}
3053

    
3054
		if(isset($config['system']['disablesegmentationoffloading']))
3055
			$flags_off |= IFCAP_TSO;
3056
		else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6']))
3057
			$flags_on |= IFCAP_TSO;
3058

    
3059
		if(isset($config['system']['disablelargereceiveoffloading']))
3060
			$flags_off |= IFCAP_LRO;
3061
		else if (isset($options['caps']['lro']))
3062
			$flags_on |= IFCAP_LRO;
3063

    
3064
		/* if the NIC supports polling *AND* it is enabled in the GUI */
3065
		if (!isset($config['system']['polling']))
3066
			$flags_off |= IFCAP_POLLING;
3067
		else if (isset($options['caps']['polling']))
3068
			$flags_on |= IFCAP_POLLING;
3069

    
3070
		pfSense_interface_capabilities($realhwif, -$flags_off);
3071
		pfSense_interface_capabilities($realhwif, $flags_on);
3072
	}
3073

    
3074
	/* invalidate interface/ip/sn cache */
3075
	get_interface_arr(true);
3076
	unset($interface_ip_arr_cache[$realif]);
3077
	unset($interface_sn_arr_cache[$realif]);
3078
	unset($interface_ipv6_arr_cache[$realif]);
3079
	unset($interface_snv6_arr_cache[$realif]);
3080

    
3081
	$tunnelif = substr($realif, 0, 3);
3082
	switch ($wancfg['ipaddr']) {
3083
	case 'dhcp':
3084
		interface_dhcp_configure($interface);
3085
		break;
3086
	case 'pppoe':
3087
	case 'l2tp':
3088
	case 'pptp':
3089
	case 'ppp':
3090
		interface_ppps_configure($interface);
3091
		break;
3092
	default:
3093
		/* XXX: Kludge for now related to #3280 */
3094
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3095
			if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "")
3096
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3097
		}
3098
		break;
3099
	}
3100

    
3101
	switch ($wancfg['ipaddrv6']) {
3102
	case 'slaac':
3103
	case 'dhcp6':
3104
		interface_dhcpv6_configure($interface, $wancfg);
3105
		break;
3106
	case '6rd':
3107
		interface_6rd_configure($interface, $wancfg);
3108
		break;
3109
	case '6to4':
3110
		interface_6to4_configure($interface, $wancfg);
3111
		break;
3112
	case 'track6':
3113
		interface_track6_configure($interface, $wancfg, $linkupevent);
3114
		break;
3115
	default:
3116
		/* XXX: Kludge for now related to #3280 */
3117
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3118
			if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3119
				//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3120
				// FIXME: Add IPv6 Support to the pfSense module
3121
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3122
			}
3123
		}
3124
		break;
3125
	}
3126

    
3127
	if (!empty($wancfg['mtu'])) {
3128
		if (stristr($realif, "_vlan")) {
3129
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3130
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
3131
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3132
			else
3133
				$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
3134

    
3135
			if ($wancfg['mtu'] > $parentmtu) {
3136
				if (get_interface_mtu($realhwif) != $wancfg['mtu'])
3137
					pfSense_interface_mtu($realhwif, $wancfg['mtu']);
3138

    
3139
				/* All vlans need to use the same mtu value as their parent. */
3140
				interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $wancfg['mtu']);
3141
			} else
3142
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3143
		} else if (substr($realif, 0, 4) == 'lagg') {
3144
			/* LAGG interface must be destroyed and re-created to change MTU */
3145
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3146
				if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3147
					foreach ($config['laggs']['lagg'] as $lagg) {
3148
						if ($lagg['laggif'] == $realif) {
3149
							interface_lagg_configure($lagg);
3150
							break;
3151
						}
3152
					}
3153
				}
3154
			}
3155
		} else {
3156
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3157
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3158

    
3159
			/* This case is needed when the parent of vlans is being configured */
3160
			interface_vlan_adapt_mtu(link_interface_to_vlans($realif), $wancfg['mtu']);
3161
		}
3162
		/* XXX: What about gre/gif/.. ? */
3163
	}
3164

    
3165
	if (does_interface_exist($wancfg['if']))
3166
		interfaces_bring_up($wancfg['if']);
3167

    
3168
	interface_netgraph_needed($interface);
3169

    
3170
	if (!$g['booting']) {
3171
		link_interface_to_vips($interface, "update");
3172

    
3173
		unset($gre);
3174
		$gre = link_interface_to_gre($interface);
3175
		if (!empty($gre))
3176
			array_walk($gre, 'interface_gre_configure');
3177

    
3178
		unset($gif);
3179
		$gif = link_interface_to_gif($interface);
3180
		if (!empty($gif))
3181
			array_walk($gif, 'interface_gif_configure');
3182

    
3183
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3184
			unset($bridgetmp);
3185
			$bridgetmp = link_interface_to_bridge($interface);
3186
			if (!empty($bridgetmp))
3187
				interface_bridge_add_member($bridgetmp, $realif);
3188
		}
3189

    
3190
		$grouptmp = link_interface_to_group($interface);
3191
		if (!empty($grouptmp))
3192
			array_walk($grouptmp, 'interface_group_add_member');
3193

    
3194
		if ($interface == "lan")
3195
			/* make new hosts file */
3196
			system_hosts_generate();
3197

    
3198
		if ($reloadall == true) {
3199

    
3200
			/* reconfigure static routes (kernel may have deleted them) */
3201
			system_routing_configure($interface);
3202

    
3203
			/* reload ipsec tunnels */
3204
			vpn_ipsec_configure();
3205

    
3206
			/* restart dnsmasq or unbound */
3207
			if (isset($config['dnsmasq']['enable']))
3208
				services_dnsmasq_configure();
3209
			elseif (isset($config['unbound']['enable']))
3210
				services_unbound_configure();
3211

    
3212
			/* update dyndns */
3213
			send_event("service reload dyndns {$interface}");
3214

    
3215
			/* XXX: which CPZONE? Needed? */
3216
			/* reload captive portal */
3217
			captiveportal_init_rules();
3218
		}
3219
	}
3220

    
3221
	interfaces_staticarp_configure($interface);
3222
	return 0;
3223
}
3224

    
3225
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3226
	global $config, $g;
3227

    
3228
	if (!is_array($wancfg))
3229
		return;
3230

    
3231
	if (!isset($wancfg['enable']))
3232
		return;
3233

    
3234
	/* If the interface is not configured via another, exit */
3235
	if (empty($wancfg['track6-interface']))
3236
		return;
3237

    
3238
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3239
	$realif = get_real_interface($interface);
3240
	$linklocal = find_interface_ipv6_ll($realif);
3241
	if (!empty($linklocal))
3242
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3243
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3244
	/* XXX: Probably should remove? */
3245
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3246

    
3247
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3248
	if (!isset($trackcfg['enable'])) {
3249
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3250
		return;
3251
	}
3252

    
3253
	switch($trackcfg['ipaddrv6']) {
3254
	case "6to4":
3255
		if ($g['debug'])
3256
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3257
		interface_track6_6to4_configure($interface, $wancfg);
3258
		break;
3259
	case "6rd":
3260
		if ($g['debug'])
3261
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3262
		interface_track6_6rd_configure($interface, $wancfg);
3263
		break;
3264
	case "dhcp6":
3265
		if ($linkupevent == true) {
3266
			/* 
3267
			 * NOTE: Usually come here from rc.linkup calling so just call directly intead of generating event
3268
			 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3269
			 *
3270
			 * XXX: Probably DHCPv6 client should handle this autmagically itself?
3271
			 */
3272
			$parentrealif = get_real_interface($wancfg['track6-interface']);
3273
			$pidv6 = find_dhcp6c_process($parentrealif);
3274
			if($pidv6)
3275
				posix_kill($pidv6, SIGHUP);
3276
		}
3277
		break;
3278
	}
3279

    
3280
	if (!$g['booting'] && $linkupevent == false) {
3281
		if (!function_exists('services_dhcpd_configure'))
3282
			require_once("services.inc");
3283

    
3284
		services_dhcpd_configure("inet6");
3285
	}
3286

    
3287
	return 0;
3288
}
3289

    
3290
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3291
	global $config, $g;
3292
	global $interface_ipv6_arr_cache;
3293
	global $interface_snv6_arr_cache;
3294

    
3295
	if (!is_array($lancfg))
3296
		return;
3297

    
3298
	/* If the interface is not configured via another, exit */
3299
	if (empty($lancfg['track6-interface']))
3300
		return;
3301

    
3302
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3303
	if (empty($wancfg)) {
3304
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3305
		return;
3306
	}
3307

    
3308
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3309
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3310
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3311
		return;
3312
	}
3313
	$hexwanv4 = return_hex_ipv4($ip4address);
3314

    
3315
	/* create the long prefix notation for math, save the prefix length */
3316
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3317
	$rd6prefixlen = $rd6prefix[1];
3318
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3319

    
3320
	/* binary presentation of the prefix for all 128 bits. */
3321
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3322

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

    
3328
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3329
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3330
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3331
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3332
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3333
	/* fill the rest out with zeros */
3334
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3335

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

    
3339
	$lanif = get_real_interface($interface);
3340
	$oip = find_interface_ipv6($lanif);
3341
	if (is_ipaddrv6($oip))
3342
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3343
	unset($interface_ipv6_arr_cache[$lanif]);
3344
	unset($interface_snv6_arr_cache[$lanif]);
3345
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3346
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3347

    
3348
	return 0;
3349
}
3350

    
3351
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3352
	global $config, $g;
3353
	global $interface_ipv6_arr_cache;
3354
	global $interface_snv6_arr_cache;
3355

    
3356
	if (!is_array($lancfg))
3357
		return;
3358

    
3359
	/* If the interface is not configured via another, exit */
3360
	if (empty($lancfg['track6-interface']))
3361
		return;
3362

    
3363
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3364
	if (empty($wancfg)) {
3365
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3366
		return;
3367
	}
3368

    
3369
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3370
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3371
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3372
		return;
3373
	}
3374
	$hexwanv4 = return_hex_ipv4($ip4address);
3375

    
3376
	/* create the long prefix notation for math, save the prefix length */
3377
	$sixto4prefix = "2002::";
3378
	$sixto4prefixlen = 16;
3379
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3380

    
3381
	/* binary presentation of the prefix for all 128 bits. */
3382
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3383

    
3384
	/* just save the left prefix length bits */
3385
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3386
	/* add the v4 address */
3387
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3388
	/* add the custom prefix id */
3389
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3390
	/* fill the rest out with zeros */
3391
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3392

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

    
3396
	$lanif = get_real_interface($interface);
3397
	$oip = find_interface_ipv6($lanif);
3398
	if (is_ipaddrv6($oip))
3399
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3400
	unset($interface_ipv6_arr_cache[$lanif]);
3401
	unset($interface_snv6_arr_cache[$lanif]);
3402
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3403
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3404

    
3405
	return 0;
3406
}
3407

    
3408
function interface_6rd_configure($interface = "wan", $wancfg) {
3409
	global $config, $g;
3410

    
3411
	/* because this is a tunnel interface we can only function
3412
	 *	with a public IPv4 address on the interface */
3413

    
3414
	if (!is_array($wancfg))
3415
		return;
3416

    
3417
	if (!is_module_loaded('if_stf.ko'))
3418
		mwexec('/sbin/kldload if_stf.ko');
3419

    
3420
	$wanif = get_real_interface($interface);
3421
	$ip4address = find_interface_ip($wanif);
3422
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3423
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3424
		return false;
3425
	}
3426
	$hexwanv4 = return_hex_ipv4($ip4address);
3427

    
3428
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3429
		$wancfg['prefix-6rd-v4plen'] = 0;
3430

    
3431
	/* create the long prefix notation for math, save the prefix length */
3432
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3433
	$rd6prefixlen = $rd6prefix[1];
3434
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3435

    
3436
	/* binary presentation of the prefix for all 128 bits. */
3437
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3438

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

    
3446
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3447
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3448

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

    
3451
	/* XXX: need to extend to support variable prefix size for v4 */
3452
	if (!is_module_loaded("if_stf"))
3453
		mwexec("/sbin/kldload if_stf.ko");
3454
	$stfiface = "{$interface}_stf";
3455
	if (does_interface_exist($stfiface))
3456
		pfSense_interface_destroy($stfiface);
3457
	$tmpstfiface = pfSense_interface_create("stf");
3458
	pfSense_interface_rename($tmpstfiface, $stfiface);
3459
	pfSense_interface_flags($stfiface, IFF_LINK2);
3460
	if ($wancfg['prefix-6rd-v4plen'] > 0)
3461
		$rd6prefixlen += intval($wancfg['prefix-6rd-v4plen']);
3462
	else
3463
		$rd6prefixlen += 32;
3464
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3465
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3466
	if ($wancfg['prefix-6rd-v4plen'] > 0 && $wancfg['prefix-6rd-v4plen'] < 32)
3467
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/{$wancfg['prefix-6rd-v4plen']}");
3468
	if ($g['debug'])
3469
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3470

    
3471
	/* write out a default router file */
3472
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3473
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3474

    
3475
	$ip4gateway = get_interface_gateway($interface);
3476
	if (is_ipaddrv4($ip4gateway))
3477
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3478

    
3479
	/* configure dependent interfaces */
3480
	if (!$g['booting'])
3481
		link_interface_to_track6($interface, "update");
3482

    
3483
	return 0;
3484
}
3485

    
3486
function interface_6to4_configure($interface = "wan", $wancfg){
3487
	global $config, $g;
3488

    
3489
	/* because this is a tunnel interface we can only function
3490
	 *	with a public IPv4 address on the interface */
3491

    
3492
	if (!is_array($wancfg))
3493
		return;
3494

    
3495
	$wanif = get_real_interface($interface);
3496
	$ip4address = find_interface_ip($wanif);
3497
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3498
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3499
		return false;
3500
	}
3501

    
3502
	/* create the long prefix notation for math, save the prefix length */
3503
	$stfprefixlen = 16;
3504
	$stfprefix = Net_IPv6::uncompress("2002::");
3505
	$stfarr = explode(":", $stfprefix);
3506
	$v4prefixlen = "0";
3507

    
3508
	/* we need the hex form of the interface IPv4 address */
3509
	$ip4arr = explode(".", $ip4address);
3510
	$hexwanv4 = "";
3511
	foreach($ip4arr as $octet)
3512
		$hexwanv4 .= sprintf("%02x", $octet);
3513

    
3514
	/* we need the hex form of the broker IPv4 address */
3515
	$ip4arr = explode(".", "192.88.99.1");
3516
	$hexbrv4 = "";
3517
	foreach($ip4arr as $octet)
3518
		$hexbrv4 .= sprintf("%02x", $octet);
3519

    
3520
	/* binary presentation of the prefix for all 128 bits. */
3521
	$stfprefixbin = "";
3522
	foreach($stfarr as $element) {
3523
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3524
	}
3525
	/* just save the left prefix length bits */
3526
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3527

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

    
3532
	/* for the local subnet too. */
3533
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3534
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3535

    
3536
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3537
	$stfbrarr = array();
3538
	$stfbrbinarr = array();
3539
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3540
	foreach($stfbrbinarr as $bin)
3541
		$stfbrarr[] = dechex(bindec($bin));
3542
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3543

    
3544
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3545
	$stflanarr = array();
3546
	$stflanbinarr = array();
3547
	$stflanbinarr = str_split($stflanbin, 16);
3548
	foreach($stflanbinarr as $bin)
3549
		$stflanarr[] = dechex(bindec($bin));
3550
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3551
	$stflanarr[7] = 1;
3552
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3553

    
3554
	/* setup the stf interface */
3555
	if (!is_module_loaded("if_stf"))
3556
		mwexec("/sbin/kldload if_stf.ko");
3557
	$stfiface = "{$interface}_stf";
3558
	if (does_interface_exist($stfiface))
3559
		pfSense_interface_destroy($stfiface);
3560
	$tmpstfiface = pfSense_interface_create("stf");
3561
	pfSense_interface_rename($tmpstfiface, $stfiface);
3562
	pfSense_interface_flags($stfiface, IFF_LINK2);
3563
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3564

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

    
3568
	/* write out a default router file */
3569
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3570
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3571

    
3572
	$ip4gateway = get_interface_gateway($interface);
3573
	if (is_ipaddrv4($ip4gateway))
3574
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3575

    
3576
	if (!$g['booting'])
3577
		link_interface_to_track6($interface, "update");
3578

    
3579
	return 0;
3580
}
3581

    
3582
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3583
	global $config, $g;
3584

    
3585
	if (!is_array($wancfg))
3586
		return;
3587

    
3588
	$wanif = get_real_interface($interface, "inet6");
3589
	$dhcp6cconf = "";
3590
	$dhcp6cconf .= "interface {$wanif} {\n";
3591

    
3592
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3593
	if($wancfg['ipaddrv6'] == "slaac") {
3594
		$dhcp6cconf .= "	information-only;\n";
3595
		$dhcp6cconf .= "	request domain-name-servers;\n";
3596
		$dhcp6cconf .= "	request domain-name;\n";
3597
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3598
		$dhcp6cconf .= "};\n";
3599
	} else {
3600
		/* skip address request if this is set */
3601
		if(!isset($wancfg['dhcp6prefixonly']))
3602
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3603
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3604
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3605

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

    
3610
		$dhcp6cconf .= "};\n";
3611

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

    
3615
		if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3616
			/* Setup the prefix delegation */
3617
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3618
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3619
			if (isset($wancfg['dhcp6-ia-pd-send-hint']))
3620
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3621
			$iflist = link_interface_to_track6($interface);
3622
			foreach ($iflist as $friendly => $ifcfg) {
3623
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3624
					if ($g['debug'])
3625
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3626
					$realif = get_real_interface($friendly);
3627
					$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3628
					$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3629
					$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3630
					$dhcp6cconf .= "	};\n";
3631
				}
3632
			}
3633
			unset($preflen, $iflist, $ifcfg);
3634
			$dhcp6cconf .= "};\n";
3635
		}
3636
	}
3637

    
3638
	// DHCP6 Config File Advanced
3639
	if ($wancfg['adv_dhcp6_config_advanced']) { $dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif); }
3640

    
3641
	// DHCP6 Config File Override
3642
	if ($wancfg['adv_dhcp6_config_file_override']) { $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif); }
3643

    
3644
	/* wide-dhcp6c works for now. */
3645
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3646
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3647
		unset($dhcp6cconf);
3648
		return 1;
3649
	}
3650
	unset($dhcp6cconf);
3651

    
3652
	$dhcp6cscript = "#!/bin/sh\n";
3653
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3654
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3655
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3656
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3657
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3658
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3659
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3660
		unset($dhcp6cscript);
3661
		return 1;
3662
	}
3663
	unset($dhcp6cscript);
3664
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3665

    
3666
	$rtsoldscript = "#!/bin/sh\n";
3667
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3668
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3669
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3670
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3671
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3672
	$rtsoldscript .= "\t/bin/sleep 1\n";
3673
	$rtsoldscript .= "fi\n";
3674
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3675
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3676
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3677
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3678
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3679
		unset($rtsoldscript);
3680
		return 1;
3681
	}
3682
	unset($rtsoldscript);
3683
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3684

    
3685
	/* accept router advertisements for this interface */
3686
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3687
	log_error("Accept router advertisements on interface {$wanif} ");
3688
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3689

    
3690
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3691
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3692
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3693
		sleep(2);
3694
	}
3695
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3696

    
3697
	/* NOTE: will be called from rtsold invoked script
3698
	 * link_interface_to_track6($interface, "update");
3699
	 */
3700

    
3701
	return 0;
3702
}
3703

    
3704
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3705
	global $g;
3706

    
3707
	$send_options = "";
3708
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3709
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_send_options']);
3710
		foreach ($options as $option) {
3711
			$send_options .= "\tsend " . trim($option) . ";\n";
3712
		}
3713
	}
3714

    
3715
	$request_options = "";
3716
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3717
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_request_options']);
3718
		foreach ($options as $option) {
3719
			$request_options .= "\trequest " . trim($option) . ";\n";
3720
		}
3721
	}
3722

    
3723
	$information_only = "";
3724
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') 
3725
		$information_only = "\tinformation-only;\n";
3726

    
3727
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3728
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '')
3729
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3730

    
3731
	$interface_statement  = "interface";
3732
	$interface_statement .= " {$wanif}";
3733
	$interface_statement .= " {\n";
3734
	$interface_statement .= "$send_options";
3735
	$interface_statement .= "$request_options";
3736
	$interface_statement .= "$information_only";
3737
	$interface_statement .= "$script";
3738
	$interface_statement .= "};\n";
3739

    
3740
	$id_assoc_statement_address = "";
3741
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3742
		$id_assoc_statement_address .= "id-assoc";
3743
		$id_assoc_statement_address .= " na";
3744
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) 
3745
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3746
		$id_assoc_statement_address .= " { ";
3747

    
3748
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') && 
3749
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) || 
3750
			 ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity')) ) {
3751
			$id_assoc_statement_address .= "\n\taddress";
3752
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3753
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3754
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) || 
3755
							($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity') ) 
3756
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3757
			$id_assoc_statement_address .= ";\n";
3758
		}
3759

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

    
3763
	$id_assoc_statement_prefix = "";
3764
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3765
		$id_assoc_statement_prefix .= "id-assoc";
3766
		$id_assoc_statement_prefix .= " pd";
3767
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) 
3768
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3769
		$id_assoc_statement_prefix .= " { ";
3770

    
3771
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') && 
3772
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) || 
3773
			 ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity')) ) {
3774
			$id_assoc_statement_prefix .= "\n\tprefix";
3775
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3776
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3777
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) || 
3778
						  ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity') ) 
3779
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3780
			$id_assoc_statement_prefix .= ";";
3781
		}
3782

    
3783
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3784
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3785
			$id_assoc_statement_prefix .= " {$wanif}";
3786
			$id_assoc_statement_prefix .= " {\n";
3787
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3788
			if ( ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) && 
3789
				 ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128) ) 
3790
				 $id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3791
			$id_assoc_statement_prefix .= "\t};";
3792
		}
3793

    
3794
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') || 
3795
			 (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) ) { 
3796
			$id_assoc_statement_prefix .= "\n";
3797
		}
3798

    
3799
		$id_assoc_statement_prefix  .= "};\n";
3800
	}
3801

    
3802
	$authentication_statement = "";
3803
	if ( ($wancfg['adv_dhcp6_authentication_statement_authname'] != '') && 
3804
		 ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed') ) {
3805
		$authentication_statement .= "authentication";
3806
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
3807
		$authentication_statement .= " {\n";
3808
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
3809
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) 
3810
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
3811
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') 
3812
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
3813
		$authentication_statement .= "};\n";
3814
	}
3815

    
3816
	$key_info_statement = "";
3817
	if ( ($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') && 
3818
		 ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') && 
3819
		 (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) && 
3820
		 ($wancfg['adv_dhcp6_key_info_statement_secret'] != '') ) {
3821
		$key_info_statement .= "keyinfo";
3822
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
3823
		$key_info_statement .= " {\n";
3824
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
3825
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
3826
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
3827
		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'])) 
3828
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
3829
		$key_info_statement .= "};\n";
3830
	}
3831

    
3832
	$dhcp6cconf  = $interface_statement;
3833
	$dhcp6cconf .= $id_assoc_statement_address;
3834
	$dhcp6cconf .= $id_assoc_statement_prefix;
3835
	$dhcp6cconf .= $authentication_statement;
3836
	$dhcp6cconf .= $key_info_statement;
3837

    
3838
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3839

    
3840
	return $dhcp6cconf;
3841
}
3842

    
3843

    
3844
function DHCP6_Config_File_Override($wancfg, $wanif) {
3845

    
3846
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
3847
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3848

    
3849
	return $dhcp6cconf;
3850
}
3851

    
3852

    
3853
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
3854

    
3855
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3856

    
3857
	return $dhcp6cconf;
3858
}
3859

    
3860

    
3861
function interface_dhcp_configure($interface = "wan") {
3862
	global $config, $g;
3863

    
3864
	$wancfg = $config['interfaces'][$interface];
3865
	$wanif = $wancfg['if'];
3866
	if (empty($wancfg))
3867
		$wancfg = array();
3868

    
3869
	/* generate dhclient_wan.conf */
3870
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3871
	if (!$fd) {
3872
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3873
		return 1;
3874
	}
3875

    
3876
	if ($wancfg['dhcphostname']) {
3877
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3878
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3879
	} else {
3880
		$dhclientconf_hostname = "";
3881
	}
3882

    
3883
	$wanif = get_real_interface($interface);
3884
	if (empty($wanif)) {
3885
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3886
		return 0;
3887
	}
3888
	$dhclientconf = "";
3889

    
3890
	$dhclientconf .= <<<EOD
3891
interface "{$wanif}" {
3892
timeout 60;
3893
retry 15;
3894
select-timeout 0;
3895
initial-interval 1;
3896
	{$dhclientconf_hostname}
3897
	script "/sbin/dhclient-script";
3898
EOD;
3899

    
3900
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3901
	$dhclientconf .= <<<EOD
3902

    
3903
	reject {$wancfg['dhcprejectfrom']};
3904
EOD;
3905
}
3906
	$dhclientconf .= <<<EOD
3907

    
3908
}
3909

    
3910
EOD;
3911

    
3912
	// DHCP Config File Advanced
3913
	if ($wancfg['adv_dhcp_config_advanced']) { $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif); }
3914

    
3915
if(is_ipaddr($wancfg['alias-address'])) {
3916
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3917
	$dhclientconf .= <<<EOD
3918
alias {
3919
	interface  "{$wanif}";
3920
	fixed-address {$wancfg['alias-address']};
3921
	option subnet-mask {$subnetmask};
3922
}
3923

    
3924
EOD;
3925
}
3926

    
3927
	// DHCP Config File Override
3928
	if ($wancfg['adv_dhcp_config_file_override']) { $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif); }
3929

    
3930
	fwrite($fd, $dhclientconf);
3931
	fclose($fd);
3932

    
3933
	/* bring wan interface up before starting dhclient */
3934
	if($wanif)
3935
		interfaces_bring_up($wanif);
3936
	else
3937
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3938

    
3939
	/* Make sure dhclient is not running */
3940
	kill_dhclient_process($wanif);
3941

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

    
3945
	return 0;
3946
}
3947

    
3948
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3949

    
3950
	$hostname = "";
3951
	if ($wancfg['dhcphostname'] != '') {
3952
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3953
	}
3954

    
3955
	/* DHCP Protocol Timings */
3956
	$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");
3957
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
3958
		$pt_variable = "{$Protocol_Timing}";
3959
		${$pt_variable} = "";
3960
		if ($wancfg[$Protocol_Timing] != "") {
3961
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
3962
		}
3963
	}
3964

    
3965
	$send_options = "";
3966
	if ($wancfg['adv_dhcp_send_options'] != '') {
3967
		$options = split(",", $wancfg['adv_dhcp_send_options']);
3968
		foreach ($options as $option) {
3969
			$send_options .= "\tsend " . trim($option) . ";\n";
3970
		}
3971
	}
3972

    
3973
	$request_options = "";
3974
	if ($wancfg['adv_dhcp_request_options'] != '') {
3975
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
3976
	}
3977

    
3978
	$required_options = "";
3979
	if ($wancfg['adv_dhcp_required_options'] != '') {
3980
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
3981
	}
3982

    
3983
	$option_modifiers = "";
3984
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
3985
		$modifiers = split(",", $wancfg['adv_dhcp_option_modifiers']);
3986
		foreach ($modifiers as $modifier) {
3987
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
3988
		}
3989
	}
3990

    
3991
 	$dhclientconf  = "interface \"{$wanif}\" {\n";
3992
 	$dhclientconf .= "\n";
3993
 	$dhclientconf .= "# DHCP Protocol Timing Values\n";
3994
 	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
3995
 	$dhclientconf .= "{$adv_dhcp_pt_retry}";
3996
 	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
3997
 	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
3998
 	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
3999
 	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4000
 	$dhclientconf .= "\n";
4001
 	$dhclientconf .= "# DHCP Protocol Options\n";
4002
 	$dhclientconf .= "{$hostname}";
4003
 	$dhclientconf .= "{$send_options}";
4004
 	$dhclientconf .= "{$request_options}";
4005
 	$dhclientconf .= "{$required_options}";
4006
 	$dhclientconf .= "{$option_modifiers}";
4007
 	$dhclientconf .= "\n";
4008
 	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4009
 	$dhclientconf .= "}\n";
4010

    
4011
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4012

    
4013
	return $dhclientconf;
4014
}
4015

    
4016

    
4017
function DHCP_Config_File_Override($wancfg, $wanif) {
4018

    
4019
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4020
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4021

    
4022
	return $dhclientconf;
4023
}
4024

    
4025

    
4026
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4027

    
4028
	/* Apply Interface Substitutions */
4029
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4030

    
4031
	/* Apply Hostname Substitutions */
4032
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4033

    
4034
	/* Arrays of MAC Address Types, Cases, Delimiters */
4035
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4036
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4037
	$various_mac_cases      = array("U", "L");
4038
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4039

    
4040
	/* Apply MAC Address Substitutions */
4041
	foreach ($various_mac_types as $various_mac_type) {
4042
		foreach ($various_mac_cases as $various_mac_case) {
4043
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4044

    
4045
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4046
				if ($res !== false) {
4047

    
4048
					/* Get MAC Address as ASCII String With Colon (:) Celimiters */
4049
					if ("$various_mac_case" == "U") $dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4050
					if ("$various_mac_case" == "L") $dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4051

    
4052
					if ("$various_mac_type" == "mac_addr_hex") {
4053
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4054
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4055
						$dhcpclientconf_mac_hex = "";
4056
						$delimiter = "";
4057
						for($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4058
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4059
							$delimiter = ":";
4060
						}
4061
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4062
					}
4063

    
4064
					/* MAC Address Delimiter Substitutions */
4065
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4066

    
4067
					/* Apply MAC Address Substitutions */
4068
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4069
				}
4070
			}
4071
		}
4072
	}
4073

    
4074
	return $dhclientconf;
4075
}
4076

    
4077
function interfaces_group_setup() {
4078
	global $config;
4079

    
4080
	if (!is_array($config['ifgroups']['ifgroupentry']))
4081
		return;
4082

    
4083
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
4084
		interface_group_setup($groupar);
4085

    
4086
	return;
4087
}
4088

    
4089
function interface_group_setup(&$groupname /* The parameter is an array */) {
4090
	global $config;
4091

    
4092
	if (!is_array($groupname))
4093
		return;
4094
	$members = explode(" ", $groupname['members']);
4095
	foreach($members as $ifs) {
4096
		$realif = get_real_interface($ifs);
4097
		if ($realif)
4098
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4099
	}
4100

    
4101
	return;
4102
}
4103

    
4104
function is_interface_group($if) {
4105
	global $config;
4106

    
4107
	if (is_array($config['ifgroups']['ifgroupentry']))
4108
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4109
			if ($groupentry['ifname'] === $if)
4110
				return true;
4111
		}
4112

    
4113
	return false;
4114
}
4115

    
4116
function interface_group_add_member($interface, $groupname) {
4117
	$interface = get_real_interface($interface);
4118
	mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4119
}
4120

    
4121
/* COMPAT Function */
4122
function convert_friendly_interface_to_real_interface_name($interface) {
4123
	return get_real_interface($interface);
4124
}
4125

    
4126
/* COMPAT Function */
4127
function get_real_wan_interface($interface = "wan") {
4128
	return get_real_interface($interface);
4129
}
4130

    
4131
/* COMPAT Function */
4132
function get_current_wan_address($interface = "wan") {
4133
	return get_interface_ip($interface);
4134
}
4135

    
4136
/*
4137
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4138
 */
4139
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
4140
	global $config;
4141

    
4142
	/* XXX: For speed reasons reference directly the interface array */
4143
	$ifdescrs = &$config['interfaces'];
4144
	//$ifdescrs = get_configured_interface_list(false, true);
4145

    
4146
	foreach ($ifdescrs as $if => $ifname) {
4147
		if ($if == $interface || $ifname['if'] == $interface)
4148
			return $if;
4149

    
4150
		if (get_real_interface($if) == $interface)
4151
			return $if;
4152

    
4153
		$int = get_parent_interface($if, true);
4154
		if (is_array($int)) {
4155
			foreach ($int as $iface) {
4156
				if ($iface == $interface)
4157
					return $if;
4158
			}
4159
		}
4160
	}
4161

    
4162
	if ($interface == "enc0")
4163
		return 'IPsec';
4164

    
4165
	return NULL;
4166
}
4167

    
4168
/* attempt to resolve interface to friendly descr */
4169
function convert_friendly_interface_to_friendly_descr($interface) {
4170
	global $config;
4171

    
4172
	switch ($interface) {
4173
	case "l2tp":
4174
		$ifdesc = "L2TP";
4175
		break;
4176
	case "pptp":
4177
		$ifdesc = "PPTP";
4178
		break;
4179
	case "pppoe":
4180
		$ifdesc = "PPPoE";
4181
		break;
4182
	case "openvpn":
4183
		$ifdesc = "OpenVPN";
4184
		break;
4185
	case "enc0":
4186
	case "ipsec":
4187
	case "IPsec":
4188
		$ifdesc = "IPsec";
4189
		break;
4190
	default:
4191
		if (isset($config['interfaces'][$interface])) {
4192
			if (empty($config['interfaces'][$interface]['descr']))
4193
				$ifdesc = strtoupper($interface);
4194
			else
4195
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4196
			break;
4197
		} else if (stristr($interface, "_vip")) {
4198
			if (is_array($config['virtualip']['vip'])) {
4199
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
4200
					if ($vip['mode'] == "carp")  {
4201
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4202
							return "{$vip['subnet']} - {$vip['descr']}";
4203
					}
4204
				}
4205
			}
4206
		} else {
4207
			/* if list */
4208
			$ifdescrs = get_configured_interface_with_descr(false, true);
4209
			foreach ($ifdescrs as $if => $ifname) {
4210
				if ($if == $interface || $ifname == $interface)
4211
					return $ifname;
4212
			}
4213
		}
4214
		break;
4215
	}
4216

    
4217
	return $ifdesc;
4218
}
4219

    
4220
function convert_real_interface_to_friendly_descr($interface) {
4221

    
4222
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4223

    
4224
	if (!empty($ifdesc))
4225
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4226

    
4227
	return $interface;
4228
}
4229

    
4230
/*
4231
 *  get_parent_interface($interface):
4232
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4233
 *				or virtual interface (i.e. vlan)
4234
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4235
 *			-- returns $interface passed in if $interface parent is not found
4236
 *			-- returns empty array if an invalid interface is passed
4237
 *	(Only handles ppps and vlans now.)
4238
 */
4239
function get_parent_interface($interface, $avoidrecurse = false) {
4240
	global $config;
4241

    
4242
	$parents = array();
4243
	//Check that we got a valid interface passed
4244
	$realif = get_real_interface($interface);
4245
	if ($realif == NULL)
4246
		return $parents;
4247

    
4248
	// If we got a real interface, find it's friendly assigned name
4249
	if ($interface == $realif && $avoidrecurse == false)
4250
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4251

    
4252
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4253
		$ifcfg = $config['interfaces'][$interface];
4254
		switch ($ifcfg['ipaddr']) {
4255
			case "ppp":
4256
			case "pppoe":
4257
			case "pptp":
4258
			case "l2tp":
4259
				if (empty($parents))
4260
					if (is_array($config['ppps']['ppp']))
4261
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4262
							if ($ifcfg['if'] == $ppp['if']) {
4263
								$ports = explode(',', $ppp['ports']);
4264
								foreach ($ports as $pid => $parent_if)
4265
									$parents[$pid] = get_real_interface($parent_if);
4266
								break;
4267
							}
4268
						}
4269
				break;
4270
			case "dhcp":
4271
			case "static":
4272
			default:
4273
				// Handle _vlans
4274
				if (stristr($realif,"_vlan"))
4275
					if (is_array($config['vlans']['vlan']))
4276
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
4277
							if ($ifcfg['if'] == $vlan['vlanif']){
4278
								$parents[0] = $vlan['if'];
4279
								break;
4280
							}
4281
				break;
4282
		}
4283
	}
4284

    
4285
	if (empty($parents))
4286
		$parents[0] = $realif;
4287

    
4288
	return $parents;
4289
}
4290

    
4291
function interface_is_wireless_clone($wlif) {
4292
	if(!stristr($wlif, "_wlan")) {
4293
		return false;
4294
	} else {
4295
		return true;
4296
	}
4297
}
4298

    
4299
function interface_get_wireless_base($wlif) {
4300
	if(!stristr($wlif, "_wlan")) {
4301
		return $wlif;
4302
	} else {
4303
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4304
	}
4305
}
4306

    
4307
function interface_get_wireless_clone($wlif) {
4308
	if(!stristr($wlif, "_wlan")) {
4309
		return $wlif . "_wlan0";
4310
	} else {
4311
		return $wlif;
4312
	}
4313
}
4314

    
4315
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4316
	global $config, $g;
4317

    
4318
	$wanif = NULL;
4319

    
4320
	switch ($interface) {
4321
	case "l2tp":
4322
		$wanif = "l2tp";
4323
		break;
4324
	case "pptp":
4325
		$wanif = "pptp";
4326
		break;
4327
	case "pppoe":
4328
		$wanif = "pppoe";
4329
		break;
4330
	case "openvpn":
4331
		$wanif = "openvpn";
4332
		break;
4333
	case "ipsec":
4334
	case "enc0":
4335
		$wanif = "enc0";
4336
		break;
4337
	case "ppp":
4338
		$wanif = "ppp";
4339
		break;
4340
	default:
4341
		// If a real interface was alread passed simply
4342
		// pass the real interface back.  This encourages
4343
		// the usage of this function in more cases so that
4344
		// we can combine logic for more flexibility.
4345
		if(does_interface_exist($interface, $flush)) {
4346
			$wanif = $interface;
4347
			break;
4348
		}
4349

    
4350
		if (empty($config['interfaces'][$interface]))
4351
			break;
4352

    
4353
		$cfg = &$config['interfaces'][$interface];
4354

    
4355
		if ($family == "inet6") {
4356
			switch ($cfg['ipaddrv6']) {
4357
			case "6rd":
4358
			case "6to4":
4359
				$wanif = "{$interface}_stf";
4360
				break;
4361
			case 'pppoe':
4362
			case 'ppp':
4363
			case 'l2tp':
4364
			case 'pptp':
4365
				if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4366
					$wanif = interface_get_wireless_clone($cfg['if']);
4367
				else
4368
					$wanif = $cfg['if'];
4369
				break;
4370
			default:
4371
				switch ($cfg['ipaddr']) {
4372
				case 'pppoe':
4373
				case 'ppp':
4374
				case 'l2tp':
4375
				case 'pptp':
4376
					if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false)
4377
						$wanif = $cfg['if'];
4378
					else {
4379
						$parents = get_parent_interface($interface);
4380
						if (!empty($parents[0]))
4381
							$wanif = $parents[0];
4382
						else
4383
							$wanif = $cfg['if'];
4384
					}
4385
					break;
4386
				default:
4387
					if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4388
						$wanif = interface_get_wireless_clone($cfg['if']);
4389
					else
4390
						$wanif = $cfg['if'];
4391
					break;
4392
				}
4393
				break;
4394
			}
4395
		} else {
4396
			// Wireless cloned NIC support (FreeBSD 8+)
4397
			// interface name format: $parentnic_wlanparentnic#
4398
			// example: ath0_wlan0
4399
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4400
				$wanif = interface_get_wireless_clone($cfg['if']);
4401
			else
4402
				$wanif = $cfg['if'];
4403
		}
4404
		break;
4405
	}
4406

    
4407
	return $wanif;
4408
}
4409

    
4410
/* Guess the physical interface by providing a IP address */
4411
function guess_interface_from_ip($ipaddress) {
4412
	if(! is_ipaddr($ipaddress)) {
4413
		return false;
4414
	}
4415
	if(is_ipaddrv4($ipaddress)) {
4416
		/* create a route table we can search */
4417
		exec("/usr/bin/netstat -rnWf inet", $output, $ret);
4418
		foreach($output as $line) {
4419
			if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
4420
				$fields = preg_split("/[ ]+/", $line);
4421
				if(ip_in_subnet($ipaddress, $fields[0])) {
4422
					return $fields[5];
4423
				}
4424
			}
4425
		}
4426
	}
4427
	/* FIXME: This works from cursory testing, regexp might need fine tuning */
4428
	if(is_ipaddrv6($ipaddress)) {
4429
		/* create a route table we can search */
4430
		exec("/usr/bin/netstat -rnWf inet6", $output, $ret);
4431
		foreach($output as $line) {
4432
			if(preg_match("/[0-9a-f]+[:]+[0-9a-f]+[:]+[\/][0-9]+/", $line)) {
4433
				$fields = preg_split("/[ ]+/", $line);
4434
				if(ip_in_subnet($ipaddress, $fields[0])) {
4435
					return $fields[5];
4436
				}
4437
			}
4438
		}
4439
	}
4440
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
4441
	if(empty($ret)) {
4442
		return false;
4443
	}
4444
	return $ret;
4445
}
4446

    
4447
/*
4448
 * find_ip_interface($ip): return the interface where an ip is defined
4449
 *   (or if $bits is specified, where an IP within the subnet is defined)
4450
 */
4451
function find_ip_interface($ip, $bits = null) {
4452
	if (!is_ipaddr($ip))
4453
		return false;
4454

    
4455
	$isv6ip = is_ipaddrv6($ip);
4456

    
4457
	/* if list */
4458
	$ifdescrs = get_configured_interface_list();
4459

    
4460
	foreach ($ifdescrs as $ifdescr => $ifname) {
4461
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4462
		if (is_null($ifip))
4463
			continue;
4464
		if (is_null($bits)) {
4465
			if ($ip == $ifip) {
4466
				$int = get_real_interface($ifname);
4467
				return $int;
4468
			}
4469
		}
4470
		else {
4471
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4472
				$int = get_real_interface($ifname);
4473
				return $int;
4474
			}
4475
		}
4476
	}
4477

    
4478
	return false;
4479
}
4480

    
4481
/*
4482
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4483
 *   (or if $bits is specified, where an IP within the subnet is found)
4484
 */
4485
function find_virtual_ip_alias($ip, $bits = null) {
4486
	global $config;
4487

    
4488
	if (!is_array($config['virtualip']['vip'])) {
4489
		return false;
4490
	}
4491
	if (!is_ipaddr($ip))
4492
		return false;
4493

    
4494
	$isv6ip = is_ipaddrv6($ip);
4495

    
4496
	foreach ($config['virtualip']['vip'] as $vip) {
4497
		if ($vip['mode'] === "ipalias") {
4498
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4499
				continue;
4500
			if (is_null($bits)) {
4501
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4502
					return $vip;
4503
				}
4504
			}
4505
			else {
4506
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4507
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4508
					return $vip;
4509
				}
4510
			}
4511
		}
4512
	}
4513
	return false;
4514
}
4515

    
4516
/*
4517
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4518
 */
4519
function find_number_of_created_carp_interfaces() {
4520
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4521
}
4522

    
4523
/*
4524
 * find_carp_interface($ip): return the carp interface where an ip is defined
4525
 */
4526
function find_carp_interface($ip) {
4527
	global $config;
4528
	if (is_array($config['virtualip']['vip'])) {
4529
		foreach ($config['virtualip']['vip'] as $vip) {
4530
			if ($vip['mode'] == "carp") {
4531
				if(is_ipaddrv4($ip)) {
4532
					$carp_ip = get_interface_ip($vip['interface']);
4533
				}
4534
				if(is_ipaddrv6($ip)) {
4535
					$carp_ip = get_interface_ipv6($vip['interface']);
4536
				}
4537
				exec("/sbin/ifconfig", $output, $return);
4538
				foreach($output as $line) {
4539
					$elements = preg_split("/[ ]+/i", $line);
4540
					if(strstr($elements[0], "vip"))
4541
						$curif = str_replace(":", "", $elements[0]);
4542
					if(stristr($line, $ip)) {
4543
						$if = $curif;
4544
						continue;
4545
					}
4546
				}
4547

    
4548
				if ($if)
4549
					return $if;
4550
			}
4551
		}
4552
	}
4553
}
4554

    
4555
function link_carp_interface_to_parent($interface) {
4556
	global $config;
4557

    
4558
	if (empty($interface))
4559
		return;
4560

    
4561
	$carp_ip = get_interface_ip($interface);
4562
	$carp_ipv6 = get_interface_ipv6($interface);
4563

    
4564
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4565
		return;
4566

    
4567
	/* if list */
4568
	$ifdescrs = get_configured_interface_list();
4569
	foreach ($ifdescrs as $ifdescr => $ifname) {
4570
		/* check IPv4 */
4571
		if(is_ipaddrv4($carp_ip)) {
4572
			$interfaceip = get_interface_ip($ifname);
4573
			$subnet_bits = get_interface_subnet($ifname);
4574
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4575
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4576
				return $ifname;
4577
		}
4578
		/* Check IPv6 */
4579
		if(is_ipaddrv6($carp_ipv6)) {
4580
			$interfaceipv6 = get_interface_ipv6($ifname);
4581
			$prefixlen = get_interface_subnetv6($ifname);
4582
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4583
				return $ifname;
4584
		}
4585
	}
4586
	return "";
4587
}
4588

    
4589

    
4590
/****f* interfaces/link_ip_to_carp_interface
4591
 * NAME
4592
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4593
 * INPUTS
4594
 *   $ip
4595
 * RESULT
4596
 *   $carp_ints
4597
 ******/
4598
function link_ip_to_carp_interface($ip) {
4599
	global $config;
4600

    
4601
	if (!is_ipaddr($ip))
4602
		return;
4603

    
4604
	$carp_ints = "";
4605
	if (is_array($config['virtualip']['vip'])) {
4606
		$first = 0;
4607
		$carp_int = array();
4608
		foreach ($config['virtualip']['vip'] as $vip) {
4609
			if ($vip['mode'] == "carp") {
4610
				$carp_ip = $vip['subnet'];
4611
				$carp_sn = $vip['subnet_bits'];
4612
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4613
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4614
					$carp_int[] = get_real_interface($vip['interface']);
4615
				}
4616
			}
4617
		}
4618
		if (!empty($carp_int))
4619
			$carp_ints = implode(" ", array_unique($carp_int));
4620
	}
4621

    
4622
	return $carp_ints;
4623
}
4624

    
4625
function link_interface_to_track6($int, $action = "") {
4626
	global $config;
4627

    
4628
	if (empty($int))
4629
		return;
4630

    
4631
	if (is_array($config['interfaces'])) {
4632
		$list = array();
4633
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4634
			if (!isset($ifcfg['enable']))
4635
				continue;
4636
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4637
				if ($action == "update")
4638
					interface_track6_configure($ifname, $ifcfg);
4639
				else if ($action == "")
4640
					$list[$ifname] = $ifcfg;
4641
			}
4642
		}
4643
		return $list;
4644
	}
4645
}
4646

    
4647
function link_interface_to_vlans($int, $action = "") {
4648
	global $config;
4649

    
4650
	if (empty($int))
4651
		return;
4652

    
4653
	if (is_array($config['vlans']['vlan'])) {
4654
		$ifaces = array();
4655
		foreach ($config['vlans']['vlan'] as $vlan) {
4656
			if ($int == $vlan['if']) {
4657
				if ($action == "update") {
4658
					interfaces_bring_up($int);
4659
				} else if ($action == "")
4660
					$ifaces[$vlan['tag']] = $vlan;
4661
			}
4662
		}
4663
		if (!empty($ifaces))
4664
			return $ifaces;
4665
	}
4666
}
4667

    
4668
function link_interface_to_vips($int, $action = "") {
4669
	global $config;
4670

    
4671
	if (is_array($config['virtualip']['vip'])) {
4672
		$result = array();
4673
		foreach ($config['virtualip']['vip'] as $vip) {
4674
			if ($int == $vip['interface']) {
4675
				if ($action == "update")
4676
					interfaces_vips_configure($int);
4677
				else
4678
					$result[] = $vip;
4679
			}
4680
		}
4681
		return $result;
4682
	}
4683
}
4684

    
4685
/****f* interfaces/link_interface_to_bridge
4686
 * NAME
4687
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4688
 * INPUTS
4689
 *   $ip
4690
 * RESULT
4691
 *   bridge[0-99]
4692
 ******/
4693
function link_interface_to_bridge($int) {
4694
	global $config;
4695

    
4696
	if (is_array($config['bridges']['bridged'])) {
4697
		foreach ($config['bridges']['bridged'] as $bridge) {
4698
			if (in_array($int, explode(',', $bridge['members'])))
4699
				return "{$bridge['bridgeif']}";
4700
		}
4701
	}
4702
}
4703

    
4704
function link_interface_to_group($int) {
4705
	global $config;
4706

    
4707
	$result = array();
4708

    
4709
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4710
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4711
			if (in_array($int, explode(" ", $group['members'])))
4712
				$result[$group['ifname']] = $int;
4713
		}
4714
	}
4715

    
4716
	return $result;
4717
}
4718

    
4719
function link_interface_to_gre($interface) {
4720
	global $config;
4721

    
4722
	$result = array();
4723

    
4724
	if (is_array($config['gres']['gre'])) {
4725
		foreach ($config['gres']['gre'] as $gre)
4726
			if($gre['if'] == $interface)
4727
				$result[] = $gre;
4728
	}
4729

    
4730
	return $result;
4731
}
4732

    
4733
function link_interface_to_gif($interface) {
4734
	global $config;
4735

    
4736
	$result = array();
4737

    
4738
	if (is_array($config['gifs']['gif'])) {
4739
		foreach ($config['gifs']['gif'] as $gif)
4740
			if($gif['if'] == $interface)
4741
				$result[] = $gif;
4742
	}
4743

    
4744
	return $result;
4745
}
4746

    
4747
/*
4748
 * find_interface_ip($interface): return the interface ip (first found)
4749
 */
4750
function find_interface_ip($interface, $flush = false) {
4751
	global $interface_ip_arr_cache;
4752
	global $interface_sn_arr_cache;
4753

    
4754
	$interface = str_replace("\n", "", $interface);
4755

    
4756
	if (!does_interface_exist($interface))
4757
		return;
4758

    
4759
	/* Setup IP cache */
4760
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4761
		$ifinfo = pfSense_get_interface_addresses($interface);
4762
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4763
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4764
	}
4765

    
4766
	return $interface_ip_arr_cache[$interface];
4767
}
4768

    
4769
/*
4770
 * find_interface_ipv6($interface): return the interface ip (first found)
4771
 */
4772
function find_interface_ipv6($interface, $flush = false) {
4773
	global $interface_ipv6_arr_cache;
4774
	global $interface_snv6_arr_cache;
4775
	global $config;
4776

    
4777
	$interface = trim($interface);
4778
	$interface = get_real_interface($interface);
4779

    
4780
	if (!does_interface_exist($interface))
4781
		return;
4782

    
4783
	/* Setup IP cache */
4784
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4785
		$ifinfo = pfSense_get_interface_addresses($interface);
4786
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4787
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4788
	}
4789

    
4790
	return $interface_ipv6_arr_cache[$interface];
4791
}
4792

    
4793
/*
4794
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4795
 */
4796
function find_interface_ipv6_ll($interface, $flush = false) {
4797
	global $interface_llv6_arr_cache;
4798
	global $config;
4799

    
4800
	$interface = str_replace("\n", "", $interface);
4801

    
4802
	if (!does_interface_exist($interface))
4803
		return;
4804

    
4805
	/* Setup IP cache */
4806
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4807
		$ifinfo = pfSense_getall_interface_addresses($interface);
4808
		foreach($ifinfo as $line) {
4809
			if (strstr($line, ":")) {
4810
				$parts = explode("/", $line);
4811
				if(is_linklocal($parts[0])) {
4812
					$ifinfo['linklocal'] = $parts[0];
4813
				}
4814
			}
4815
		}
4816
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4817
	}
4818
	return $interface_llv6_arr_cache[$interface];
4819
}
4820

    
4821
function find_interface_subnet($interface, $flush = false) {
4822
	global $interface_sn_arr_cache;
4823
	global $interface_ip_arr_cache;
4824

    
4825
	$interface = str_replace("\n", "", $interface);
4826
	if (does_interface_exist($interface) == false)
4827
		return;
4828

    
4829
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4830
		$ifinfo = pfSense_get_interface_addresses($interface);
4831
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4832
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4833
	}
4834

    
4835
	return $interface_sn_arr_cache[$interface];
4836
}
4837

    
4838
function find_interface_subnetv6($interface, $flush = false) {
4839
	global $interface_snv6_arr_cache;
4840
	global $interface_ipv6_arr_cache;
4841

    
4842
	$interface = str_replace("\n", "", $interface);
4843
	if (does_interface_exist($interface) == false)
4844
		return;
4845

    
4846
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4847
		$ifinfo = pfSense_get_interface_addresses($interface);
4848
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4849
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4850
	}
4851

    
4852
	return $interface_snv6_arr_cache[$interface];
4853
}
4854

    
4855
function ip_in_interface_alias_subnet($interface, $ipalias) {
4856
	global $config;
4857

    
4858
	if (empty($interface) || !is_ipaddr($ipalias))
4859
		return false;
4860
	if (is_array($config['virtualip']['vip'])) {
4861
		foreach ($config['virtualip']['vip'] as $vip) {
4862
			switch ($vip['mode']) {
4863
			case "ipalias":
4864
				if ($vip['interface'] <> $interface)
4865
					break;
4866
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4867
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4868
					return true;
4869
				break;
4870
			}
4871
		}
4872
	}
4873

    
4874
	return false;
4875
}
4876

    
4877
function get_interface_ip($interface = "wan") {
4878
	$realif = get_failover_interface($interface);
4879
	if (!$realif) {
4880
		if (strstr($interface, "_vip"))
4881
			return get_configured_carp_interface_list($interface);
4882
		else
4883
			return null;
4884
	}
4885

    
4886
	$curip = find_interface_ip($realif);
4887
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4888
		return $curip;
4889
	else
4890
		return null;
4891
}
4892

    
4893
function get_interface_ipv6($interface = "wan", $flush = false) {
4894
	global $config;
4895

    
4896
	$realif = get_failover_interface($interface, "inet6");
4897
	if (!$realif) {
4898
		if (strstr($interface, "_vip"))
4899
			return get_configured_carp_interface_list($interface, "inet6");
4900
		else
4901
			return null;
4902
	}
4903

    
4904
	/*
4905
	 * NOTE: On the case when only the prefix is requested,
4906
	 * the communication on WAN will be done over link-local.
4907
	 */
4908
	if (is_array($config['interfaces'][$interface])) {
4909
		switch ($config['interfaces'][$interface]['ipaddr']) {
4910
		case 'pppoe':
4911
		case 'l2tp':
4912
		case 'pptp':
4913
		case 'ppp':
4914
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4915
				$realif = get_real_interface($interface, "inet6", true);
4916
			break;
4917
		}
4918
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4919
			$curip = find_interface_ipv6_ll($realif, $flush);
4920
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4921
				return $curip;
4922
		}
4923
	}
4924

    
4925
	$curip = find_interface_ipv6($realif, $flush);
4926
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4927
		return $curip;
4928
	else
4929
		return null;
4930
}
4931

    
4932
function get_interface_linklocal($interface = "wan") {
4933

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

    
4943
	$curip = find_interface_ipv6_ll($realif);
4944
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4945
		return $curip;
4946
	else
4947
		return null;
4948
}
4949

    
4950
function get_interface_subnet($interface = "wan") {
4951
	$realif = get_real_interface($interface);
4952
	if (!$realif) {
4953
		if (strstr($interface, "_vip")) {
4954
			list($interface, $vhid) = explode("_vip", $interface);
4955
			$realif = get_real_interface($interface);
4956
		} else
4957
			return null;
4958
	}
4959

    
4960
	$cursn = find_interface_subnet($realif);
4961
	if (!empty($cursn))
4962
		return $cursn;
4963

    
4964
	return null;
4965
}
4966

    
4967
function get_interface_subnetv6($interface = "wan") {
4968
	global $config;
4969

    
4970
	$realif = get_real_interface($interface, "inet6");
4971
	if (!$realif) {
4972
		if (strstr($interface, "_vip")) {
4973
			list($interface, $vhid) = explode("_vip", $interface);
4974
			$realif = get_real_interface($interface);
4975
		} else
4976
			return null;
4977
	}
4978

    
4979
	$cursn = find_interface_subnetv6($realif);
4980
	if (!empty($cursn))
4981
		return $cursn;
4982

    
4983
	return null;
4984
}
4985

    
4986
/* return outside interfaces with a gateway */
4987
function get_interfaces_with_gateway() {
4988
	global $config;
4989

    
4990
	$ints = array();
4991

    
4992
	/* loop interfaces, check config for outbound */
4993
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4994
		switch ($ifname['ipaddr']) {
4995
			case "dhcp":
4996
			case "ppp";
4997
			case "pppoe":
4998
			case "pptp":
4999
			case "l2tp":
5000
			case "ppp";
5001
				$ints[$ifdescr] = $ifdescr;
5002
			break;
5003
			default:
5004
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
5005
				    !empty($ifname['gateway']))
5006
					$ints[$ifdescr] = $ifdescr;
5007
			break;
5008
		}
5009
	}
5010
	return $ints;
5011
}
5012

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

    
5017
	if (!empty($config['interfaces'][$friendly])) {
5018
		$ifname = &$config['interfaces'][$friendly];
5019
		switch ($ifname['ipaddr']) {
5020
			case "dhcp":
5021
			case "pppoe":
5022
			case "pptp":
5023
			case "l2tp":
5024
			case "ppp";
5025
				return true;
5026
			break;
5027
			default:
5028
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
5029
					return true;
5030
				$tunnelif = substr($ifname['if'], 0, 3);
5031
				if ($tunnelif == "gif" || $tunnelif == "gre")
5032
					return true;
5033
				if (!empty($ifname['gateway']))
5034
					return true;
5035
			break;
5036
		}
5037
	}
5038

    
5039
	return false;
5040
}
5041

    
5042
/* return true if interface has a gateway */
5043
function interface_has_gatewayv6($friendly) {
5044
	global $config;
5045

    
5046
	if (!empty($config['interfaces'][$friendly])) {
5047
		$ifname = &$config['interfaces'][$friendly];
5048
		switch ($ifname['ipaddrv6']) {
5049
			case "slaac":
5050
			case "dhcp6":
5051
			case "6to4":
5052
			case "6rd":
5053
				return true;
5054
				break;
5055
			default:
5056
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
5057
					return true;
5058
				$tunnelif = substr($ifname['if'], 0, 3);
5059
				if ($tunnelif == "gif" || $tunnelif == "gre")
5060
					return true;
5061
				if (!empty($ifname['gatewayv6']))
5062
					return true;
5063
				break;
5064
		}
5065
	}
5066

    
5067
	return false;
5068
}
5069

    
5070
/****f* interfaces/is_altq_capable
5071
 * NAME
5072
 *   is_altq_capable - Test if interface is capable of using ALTQ
5073
 * INPUTS
5074
 *   $int            - string containing interface name
5075
 * RESULT
5076
 *   boolean         - true or false
5077
 ******/
5078

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

    
5092
	$int_family = remove_ifindex($int);
5093

    
5094
	if (in_array($int_family, $capable))
5095
		return true;
5096
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
5097
		return true;
5098
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
5099
		return true;
5100
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
5101
		return true;
5102
	else
5103
		return false;
5104
}
5105

    
5106
/****f* interfaces/is_interface_wireless
5107
 * NAME
5108
 *   is_interface_wireless - Returns if an interface is wireless
5109
 * RESULT
5110
 *   $tmp       - Returns if an interface is wireless
5111
 ******/
5112
function is_interface_wireless($interface) {
5113
	global $config, $g;
5114

    
5115
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5116
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
5117
		if (preg_match($g['wireless_regex'], $interface)) {
5118
			if (isset($config['interfaces'][$friendly]))
5119
				$config['interfaces'][$friendly]['wireless'] = array();
5120
			return true;
5121
		}
5122
		return false;
5123
	} else
5124
		return true;
5125
}
5126

    
5127
function get_wireless_modes($interface) {
5128
	/* return wireless modes and channels */
5129
	$wireless_modes = array();
5130

    
5131
	$cloned_interface = get_real_interface($interface);
5132

    
5133
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5134
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5135
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5136
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5137

    
5138
		$interface_channels = "";
5139
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5140
		$interface_channel_count = count($interface_channels);
5141

    
5142
		$c = 0;
5143
		while ($c < $interface_channel_count) {
5144
			$channel_line = explode(",", $interface_channels["$c"]);
5145
			$wireless_mode = trim($channel_line[0]);
5146
			$wireless_channel = trim($channel_line[1]);
5147
			if(trim($wireless_mode) != "") {
5148
				/* if we only have 11g also set 11b channels */
5149
				if($wireless_mode == "11g") {
5150
					if(!isset($wireless_modes["11b"]))
5151
						$wireless_modes["11b"] = array();
5152
				} else if($wireless_mode == "11g ht") {
5153
					if(!isset($wireless_modes["11b"]))
5154
						$wireless_modes["11b"] = array();
5155
					if(!isset($wireless_modes["11g"]))
5156
						$wireless_modes["11g"] = array();
5157
					$wireless_mode = "11ng";
5158
				} else if($wireless_mode == "11a ht") {
5159
					if(!isset($wireless_modes["11a"]))
5160
						$wireless_modes["11a"] = array();
5161
					$wireless_mode = "11na";
5162
				}
5163
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5164
			}
5165
			$c++;
5166
		}
5167
	}
5168
	return($wireless_modes);
5169
}
5170

    
5171
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5172
function get_wireless_channel_info($interface) {
5173
	$wireless_channels = array();
5174

    
5175
	$cloned_interface = get_real_interface($interface);
5176

    
5177
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5178
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5179
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5180
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5181

    
5182
		$interface_channels = "";
5183
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5184

    
5185
		foreach ($interface_channels as $channel_line) {
5186
			$channel_line = explode(",", $channel_line);
5187
			if(!isset($wireless_channels[$channel_line[0]]))
5188
				$wireless_channels[$channel_line[0]] = $channel_line;
5189
		}
5190
	}
5191
	return($wireless_channels);
5192
}
5193

    
5194
/****f* interfaces/get_interface_mtu
5195
 * NAME
5196
 *   get_interface_mtu - Return the mtu of an interface
5197
 * RESULT
5198
 *   $tmp       - Returns the mtu of an interface
5199
 ******/
5200
function get_interface_mtu($interface) {
5201
	$mtu = pfSense_get_interface_addresses($interface);
5202
	return $mtu['mtu'];
5203
}
5204

    
5205
function get_interface_mac($interface) {
5206

    
5207
	$macinfo = pfSense_get_interface_addresses($interface);
5208
	return $macinfo["macaddr"];
5209
}
5210

    
5211
/****f* pfsense-utils/generate_random_mac_address
5212
 * NAME
5213
 *   generate_random_mac - generates a random mac address
5214
 * INPUTS
5215
 *   none
5216
 * RESULT
5217
 *   $mac - a random mac address
5218
 ******/
5219
function generate_random_mac_address() {
5220
	$mac = "02";
5221
	for($x=0; $x<5; $x++)
5222
		$mac .= ":" . dechex(rand(16, 255));
5223
	return $mac;
5224
}
5225

    
5226
/****f* interfaces/is_jumbo_capable
5227
 * NAME
5228
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5229
 * INPUTS
5230
 *   $int             - string containing interface name
5231
 * RESULT
5232
 *   boolean          - true or false
5233
 ******/
5234
function is_jumbo_capable($iface) {
5235
	$iface = trim($iface);
5236
	$capable = pfSense_get_interface_addresses($iface);
5237

    
5238
	if (isset($capable['caps']['vlanmtu']))
5239
		return true;
5240

    
5241
	return false;
5242
}
5243

    
5244
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5245
	global $g;
5246

    
5247
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5248

    
5249
	if(!empty($iface) && !empty($pppif)){
5250
		$cron_cmd = <<<EOD
5251
#!/bin/sh
5252
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5253
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5254

    
5255
EOD;
5256

    
5257
		@file_put_contents($cron_file, $cron_cmd);
5258
		chmod($cron_file, 0755);
5259
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5260
	} else
5261
		unlink_if_exists($cron_file);
5262
}
5263

    
5264
function get_interface_default_mtu($type = "ethernet") {
5265
	switch ($type) {
5266
	case "gre":
5267
		return 1476;
5268
		break;
5269
	case "gif":
5270
		return 1280;
5271
		break;
5272
	case "tun":
5273
	case "vlan":
5274
	case "tap":
5275
	case "ethernet":
5276
	default:
5277
		return 1500;
5278
		break;
5279
	}
5280

    
5281
	/* Never reached */
5282
	return 1500;
5283
}
5284

    
5285
function get_vip_descr($ipaddress) {
5286
	global $config;
5287

    
5288
	foreach ($config['virtualip']['vip'] as $vip) {
5289
		if ($vip['subnet'] == $ipaddress) {
5290
			return ($vip['descr']);
5291
		}
5292
	}
5293
	return "";
5294
}
5295

    
5296
function interfaces_staticarp_configure($if) {
5297
	global $config, $g;
5298
	if(isset($config['system']['developerspew'])) {
5299
		$mt = microtime();
5300
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5301
	}
5302

    
5303
	$ifcfg = $config['interfaces'][$if];
5304

    
5305
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5306
		return 0;
5307

    
5308
	/* Enable staticarp, if enabled */
5309
	if(isset($config['dhcpd'][$if]['staticarp'])) {
5310
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
5311
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5312
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5313

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

    
5317
			}
5318

    
5319
		}
5320
	} else {
5321
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
5322
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5323
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5324
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5325
				if (isset($arpent['arp_table_static_entry'])) {
5326
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5327
				}
5328
			}
5329
		}
5330
	}
5331

    
5332
	return 0;
5333
}
5334

    
5335
function get_failover_interface($interface, $family = "all") {
5336
	global $config;
5337

    
5338
	/* shortcut to get_real_interface if we find it in the config */
5339
	if (is_array($config['interfaces'][$interface])) {
5340
		return get_real_interface($interface, $family);
5341
	}
5342

    
5343
	/* compare against gateway groups */
5344
	$a_groups = return_gateway_groups_array();
5345
	if (is_array($a_groups[$interface])) {
5346
		/* we found a gateway group, fetch the interface or vip */
5347
		if ($a_groups[$interface][0]['vip'] <> "")
5348
			return $a_groups[$interface][0]['vip'];
5349
		else
5350
			return $a_groups[$interface][0]['int'];
5351
	}
5352
	/* fall through to get_real_interface */
5353
	/* XXX: Really needed? */
5354
	return get_real_interface($interface, $family);
5355
}
5356

    
5357
function remove_ifindex($ifname) {
5358
	return preg_replace("/[0-9]+$/", "", $ifname);
5359
}
5360

    
5361
?>
(26-26/68)