Projet

Général

Profil

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

univnautes / etc / inc / interfaces.inc @ 340ce958

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
	if (!$g['booting']) {
999
		$iflist = get_configured_interface_list();
1000
		foreach($iflist as $ifname) {
1001
			if($config['interfaces'][$ifname]['if'] == $gifif) {
1002
				if(get_interface_gateway($ifname)) {
1003
					system_routing_configure($ifname);
1004
					break;
1005
				}
1006
				if(get_interface_gateway_v6($ifname)) {
1007
					system_routing_configure($ifname);
1008
					break;
1009
				}
1010
			}
1011
		}
1012
	}
1013

    
1014

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

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

    
1027
	interfaces_bring_up($gifif);
1028

    
1029
	return $gifif;
1030
}
1031

    
1032
function interfaces_configure() {
1033
	global $config, $g;
1034

    
1035
	if ($g['platform'] == 'jail')
1036
		return;
1037

    
1038
	/* Set up our loopback interface */
1039
	interfaces_loopback_configure();
1040

    
1041
	/* create the unconfigured wireless clones */
1042
	interfaces_create_wireless_clones();
1043

    
1044
	/* set up LAGG virtual interfaces */
1045
	interfaces_lagg_configure();
1046

    
1047
	/* set up VLAN virtual interfaces */
1048
	interfaces_vlan_configure();
1049

    
1050
	interfaces_qinq_configure();
1051

    
1052
	$iflist = get_configured_interface_with_descr();
1053
	$delayed_list = array();
1054
	$bridge_list = array();
1055
	$track6_list = array();
1056

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

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

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

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

    
1093
	/* set up GRE virtual interfaces */
1094
	interfaces_gre_configure(1);
1095

    
1096
	/* set up GIF virtual interfaces */
1097
	interfaces_gif_configure(1);
1098

    
1099
	/* set up BRIDGe virtual interfaces */
1100
	interfaces_bridge_configure(1);
1101

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

    
1108
		interface_configure($if, $reload);
1109

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

    
1114
	/* bring up vip interfaces */
1115
	interfaces_vips_configure();
1116

    
1117
	/* set up GRE virtual interfaces */
1118
	interfaces_gre_configure(2);
1119

    
1120
	/* set up GIF virtual interfaces */
1121
	interfaces_gif_configure(2);
1122

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

    
1129
		interface_configure($if, $reload);
1130

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

    
1135
	/* set up BRIDGe virtual interfaces */
1136
	interfaces_bridge_configure(2);
1137

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

    
1144
		interface_configure($if, $reload);
1145

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

    
1150
	/* configure interface groups */
1151
	interfaces_group_setup();
1152

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

    
1157
		/* reload IPsec tunnels */
1158
		vpn_ipsec_configure();
1159

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

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

    
1170
	return 0;
1171
}
1172

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

    
1178
function interface_vip_bring_down($vip) {
1179
	global $g;
1180

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

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

    
1206
	if (!isset($config['interfaces'][$interface]))
1207
		return;
1208

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

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

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

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

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

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

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

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

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

    
1371
	return;
1372
}
1373

    
1374
function interfaces_carp_set_maintenancemode($carp_maintenancemode){
1375
	global $config;
1376
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1377
		unset($config["virtualip_carp_maintenancemode"]);
1378
		write_config("Leave CARP maintenance mode");
1379
		if(is_array($config['virtualip']['vip'])) {
1380
			$viparr = &$config['virtualip']['vip'];
1381
			foreach ($viparr as $vip) {
1382
				switch ($vip['mode']) {
1383
				case "carp":
1384
					interface_vip_bring_down($vip);
1385
					//sleep(1);
1386
					break;
1387
				}
1388
			}
1389
		}
1390
	} else {
1391
		if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1392
			$config["virtualip_carp_maintenancemode"] = true;
1393
			write_config("Enter CARP maintenance mode");
1394
		}
1395
	}
1396

    
1397
	$viparr = &$config['virtualip']['vip'];
1398
	foreach ($viparr as $vip) {
1399
		if ($vip['mode'] == "carp") {
1400
			interface_carp_configure($vip);
1401
		}
1402
	}
1403
}
1404

    
1405
function interfaces_ptpid_used($ptpid) {
1406
	global $config;
1407

    
1408
	if (is_array($config['ppps']['ppp']))
1409
		foreach ($config['ppps']['ppp'] as & $settings)
1410
			if ($ptpid == $settings['ptpid'])
1411
				return true;
1412

    
1413
	return false;
1414
}
1415

    
1416
function interfaces_ptpid_next() {
1417

    
1418
	$ptpid = 0;
1419
	while(interfaces_ptpid_used($ptpid))
1420
		$ptpid++;
1421

    
1422
	return $ptpid;
1423
}
1424

    
1425
function getMPDCRONSettings($pppif) {
1426
	global $config;
1427

    
1428
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1429
	if (is_array($config['cron']['item'])) {
1430
		foreach ($config['cron']['item'] as $i => $item) {
1431
			if (stripos($item['command'], $cron_cmd_file) !== false)
1432
				return array("ID" => $i, "ITEM" => $item);
1433
		}
1434
	}
1435

    
1436
	return NULL;
1437
}
1438

    
1439
function handle_pppoe_reset($post_array) {
1440
	global $config, $g;
1441

    
1442
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1443
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1444

    
1445
	if (!is_array($config['cron']['item']))
1446
		$config['cron']['item'] = array();
1447

    
1448
	$itemhash = getMPDCRONSettings($pppif);
1449

    
1450
	// reset cron items if necessary and return
1451
	if (empty($post_array['pppoe-reset-type'])) {
1452
		if (isset($itemhash))
1453
			unset($config['cron']['item'][$itemhash['ID']]);
1454
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1455
		return;
1456
	}
1457

    
1458
	if (empty($itemhash))
1459
		$itemhash = array();
1460
	$item = array();
1461
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1462
		$item['minute'] = $post_array['pppoe_resetminute'];
1463
		$item['hour'] = $post_array['pppoe_resethour'];
1464
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1465
			$date = explode("/", $post_array['pppoe_resetdate']);
1466
			$item['mday'] = $date[1];
1467
			$item['month'] = $date[0];
1468
		} else {
1469
			$item['mday'] = "*";
1470
			$item['month'] = "*";
1471
		}
1472
		$item['wday'] = "*";
1473
		$item['who'] = "root";
1474
		$item['command'] = $cron_cmd_file;
1475
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1476
		switch ($post_array['pppoe_pr_preset_val']) {
1477
		case "monthly":
1478
			$item['minute'] = "0";
1479
			$item['hour'] = "0";
1480
			$item['mday'] = "1";
1481
			$item['month'] = "*";
1482
			$item['wday'] = "*";
1483
			break;
1484
		case "weekly":
1485
			$item['minute'] = "0";
1486
			$item['hour'] = "0";
1487
			$item['mday'] = "*";
1488
			$item['month'] = "*";
1489
			$item['wday'] = "0";
1490
			break;
1491
		case "daily":
1492
			$item['minute'] = "0";
1493
			$item['hour'] = "0";
1494
			$item['mday'] = "*";
1495
			$item['month'] = "*";
1496
			$item['wday'] = "*";
1497
			break;
1498
		case "hourly":
1499
			$item['minute'] = "0";
1500
			$item['hour'] = "*";
1501
			$item['mday'] = "*";
1502
			$item['month'] = "*";
1503
			$item['wday'] = "*";
1504
			break;
1505
		} // end switch
1506
		$item['who'] = "root";
1507
		$item['command'] = $cron_cmd_file;
1508
	}
1509
	if (empty($item))
1510
		return;
1511
	if (isset($itemhash['ID']))
1512
		$config['cron']['item'][$itemhash['ID']] = $item;
1513
	else
1514
		$config['cron']['item'][] = $item;
1515
}
1516

    
1517
/*
1518
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1519
 * It writes the mpd config file to /var/etc every time the link is opened.
1520
 */
1521
function interface_ppps_configure($interface) {
1522
	global $config, $g;
1523

    
1524
	/* Return for unassigned interfaces. This is a minimum requirement. */
1525
	if (empty($config['interfaces'][$interface]))
1526
		return 0;
1527
	$ifcfg = $config['interfaces'][$interface];
1528
	if (!isset($ifcfg['enable']))
1529
		return 0;
1530

    
1531
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1532
	if(!is_dir("/var/spool/lock")) {
1533
		mkdir("/var/spool/lock", 0777, true);
1534
	}
1535
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1536
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1537
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1538

    
1539
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1540
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1541
			if ($ifcfg['if'] == $ppp['if'])
1542
				break;
1543
		}
1544
	}
1545
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1546
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1547
		return 0;
1548
	}
1549
	$pppif = $ifcfg['if'];
1550
	if ($ppp['type'] == "ppp")
1551
		$type = "modem";
1552
	else
1553
		$type = $ppp['type'];
1554
	$upper_type = strtoupper($ppp['type']);
1555

    
1556
	if($g['booting']) {
1557
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1558
		echo "starting {$pppif} link...";
1559
		// Do not re-configure the interface if we are booting and it's already been started
1560
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1561
			return 0;
1562
	}
1563

    
1564
	$ports = explode(',',$ppp['ports']);
1565
	if ($type != "modem") {
1566
		foreach ($ports as $pid => $port) {
1567
			$ports[$pid] = get_real_interface($port);
1568
			if (empty($ports[$pid]))
1569
				return 0;
1570
		}
1571
	}
1572
	$localips = explode(',',$ppp['localip']);
1573
	$gateways = explode(',',$ppp['gateway']);
1574
	$subnets = explode(',',$ppp['subnet']);
1575

    
1576
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1577
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1578
	 */
1579
	foreach($ports as $pid => $port){
1580
		switch ($ppp['type']) {
1581
			case "pppoe":
1582
				/* Bring the parent interface up */
1583
				interfaces_bring_up($port);
1584
				pfSense_ngctl_attach(".", $port);
1585
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1586
				mwexec("ngctl msg {$port}: setautosrc 1");
1587
				break;
1588
			case "pptp":
1589
			case "l2tp":
1590
				/* configure interface */
1591
				if(is_ipaddr($localips[$pid])){
1592
					// Manually configure interface IP/subnet
1593
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1594
					interfaces_bring_up($port);
1595
				} else if (empty($localips[$pid]))
1596
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1597

    
1598
				if(!is_ipaddr($localips[$pid])){
1599
					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!");
1600
					$localips[$pid] = "0.0.0.0";
1601
				}
1602
				if(!is_ipaddr($gateways[$pid])){
1603
					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));
1604
					return 0;
1605
				}
1606
				pfSense_ngctl_attach(".", $port);
1607
				break;
1608
			case "ppp":
1609
				if (!file_exists("{$port}")) {
1610
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1611
					return 0;
1612
				}
1613
				break;
1614
			default:
1615
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1616
				break;
1617
		}
1618
	}
1619

    
1620
	if (is_array($ports) && count($ports) > 1)
1621
		$multilink = "enable";
1622
	else
1623
		$multilink = "disable";
1624

    
1625
	if ($type == "modem"){
1626
		if (is_ipaddr($ppp['localip']))
1627
			$localip = $ppp['localip'];
1628
		else
1629
			$localip = '0.0.0.0';
1630

    
1631
		if (is_ipaddr($ppp['gateway']))
1632
			$gateway = $ppp['gateway'];
1633
		else
1634
			$gateway = "10.64.64.{$pppid}";
1635
		$ranges = "{$localip}/0 {$gateway}/0";
1636

    
1637
		if (empty($ppp['apnum']))
1638
			$ppp['apnum'] = 1;
1639
	} else
1640
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1641

    
1642
	if (isset($ppp['ondemand']))
1643
		$ondemand = "enable";
1644
	else
1645
		$ondemand = "disable";
1646
	if (!isset($ppp['idletimeout']))
1647
		$ppp['idletimeout'] = 0;
1648

    
1649
	if (empty($ppp['username']) && $type == "modem"){
1650
		$ppp['username'] = "user";
1651
		$ppp['password'] = "none";
1652
	}
1653
	if (empty($ppp['password']) && $type == "modem")
1654
		$passwd = "none";
1655
	else
1656
		$passwd = base64_decode($ppp['password']);
1657

    
1658
	$bandwidths = explode(',',$ppp['bandwidth']);
1659
	$defaultmtu = "1492";
1660
	if (!empty($ifcfg['mtu']))
1661
		$defaultmtu = intval($ifcfg['mtu']);
1662
	$mtus = explode(',',$ppp['mtu']);
1663
	$mrus = explode(',',$ppp['mru']);
1664

    
1665
	if (isset($ppp['mrru']))
1666
		$mrrus = explode(',',$ppp['mrru']);
1667

    
1668
	// Construct the mpd.conf file
1669
	$mpdconf = <<<EOD
1670
startup:
1671
	# configure the console
1672
	set console close
1673
	# configure the web server
1674
	set web close
1675

    
1676
default:
1677
{$ppp['type']}client:
1678
	create bundle static {$interface}
1679
	set bundle enable ipv6cp
1680
	set iface name {$pppif}
1681

    
1682
EOD;
1683
	$setdefaultgw = false;
1684
	$founddefaultgw = false;
1685
	if (is_array($config['gateways']['gateway_item'])) {
1686
		foreach($config['gateways']['gateway_item'] as $gateway) {
1687
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1688
				$setdefaultgw = true;
1689
				break;
1690
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1691
				$founddefaultgw = true;
1692
				break;
1693
			}
1694
		}
1695
	}
1696

    
1697
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1698
		$setdefaultgw = true;
1699
		$mpdconf .= <<<EOD
1700
	set iface route default
1701

    
1702
EOD;
1703
	}
1704
	$mpdconf .= <<<EOD
1705
	set iface {$ondemand} on-demand
1706
	set iface idle {$ppp['idletimeout']}
1707

    
1708
EOD;
1709

    
1710
	if (isset($ppp['ondemand']))
1711
		$mpdconf .= <<<EOD
1712
	set iface addrs 10.10.1.1 10.10.1.2
1713

    
1714
EOD;
1715

    
1716
	if (isset($ppp['tcpmssfix']))
1717
		$tcpmss = "disable";
1718
	else
1719
		$tcpmss = "enable";
1720
		$mpdconf .= <<<EOD
1721
	set iface {$tcpmss} tcpmssfix
1722

    
1723
EOD;
1724

    
1725
	$mpdconf .= <<<EOD
1726
	set iface up-script /usr/local/sbin/ppp-linkup
1727
	set iface down-script /usr/local/sbin/ppp-linkdown
1728
	set ipcp ranges {$ranges}
1729

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

    
1735
EOD;
1736

    
1737
	if (isset($config['system']['dnsallowoverride']))
1738
		$mpdconf .= <<<EOD
1739
	set ipcp enable req-pri-dns
1740
	set ipcp enable req-sec-dns
1741

    
1742
EOD;
1743
	if (!isset($ppp['verbose_log']))
1744
		$mpdconf .= <<<EOD
1745
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1746

    
1747
EOD;
1748
	foreach($ports as $pid => $port){
1749
		$port = get_real_interface($port);
1750
		$mpdconf .= <<<EOD
1751

    
1752
	create link static {$interface}_link{$pid} {$type}
1753
	set link action bundle {$interface}
1754
	set link {$multilink} multilink
1755
	set link keep-alive 10 60
1756
	set link max-redial 0
1757

    
1758
EOD;
1759
		if (isset($ppp['shortseq']))
1760
			$mpdconf .= <<<EOD
1761
	set link no shortseq
1762

    
1763
EOD;
1764

    
1765
		if (isset($ppp['acfcomp']))
1766
			$mpdconf .= <<<EOD
1767
	set link no acfcomp
1768

    
1769
EOD;
1770

    
1771
		if (isset($ppp['protocomp']))
1772
			$mpdconf .= <<<EOD
1773
	set link no protocomp
1774

    
1775
EOD;
1776

    
1777
		$mpdconf .= <<<EOD
1778
	set link disable chap pap
1779
	set link accept chap pap eap
1780
	set link disable incoming
1781

    
1782
EOD;
1783

    
1784

    
1785
		if (!empty($bandwidths[$pid]))
1786
			$mpdconf .= <<<EOD
1787
	set link bandwidth {$bandwidths[$pid]}
1788

    
1789
EOD;
1790

    
1791
		if (empty($mtus[$pid]))
1792
			$mtus[$pid] = $defaultmtu;
1793
			$mpdconf .= <<<EOD
1794
	set link mtu {$mtus[$pid]}
1795

    
1796
EOD;
1797

    
1798
		if (!empty($mrus[$pid]))
1799
			$mpdconf .= <<<EOD
1800
	set link mru {$mrus[$pid]}
1801

    
1802
EOD;
1803

    
1804
		if (!empty($mrrus[$pid]))
1805
			$mpdconf .= <<<EOD
1806
	set link mrru {$mrrus[$pid]}
1807

    
1808
EOD;
1809

    
1810
		$mpdconf .= <<<EOD
1811
	set auth authname "{$ppp['username']}"
1812
	set auth password {$passwd}
1813

    
1814
EOD;
1815
		if ($type == "modem") {
1816
			$mpdconf .= <<<EOD
1817
	set modem device {$ppp['ports']}
1818
	set modem script DialPeer
1819
	set modem idle-script Ringback
1820
	set modem watch -cd
1821
	set modem var \$DialPrefix "DT"
1822
	set modem var \$Telephone "{$ppp['phone']}"
1823

    
1824
EOD;
1825
		}
1826
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1827
			$mpdconf .= <<<EOD
1828
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1829

    
1830
EOD;
1831
		}
1832
		if (isset($ppp['initstr']) && $type == "modem") {
1833
			$initstr = base64_decode($ppp['initstr']);
1834
			$mpdconf .= <<<EOD
1835
	set modem var \$InitString "{$initstr}"
1836

    
1837
EOD;
1838
		}
1839
		if (isset($ppp['simpin']) && $type == "modem") {
1840
			if($ppp['pin-wait'] == "")
1841
				$ppp['pin-wait'] = 0;
1842
			$mpdconf .= <<<EOD
1843
	set modem var \$SimPin "{$ppp['simpin']}"
1844
	set modem var \$PinWait "{$ppp['pin-wait']}"
1845

    
1846
EOD;
1847
		}
1848
		if (isset($ppp['apn']) && $type == "modem") {
1849
			$mpdconf .= <<<EOD
1850
	set modem var \$APN "{$ppp['apn']}"
1851
	set modem var \$APNum "{$ppp['apnum']}"
1852

    
1853
EOD;
1854
		}
1855
		if ($type == "pppoe") {
1856
			// Send a null service name if none is set.
1857
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1858
			$mpdconf .= <<<EOD
1859
	set pppoe service "{$provider}"
1860

    
1861
EOD;
1862
		}
1863
		if ($type == "pppoe")
1864
			$mpdconf .= <<<EOD
1865
	set pppoe iface {$port}
1866

    
1867
EOD;
1868

    
1869
		if ($type == "pptp" || $type == "l2tp") {
1870
			$mpdconf .= <<<EOD
1871
	set {$type} self {$localips[$pid]}
1872
	set {$type} peer {$gateways[$pid]}
1873

    
1874
EOD;
1875
		}
1876

    
1877
		$mpdconf .= "\topen\n";
1878
	} //end foreach($port)
1879

    
1880

    
1881
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1882
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1883
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1884
	else {
1885
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1886
		if (!$fd) {
1887
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1888
			return 0;
1889
		}
1890
		// Write out mpd_ppp.conf
1891
		fwrite($fd, $mpdconf);
1892
		fclose($fd);
1893
		unset($mpdconf);
1894
	}
1895

    
1896
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1897
	if (isset($ppp['uptime'])) {
1898
		if (!file_exists("/conf/{$pppif}.log")) {
1899
			conf_mount_rw();
1900
			file_put_contents("/conf/{$pppif}.log", '');
1901
			conf_mount_ro();
1902
		}
1903
	} else {
1904
		if (file_exists("/conf/{$pppif}.log")) {
1905
			conf_mount_rw();
1906
			@unlink("/conf/{$pppif}.log");
1907
			conf_mount_ro();
1908
		}
1909
	}
1910

    
1911
	/* clean up old lock files */
1912
	foreach($ports as $port) {
1913
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1914
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1915
	}
1916

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

    
1921
	// Check for PPPoE periodic reset request
1922
	if ($type == "pppoe") {
1923
		if (!empty($ppp['pppoe-reset-type']))
1924
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1925
		else
1926
			interface_setup_pppoe_reset_file($ppp['if']);
1927
	}
1928
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1929
	$i = 0;
1930
	while($i < 10) {
1931
		exec("/sbin/ifconfig " . escapeshellarg($ppp['if']) . " 2>&1", $out, $ret);
1932
		if($ret == 0)
1933
			break;
1934
		sleep(1);
1935
		$i++;
1936
	}
1937

    
1938
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
1939
	/* We should be able to launch the right version for each modem */
1940
	/* We can also guess the mondev from the manufacturer */
1941
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
1942
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
1943
	foreach($ports as $port) {
1944
		if(preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1945
			$mondev  = substr(basename($port), 0, -1);
1946
			$devlist = glob("/dev/{$mondev}?");
1947
			$mondev = basename(end($devlist));
1948
		}
1949
		if(preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1950
			$mondev  = substr(basename($port), 0, -1) . "1";
1951
		}
1952
		log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
1953
		mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
1954
	}
1955

    
1956
	return 1;
1957
}
1958

    
1959
function interfaces_sync_setup() {
1960
	global $g, $config;
1961

    
1962
	if (isset($config['system']['developerspew'])) {
1963
		$mt = microtime();
1964
		echo "interfaces_sync_setup() being called $mt\n";
1965
	}
1966

    
1967
	if ($g['booting']) {
1968
		echo gettext("Configuring CARP settings...");
1969
		mute_kernel_msgs();
1970
	}
1971

    
1972
	/* suck in configuration items */
1973
	if ($config['hasync']) {
1974
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1975
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1976
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1977
	} else {
1978
		unset($pfsyncinterface);
1979
		unset($pfsyncenabled);
1980
	}
1981

    
1982
	set_sysctl(array(
1983
		"net.inet.carp.preempt" => "1",
1984
		"net.inet.carp.log" => "1")
1985
	);
1986

    
1987
	if (!empty($pfsyncinterface))
1988
		$carp_sync_int = get_real_interface($pfsyncinterface);
1989
	else
1990
		unset($carp_sync_int);
1991

    
1992
	/* setup pfsync interface */
1993
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
1994
		if (is_ipaddr($pfsyncpeerip))
1995
			$syncpeer = "syncpeer {$pfsyncpeerip}";
1996
		else
1997
			$syncpeer = "-syncpeer";
1998

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

    
2001
		sleep(1);
2002

    
2003
		/* 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
2004
		 * for existing sessions.
2005
		 */
2006
		log_error("waiting for pfsync...");
2007
		$i = 0;
2008
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2009
			$i++;
2010
			sleep(1);
2011
		}
2012
		log_error("pfsync done in $i seconds.");
2013
		log_error("Configuring CARP settings finalize...");
2014
	} else {
2015
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2016
	}
2017

    
2018
	if($config['virtualip']['vip'])
2019
		set_single_sysctl("net.inet.carp.allow", "1");
2020
	else
2021
		set_single_sysctl("net.inet.carp.allow", "0");
2022

    
2023
	if ($g['booting']) {
2024
		unmute_kernel_msgs();
2025
		echo gettext("done.") . "\n";
2026
	}
2027
}
2028

    
2029
function interface_proxyarp_configure($interface = "") {
2030
	global $config, $g;
2031
	if(isset($config['system']['developerspew'])) {
2032
		$mt = microtime();
2033
		echo "interface_proxyarp_configure() being called $mt\n";
2034
	}
2035

    
2036
	/* kill any running choparp */
2037
	if (empty($interface))
2038
		killbyname("choparp");
2039
	else {
2040
		$vipif = get_real_interface($interface);
2041
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
2042
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2043
	}
2044

    
2045
	$paa = array();
2046
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2047

    
2048
		/* group by interface */
2049
		foreach ($config['virtualip']['vip'] as $vipent) {
2050
			if ($vipent['mode'] === "proxyarp") {
2051
				if ($vipent['interface'])
2052
					$proxyif = $vipent['interface'];
2053
				else
2054
					$proxyif = "wan";
2055

    
2056
				if (!empty($interface) && $interface != $proxyif)
2057
					continue;
2058

    
2059
				if (!is_array($paa[$proxyif]))
2060
					$paa[$proxyif] = array();
2061

    
2062
				$paa[$proxyif][] = $vipent;
2063
			}
2064
		}
2065
	}
2066

    
2067
	if (!empty($interface)) {
2068
		if (is_array($paa[$interface])) {
2069
			$paaifip = get_interface_ip($interface);
2070
			if (!is_ipaddr($paaifip))
2071
				return;
2072
			$args = get_real_interface($interface) . " auto";
2073
			foreach ($paa[$interface] 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
	} else if (count($paa) > 0) {
2082
		foreach ($paa as $paif => $paents)  {
2083
			$paaifip = get_interface_ip($paif);
2084
			if (!is_ipaddr($paaifip))
2085
				continue;
2086
			$args = get_real_interface($paif) . " auto";
2087
			foreach ($paents as $paent) {
2088
				if (isset($paent['subnet']))
2089
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2090
				else if (isset($paent['range']))
2091
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2092
			}
2093
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2094
		}
2095
	}
2096
}
2097

    
2098
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2099
	global $g, $config;
2100

    
2101
	if (is_array($config['virtualip']['vip'])) {
2102
		foreach ($config['virtualip']['vip'] as $vip) {
2103
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2104
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2105
					interface_vip_bring_down($vip);
2106
				else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2107
					interface_vip_bring_down($vip);
2108
			}
2109
		}
2110
	}
2111
}
2112

    
2113
function interfaces_vips_configure($interface = "") {
2114
	global $g, $config;
2115
	if(isset($config['system']['developerspew'])) {
2116
		$mt = microtime();
2117
		echo "interfaces_vips_configure() being called $mt\n";
2118
	}
2119
	$paa = array();
2120
	if(is_array($config['virtualip']['vip'])) {
2121
		$carp_setuped = false;
2122
		$anyproxyarp = false;
2123
		foreach ($config['virtualip']['vip'] as $vip) {
2124
			switch ($vip['mode']) {
2125
			case "proxyarp":
2126
				/* nothing it is handled on interface_proxyarp_configure() */
2127
				if ($interface <> "" && $vip['interface'] <> $interface)
2128
					continue;
2129
				$anyproxyarp = true;
2130
				break;
2131
			case "ipalias":
2132
				if ($interface <> "" && $vip['interface'] <> $interface)
2133
					continue;
2134
				interface_ipalias_configure($vip);
2135
				break;
2136
			case "carp":
2137
				if ($interface <> "" && $vip['interface'] <> $interface)
2138
					continue;
2139
				if ($carp_setuped == false)
2140
					$carp_setuped = true;
2141
				interface_carp_configure($vip);
2142
				break;
2143
			}
2144
		}
2145
		if ($carp_setuped == true)
2146
			interfaces_sync_setup();
2147
		if ($anyproxyarp == true)
2148
			interface_proxyarp_configure();
2149
	}
2150
}
2151

    
2152
function interface_ipalias_configure(&$vip) {
2153
	global $config;
2154

    
2155
	if ($vip['mode'] != 'ipalias')
2156
		return;
2157

    
2158
	if ($vip['interface'] != 'lo0' && stripos($vip['interface'], '_vip') === false) {
2159
		if (!isset($config['interfaces'][$vip['interface']]))
2160
			return;
2161

    
2162
		if (!isset($config['interfaces'][$vip['interface']]['enable']))
2163
			return;
2164
	}
2165

    
2166
	$af = 'inet';
2167
	if(is_ipaddrv6($vip['subnet']))
2168
		$af = 'inet6';
2169
	$iface = $vip['interface'];
2170
	$vipadd = '';
2171
	if (strpos($vip['interface'], '_vip')) {
2172
		$carpvip = get_configured_carp_interface_list($vip['interface'], $af, 'vip');
2173
		$iface = $carpvip['interface'];
2174
		$vipadd = "vhid {$carpvip['vhid']}";
2175
	}
2176
	$if = get_real_interface($iface);
2177
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vipadd}");
2178
	unset($iface, $af, $if, $carpvip, $vipadd);
2179
}
2180

    
2181
function interface_reload_carps($cif) {
2182
	global $config;
2183

    
2184
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2185
	if (empty($carpifs))
2186
		return;
2187

    
2188
	$carps = explode(" ", $carpifs);
2189
	if(is_array($config['virtualip']['vip'])) {
2190
		$viparr = &$config['virtualip']['vip'];
2191
		foreach ($viparr as $vip) {
2192
			if (in_array($vip['carpif'], $carps)) {
2193
				switch ($vip['mode']) {
2194
				case "carp":
2195
					interface_vip_bring_down($vip);
2196
					sleep(1);
2197
					interface_carp_configure($vip);
2198
					break;
2199
				case "ipalias":
2200
					interface_vip_bring_down($vip);
2201
					sleep(1);
2202
					interface_ipalias_configure($vip);
2203
					break;
2204
				}
2205
			}
2206
		}
2207
	}
2208
}
2209

    
2210
function interface_carp_configure(&$vip) {
2211
	global $config, $g;
2212
	if(isset($config['system']['developerspew'])) {
2213
		$mt = microtime();
2214
		echo "interface_carp_configure() being called $mt\n";
2215
	}
2216

    
2217
	if ($vip['mode'] != "carp")
2218
		return;
2219

    
2220
	/* NOTE: Maybe its useless nowdays */
2221
	$realif = get_real_interface($vip['interface']);
2222
	if (!does_interface_exist($realif)) {
2223
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2224
		return;
2225
	}
2226

    
2227
	if (is_ipaddrv4($vip['subnet'])) {
2228
		/* Ensure a IP on this interface exists prior to configuring CARP. */
2229
		$ww_subnet_ip = find_interface_ip($realif);
2230
		if (!is_ipaddrv4($ww_subnet_ip)) {
2231
			file_notice("CARP", sprintf(gettext("Interface does not have required IP address in the subnet of virtual IP address %s. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2232
			return;
2233
		}
2234
	} else if (is_ipaddrv6($vip['subnet'])) {
2235
		/* Ensure a IP on this interface exists prior to configuring CARP. */
2236
		$ww_subnet_ip = find_interface_ipv6($realif);
2237
		if (!is_ipaddrv6($ww_subnet_ip)) {
2238
			file_notice("CARP", sprintf(gettext("Interface does not have required IPv6 address in the subnet of virtual IPv6 address %s. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2239
			return;
2240
		}
2241
	}
2242

    
2243
	$vip_password = $vip['password'];
2244
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2245
	if ($vip['password'] != "")
2246
		$password = " pass {$vip_password}";
2247

    
2248
	$advbase = "";
2249
	if (!empty($vip['advbase']))
2250
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2251

    
2252
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2253
	if ($carp_maintenancemode)
2254
		$advskew = "advskew 254";
2255
	else
2256
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2257
	
2258
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) . " {$advskew} {$advbase} {$password}");
2259

    
2260
	if (is_ipaddrv4($vip['subnet']))
2261
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2262
	else if (is_ipaddrv6($vip['subnet']))
2263
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2264

    
2265
	return $realif;
2266
}
2267

    
2268
function interface_wireless_clone($realif, $wlcfg) {
2269
	global $config, $g;
2270
	/*   Check to see if interface has been cloned as of yet.
2271
	 *   If it has not been cloned then go ahead and clone it.
2272
	 */
2273
	$needs_clone = false;
2274
	if(is_array($wlcfg['wireless']))
2275
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2276
	else
2277
		$wlcfg_mode = $wlcfg['mode'];
2278
	switch($wlcfg_mode) {
2279
	case "hostap":
2280
		$mode = "wlanmode hostap";
2281
		break;
2282
	case "adhoc":
2283
		$mode = "wlanmode adhoc";
2284
		break;
2285
	default:
2286
		$mode = "";
2287
		break;
2288
	}
2289
	$baseif = interface_get_wireless_base($wlcfg['if']);
2290
	if(does_interface_exist($realif)) {
2291
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2292
		$ifconfig_str = implode($output);
2293
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
2294
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2295
			$needs_clone = true;
2296
		}
2297
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
2298
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2299
			$needs_clone = true;
2300
		}
2301
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2302
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2303
			$needs_clone = true;
2304
		}
2305
	} else {
2306
		$needs_clone = true;
2307
	}
2308

    
2309
	if($needs_clone == true) {
2310
		/* remove previous instance if it exists */
2311
		if(does_interface_exist($realif))
2312
			pfSense_interface_destroy($realif);
2313

    
2314
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2315
		// Create the new wlan interface. FreeBSD returns the new interface name.
2316
		// example:  wlan2
2317
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2318
		if($ret <> 0) {
2319
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2320
			return false;
2321
		}
2322
		$newif = trim($out[0]);
2323
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2324
		pfSense_interface_rename($newif, $realif);
2325
		// FIXME: not sure what ngctl is for. Doesn't work.
2326
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
2327
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2328
	}
2329
	return true;
2330
}
2331

    
2332
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2333
	global $config, $g;
2334

    
2335
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2336
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2337
				 'regdomain', 'regcountry', 'reglocation');
2338

    
2339
	if(!is_interface_wireless($ifcfg['if']))
2340
		return;
2341

    
2342
	$baseif = interface_get_wireless_base($ifcfg['if']);
2343

    
2344
	// Sync shared settings for assigned clones
2345
	$iflist = get_configured_interface_list(false, true);
2346
	foreach ($iflist as $if) {
2347
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2348
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2349
				foreach ($shared_settings as $setting) {
2350
					if ($sync_changes) {
2351
						if (isset($ifcfg['wireless'][$setting]))
2352
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2353
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2354
							unset($config['interfaces'][$if]['wireless'][$setting]);
2355
					} else {
2356
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2357
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2358
						else if (isset($ifcfg['wireless'][$setting]))
2359
							unset($ifcfg['wireless'][$setting]);
2360
					}
2361
				}
2362
				if (!$sync_changes)
2363
					break;
2364
			}
2365
		}
2366
	}
2367

    
2368
	// Read or write settings at shared area
2369
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2370
		foreach ($shared_settings as $setting) {
2371
			if ($sync_changes) {
2372
				if (isset($ifcfg['wireless'][$setting]))
2373
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2374
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2375
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2376
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2377
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2378
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2379
				else if (isset($ifcfg['wireless'][$setting]))
2380
					unset($ifcfg['wireless'][$setting]);
2381
			}
2382
		}
2383
	}
2384

    
2385
	// Sync the mode on the clone creation page with the configured mode on the interface
2386
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2387
		foreach ($config['wireless']['clone'] as &$clone) {
2388
			if ($clone['cloneif'] == $ifcfg['if']) {
2389
				if ($sync_changes) {
2390
					$clone['mode'] = $ifcfg['wireless']['mode'];
2391
				} else {
2392
					$ifcfg['wireless']['mode'] = $clone['mode'];
2393
				}
2394
				break;
2395
			}
2396
		}
2397
		unset($clone);
2398
	}
2399
}
2400

    
2401
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2402
	global $config, $g;
2403

    
2404
	/*    open up a shell script that will be used to output the commands.
2405
	 *    since wireless is changing a lot, these series of commands are fragile
2406
	 *    and will sometimes need to be verified by a operator by executing the command
2407
	 *    and returning the output of the command to the developers for inspection.  please
2408
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2409
	 */
2410

    
2411
	// Remove script file
2412
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2413

    
2414
	// Clone wireless nic if needed.
2415
	interface_wireless_clone($if, $wl);
2416

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

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

    
2424
	/* set values for /path/program */
2425
	$hostapd = "/usr/sbin/hostapd";
2426
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2427
	$ifconfig = "/sbin/ifconfig";
2428
	$sysctl = "/sbin/sysctl";
2429
	$killall = "/usr/bin/killall";
2430

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

    
2433
	$wlcmd = array();
2434
	$wl_sysctl = array();
2435
	/* Make sure it's up */
2436
	$wlcmd[] = "up";
2437
	/* Set a/b/g standard */
2438
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2439
	$wlcmd[] = "mode " . escapeshellarg($standard);
2440

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

    
2446
	/* Set ssid */
2447
	if($wlcfg['ssid'])
2448
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2449

    
2450
	/* Set 802.11g protection mode */
2451
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2452

    
2453
	/* set wireless channel value */
2454
	if(isset($wlcfg['channel'])) {
2455
		if($wlcfg['channel'] == "0") {
2456
			$wlcmd[] = "channel any";
2457
		} else {
2458
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2459
		}
2460
	}
2461

    
2462
	/* Set antenna diversity value */
2463
	if(isset($wlcfg['diversity']))
2464
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2465

    
2466
	/* Set txantenna value */
2467
	if(isset($wlcfg['txantenna']))
2468
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2469

    
2470
	/* Set rxantenna value */
2471
	if(isset($wlcfg['rxantenna']))
2472
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2473

    
2474
	/* set Distance value */
2475
	if($wlcfg['distance'])
2476
		$distance = escapeshellarg($wlcfg['distance']);
2477

    
2478
	/* Set wireless hostap mode */
2479
	if ($wlcfg['mode'] == "hostap") {
2480
		$wlcmd[] = "mediaopt hostap";
2481
	} else {
2482
		$wlcmd[] = "-mediaopt hostap";
2483
	}
2484

    
2485
	/* Set wireless adhoc mode */
2486
	if ($wlcfg['mode'] == "adhoc") {
2487
		$wlcmd[] = "mediaopt adhoc";
2488
	} else {
2489
		$wlcmd[] = "-mediaopt adhoc";
2490
	}
2491

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

    
2494
	/* handle hide ssid option */
2495
	if(isset($wlcfg['hidessid']['enable'])) {
2496
		$wlcmd[] = "hidessid";
2497
	} else {
2498
		$wlcmd[] = "-hidessid";
2499
	}
2500

    
2501
	/* handle pureg (802.11g) only option */
2502
	if(isset($wlcfg['pureg']['enable'])) {
2503
		$wlcmd[] = "mode 11g pureg";
2504
	} else {
2505
		$wlcmd[] = "-pureg";
2506
	}
2507

    
2508
	/* handle puren (802.11n) only option */
2509
	if(isset($wlcfg['puren']['enable'])) {
2510
		$wlcmd[] = "puren";
2511
	} else {
2512
		$wlcmd[] = "-puren";
2513
	}
2514

    
2515
	/* enable apbridge option */
2516
	if(isset($wlcfg['apbridge']['enable'])) {
2517
		$wlcmd[] = "apbridge";
2518
	} else {
2519
		$wlcmd[] = "-apbridge";
2520
	}
2521

    
2522
	/* handle turbo option */
2523
	if(isset($wlcfg['turbo']['enable'])) {
2524
		$wlcmd[] = "mediaopt turbo";
2525
	} else {
2526
		$wlcmd[] = "-mediaopt turbo";
2527
	}
2528

    
2529
	/* handle txpower setting */
2530
	/* if($wlcfg['txpower'] <> "")
2531
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2532
	*/
2533
	/* handle wme option */
2534
	if(isset($wlcfg['wme']['enable'])) {
2535
		$wlcmd[] = "wme";
2536
	} else {
2537
		$wlcmd[] = "-wme";
2538
	}
2539

    
2540
	/* set up wep if enabled */
2541
	$wepset = "";
2542
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2543
		switch($wlcfg['wpa']['auth_algs']) {
2544
			case "1":
2545
				$wepset .= "authmode open wepmode on ";
2546
				break;
2547
			case "2":
2548
				$wepset .= "authmode shared wepmode on ";
2549
				break;
2550
			case "3":
2551
				$wepset .= "authmode mixed wepmode on ";
2552
		}
2553
		$i = 1;
2554
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2555
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2556
			if (isset($wepkey['txkey'])) {
2557
				$wlcmd[] = "weptxkey {$i} ";
2558
			}
2559
			$i++;
2560
		}
2561
		$wlcmd[] = $wepset;
2562
	} else {
2563
		$wlcmd[] = "authmode open wepmode off ";
2564
	}
2565

    
2566
	kill_hostapd($if);
2567
	mwexec(kill_wpasupplicant("{$if}"));
2568

    
2569
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2570
	conf_mount_rw();
2571

    
2572
	switch ($wlcfg['mode']) {
2573
	case 'bss':
2574
		if (isset($wlcfg['wpa']['enable'])) {
2575
			$wpa .= <<<EOD
2576
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2577
ctrl_interface_group=0
2578
ap_scan=1
2579
#fast_reauth=1
2580
network={
2581
ssid="{$wlcfg['ssid']}"
2582
scan_ssid=1
2583
priority=5
2584
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2585
psk="{$wlcfg['wpa']['passphrase']}"
2586
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2587
group={$wlcfg['wpa']['wpa_pairwise']}
2588
}
2589
EOD;
2590

    
2591
			@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2592
			unset($wpa);
2593
		}
2594
		break;
2595
	case 'hostap':
2596
		if (!empty($wlcfg['wpa']['passphrase']))
2597
			$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2598
		else
2599
			$wpa_passphrase = "";
2600
		if (isset($wlcfg['wpa']['enable'])) {
2601
			$wpa .= <<<EOD
2602
interface={$if}
2603
driver=bsd
2604
logger_syslog=-1
2605
logger_syslog_level=0
2606
logger_stdout=-1
2607
logger_stdout_level=0
2608
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2609
ctrl_interface={$g['varrun_path']}/hostapd
2610
ctrl_interface_group=wheel
2611
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2612
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2613
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2614
ssid={$wlcfg['ssid']}
2615
debug={$wlcfg['wpa']['debug_mode']}
2616
auth_algs={$wlcfg['wpa']['auth_algs']}
2617
wpa={$wlcfg['wpa']['wpa_mode']}
2618
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2619
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2620
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2621
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2622
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2623
{$wpa_passphrase}
2624

    
2625
EOD;
2626

    
2627
			if (isset($wlcfg['wpa']['rsn_preauth'])) {
2628
				$wpa .= <<<EOD
2629
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2630
rsn_preauth=1
2631
rsn_preauth_interfaces={$if}
2632

    
2633
EOD;
2634
			}
2635
			if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2636
				$wpa .= "ieee8021x=1\n";
2637

    
2638
			if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2639
				$auth_server_port = "1812";
2640
				if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port']))
2641
					$auth_server_port = intval($wlcfg['auth_server_port']);
2642
				$wpa .= <<<EOD
2643

    
2644
auth_server_addr={$wlcfg['auth_server_addr']}
2645
auth_server_port={$auth_server_port}
2646
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2647

    
2648
EOD;
2649
				if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2650
					$auth_server_port2 = "1812";
2651
					if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2']))
2652
						$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2653

    
2654
					$wpa .= <<<EOD
2655
auth_server_addr={$wlcfg['auth_server_addr2']}
2656
auth_server_port={$auth_server_port2}
2657
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2658

    
2659
EOD;
2660
					}
2661
				}
2662
			}
2663

    
2664
			@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2665
			unset($wpa);
2666
		}
2667
		break;
2668
	}
2669

    
2670
	/*
2671
	 *    all variables are set, lets start up everything
2672
	 */
2673

    
2674
	$baseif = interface_get_wireless_base($if);
2675
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2676
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2677

    
2678
	/* set sysctls for the wireless interface */
2679
	if (!empty($wl_sysctl)) {
2680
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2681
		foreach ($wl_sysctl as $wl_sysctl_line) {
2682
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2683
		}
2684
	}
2685

    
2686
	/* set ack timers according to users preference (if he/she has any) */
2687
	if($distance) {
2688
		fwrite($fd_set, "# Enable ATH distance settings\n");
2689
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2690
	}
2691

    
2692
	if (isset($wlcfg['wpa']['enable'])) {
2693
		if ($wlcfg['mode'] == "bss") {
2694
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2695
		}
2696
		if ($wlcfg['mode'] == "hostap") {
2697
			/* add line to script to restore old mac to make hostapd happy */
2698
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2699
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2700
				if (is_macaddr($if_oldmac))
2701
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2702
						" link " . escapeshellarg($if_oldmac) . "\n");
2703
			}
2704

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

    
2707
			/* add line to script to restore spoofed mac after running hostapd */
2708
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2709
				if ($wl['spoofmac'])
2710
					$if_curmac = $wl['spoofmac'];
2711
				else
2712
					$if_curmac = get_interface_mac($if);
2713
				if (is_macaddr($if_curmac))
2714
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2715
						" link " . escapeshellarg($if_curmac) . "\n");
2716
			}
2717
		}
2718
	}
2719

    
2720
	fclose($fd_set);
2721
	conf_mount_ro();
2722

    
2723
	/* Making sure regulatory settings have actually changed
2724
	 * before applying, because changing them requires bringing
2725
	 * down all wireless networks on the interface. */
2726
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2727
	$ifconfig_str = implode($output);
2728
	unset($output);
2729
	$reg_changing = false;
2730

    
2731
	/* special case for the debug country code */
2732
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2733
		$reg_changing = true;
2734
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2735
		$reg_changing = true;
2736
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2737
		$reg_changing = true;
2738
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2739
		$reg_changing = true;
2740
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2741
		$reg_changing = true;
2742

    
2743
	if ($reg_changing) {
2744
		/* set regulatory domain */
2745
		if($wlcfg['regdomain'])
2746
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2747

    
2748
		/* set country */
2749
		if($wlcfg['regcountry'])
2750
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2751

    
2752
		/* set location */
2753
		if($wlcfg['reglocation'])
2754
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2755

    
2756
		$wlregcmd_args = implode(" ", $wlregcmd);
2757

    
2758
		/* build a complete list of the wireless clones for this interface */
2759
		$clone_list = array();
2760
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2761
			$clone_list[] = interface_get_wireless_clone($baseif);
2762
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2763
			foreach ($config['wireless']['clone'] as $clone) {
2764
				if ($clone['if'] == $baseif)
2765
					$clone_list[] = $clone['cloneif'];
2766
			}
2767
		}
2768

    
2769
		/* find which clones are up and bring them down */
2770
		$clones_up = array();
2771
		foreach ($clone_list as $clone_if) {
2772
			$clone_status = pfSense_get_interface_addresses($clone_if);
2773
			if ($clone_status['status'] == 'up') {
2774
				$clones_up[] = $clone_if;
2775
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2776
			}
2777
		}
2778

    
2779
		/* apply the regulatory settings */
2780
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2781

    
2782
		/* bring the clones back up that were previously up */
2783
		foreach ($clones_up as $clone_if) {
2784
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2785

    
2786
			/*
2787
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2788
			 * is in infrastructure mode, and WPA is enabled.
2789
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2790
			 */
2791
			if ($clone_if != $if) {
2792
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2793
				if ( !empty($friendly_if)
2794
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2795
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2796
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2797
				}
2798
			}
2799
		}
2800
	}
2801

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

    
2806
	/* configure wireless */
2807
	$wlcmd_args = implode(" ", $wlcmd);
2808
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2809
	unset($wlcmd_args, $wlcmd);
2810

    
2811

    
2812
	sleep(1);
2813
	/* execute hostapd and wpa_supplicant if required in shell */
2814
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2815

    
2816
	return 0;
2817

    
2818
}
2819

    
2820
function kill_hostapd($interface) {
2821
	global $g;
2822

    
2823
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid"))
2824
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2825
}
2826

    
2827
function kill_wpasupplicant($interface) {
2828
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2829
}
2830

    
2831
function find_dhclient_process($interface) {
2832
	if ($interface)
2833
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2834
	else
2835
		$pid = 0;
2836

    
2837
	return intval($pid);
2838
}
2839

    
2840
function kill_dhclient_process($interface) {
2841
	if (empty($interface) || !does_interface_exist($interface))
2842
		return;
2843

    
2844
	$i = 0;
2845
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2846
		/* 3rd time make it die for sure */
2847
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2848
		posix_kill($pid, $sig);
2849
		sleep(1);
2850
		$i++;
2851
	}
2852
	unset($i);
2853
}
2854

    
2855
function find_dhcp6c_process($interface) {
2856
	global $g;
2857

    
2858
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid"))
2859
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2860
	else
2861
		return(false);
2862

    
2863
	return intval($pid);
2864
}
2865

    
2866
function interface_vlan_mtu_configured($realhwif, $mtu) {
2867
	global $config;
2868

    
2869
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
2870
		foreach ($config['vlans']['vlan'] as $vlan) {
2871
			if ($vlan['if'] != $realhwif)
2872
				continue;
2873
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2874
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
2875
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2876
					$mtu = $portmtu;
2877
			}
2878
		}
2879
	}
2880

    
2881
	return $mtu;
2882
}
2883

    
2884
function interface_virtual_create($interface) {
2885
	global $config;
2886

    
2887
	if (strstr($interface, "_vlan")) {
2888
		interfaces_vlan_configure($vlan);
2889
	} else if (substr($interface, 0, 3) == "gre") {
2890
		interfaces_gre_configure(0, $interface);
2891
	} else if (substr($interface, 0, 3) == "gif") {
2892
		interfaces_gif_configure(0, $interface);
2893
	} else if (substr($interface, 0, 5) == "ovpns") {
2894
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
2895
			foreach ($config['openvpn']['openvpn-server'] as $server) {
2896
				if ($interface == "ovpns{$server['vpnid']}") {
2897
					if (!function_exists('openvpn_resync'))
2898
						require_once('openvpn.inc');
2899
					log_error("OpenVPN: Resync server {$server['description']}");
2900
					openvpn_resync('server', $server);
2901
				}
2902
			}
2903
			unset($server);
2904
		}
2905
	} else if (substr($interface, 0, 5) == "ovpnc") {
2906
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
2907
			foreach ($config['openvpn']['openvpn-client'] as $client) {
2908
				if ($interface == "ovpnc{$client['vpnid']}") {
2909
					if (!function_exists('openvpn_resync'))
2910
						require_once('openvpn.inc');
2911
					log_error("OpenVPN: Resync server {$client['description']}");
2912
					openvpn_resync('client', $client);
2913
				}
2914
			}
2915
			unset($client);
2916
		}
2917
	} else if (substr($interface, 0, 4) == "lagg") {
2918
		interfaces_lagg_configure($interface);
2919
	} else if (substr($interface, 0, 6) == "bridge") {
2920
		interfaces_bridge_configure(0, $interface);
2921
	}
2922
}
2923

    
2924
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
2925
	global $config;
2926

    
2927
	if (!is_array($vlanifs))
2928
		return;
2929

    
2930
	/* All vlans need to use the same mtu value as their parent. */
2931
	foreach ($vlanifs as $vlan) {
2932
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
2933
		if (!empty($assignedport)) {
2934
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
2935
				/*
2936
				* XXX: This is really never going to happen just keep the code for safety and readbility.
2937
				* It never happens since interface_vlan_mtu_configured finds the biggest mtu on vlans.
2938
				* Also if it has a lower mtu configured just respect user choice.
2939
				*/
2940
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu)
2941
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2942
			} else {
2943
				if (get_interface_mtu($vlan['vlanif']) != $mtu)
2944
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
2945
			}
2946
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu)
2947
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
2948
	}
2949
}
2950

    
2951
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2952
	global $config, $g;
2953
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2954
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2955

    
2956
	$wancfg = $config['interfaces'][$interface];
2957

    
2958
	if (!isset($wancfg['enable']))
2959
		return;
2960

    
2961
	$realif = get_real_interface($interface);
2962
	$realhwif_array = get_parent_interface($interface);
2963
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2964
	$realhwif = $realhwif_array[0];
2965

    
2966
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2967
		/* remove all IPv4 and IPv6 addresses */
2968
		$tmpifaces = pfSense_getall_interface_addresses($realif);
2969
		if (is_array($tmpifaces)) {
2970
			foreach ($tmpifaces as $tmpiface) {
2971
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
2972
					if (!is_linklocal($tmpiface))
2973
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
2974
				} else {
2975
					if (is_subnetv4($tmpiface)) {
2976
						$tmpip = explode('/', $tmpiface);
2977
						$tmpip = $tmpip[0];
2978
					} else
2979
						$tmpip = $tmpiface;
2980
					pfSense_interface_deladdress($realif, $tmpip);
2981
				}
2982
			}
2983
		}
2984

    
2985
		/* only bring down the interface when both v4 and v6 are set to NONE */
2986
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6']))
2987
			interface_bring_down($interface);
2988
	}
2989

    
2990
	$interface_to_check = $realif;
2991
	switch ($wancfg['ipaddr']) {
2992
	case 'pppoe':
2993
	case 'l2tp':
2994
	case 'pptp':
2995
	case 'ppp':
2996
		$interface_to_check = $realhwif;
2997
		break;
2998
	}
2999

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

    
3004
	/* Disable Accepting router advertisements unless specifically requested */
3005
	if ($g['debug'])
3006
		log_error("Deny router advertisements for interface {$interface}");
3007
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
3008

    
3009
	/* wireless configuration? */
3010
	if (is_array($wancfg['wireless']))
3011
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3012

    
3013
	$mac = get_interface_mac($realhwif);
3014
	/*
3015
	 * Don't try to reapply the spoofed MAC if it's already applied.
3016
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3017
	 * the interface config again, which attempts to spoof the MAC again,
3018
	 * which cycles the link again...
3019
	 */
3020
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
3021
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3022
			" link " . escapeshellarg($wancfg['spoofmac']));
3023

    
3024
		/*
3025
		 * All vlans need to spoof their parent mac address, too.  see
3026
		 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
3027
		 */
3028
		if (is_array($config['vlans']['vlan'])) {
3029
			foreach ($config['vlans']['vlan'] as $vlan) {
3030
				if ($vlan['if'] == $realhwif)
3031
					mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
3032
					" link " . escapeshellarg($wancfg['spoofmac']));
3033
			}
3034
		}
3035
	}  else {
3036

    
3037
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3038
			/*   this is not a valid mac address.  generate a
3039
			 *   temporary mac address so the machine can get online.
3040
			 */
3041
			echo gettext("Generating new MAC address.");
3042
			$random_mac = generate_random_mac_address();
3043
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3044
				" link " . escapeshellarg($random_mac));
3045
			$wancfg['spoofmac'] = $random_mac;
3046
			write_config();
3047
			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");
3048
		}
3049
	}
3050

    
3051
	/* media */
3052
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3053
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3054
		if ($wancfg['media'])
3055
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3056
		if ($wancfg['mediaopt'])
3057
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3058
		mwexec($cmd);
3059
	}
3060
	$options = pfSense_get_interface_addresses($realhwif);
3061

    
3062
	/* skip vlans for checksumming and polling */
3063
	if (!stristr($realif, "_vlan") && is_array($options)) {
3064
		$flags_on = 0;
3065
		$flags_off = 0;
3066
		if(isset($config['system']['disablechecksumoffloading'])) {
3067
			if (isset($options['encaps']['txcsum']))
3068
				$flags_off |= IFCAP_TXCSUM;
3069
			if (isset($options['encaps']['rxcsum']))
3070
				$flags_off |= IFCAP_RXCSUM;
3071
		} else {
3072
			if (isset($options['caps']['txcsum']))
3073
				$flags_on |= IFCAP_TXCSUM;
3074
			if (isset($options['caps']['rxcsum']))
3075
				$flags_on |= IFCAP_RXCSUM;
3076
		}
3077

    
3078
		if(isset($config['system']['disablesegmentationoffloading']))
3079
			$flags_off |= IFCAP_TSO;
3080
		else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6']))
3081
			$flags_on |= IFCAP_TSO;
3082

    
3083
		if(isset($config['system']['disablelargereceiveoffloading']))
3084
			$flags_off |= IFCAP_LRO;
3085
		else if (isset($options['caps']['lro']))
3086
			$flags_on |= IFCAP_LRO;
3087

    
3088
		/* if the NIC supports polling *AND* it is enabled in the GUI */
3089
		if (!isset($config['system']['polling']))
3090
			$flags_off |= IFCAP_POLLING;
3091
		else if (isset($options['caps']['polling']))
3092
			$flags_on |= IFCAP_POLLING;
3093

    
3094
		pfSense_interface_capabilities($realhwif, -$flags_off);
3095
		pfSense_interface_capabilities($realhwif, $flags_on);
3096
	}
3097

    
3098
	/* invalidate interface/ip/sn cache */
3099
	get_interface_arr(true);
3100
	unset($interface_ip_arr_cache[$realif]);
3101
	unset($interface_sn_arr_cache[$realif]);
3102
	unset($interface_ipv6_arr_cache[$realif]);
3103
	unset($interface_snv6_arr_cache[$realif]);
3104

    
3105
	$tunnelif = substr($realif, 0, 3);
3106
	switch ($wancfg['ipaddr']) {
3107
	case 'dhcp':
3108
		interface_dhcp_configure($interface);
3109
		break;
3110
	case 'pppoe':
3111
	case 'l2tp':
3112
	case 'pptp':
3113
	case 'ppp':
3114
		interface_ppps_configure($interface);
3115
		break;
3116
	default:
3117
		/* XXX: Kludge for now related to #3280 */
3118
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3119
			if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "")
3120
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3121
		}
3122
		break;
3123
	}
3124

    
3125
	switch ($wancfg['ipaddrv6']) {
3126
	case 'slaac':
3127
	case 'dhcp6':
3128
		interface_dhcpv6_configure($interface, $wancfg);
3129
		break;
3130
	case '6rd':
3131
		interface_6rd_configure($interface, $wancfg);
3132
		break;
3133
	case '6to4':
3134
		interface_6to4_configure($interface, $wancfg);
3135
		break;
3136
	case 'track6':
3137
		interface_track6_configure($interface, $wancfg, $linkupevent);
3138
		break;
3139
	default:
3140
		/* XXX: Kludge for now related to #3280 */
3141
		if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3142
			if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3143
				//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3144
				// FIXME: Add IPv6 Support to the pfSense module
3145
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3146
			}
3147
		}
3148
		break;
3149
	}
3150

    
3151
	if (!empty($wancfg['mtu'])) {
3152
		if (stristr($realif, "_vlan")) {
3153
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3154
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu']))
3155
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3156
			else
3157
				$parentmtu = interface_vlan_mtu_configured($realhwif, $wancfg['mtu']);
3158

    
3159
			if ($wancfg['mtu'] > $parentmtu) {
3160
				if (get_interface_mtu($realhwif) != $wancfg['mtu'])
3161
					pfSense_interface_mtu($realhwif, $wancfg['mtu']);
3162

    
3163
				/* All vlans need to use the same mtu value as their parent. */
3164
				interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $wancfg['mtu']);
3165
			} else
3166
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3167
		} else if (substr($realif, 0, 4) == 'lagg') {
3168
			/* LAGG interface must be destroyed and re-created to change MTU */
3169
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3170
				if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3171
					foreach ($config['laggs']['lagg'] as $lagg) {
3172
						if ($lagg['laggif'] == $realif) {
3173
							interface_lagg_configure($lagg);
3174
							break;
3175
						}
3176
					}
3177
				}
3178
			}
3179
		} else {
3180
			if ($wancfg['mtu'] != get_interface_mtu($realif))
3181
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3182

    
3183
			/* This case is needed when the parent of vlans is being configured */
3184
			interface_vlan_adapt_mtu(link_interface_to_vlans($realif), $wancfg['mtu']);
3185
		}
3186
		/* XXX: What about gre/gif/.. ? */
3187
	}
3188

    
3189
	if (does_interface_exist($wancfg['if']))
3190
		interfaces_bring_up($wancfg['if']);
3191

    
3192
	interface_netgraph_needed($interface);
3193

    
3194
	if (!$g['booting']) {
3195
		link_interface_to_vips($interface, "update");
3196

    
3197
		unset($gre);
3198
		$gre = link_interface_to_gre($interface);
3199
		if (!empty($gre))
3200
			array_walk($gre, 'interface_gre_configure');
3201

    
3202
		unset($gif);
3203
		$gif = link_interface_to_gif($interface);
3204
		if (!empty($gif))
3205
			array_walk($gif, 'interface_gif_configure');
3206

    
3207
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3208
			unset($bridgetmp);
3209
			$bridgetmp = link_interface_to_bridge($interface);
3210
			if (!empty($bridgetmp))
3211
				interface_bridge_add_member($bridgetmp, $realif);
3212
		}
3213

    
3214
		$grouptmp = link_interface_to_group($interface);
3215
		if (!empty($grouptmp))
3216
			array_walk($grouptmp, 'interface_group_add_member');
3217

    
3218
		if ($interface == "lan")
3219
			/* make new hosts file */
3220
			system_hosts_generate();
3221

    
3222
		if ($reloadall == true) {
3223

    
3224
			/* reconfigure static routes (kernel may have deleted them) */
3225
			system_routing_configure($interface);
3226

    
3227
			/* reload ipsec tunnels */
3228
			vpn_ipsec_configure();
3229

    
3230
			/* restart dnsmasq or unbound */
3231
			if (isset($config['dnsmasq']['enable']))
3232
				services_dnsmasq_configure();
3233
			elseif (isset($config['unbound']['enable']))
3234
				services_unbound_configure();
3235

    
3236
			/* update dyndns */
3237
			send_event("service reload dyndns {$interface}");
3238

    
3239
			/* XXX: which CPZONE? Needed? */
3240
			/* reload captive portal */
3241
			captiveportal_init_rules();
3242
		}
3243
	}
3244

    
3245
	interfaces_staticarp_configure($interface);
3246
	return 0;
3247
}
3248

    
3249
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3250
	global $config, $g;
3251

    
3252
	if (!is_array($wancfg))
3253
		return;
3254

    
3255
	if (!isset($wancfg['enable']))
3256
		return;
3257

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

    
3262
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3263
	$realif = get_real_interface($interface);
3264
	$linklocal = find_interface_ipv6_ll($realif);
3265
	if (!empty($linklocal))
3266
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3267
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3268
	/* XXX: Probably should remove? */
3269
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3270

    
3271
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3272
	if (!isset($trackcfg['enable'])) {
3273
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3274
		return;
3275
	}
3276

    
3277
	switch($trackcfg['ipaddrv6']) {
3278
	case "6to4":
3279
		if ($g['debug'])
3280
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3281
		interface_track6_6to4_configure($interface, $wancfg);
3282
		break;
3283
	case "6rd":
3284
		if ($g['debug'])
3285
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3286
		interface_track6_6rd_configure($interface, $wancfg);
3287
		break;
3288
	case "dhcp6":
3289
		if ($linkupevent == true) {
3290
			/* 
3291
			 * NOTE: Usually come here from rc.linkup calling so just call directly intead of generating event
3292
			 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3293
			 *
3294
			 * XXX: Probably DHCPv6 client should handle this autmagically itself?
3295
			 */
3296
			$parentrealif = get_real_interface($wancfg['track6-interface']);
3297
			$pidv6 = find_dhcp6c_process($parentrealif);
3298
			if($pidv6)
3299
				posix_kill($pidv6, SIGHUP);
3300
		}
3301
		break;
3302
	}
3303

    
3304
	if (!$g['booting'] && $linkupevent == false) {
3305
		if (!function_exists('services_dhcpd_configure'))
3306
			require_once("services.inc");
3307

    
3308
		services_dhcpd_configure("inet6");
3309
	}
3310

    
3311
	return 0;
3312
}
3313

    
3314
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3315
	global $config, $g;
3316
	global $interface_ipv6_arr_cache;
3317
	global $interface_snv6_arr_cache;
3318

    
3319
	if (!is_array($lancfg))
3320
		return;
3321

    
3322
	/* If the interface is not configured via another, exit */
3323
	if (empty($lancfg['track6-interface']))
3324
		return;
3325

    
3326
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3327
	if (empty($wancfg)) {
3328
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3329
		return;
3330
	}
3331

    
3332
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3333
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3334
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3335
		return;
3336
	}
3337
	$hexwanv4 = return_hex_ipv4($ip4address);
3338

    
3339
	/* create the long prefix notation for math, save the prefix length */
3340
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3341
	$rd6prefixlen = $rd6prefix[1];
3342
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3343

    
3344
	/* binary presentation of the prefix for all 128 bits. */
3345
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3346

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

    
3352
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3353
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3354
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3355
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3356
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3357
	/* fill the rest out with zeros */
3358
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3359

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

    
3363
	$lanif = get_real_interface($interface);
3364
	$oip = find_interface_ipv6($lanif);
3365
	if (is_ipaddrv6($oip))
3366
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3367
	unset($interface_ipv6_arr_cache[$lanif]);
3368
	unset($interface_snv6_arr_cache[$lanif]);
3369
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3370
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3371

    
3372
	return 0;
3373
}
3374

    
3375
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3376
	global $config, $g;
3377
	global $interface_ipv6_arr_cache;
3378
	global $interface_snv6_arr_cache;
3379

    
3380
	if (!is_array($lancfg))
3381
		return;
3382

    
3383
	/* If the interface is not configured via another, exit */
3384
	if (empty($lancfg['track6-interface']))
3385
		return;
3386

    
3387
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3388
	if (empty($wancfg)) {
3389
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3390
		return;
3391
	}
3392

    
3393
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3394
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3395
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3396
		return;
3397
	}
3398
	$hexwanv4 = return_hex_ipv4($ip4address);
3399

    
3400
	/* create the long prefix notation for math, save the prefix length */
3401
	$sixto4prefix = "2002::";
3402
	$sixto4prefixlen = 16;
3403
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3404

    
3405
	/* binary presentation of the prefix for all 128 bits. */
3406
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3407

    
3408
	/* just save the left prefix length bits */
3409
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3410
	/* add the v4 address */
3411
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3412
	/* add the custom prefix id */
3413
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3414
	/* fill the rest out with zeros */
3415
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3416

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

    
3420
	$lanif = get_real_interface($interface);
3421
	$oip = find_interface_ipv6($lanif);
3422
	if (is_ipaddrv6($oip))
3423
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3424
	unset($interface_ipv6_arr_cache[$lanif]);
3425
	unset($interface_snv6_arr_cache[$lanif]);
3426
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3427
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3428

    
3429
	return 0;
3430
}
3431

    
3432
function interface_6rd_configure($interface = "wan", $wancfg) {
3433
	global $config, $g;
3434

    
3435
	/* because this is a tunnel interface we can only function
3436
	 *	with a public IPv4 address on the interface */
3437

    
3438
	if (!is_array($wancfg))
3439
		return;
3440

    
3441
	if (!is_module_loaded('if_stf.ko'))
3442
		mwexec('/sbin/kldload if_stf.ko');
3443

    
3444
	$wanif = get_real_interface($interface);
3445
	$ip4address = find_interface_ip($wanif);
3446
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3447
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3448
		return false;
3449
	}
3450
	$hexwanv4 = return_hex_ipv4($ip4address);
3451

    
3452
	if (!is_numeric($wancfg['prefix-6rd-v4plen']))
3453
		$wancfg['prefix-6rd-v4plen'] = 0;
3454

    
3455
	/* create the long prefix notation for math, save the prefix length */
3456
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3457
	$rd6prefixlen = $rd6prefix[1];
3458
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3459

    
3460
	/* binary presentation of the prefix for all 128 bits. */
3461
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3462

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

    
3470
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3471
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3472

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

    
3475
	/* XXX: need to extend to support variable prefix size for v4 */
3476
	if (!is_module_loaded("if_stf"))
3477
		mwexec("/sbin/kldload if_stf.ko");
3478
	$stfiface = "{$interface}_stf";
3479
	if (does_interface_exist($stfiface))
3480
		pfSense_interface_destroy($stfiface);
3481
	$tmpstfiface = pfSense_interface_create("stf");
3482
	pfSense_interface_rename($tmpstfiface, $stfiface);
3483
	pfSense_interface_flags($stfiface, IFF_LINK2);
3484
	if ($wancfg['prefix-6rd-v4plen'] > 0)
3485
		$rd6prefixlen += intval($wancfg['prefix-6rd-v4plen']);
3486
	else
3487
		$rd6prefixlen += 32;
3488
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3489
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3490
	if ($wancfg['prefix-6rd-v4plen'] > 0 && $wancfg['prefix-6rd-v4plen'] < 32)
3491
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/{$wancfg['prefix-6rd-v4plen']}");
3492
	if ($g['debug'])
3493
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3494

    
3495
	/* write out a default router file */
3496
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3497
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3498

    
3499
	$ip4gateway = get_interface_gateway($interface);
3500
	if (is_ipaddrv4($ip4gateway))
3501
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3502

    
3503
	/* configure dependent interfaces */
3504
	if (!$g['booting'])
3505
		link_interface_to_track6($interface, "update");
3506

    
3507
	return 0;
3508
}
3509

    
3510
function interface_6to4_configure($interface = "wan", $wancfg){
3511
	global $config, $g;
3512

    
3513
	/* because this is a tunnel interface we can only function
3514
	 *	with a public IPv4 address on the interface */
3515

    
3516
	if (!is_array($wancfg))
3517
		return;
3518

    
3519
	$wanif = get_real_interface($interface);
3520
	$ip4address = find_interface_ip($wanif);
3521
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3522
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3523
		return false;
3524
	}
3525

    
3526
	/* create the long prefix notation for math, save the prefix length */
3527
	$stfprefixlen = 16;
3528
	$stfprefix = Net_IPv6::uncompress("2002::");
3529
	$stfarr = explode(":", $stfprefix);
3530
	$v4prefixlen = "0";
3531

    
3532
	/* we need the hex form of the interface IPv4 address */
3533
	$ip4arr = explode(".", $ip4address);
3534
	$hexwanv4 = "";
3535
	foreach($ip4arr as $octet)
3536
		$hexwanv4 .= sprintf("%02x", $octet);
3537

    
3538
	/* we need the hex form of the broker IPv4 address */
3539
	$ip4arr = explode(".", "192.88.99.1");
3540
	$hexbrv4 = "";
3541
	foreach($ip4arr as $octet)
3542
		$hexbrv4 .= sprintf("%02x", $octet);
3543

    
3544
	/* binary presentation of the prefix for all 128 bits. */
3545
	$stfprefixbin = "";
3546
	foreach($stfarr as $element) {
3547
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3548
	}
3549
	/* just save the left prefix length bits */
3550
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3551

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

    
3556
	/* for the local subnet too. */
3557
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3558
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3559

    
3560
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3561
	$stfbrarr = array();
3562
	$stfbrbinarr = array();
3563
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3564
	foreach($stfbrbinarr as $bin)
3565
		$stfbrarr[] = dechex(bindec($bin));
3566
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3567

    
3568
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3569
	$stflanarr = array();
3570
	$stflanbinarr = array();
3571
	$stflanbinarr = str_split($stflanbin, 16);
3572
	foreach($stflanbinarr as $bin)
3573
		$stflanarr[] = dechex(bindec($bin));
3574
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3575
	$stflanarr[7] = 1;
3576
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3577

    
3578
	/* setup the stf interface */
3579
	if (!is_module_loaded("if_stf"))
3580
		mwexec("/sbin/kldload if_stf.ko");
3581
	$stfiface = "{$interface}_stf";
3582
	if (does_interface_exist($stfiface))
3583
		pfSense_interface_destroy($stfiface);
3584
	$tmpstfiface = pfSense_interface_create("stf");
3585
	pfSense_interface_rename($tmpstfiface, $stfiface);
3586
	pfSense_interface_flags($stfiface, IFF_LINK2);
3587
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3588

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

    
3592
	/* write out a default router file */
3593
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3594
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3595

    
3596
	$ip4gateway = get_interface_gateway($interface);
3597
	if (is_ipaddrv4($ip4gateway))
3598
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3599

    
3600
	if (!$g['booting'])
3601
		link_interface_to_track6($interface, "update");
3602

    
3603
	return 0;
3604
}
3605

    
3606
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3607
	global $config, $g;
3608

    
3609
	if (!is_array($wancfg))
3610
		return;
3611

    
3612
	$wanif = get_real_interface($interface, "inet6");
3613
	$dhcp6cconf = "";
3614
	$dhcp6cconf .= "interface {$wanif} {\n";
3615

    
3616
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3617
	if($wancfg['ipaddrv6'] == "slaac") {
3618
		$dhcp6cconf .= "	information-only;\n";
3619
		$dhcp6cconf .= "	request domain-name-servers;\n";
3620
		$dhcp6cconf .= "	request domain-name;\n";
3621
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3622
		$dhcp6cconf .= "};\n";
3623
	} else {
3624
		/* skip address request if this is set */
3625
		if(!isset($wancfg['dhcp6prefixonly']))
3626
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3627
		if(is_numeric($wancfg['dhcp6-ia-pd-len']))
3628
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3629

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

    
3634
		$dhcp6cconf .= "};\n";
3635

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

    
3639
		if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3640
			/* Setup the prefix delegation */
3641
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3642
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3643
			if (isset($wancfg['dhcp6-ia-pd-send-hint']))
3644
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3645
			$iflist = link_interface_to_track6($interface);
3646
			foreach ($iflist as $friendly => $ifcfg) {
3647
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3648
					if ($g['debug'])
3649
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3650
					$realif = get_real_interface($friendly);
3651
					$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3652
					$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3653
					$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3654
					$dhcp6cconf .= "	};\n";
3655
				}
3656
			}
3657
			unset($preflen, $iflist, $ifcfg);
3658
			$dhcp6cconf .= "};\n";
3659
		}
3660
	}
3661

    
3662
	// DHCP6 Config File Advanced
3663
	if ($wancfg['adv_dhcp6_config_advanced']) { $dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif); }
3664

    
3665
	// DHCP6 Config File Override
3666
	if ($wancfg['adv_dhcp6_config_file_override']) { $dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif); }
3667

    
3668
	/* wide-dhcp6c works for now. */
3669
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3670
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3671
		unset($dhcp6cconf);
3672
		return 1;
3673
	}
3674
	unset($dhcp6cconf);
3675

    
3676
	$dhcp6cscript = "#!/bin/sh\n";
3677
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3678
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3679
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3680
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3681
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3682
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3683
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3684
		unset($dhcp6cscript);
3685
		return 1;
3686
	}
3687
	unset($dhcp6cscript);
3688
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3689

    
3690
	$rtsoldscript = "#!/bin/sh\n";
3691
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3692
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3693
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3694
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Recieved RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
3695
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3696
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3697
	$rtsoldscript .= "\t/bin/sleep 1\n";
3698
	$rtsoldscript .= "fi\n";
3699
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3700
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3701
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3702
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3703
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3704
		unset($rtsoldscript);
3705
		return 1;
3706
	}
3707
	unset($rtsoldscript);
3708
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3709

    
3710
	/* accept router advertisements for this interface */
3711
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3712
	log_error("Accept router advertisements on interface {$wanif} ");
3713
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3714

    
3715
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3716
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3717
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3718
		sleep(2);
3719
	}
3720
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3721

    
3722
	/* NOTE: will be called from rtsold invoked script
3723
	 * link_interface_to_track6($interface, "update");
3724
	 */
3725

    
3726
	return 0;
3727
}
3728

    
3729
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3730
	global $g;
3731

    
3732
	$send_options = "";
3733
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3734
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_send_options']);
3735
		foreach ($options as $option) {
3736
			$send_options .= "\tsend " . trim($option) . ";\n";
3737
		}
3738
	}
3739

    
3740
	$request_options = "";
3741
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3742
		$options = split(",", $wancfg['adv_dhcp6_interface_statement_request_options']);
3743
		foreach ($options as $option) {
3744
			$request_options .= "\trequest " . trim($option) . ";\n";
3745
		}
3746
	}
3747

    
3748
	$information_only = "";
3749
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') 
3750
		$information_only = "\tinformation-only;\n";
3751

    
3752
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3753
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '')
3754
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3755

    
3756
	$interface_statement  = "interface";
3757
	$interface_statement .= " {$wanif}";
3758
	$interface_statement .= " {\n";
3759
	$interface_statement .= "$send_options";
3760
	$interface_statement .= "$request_options";
3761
	$interface_statement .= "$information_only";
3762
	$interface_statement .= "$script";
3763
	$interface_statement .= "};\n";
3764

    
3765
	$id_assoc_statement_address = "";
3766
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3767
		$id_assoc_statement_address .= "id-assoc";
3768
		$id_assoc_statement_address .= " na";
3769
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) 
3770
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3771
		$id_assoc_statement_address .= " { ";
3772

    
3773
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') && 
3774
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) || 
3775
			 ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity')) ) {
3776
			$id_assoc_statement_address .= "\n\taddress";
3777
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3778
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3779
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) || 
3780
							($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity') ) 
3781
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3782
			$id_assoc_statement_address .= ";\n";
3783
		}
3784

    
3785
		$id_assoc_statement_address  .= "};\n";
3786
	}
3787

    
3788
	$id_assoc_statement_prefix = "";
3789
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3790
		$id_assoc_statement_prefix .= "id-assoc";
3791
		$id_assoc_statement_prefix .= " pd";
3792
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) 
3793
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3794
		$id_assoc_statement_prefix .= " { ";
3795

    
3796
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') && 
3797
			 (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) || 
3798
			 ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity')) ) {
3799
			$id_assoc_statement_prefix .= "\n\tprefix";
3800
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3801
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3802
			if ( (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) || 
3803
						  ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity') ) 
3804
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3805
			$id_assoc_statement_prefix .= ";";
3806
		}
3807

    
3808
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3809
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3810
			$id_assoc_statement_prefix .= " {$wanif}";
3811
			$id_assoc_statement_prefix .= " {\n";
3812
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3813
			if ( ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) && 
3814
				 ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128) ) 
3815
				 $id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3816
			$id_assoc_statement_prefix .= "\t};";
3817
		}
3818

    
3819
		if ( ($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') || 
3820
			 (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) ) { 
3821
			$id_assoc_statement_prefix .= "\n";
3822
		}
3823

    
3824
		$id_assoc_statement_prefix  .= "};\n";
3825
	}
3826

    
3827
	$authentication_statement = "";
3828
	if ( ($wancfg['adv_dhcp6_authentication_statement_authname'] != '') && 
3829
		 ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed') ) {
3830
		$authentication_statement .= "authentication";
3831
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
3832
		$authentication_statement .= " {\n";
3833
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
3834
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) 
3835
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
3836
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') 
3837
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
3838
		$authentication_statement .= "};\n";
3839
	}
3840

    
3841
	$key_info_statement = "";
3842
	if ( ($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') && 
3843
		 ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') && 
3844
		 (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) && 
3845
		 ($wancfg['adv_dhcp6_key_info_statement_secret'] != '') ) {
3846
		$key_info_statement .= "keyinfo";
3847
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
3848
		$key_info_statement .= " {\n";
3849
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
3850
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
3851
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
3852
		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'])) 
3853
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
3854
		$key_info_statement .= "};\n";
3855
	}
3856

    
3857
	$dhcp6cconf  = $interface_statement;
3858
	$dhcp6cconf .= $id_assoc_statement_address;
3859
	$dhcp6cconf .= $id_assoc_statement_prefix;
3860
	$dhcp6cconf .= $authentication_statement;
3861
	$dhcp6cconf .= $key_info_statement;
3862

    
3863
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3864

    
3865
	return $dhcp6cconf;
3866
}
3867

    
3868

    
3869
function DHCP6_Config_File_Override($wancfg, $wanif) {
3870

    
3871
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
3872
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3873

    
3874
	return $dhcp6cconf;
3875
}
3876

    
3877

    
3878
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
3879

    
3880
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
3881

    
3882
	return $dhcp6cconf;
3883
}
3884

    
3885

    
3886
function interface_dhcp_configure($interface = "wan") {
3887
	global $config, $g;
3888

    
3889
	$wancfg = $config['interfaces'][$interface];
3890
	$wanif = $wancfg['if'];
3891
	if (empty($wancfg))
3892
		$wancfg = array();
3893

    
3894
	/* generate dhclient_wan.conf */
3895
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3896
	if (!$fd) {
3897
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3898
		return 1;
3899
	}
3900

    
3901
	if ($wancfg['dhcphostname']) {
3902
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3903
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3904
	} else {
3905
		$dhclientconf_hostname = "";
3906
	}
3907

    
3908
	$wanif = get_real_interface($interface);
3909
	if (empty($wanif)) {
3910
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3911
		return 0;
3912
	}
3913
	$dhclientconf = "";
3914

    
3915
	$dhclientconf .= <<<EOD
3916
interface "{$wanif}" {
3917
timeout 60;
3918
retry 15;
3919
select-timeout 0;
3920
initial-interval 1;
3921
	{$dhclientconf_hostname}
3922
	script "/sbin/dhclient-script";
3923
EOD;
3924

    
3925
if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
3926
	$dhclientconf .= <<<EOD
3927

    
3928
	reject {$wancfg['dhcprejectfrom']};
3929
EOD;
3930
}
3931
	$dhclientconf .= <<<EOD
3932

    
3933
}
3934

    
3935
EOD;
3936

    
3937
	// DHCP Config File Advanced
3938
	if ($wancfg['adv_dhcp_config_advanced']) { $dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif); }
3939

    
3940
if(is_ipaddr($wancfg['alias-address'])) {
3941
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3942
	$dhclientconf .= <<<EOD
3943
alias {
3944
	interface  "{$wanif}";
3945
	fixed-address {$wancfg['alias-address']};
3946
	option subnet-mask {$subnetmask};
3947
}
3948

    
3949
EOD;
3950
}
3951

    
3952
	// DHCP Config File Override
3953
	if ($wancfg['adv_dhcp_config_file_override']) { $dhclientconf = DHCP_Config_File_Override($wancfg, $wanif); }
3954

    
3955
	fwrite($fd, $dhclientconf);
3956
	fclose($fd);
3957

    
3958
	/* bring wan interface up before starting dhclient */
3959
	if($wanif)
3960
		interfaces_bring_up($wanif);
3961
	else
3962
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3963

    
3964
	/* Make sure dhclient is not running */
3965
	kill_dhclient_process($wanif);
3966

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

    
3970
	return 0;
3971
}
3972

    
3973
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
3974

    
3975
	$hostname = "";
3976
	if ($wancfg['dhcphostname'] != '') {
3977
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3978
	}
3979

    
3980
	/* DHCP Protocol Timings */
3981
	$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");
3982
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
3983
		$pt_variable = "{$Protocol_Timing}";
3984
		${$pt_variable} = "";
3985
		if ($wancfg[$Protocol_Timing] != "") {
3986
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
3987
		}
3988
	}
3989

    
3990
	$send_options = "";
3991
	if ($wancfg['adv_dhcp_send_options'] != '') {
3992
		$options = split(",", $wancfg['adv_dhcp_send_options']);
3993
		foreach ($options as $option) {
3994
			$send_options .= "\tsend " . trim($option) . ";\n";
3995
		}
3996
	}
3997

    
3998
	$request_options = "";
3999
	if ($wancfg['adv_dhcp_request_options'] != '') {
4000
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4001
	}
4002

    
4003
	$required_options = "";
4004
	if ($wancfg['adv_dhcp_required_options'] != '') {
4005
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4006
	}
4007

    
4008
	$option_modifiers = "";
4009
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4010
		$modifiers = split(",", $wancfg['adv_dhcp_option_modifiers']);
4011
		foreach ($modifiers as $modifier) {
4012
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4013
		}
4014
	}
4015

    
4016
 	$dhclientconf  = "interface \"{$wanif}\" {\n";
4017
 	$dhclientconf .= "\n";
4018
 	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4019
 	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4020
 	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4021
 	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4022
 	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4023
 	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4024
 	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4025
 	$dhclientconf .= "\n";
4026
 	$dhclientconf .= "# DHCP Protocol Options\n";
4027
 	$dhclientconf .= "{$hostname}";
4028
 	$dhclientconf .= "{$send_options}";
4029
 	$dhclientconf .= "{$request_options}";
4030
 	$dhclientconf .= "{$required_options}";
4031
 	$dhclientconf .= "{$option_modifiers}";
4032
 	$dhclientconf .= "\n";
4033
 	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4034
 	$dhclientconf .= "}\n";
4035

    
4036
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4037

    
4038
	return $dhclientconf;
4039
}
4040

    
4041

    
4042
function DHCP_Config_File_Override($wancfg, $wanif) {
4043

    
4044
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4045
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4046

    
4047
	return $dhclientconf;
4048
}
4049

    
4050

    
4051
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4052

    
4053
	/* Apply Interface Substitutions */
4054
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4055

    
4056
	/* Apply Hostname Substitutions */
4057
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4058

    
4059
	/* Arrays of MAC Address Types, Cases, Delimiters */
4060
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4061
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4062
	$various_mac_cases      = array("U", "L");
4063
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4064

    
4065
	/* Apply MAC Address Substitutions */
4066
	foreach ($various_mac_types as $various_mac_type) {
4067
		foreach ($various_mac_cases as $various_mac_case) {
4068
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4069

    
4070
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4071
				if ($res !== false) {
4072

    
4073
					/* Get MAC Address as ASCII String With Colon (:) Celimiters */
4074
					if ("$various_mac_case" == "U") $dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4075
					if ("$various_mac_case" == "L") $dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4076

    
4077
					if ("$various_mac_type" == "mac_addr_hex") {
4078
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4079
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4080
						$dhcpclientconf_mac_hex = "";
4081
						$delimiter = "";
4082
						for($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4083
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4084
							$delimiter = ":";
4085
						}
4086
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4087
					}
4088

    
4089
					/* MAC Address Delimiter Substitutions */
4090
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4091

    
4092
					/* Apply MAC Address Substitutions */
4093
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4094
				}
4095
			}
4096
		}
4097
	}
4098

    
4099
	return $dhclientconf;
4100
}
4101

    
4102
function interfaces_group_setup() {
4103
	global $config;
4104

    
4105
	if (!is_array($config['ifgroups']['ifgroupentry']))
4106
		return;
4107

    
4108
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
4109
		interface_group_setup($groupar);
4110

    
4111
	return;
4112
}
4113

    
4114
function interface_group_setup(&$groupname /* The parameter is an array */) {
4115
	global $config;
4116

    
4117
	if (!is_array($groupname))
4118
		return;
4119
	$members = explode(" ", $groupname['members']);
4120
	foreach($members as $ifs) {
4121
		$realif = get_real_interface($ifs);
4122
		if ($realif)
4123
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4124
	}
4125

    
4126
	return;
4127
}
4128

    
4129
function is_interface_group($if) {
4130
	global $config;
4131

    
4132
	if (is_array($config['ifgroups']['ifgroupentry']))
4133
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4134
			if ($groupentry['ifname'] === $if)
4135
				return true;
4136
		}
4137

    
4138
	return false;
4139
}
4140

    
4141
function interface_group_add_member($interface, $groupname) {
4142
	$interface = get_real_interface($interface);
4143
	mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4144
}
4145

    
4146
/* COMPAT Function */
4147
function convert_friendly_interface_to_real_interface_name($interface) {
4148
	return get_real_interface($interface);
4149
}
4150

    
4151
/* COMPAT Function */
4152
function get_real_wan_interface($interface = "wan") {
4153
	return get_real_interface($interface);
4154
}
4155

    
4156
/* COMPAT Function */
4157
function get_current_wan_address($interface = "wan") {
4158
	return get_interface_ip($interface);
4159
}
4160

    
4161
/*
4162
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4163
 */
4164
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
4165
	global $config;
4166

    
4167
	if (stripos($interface, "_vip")) {
4168
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
4169
			if ($vip['mode'] == "carp")  {
4170
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4171
				return $vip['interface'];
4172
			}
4173
		}
4174
	}
4175

    
4176
	/* XXX: For speed reasons reference directly the interface array */
4177
	$ifdescrs = &$config['interfaces'];
4178
	//$ifdescrs = get_configured_interface_list(false, true);
4179

    
4180
	foreach ($ifdescrs as $if => $ifname) {
4181
		if ($if == $interface || $ifname['if'] == $interface)
4182
			return $if;
4183

    
4184
		if (get_real_interface($if) == $interface)
4185
			return $if;
4186

    
4187
		$int = get_parent_interface($if, true);
4188
		if (is_array($int)) {
4189
			foreach ($int as $iface) {
4190
				if ($iface == $interface)
4191
					return $if;
4192
			}
4193
		}
4194
	}
4195

    
4196
	if ($interface == "enc0")
4197
		return 'IPsec';
4198

    
4199
	return NULL;
4200
}
4201

    
4202
/* attempt to resolve interface to friendly descr */
4203
function convert_friendly_interface_to_friendly_descr($interface) {
4204
	global $config;
4205

    
4206
	switch ($interface) {
4207
	case "l2tp":
4208
		$ifdesc = "L2TP";
4209
		break;
4210
	case "pptp":
4211
		$ifdesc = "PPTP";
4212
		break;
4213
	case "pppoe":
4214
		$ifdesc = "PPPoE";
4215
		break;
4216
	case "openvpn":
4217
		$ifdesc = "OpenVPN";
4218
		break;
4219
	case "enc0":
4220
	case "ipsec":
4221
	case "IPsec":
4222
		$ifdesc = "IPsec";
4223
		break;
4224
	default:
4225
		if (isset($config['interfaces'][$interface])) {
4226
			if (empty($config['interfaces'][$interface]['descr']))
4227
				$ifdesc = strtoupper($interface);
4228
			else
4229
				$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4230
			break;
4231
		} else if (stristr($interface, "_vip")) {
4232
			if (is_array($config['virtualip']['vip'])) {
4233
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
4234
					if ($vip['mode'] == "carp")  {
4235
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
4236
							return "{$vip['subnet']} - {$vip['descr']}";
4237
					}
4238
				}
4239
			}
4240
		} else {
4241
			/* if list */
4242
			$ifdescrs = get_configured_interface_with_descr(false, true);
4243
			foreach ($ifdescrs as $if => $ifname) {
4244
				if ($if == $interface || $ifname == $interface)
4245
					return $ifname;
4246
			}
4247
		}
4248
		break;
4249
	}
4250

    
4251
	return $ifdesc;
4252
}
4253

    
4254
function convert_real_interface_to_friendly_descr($interface) {
4255

    
4256
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4257

    
4258
	if (!empty($ifdesc))
4259
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4260

    
4261
	return $interface;
4262
}
4263

    
4264
/*
4265
 *  get_parent_interface($interface):
4266
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4267
 *				or virtual interface (i.e. vlan)
4268
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4269
 *			-- returns $interface passed in if $interface parent is not found
4270
 *			-- returns empty array if an invalid interface is passed
4271
 *	(Only handles ppps and vlans now.)
4272
 */
4273
function get_parent_interface($interface, $avoidrecurse = false) {
4274
	global $config;
4275

    
4276
	$parents = array();
4277
	//Check that we got a valid interface passed
4278
	$realif = get_real_interface($interface);
4279
	if ($realif == NULL)
4280
		return $parents;
4281

    
4282
	// If we got a real interface, find it's friendly assigned name
4283
	if ($interface == $realif && $avoidrecurse == false)
4284
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4285

    
4286
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4287
		$ifcfg = $config['interfaces'][$interface];
4288
		switch ($ifcfg['ipaddr']) {
4289
			case "ppp":
4290
			case "pppoe":
4291
			case "pptp":
4292
			case "l2tp":
4293
				if (empty($parents))
4294
					if (is_array($config['ppps']['ppp']))
4295
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4296
							if ($ifcfg['if'] == $ppp['if']) {
4297
								$ports = explode(',', $ppp['ports']);
4298
								foreach ($ports as $pid => $parent_if)
4299
									$parents[$pid] = get_real_interface($parent_if);
4300
								break;
4301
							}
4302
						}
4303
				break;
4304
			case "dhcp":
4305
			case "static":
4306
			default:
4307
				// Handle _vlans
4308
				if (stristr($realif,"_vlan"))
4309
					if (is_array($config['vlans']['vlan']))
4310
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
4311
							if ($ifcfg['if'] == $vlan['vlanif']){
4312
								$parents[0] = $vlan['if'];
4313
								break;
4314
							}
4315
				break;
4316
		}
4317
	}
4318

    
4319
	if (empty($parents))
4320
		$parents[0] = $realif;
4321

    
4322
	return $parents;
4323
}
4324

    
4325
function interface_is_wireless_clone($wlif) {
4326
	if(!stristr($wlif, "_wlan")) {
4327
		return false;
4328
	} else {
4329
		return true;
4330
	}
4331
}
4332

    
4333
function interface_get_wireless_base($wlif) {
4334
	if(!stristr($wlif, "_wlan")) {
4335
		return $wlif;
4336
	} else {
4337
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4338
	}
4339
}
4340

    
4341
function interface_get_wireless_clone($wlif) {
4342
	if(!stristr($wlif, "_wlan")) {
4343
		return $wlif . "_wlan0";
4344
	} else {
4345
		return $wlif;
4346
	}
4347
}
4348

    
4349
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4350
	global $config, $g;
4351

    
4352
	$wanif = NULL;
4353

    
4354
	switch ($interface) {
4355
	case "l2tp":
4356
		$wanif = "l2tp";
4357
		break;
4358
	case "pptp":
4359
		$wanif = "pptp";
4360
		break;
4361
	case "pppoe":
4362
		$wanif = "pppoe";
4363
		break;
4364
	case "openvpn":
4365
		$wanif = "openvpn";
4366
		break;
4367
	case "ipsec":
4368
	case "enc0":
4369
		$wanif = "enc0";
4370
		break;
4371
	case "ppp":
4372
		$wanif = "ppp";
4373
		break;
4374
	default:
4375
		// If a real interface was alread passed simply
4376
		// pass the real interface back.  This encourages
4377
		// the usage of this function in more cases so that
4378
		// we can combine logic for more flexibility.
4379
		if(does_interface_exist($interface, $flush)) {
4380
			$wanif = $interface;
4381
			break;
4382
		}
4383

    
4384
		if (empty($config['interfaces'][$interface]))
4385
			break;
4386

    
4387
		$cfg = &$config['interfaces'][$interface];
4388

    
4389
		if ($family == "inet6") {
4390
			switch ($cfg['ipaddrv6']) {
4391
			case "6rd":
4392
			case "6to4":
4393
				$wanif = "{$interface}_stf";
4394
				break;
4395
			case 'pppoe':
4396
			case 'ppp':
4397
			case 'l2tp':
4398
			case 'pptp':
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
				break;
4404
			default:
4405
				switch ($cfg['ipaddr']) {
4406
				case 'pppoe':
4407
				case 'ppp':
4408
				case 'l2tp':
4409
				case 'pptp':
4410
					if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false)
4411
						$wanif = $cfg['if'];
4412
					else {
4413
						$parents = get_parent_interface($interface);
4414
						if (!empty($parents[0]))
4415
							$wanif = $parents[0];
4416
						else
4417
							$wanif = $cfg['if'];
4418
					}
4419
					break;
4420
				default:
4421
					if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4422
						$wanif = interface_get_wireless_clone($cfg['if']);
4423
					else
4424
						$wanif = $cfg['if'];
4425
					break;
4426
				}
4427
				break;
4428
			}
4429
		} else {
4430
			// Wireless cloned NIC support (FreeBSD 8+)
4431
			// interface name format: $parentnic_wlanparentnic#
4432
			// example: ath0_wlan0
4433
			if( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if']))
4434
				$wanif = interface_get_wireless_clone($cfg['if']);
4435
			else
4436
				$wanif = $cfg['if'];
4437
		}
4438
		break;
4439
	}
4440

    
4441
	return $wanif;
4442
}
4443

    
4444
/* Guess the physical interface by providing a IP address */
4445
function guess_interface_from_ip($ipaddress) {
4446

    
4447
	$family = '';
4448
	if(is_ipaddrv4($ipaddress))
4449
		$family = 'inet';
4450
	if (empty($family) && is_ipaddrv6($ipaddress))
4451
		$family = 'inet6';
4452

    
4453
	if (empty($family))
4454
		return false;
4455

    
4456
	/* create a route table we can search */
4457
	$output = '';
4458
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4459
	$output[0] = trim($output[0], " \n");
4460
	if (!empty($output[0]))
4461
		return $output[0];
4462

    
4463
	return false;
4464
}
4465

    
4466
/*
4467
 * find_ip_interface($ip): return the interface where an ip is defined
4468
 *   (or if $bits is specified, where an IP within the subnet is defined)
4469
 */
4470
function find_ip_interface($ip, $bits = null) {
4471
	if (!is_ipaddr($ip))
4472
		return false;
4473

    
4474
	$isv6ip = is_ipaddrv6($ip);
4475

    
4476
	/* if list */
4477
	$ifdescrs = get_configured_interface_list();
4478

    
4479
	foreach ($ifdescrs as $ifdescr => $ifname) {
4480
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4481
		if (is_null($ifip))
4482
			continue;
4483
		if (is_null($bits)) {
4484
			if ($ip == $ifip) {
4485
				$int = get_real_interface($ifname);
4486
				return $int;
4487
			}
4488
		}
4489
		else {
4490
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4491
				$int = get_real_interface($ifname);
4492
				return $int;
4493
			}
4494
		}
4495
	}
4496

    
4497
	return false;
4498
}
4499

    
4500
/*
4501
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4502
 *   (or if $bits is specified, where an IP within the subnet is found)
4503
 */
4504
function find_virtual_ip_alias($ip, $bits = null) {
4505
	global $config;
4506

    
4507
	if (!is_array($config['virtualip']['vip'])) {
4508
		return false;
4509
	}
4510
	if (!is_ipaddr($ip))
4511
		return false;
4512

    
4513
	$isv6ip = is_ipaddrv6($ip);
4514

    
4515
	foreach ($config['virtualip']['vip'] as $vip) {
4516
		if ($vip['mode'] === "ipalias") {
4517
			if (is_ipaddrv6($vip['subnet']) != $isv6ip)
4518
				continue;
4519
			if (is_null($bits)) {
4520
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4521
					return $vip;
4522
				}
4523
			}
4524
			else {
4525
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))
4526
					|| (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4527
					return $vip;
4528
				}
4529
			}
4530
		}
4531
	}
4532
	return false;
4533
}
4534

    
4535
/*
4536
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4537
 */
4538
function find_number_of_created_carp_interfaces() {
4539
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4540
}
4541

    
4542
/*
4543
 * find_carp_interface($ip): return the carp interface where an ip is defined
4544
 */
4545
function find_carp_interface($ip) {
4546
	global $config;
4547
	if (is_array($config['virtualip']['vip'])) {
4548
		foreach ($config['virtualip']['vip'] as $vip) {
4549
			if ($vip['mode'] == "carp") {
4550
				if(is_ipaddrv4($ip)) {
4551
					$carp_ip = get_interface_ip($vip['interface']);
4552
				}
4553
				if(is_ipaddrv6($ip)) {
4554
					$carp_ip = get_interface_ipv6($vip['interface']);
4555
				}
4556
				exec("/sbin/ifconfig", $output, $return);
4557
				foreach($output as $line) {
4558
					$elements = preg_split("/[ ]+/i", $line);
4559
					if(strstr($elements[0], "vip"))
4560
						$curif = str_replace(":", "", $elements[0]);
4561
					if(stristr($line, $ip)) {
4562
						$if = $curif;
4563
						continue;
4564
					}
4565
				}
4566

    
4567
				if ($if)
4568
					return $if;
4569
			}
4570
		}
4571
	}
4572
}
4573

    
4574
function link_carp_interface_to_parent($interface) {
4575
	global $config;
4576

    
4577
	if (empty($interface))
4578
		return;
4579

    
4580
	$carp_ip = get_interface_ip($interface);
4581
	$carp_ipv6 = get_interface_ipv6($interface);
4582

    
4583
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
4584
		return;
4585

    
4586
	/* if list */
4587
	$ifdescrs = get_configured_interface_list();
4588
	foreach ($ifdescrs as $ifdescr => $ifname) {
4589
		/* check IPv4 */
4590
		if(is_ipaddrv4($carp_ip)) {
4591
			$interfaceip = get_interface_ip($ifname);
4592
			$subnet_bits = get_interface_subnet($ifname);
4593
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4594
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
4595
				return $ifname;
4596
		}
4597
		/* Check IPv6 */
4598
		if(is_ipaddrv6($carp_ipv6)) {
4599
			$interfaceipv6 = get_interface_ipv6($ifname);
4600
			$prefixlen = get_interface_subnetv6($ifname);
4601
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
4602
				return $ifname;
4603
		}
4604
	}
4605
	return "";
4606
}
4607

    
4608

    
4609
/****f* interfaces/link_ip_to_carp_interface
4610
 * NAME
4611
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4612
 * INPUTS
4613
 *   $ip
4614
 * RESULT
4615
 *   $carp_ints
4616
 ******/
4617
function link_ip_to_carp_interface($ip) {
4618
	global $config;
4619

    
4620
	if (!is_ipaddr($ip))
4621
		return;
4622

    
4623
	$carp_ints = "";
4624
	if (is_array($config['virtualip']['vip'])) {
4625
		$first = 0;
4626
		$carp_int = array();
4627
		foreach ($config['virtualip']['vip'] as $vip) {
4628
			if ($vip['mode'] == "carp") {
4629
				$carp_ip = $vip['subnet'];
4630
				$carp_sn = $vip['subnet_bits'];
4631
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4632
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4633
					$carp_int[] = get_real_interface($vip['interface']);
4634
				}
4635
			}
4636
		}
4637
		if (!empty($carp_int))
4638
			$carp_ints = implode(" ", array_unique($carp_int));
4639
	}
4640

    
4641
	return $carp_ints;
4642
}
4643

    
4644
function link_interface_to_track6($int, $action = "") {
4645
	global $config;
4646

    
4647
	if (empty($int))
4648
		return;
4649

    
4650
	if (is_array($config['interfaces'])) {
4651
		$list = array();
4652
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4653
			if (!isset($ifcfg['enable']))
4654
				continue;
4655
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4656
				if ($action == "update")
4657
					interface_track6_configure($ifname, $ifcfg);
4658
				else if ($action == "")
4659
					$list[$ifname] = $ifcfg;
4660
			}
4661
		}
4662
		return $list;
4663
	}
4664
}
4665

    
4666
function link_interface_to_vlans($int, $action = "") {
4667
	global $config;
4668

    
4669
	if (empty($int))
4670
		return;
4671

    
4672
	if (is_array($config['vlans']['vlan'])) {
4673
		$ifaces = array();
4674
		foreach ($config['vlans']['vlan'] as $vlan) {
4675
			if ($int == $vlan['if']) {
4676
				if ($action == "update") {
4677
					interfaces_bring_up($int);
4678
				} else if ($action == "")
4679
					$ifaces[$vlan['tag']] = $vlan;
4680
			}
4681
		}
4682
		if (!empty($ifaces))
4683
			return $ifaces;
4684
	}
4685
}
4686

    
4687
function link_interface_to_vips($int, $action = "") {
4688
	global $config;
4689

    
4690
	if (is_array($config['virtualip']['vip'])) {
4691
		$result = array();
4692
		foreach ($config['virtualip']['vip'] as $vip) {
4693
			if ($int == $vip['interface']) {
4694
				if ($action == "update")
4695
					interfaces_vips_configure($int);
4696
				else
4697
					$result[] = $vip;
4698
			}
4699
		}
4700
		return $result;
4701
	}
4702
}
4703

    
4704
/****f* interfaces/link_interface_to_bridge
4705
 * NAME
4706
 *   link_interface_to_bridge - Finds out a bridge group for an interface
4707
 * INPUTS
4708
 *   $ip
4709
 * RESULT
4710
 *   bridge[0-99]
4711
 ******/
4712
function link_interface_to_bridge($int) {
4713
	global $config;
4714

    
4715
	if (is_array($config['bridges']['bridged'])) {
4716
		foreach ($config['bridges']['bridged'] as $bridge) {
4717
			if (in_array($int, explode(',', $bridge['members'])))
4718
				return "{$bridge['bridgeif']}";
4719
		}
4720
	}
4721
}
4722

    
4723
function link_interface_to_group($int) {
4724
	global $config;
4725

    
4726
	$result = array();
4727

    
4728
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4729
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
4730
			if (in_array($int, explode(" ", $group['members'])))
4731
				$result[$group['ifname']] = $int;
4732
		}
4733
	}
4734

    
4735
	return $result;
4736
}
4737

    
4738
function link_interface_to_gre($interface) {
4739
	global $config;
4740

    
4741
	$result = array();
4742

    
4743
	if (is_array($config['gres']['gre'])) {
4744
		foreach ($config['gres']['gre'] as $gre)
4745
			if($gre['if'] == $interface)
4746
				$result[] = $gre;
4747
	}
4748

    
4749
	return $result;
4750
}
4751

    
4752
function link_interface_to_gif($interface) {
4753
	global $config;
4754

    
4755
	$result = array();
4756

    
4757
	if (is_array($config['gifs']['gif'])) {
4758
		foreach ($config['gifs']['gif'] as $gif)
4759
			if($gif['if'] == $interface)
4760
				$result[] = $gif;
4761
	}
4762

    
4763
	return $result;
4764
}
4765

    
4766
/*
4767
 * find_interface_ip($interface): return the interface ip (first found)
4768
 */
4769
function find_interface_ip($interface, $flush = false) {
4770
	global $interface_ip_arr_cache;
4771
	global $interface_sn_arr_cache;
4772

    
4773
	$interface = str_replace("\n", "", $interface);
4774

    
4775
	if (!does_interface_exist($interface))
4776
		return;
4777

    
4778
	/* Setup IP cache */
4779
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4780
		$ifinfo = pfSense_get_interface_addresses($interface);
4781
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4782
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4783
	}
4784

    
4785
	return $interface_ip_arr_cache[$interface];
4786
}
4787

    
4788
/*
4789
 * find_interface_ipv6($interface): return the interface ip (first found)
4790
 */
4791
function find_interface_ipv6($interface, $flush = false) {
4792
	global $interface_ipv6_arr_cache;
4793
	global $interface_snv6_arr_cache;
4794
	global $config;
4795

    
4796
	$interface = trim($interface);
4797
	$interface = get_real_interface($interface);
4798

    
4799
	if (!does_interface_exist($interface))
4800
		return;
4801

    
4802
	/* Setup IP cache */
4803
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4804
		$ifinfo = pfSense_get_interface_addresses($interface);
4805
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4806
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4807
	}
4808

    
4809
	return $interface_ipv6_arr_cache[$interface];
4810
}
4811

    
4812
/*
4813
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4814
 */
4815
function find_interface_ipv6_ll($interface, $flush = false) {
4816
	global $interface_llv6_arr_cache;
4817
	global $config;
4818

    
4819
	$interface = str_replace("\n", "", $interface);
4820

    
4821
	if (!does_interface_exist($interface))
4822
		return;
4823

    
4824
	/* Setup IP cache */
4825
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4826
		$ifinfo = pfSense_getall_interface_addresses($interface);
4827
		foreach($ifinfo as $line) {
4828
			if (strstr($line, ":")) {
4829
				$parts = explode("/", $line);
4830
				if(is_linklocal($parts[0])) {
4831
					$ifinfo['linklocal'] = $parts[0];
4832
				}
4833
			}
4834
		}
4835
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4836
	}
4837
	return $interface_llv6_arr_cache[$interface];
4838
}
4839

    
4840
function find_interface_subnet($interface, $flush = false) {
4841
	global $interface_sn_arr_cache;
4842
	global $interface_ip_arr_cache;
4843

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

    
4848
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4849
		$ifinfo = pfSense_get_interface_addresses($interface);
4850
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4851
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4852
	}
4853

    
4854
	return $interface_sn_arr_cache[$interface];
4855
}
4856

    
4857
function find_interface_subnetv6($interface, $flush = false) {
4858
	global $interface_snv6_arr_cache;
4859
	global $interface_ipv6_arr_cache;
4860

    
4861
	$interface = str_replace("\n", "", $interface);
4862
	if (does_interface_exist($interface) == false)
4863
		return;
4864

    
4865
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4866
		$ifinfo = pfSense_get_interface_addresses($interface);
4867
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
4868
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
4869
	}
4870

    
4871
	return $interface_snv6_arr_cache[$interface];
4872
}
4873

    
4874
function ip_in_interface_alias_subnet($interface, $ipalias) {
4875
	global $config;
4876

    
4877
	if (empty($interface) || !is_ipaddr($ipalias))
4878
		return false;
4879
	if (is_array($config['virtualip']['vip'])) {
4880
		foreach ($config['virtualip']['vip'] as $vip) {
4881
			switch ($vip['mode']) {
4882
			case "ipalias":
4883
				if ($vip['interface'] <> $interface)
4884
					break;
4885
				$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
4886
				if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits']))
4887
					return true;
4888
				break;
4889
			}
4890
		}
4891
	}
4892

    
4893
	return false;
4894
}
4895

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

    
4905
	$curip = find_interface_ip($realif);
4906
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4907
		return $curip;
4908
	else
4909
		return null;
4910
}
4911

    
4912
function get_interface_ipv6($interface = "wan", $flush = false) {
4913
	global $config;
4914

    
4915
	$realif = get_failover_interface($interface, "inet6");
4916
	if (!$realif) {
4917
		if (strstr($interface, "_vip"))
4918
			return get_configured_carp_interface_list($interface, "inet6");
4919
		else
4920
			return null;
4921
	}
4922

    
4923
	/*
4924
	 * NOTE: On the case when only the prefix is requested,
4925
	 * the communication on WAN will be done over link-local.
4926
	 */
4927
	if (is_array($config['interfaces'][$interface])) {
4928
		switch ($config['interfaces'][$interface]['ipaddr']) {
4929
		case 'pppoe':
4930
		case 'l2tp':
4931
		case 'pptp':
4932
		case 'ppp':
4933
			if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6')
4934
				$realif = get_real_interface($interface, "inet6", true);
4935
			break;
4936
		}
4937
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
4938
			$curip = find_interface_ipv6_ll($realif, $flush);
4939
			if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4940
				return $curip;
4941
		}
4942
	}
4943

    
4944
	$curip = find_interface_ipv6($realif, $flush);
4945
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4946
		return $curip;
4947
	else
4948
		return null;
4949
}
4950

    
4951
function get_interface_linklocal($interface = "wan") {
4952

    
4953
	$realif = get_failover_interface($interface, "inet6");
4954
	if (!$realif) {
4955
		if (strstr($interface, "_vip")) {
4956
			list($interface, $vhid) = explode("_vip", $interface);
4957
			$realif = get_real_interface($interface);
4958
		} else
4959
			return null;
4960
	}
4961

    
4962
	$curip = find_interface_ipv6_ll($realif);
4963
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4964
		return $curip;
4965
	else
4966
		return null;
4967
}
4968

    
4969
function get_interface_subnet($interface = "wan") {
4970
	$realif = get_real_interface($interface);
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_subnet($realif);
4980
	if (!empty($cursn))
4981
		return $cursn;
4982

    
4983
	return null;
4984
}
4985

    
4986
function get_interface_subnetv6($interface = "wan") {
4987
	global $config;
4988

    
4989
	$realif = get_real_interface($interface, "inet6");
4990
	if (!$realif) {
4991
		if (strstr($interface, "_vip")) {
4992
			list($interface, $vhid) = explode("_vip", $interface);
4993
			$realif = get_real_interface($interface);
4994
		} else
4995
			return null;
4996
	}
4997

    
4998
	$cursn = find_interface_subnetv6($realif);
4999
	if (!empty($cursn))
5000
		return $cursn;
5001

    
5002
	return null;
5003
}
5004

    
5005
/* return outside interfaces with a gateway */
5006
function get_interfaces_with_gateway() {
5007
	global $config;
5008

    
5009
	$ints = array();
5010

    
5011
	/* loop interfaces, check config for outbound */
5012
	foreach($config['interfaces'] as $ifdescr => $ifname) {
5013
		switch ($ifname['ipaddr']) {
5014
			case "dhcp":
5015
			case "ppp";
5016
			case "pppoe":
5017
			case "pptp":
5018
			case "l2tp":
5019
			case "ppp";
5020
				$ints[$ifdescr] = $ifdescr;
5021
			break;
5022
			default:
5023
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
5024
				    !empty($ifname['gateway']))
5025
					$ints[$ifdescr] = $ifdescr;
5026
			break;
5027
		}
5028
	}
5029
	return $ints;
5030
}
5031

    
5032
/* return true if interface has a gateway */
5033
function interface_has_gateway($friendly) {
5034
	global $config;
5035

    
5036
	if (!empty($config['interfaces'][$friendly])) {
5037
		$ifname = &$config['interfaces'][$friendly];
5038
		switch ($ifname['ipaddr']) {
5039
			case "dhcp":
5040
			case "pppoe":
5041
			case "pptp":
5042
			case "l2tp":
5043
			case "ppp";
5044
				return true;
5045
			break;
5046
			default:
5047
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
5048
					return true;
5049
				$tunnelif = substr($ifname['if'], 0, 3);
5050
				if ($tunnelif == "gif" || $tunnelif == "gre")
5051
					return true;
5052
				if (!empty($ifname['gateway']))
5053
					return true;
5054
			break;
5055
		}
5056
	}
5057

    
5058
	return false;
5059
}
5060

    
5061
/* return true if interface has a gateway */
5062
function interface_has_gatewayv6($friendly) {
5063
	global $config;
5064

    
5065
	if (!empty($config['interfaces'][$friendly])) {
5066
		$ifname = &$config['interfaces'][$friendly];
5067
		switch ($ifname['ipaddrv6']) {
5068
			case "slaac":
5069
			case "dhcp6":
5070
			case "6to4":
5071
			case "6rd":
5072
				return true;
5073
				break;
5074
			default:
5075
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
5076
					return true;
5077
				$tunnelif = substr($ifname['if'], 0, 3);
5078
				if ($tunnelif == "gif" || $tunnelif == "gre")
5079
					return true;
5080
				if (!empty($ifname['gatewayv6']))
5081
					return true;
5082
				break;
5083
		}
5084
	}
5085

    
5086
	return false;
5087
}
5088

    
5089
/****f* interfaces/is_altq_capable
5090
 * NAME
5091
 *   is_altq_capable - Test if interface is capable of using ALTQ
5092
 * INPUTS
5093
 *   $int            - string containing interface name
5094
 * RESULT
5095
 *   boolean         - true or false
5096
 ******/
5097

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

    
5111
	$int_family = remove_ifindex($int);
5112

    
5113
	if (in_array($int_family, $capable))
5114
		return true;
5115
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
5116
		return true;
5117
	else if (stristr($int, "_vlan")) /* VLANs are name $parent_$vlan now */
5118
		return true;
5119
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
5120
		return true;
5121
	else
5122
		return false;
5123
}
5124

    
5125
/****f* interfaces/is_interface_wireless
5126
 * NAME
5127
 *   is_interface_wireless - Returns if an interface is wireless
5128
 * RESULT
5129
 *   $tmp       - Returns if an interface is wireless
5130
 ******/
5131
function is_interface_wireless($interface) {
5132
	global $config, $g;
5133

    
5134
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5135
	if(!isset($config['interfaces'][$friendly]['wireless'])) {
5136
		if (preg_match($g['wireless_regex'], $interface)) {
5137
			if (isset($config['interfaces'][$friendly]))
5138
				$config['interfaces'][$friendly]['wireless'] = array();
5139
			return true;
5140
		}
5141
		return false;
5142
	} else
5143
		return true;
5144
}
5145

    
5146
function get_wireless_modes($interface) {
5147
	/* return wireless modes and channels */
5148
	$wireless_modes = array();
5149

    
5150
	$cloned_interface = get_real_interface($interface);
5151

    
5152
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5153
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5154
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5155
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5156

    
5157
		$interface_channels = "";
5158
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5159
		$interface_channel_count = count($interface_channels);
5160

    
5161
		$c = 0;
5162
		while ($c < $interface_channel_count) {
5163
			$channel_line = explode(",", $interface_channels["$c"]);
5164
			$wireless_mode = trim($channel_line[0]);
5165
			$wireless_channel = trim($channel_line[1]);
5166
			if(trim($wireless_mode) != "") {
5167
				/* if we only have 11g also set 11b channels */
5168
				if($wireless_mode == "11g") {
5169
					if(!isset($wireless_modes["11b"]))
5170
						$wireless_modes["11b"] = array();
5171
				} else if($wireless_mode == "11g ht") {
5172
					if(!isset($wireless_modes["11b"]))
5173
						$wireless_modes["11b"] = array();
5174
					if(!isset($wireless_modes["11g"]))
5175
						$wireless_modes["11g"] = array();
5176
					$wireless_mode = "11ng";
5177
				} else if($wireless_mode == "11a ht") {
5178
					if(!isset($wireless_modes["11a"]))
5179
						$wireless_modes["11a"] = array();
5180
					$wireless_mode = "11na";
5181
				}
5182
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5183
			}
5184
			$c++;
5185
		}
5186
	}
5187
	return($wireless_modes);
5188
}
5189

    
5190
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5191
function get_wireless_channel_info($interface) {
5192
	$wireless_channels = array();
5193

    
5194
	$cloned_interface = get_real_interface($interface);
5195

    
5196
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
5197
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5198
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5199
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5200

    
5201
		$interface_channels = "";
5202
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5203

    
5204
		foreach ($interface_channels as $channel_line) {
5205
			$channel_line = explode(",", $channel_line);
5206
			if(!isset($wireless_channels[$channel_line[0]]))
5207
				$wireless_channels[$channel_line[0]] = $channel_line;
5208
		}
5209
	}
5210
	return($wireless_channels);
5211
}
5212

    
5213
/****f* interfaces/get_interface_mtu
5214
 * NAME
5215
 *   get_interface_mtu - Return the mtu of an interface
5216
 * RESULT
5217
 *   $tmp       - Returns the mtu of an interface
5218
 ******/
5219
function get_interface_mtu($interface) {
5220
	$mtu = pfSense_get_interface_addresses($interface);
5221
	return $mtu['mtu'];
5222
}
5223

    
5224
function get_interface_mac($interface) {
5225

    
5226
	$macinfo = pfSense_get_interface_addresses($interface);
5227
	return $macinfo["macaddr"];
5228
}
5229

    
5230
/****f* pfsense-utils/generate_random_mac_address
5231
 * NAME
5232
 *   generate_random_mac - generates a random mac address
5233
 * INPUTS
5234
 *   none
5235
 * RESULT
5236
 *   $mac - a random mac address
5237
 ******/
5238
function generate_random_mac_address() {
5239
	$mac = "02";
5240
	for($x=0; $x<5; $x++)
5241
		$mac .= ":" . dechex(rand(16, 255));
5242
	return $mac;
5243
}
5244

    
5245
/****f* interfaces/is_jumbo_capable
5246
 * NAME
5247
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5248
 * INPUTS
5249
 *   $int             - string containing interface name
5250
 * RESULT
5251
 *   boolean          - true or false
5252
 ******/
5253
function is_jumbo_capable($iface) {
5254
	$iface = trim($iface);
5255
	$capable = pfSense_get_interface_addresses($iface);
5256

    
5257
	if (isset($capable['caps']['vlanmtu']))
5258
		return true;
5259

    
5260
	return false;
5261
}
5262

    
5263
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5264
	global $g;
5265

    
5266
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5267

    
5268
	if(!empty($iface) && !empty($pppif)){
5269
		$cron_cmd = <<<EOD
5270
#!/bin/sh
5271
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5272
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5273

    
5274
EOD;
5275

    
5276
		@file_put_contents($cron_file, $cron_cmd);
5277
		chmod($cron_file, 0755);
5278
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5279
	} else
5280
		unlink_if_exists($cron_file);
5281
}
5282

    
5283
function get_interface_default_mtu($type = "ethernet") {
5284
	switch ($type) {
5285
	case "gre":
5286
		return 1476;
5287
		break;
5288
	case "gif":
5289
		return 1280;
5290
		break;
5291
	case "tun":
5292
	case "vlan":
5293
	case "tap":
5294
	case "ethernet":
5295
	default:
5296
		return 1500;
5297
		break;
5298
	}
5299

    
5300
	/* Never reached */
5301
	return 1500;
5302
}
5303

    
5304
function get_vip_descr($ipaddress) {
5305
	global $config;
5306

    
5307
	foreach ($config['virtualip']['vip'] as $vip) {
5308
		if ($vip['subnet'] == $ipaddress) {
5309
			return ($vip['descr']);
5310
		}
5311
	}
5312
	return "";
5313
}
5314

    
5315
function interfaces_staticarp_configure($if) {
5316
	global $config, $g;
5317
	if(isset($config['system']['developerspew'])) {
5318
		$mt = microtime();
5319
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5320
	}
5321

    
5322
	$ifcfg = $config['interfaces'][$if];
5323

    
5324
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable']))
5325
		return 0;
5326

    
5327
	/* Enable staticarp, if enabled */
5328
	if(isset($config['dhcpd'][$if]['staticarp'])) {
5329
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
5330
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5331
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5332

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

    
5336
			}
5337

    
5338
		}
5339
	} else {
5340
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
5341
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5342
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5343
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5344
				if (isset($arpent['arp_table_static_entry'])) {
5345
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5346
				}
5347
			}
5348
		}
5349
	}
5350

    
5351
	return 0;
5352
}
5353

    
5354
function get_failover_interface($interface, $family = "all") {
5355
	global $config;
5356

    
5357
	/* shortcut to get_real_interface if we find it in the config */
5358
	if (is_array($config['interfaces'][$interface])) {
5359
		return get_real_interface($interface, $family);
5360
	}
5361

    
5362
	/* compare against gateway groups */
5363
	$a_groups = return_gateway_groups_array();
5364
	if (is_array($a_groups[$interface])) {
5365
		/* we found a gateway group, fetch the interface or vip */
5366
		if ($a_groups[$interface][0]['vip'] <> "")
5367
			return $a_groups[$interface][0]['vip'];
5368
		else
5369
			return $a_groups[$interface][0]['int'];
5370
	}
5371
	/* fall through to get_real_interface */
5372
	/* XXX: Really needed? */
5373
	return get_real_interface($interface, $family);
5374
}
5375

    
5376
function remove_ifindex($ifname) {
5377
	return preg_replace("/[0-9]+$/", "", $ifname);
5378
}
5379

    
5380
?>
(26-26/68)