Project

General

Profile

Download (169 KB) Statistics
| Branch: | Tag: | Revision:
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

    
38
/* include all configuration functions */
39
require_once("globals.inc");
40
require_once("util.inc");
41
require_once("gwlb.inc");
42

    
43
function interfaces_bring_up($interface) {
44
	if (!$interface) {
45
		log_error(gettext("interfaces_bring_up() was called but no variable defined."));
46
		log_error("Backtrace: " . debug_backtrace());
47
		return;
48
	}
49
	pfSense_interface_flags($interface, IFF_UP);
50
}
51

    
52
/*
53
 * Return the interface array
54
 */
55
function get_interface_arr($flush = false) {
56
	global $interface_arr_cache;
57

    
58
	/* If the cache doesn't exist, build it */
59
	if (!isset($interface_arr_cache) or $flush) {
60
		$interface_arr_cache = pfSense_interface_listget();
61
	}
62

    
63
	return $interface_arr_cache;
64
}
65

    
66
/*
67
 * does_interface_exist($interface): return true or false if a interface is
68
 * detected.
69
 */
70
function does_interface_exist($interface, $flush = true) {
71
	global $config;
72

    
73
	if (!$interface) {
74
		return false;
75
	}
76

    
77
	$ints = get_interface_arr($flush);
78
	if (in_array($interface, $ints)) {
79
		return true;
80
	} else {
81
		return false;
82
	}
83
}
84

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

    
92
	if (!$vip) {
93
		return false;
94
	}
95

    
96

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

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

    
119
	return false;
120
}
121

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

    
125
	$found = false;
126
	if (!empty($config['l2tp']) &&
127
	    $config['l2tp']['mode'] == "server") {
128
		$found = true;
129
	}
130
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
131
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
132
			if ($pppoe['mode'] != "server") {
133
				continue;
134
			}
135
			if ($pppoe['interface'] == $interface) {
136
				$found = true;
137
				break;
138
			}
139
		}
140
	}
141
	if ($found == false) {
142
		$found = interface_isppp_type($interface);
143
	}
144

    
145
	if ($found == false) {
146
		$realif = get_real_interface($interface);
147
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
148
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
149
				$ports = explode(',', $ppp['ports']);
150
				foreach ($ports as $pid => $port) {
151
					$port = get_real_interface($port);
152
					if ($realif == $port) {
153
						$found = true;
154
						break;
155
					}
156
					/* Find the parent interfaces of the vlans in the MLPPP configs
157
					* there should be only one element in the array here
158
					* -- this could be better . . . */
159
					$parent_if = get_parent_interface($port);
160
					if ($realif == $parent_if[0]) {
161
						$found = true;
162
						break;
163
					}
164
				}
165
			}
166
		}
167
	}
168

    
169
	if ($found == false) {
170
		$realif = get_real_interface($interface);
171
		pfSense_ngctl_detach("{$realif}:", $realif);
172
	}
173
	/* NOTE: We make sure for this on interface_ppps_configure()
174
	 *	no need to do it here again.
175
	 *	else
176
	 *		pfSense_ngctl_attach(".", $realif);
177
	 */
178
}
179

    
180
function interfaces_loopback_configure() {
181
	global $g;
182

    
183
	if (platform_booting()) {
184
		echo gettext("Configuring loopback interface...");
185
	}
186
	pfSense_interface_setaddress("lo0", "127.0.0.1");
187
	interfaces_bring_up("lo0");
188
	if (platform_booting()) {
189
		echo gettext("done.") . "\n";
190
	}
191
	return 0;
192
}
193

    
194
function interfaces_vlan_configure($realif = "") {
195
	global $config, $g;
196
	if (platform_booting()) {
197
		echo gettext("Configuring VLAN interfaces...");
198
	}
199
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
200
		foreach ($config['vlans']['vlan'] as $vlan) {
201
			if (empty($vlan['vlanif'])) {
202
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
203
			}
204
			if (!empty($realif) && $realif != $vlan['vlanif']) {
205
				continue;
206
			}
207

    
208
			/* XXX: Maybe we should report any errors?! */
209
			interface_vlan_configure($vlan);
210
		}
211
	}
212
	if (platform_booting()) {
213
		echo gettext("done.") . "\n";
214
	}
215
}
216

    
217
function interface_vlan_configure(&$vlan) {
218
	global $config, $g;
219

    
220
	if (!is_array($vlan)) {
221
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
222
		return;
223
	}
224
	$if = $vlan['if'];
225
	if (empty($if)) {
226
		log_error(gettext("interface_vlan_configure called with if undefined."));
227
		return;
228
	}
229

    
230
	$vlanif = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
231
	$tag = $vlan['tag'];
232
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
233

    
234
	/* make sure the parent interface is up */
235
	interfaces_bring_up($if);
236
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
237
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
238

    
239
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
240
		pfSense_interface_destroy($vlanif);
241
	}
242

    
243
	$tmpvlanif = pfSense_interface_create("vlan");
244
	pfSense_interface_rename($tmpvlanif, $vlanif);
245
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
246

    
247
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
248

    
249
	interfaces_bring_up($vlanif);
250

    
251
	/* invalidate interface cache */
252
	get_interface_arr(true);
253

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

    
257
	return $vlanif;
258
}
259

    
260
function interface_qinq_configure(&$vlan, $fd = NULL) {
261
	global $config, $g;
262

    
263
	if (!is_array($vlan)) {
264
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
265
		return;
266
	}
267

    
268
	$qinqif = $vlan['if'];
269
	$tag = $vlan['tag'];
270
	if (empty($qinqif)) {
271
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
272
		return;
273
	}
274

    
275
	if (!does_interface_exist($qinqif)) {
276
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
277
		return;
278
	}
279

    
280
	$vlanif = interface_vlan_configure($vlan);
281

    
282
	if ($fd == NULL) {
283
		$exec = true;
284
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
285
	} else {
286
		$exec = false;
287
	}
288
	/* make sure the parent is converted to ng_vlan(4) and is up */
289
	interfaces_bring_up($qinqif);
290

    
291
	pfSense_ngctl_attach(".", $qinqif);
292
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
293
		fwrite($fd, "shutdown {$qinqif}qinq:\n");
294
		exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
295
		if (empty($result)) {
296
			fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
297
			fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
298
			fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
299
		}
300
	} else {
301
		fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
302
		fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
303
		fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
304
	}
305

    
306
	/* invalidate interface cache */
307
	get_interface_arr(true);
308

    
309
	if (!stristr($qinqif, "_vlan")) {
310
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
311
	}
312

    
313
	$macaddr = get_interface_mac($qinqif);
314
	if (!empty($vlan['members'])) {
315
		$members = explode(" ", $vlan['members']);
316
		foreach ($members as $qtag) {
317
			$qinq = array();
318
			$qinq['tag'] = $qtag;
319
			$qinq['if'] = $vlanif;
320
			interface_qinq2_configure($qinq, $fd, $macaddr);
321
		}
322
	}
323
	if ($exec == true) {
324
		fclose($fd);
325
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
326
	}
327

    
328
	interfaces_bring_up($qinqif);
329
	if (!empty($vlan['members'])) {
330
		$members = explode(" ", $vlan['members']);
331
		foreach ($members as $qif) {
332
			interfaces_bring_up("{$vlanif}_{$qif}");
333
		}
334
	}
335

    
336
	return $vlanif;
337
}
338

    
339
function interfaces_qinq_configure() {
340
	global $config, $g;
341
	if (platform_booting()) {
342
		echo gettext("Configuring QinQ interfaces...");
343
	}
344
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
345
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
346
			/* XXX: Maybe we should report any errors?! */
347
			interface_qinq_configure($qinq);
348
		}
349
	}
350
	if (platform_booting()) {
351
		echo gettext("done.") . "\n";
352
	}
353
}
354

    
355
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
356
	global $config, $g;
357

    
358
	if (!is_array($qinq)) {
359
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
360
		return;
361
	}
362

    
363
	$if = $qinq['if'];
364
	$tag = $qinq['tag'];
365
	$vlanif = "{$if}_{$tag}";
366
	if (empty($if)) {
367
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
368
		return;
369
	}
370

    
371
	fwrite($fd, "shutdown {$if}h{$tag}:\n");
372
	fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
373
	fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
374
	fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
375
	fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
376
	fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
377

    
378
	/* invalidate interface cache */
379
	get_interface_arr(true);
380

    
381
	return $vlanif;
382
}
383

    
384
function interfaces_create_wireless_clones() {
385
	global $config, $g;
386

    
387
	if (platform_booting()) {
388
		echo gettext("Creating wireless clone interfaces...");
389
	}
390

    
391
	$iflist = get_configured_interface_list();
392

    
393
	foreach ($iflist as $if) {
394
		$realif = $config['interfaces'][$if]['if'];
395
		if (is_interface_wireless($realif)) {
396
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
397
		}
398
	}
399

    
400
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
401
		foreach ($config['wireless']['clone'] as $clone) {
402
			if (empty($clone['cloneif'])) {
403
				continue;
404
			}
405
			if (does_interface_exist($clone['cloneif'])) {
406
				continue;
407
			}
408
			/* XXX: Maybe we should report any errors?! */
409
			interface_wireless_clone($clone['cloneif'], $clone);
410
		}
411
	}
412
	if (platform_booting()) {
413
		echo gettext("done.") . "\n";
414
	}
415

    
416
}
417

    
418
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
419
	global $config;
420

    
421
	$i = 0;
422
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
423
		foreach ($config['bridges']['bridged'] as $bridge) {
424
			if (empty($bridge['bridgeif'])) {
425
				$bridge['bridgeif'] = "bridge{$i}";
426
			}
427
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
428
				continue;
429
			}
430

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

    
458
function interface_bridge_configure(&$bridge, $checkmember = 0) {
459
	global $config, $g;
460

    
461
	if (!is_array($bridge)) {
462
		return;
463
	}
464

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

    
470
	$members = explode(',', $bridge['members']);
471
	if (!count($members)) {
472
		return;
473
	}
474

    
475
	/* Calculate smaller mtu and enforce it */
476
	$smallermtu = 0;
477
	$commonrx = true;
478
	$commontx = true;
479
	$foundgif = false;
480
	foreach ($members as $member) {
481
		$realif = get_real_interface($member);
482
		$mtu = get_interface_mtu($realif);
483
		if (substr($realif, 0, 3) == "gif") {
484
			$foundgif = true;
485
			if ($checkmember == 1) {
486
				return;
487
			}
488
			if ($mtu <= 1500) {
489
				continue;
490
			}
491
		}
492
		if ($smallermtu == 0 && !empty($mtu)) {
493
			$smallermtu = $mtu;
494
		} else if (!empty($mtu) && $mtu < $smallermtu) {
495
			$smallermtu = $mtu;
496
		}
497
	}
498
	if ($foundgif == false && $checkmember == 2) {
499
		return;
500
	}
501

    
502
	/* Just in case anything is not working well */
503
	if ($smallermtu == 0) {
504
		$smallermtu = 1500;
505
	}
506

    
507
	if (platform_booting() || !empty($bridge['bridgeif'])) {
508
		pfSense_interface_destroy($bridge['bridgeif']);
509
		pfSense_interface_create($bridge['bridgeif']);
510
		$bridgeif = escapeshellarg($bridge['bridgeif']);
511
	} else {
512
		$bridgeif = pfSense_interface_create("bridge");
513
		$bridge['bridgeif'] = $bridgeif;
514
	}
515

    
516
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
517
	if ($bridgemtu > $smallermtu) {
518
		$smallermtu = $bridgemtu;
519
	}
520

    
521
	$checklist = get_configured_interface_list();
522

    
523
	/* Add interfaces to bridge */
524
	foreach ($members as $member) {
525
		if (empty($checklist[$member])) {
526
			continue;
527
		}
528
		$realif = get_real_interface($member);
529
		if (!$realif) {
530
			log_error(gettext("realif not defined in interfaces bridge - up"));
531
			continue;
532
		}
533
		/* make sure the parent interface is up */
534
		pfSense_interface_mtu($realif, $smallermtu);
535
		interfaces_bring_up($realif);
536
		enable_hardware_offloading($member);
537
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
538
	}
539

    
540
	if (isset($bridge['enablestp'])) {
541
		/* Choose spanning tree proto */
542
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
543

    
544
		if (!empty($bridge['stp'])) {
545
			$stpifs = explode(',', $bridge['stp']);
546
			foreach ($stpifs as $stpif) {
547
				$realif = get_real_interface($stpif);
548
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
549
			}
550
		}
551
		if (!empty($bridge['maxage'])) {
552
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
553
		}
554
		if (!empty($bridge['fwdelay'])) {
555
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
556
		}
557
		if (!empty($bridge['hellotime'])) {
558
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
559
		}
560
		if (!empty($bridge['priority'])) {
561
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
562
		}
563
		if (!empty($bridge['holdcnt'])) {
564
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
565
		}
566
		if (!empty($bridge['ifpriority'])) {
567
			$pconfig = explode(",", $bridge['ifpriority']);
568
			$ifpriority = array();
569
			foreach ($pconfig as $cfg) {
570
				$embcfg = explode_assoc(":", $cfg);
571
				foreach ($embcfg as $key => $value) {
572
					$ifpriority[$key] = $value;
573
				}
574
			}
575
			foreach ($ifpriority as $key => $value) {
576
				$realif = get_real_interface($key);
577
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
578
			}
579
		}
580
		if (!empty($bridge['ifpathcost'])) {
581
			$pconfig = explode(",", $bridge['ifpathcost']);
582
			$ifpathcost = array();
583
			foreach ($pconfig as $cfg) {
584
				$embcfg = explode_assoc(":", $cfg);
585
				foreach ($embcfg as $key => $value) {
586
					$ifpathcost[$key] = $value;
587
				}
588
			}
589
			foreach ($ifpathcost as $key => $value) {
590
				$realif = get_real_interface($key);
591
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
592
			}
593
		}
594
	}
595

    
596
	if ($bridge['maxaddr'] <> "") {
597
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
598
	}
599
	if ($bridge['timeout'] <> "") {
600
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
601
	}
602
	if ($bridge['span'] <> "") {
603
		$realif = get_real_interface($bridge['span']);
604
		mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
605
	}
606
	if (!empty($bridge['edge'])) {
607
		$edgeifs = explode(',', $bridge['edge']);
608
		foreach ($edgeifs as $edgeif) {
609
			$realif = get_real_interface($edgeif);
610
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
611
		}
612
	}
613
	if (!empty($bridge['autoedge'])) {
614
		$edgeifs = explode(',', $bridge['autoedge']);
615
		foreach ($edgeifs as $edgeif) {
616
			$realif = get_real_interface($edgeif);
617
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
618
		}
619
	}
620
	if (!empty($bridge['ptp'])) {
621
		$ptpifs = explode(',', $bridge['ptp']);
622
		foreach ($ptpifs as $ptpif) {
623
			$realif = get_real_interface($ptpif);
624
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
625
		}
626
	}
627
	if (!empty($bridge['autoptp'])) {
628
		$ptpifs = explode(',', $bridge['autoptp']);
629
		foreach ($ptpifs as $ptpif) {
630
			$realif = get_real_interface($ptpif);
631
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
632
		}
633
	}
634
	if (!empty($bridge['static'])) {
635
		$stickyifs = explode(',', $bridge['static']);
636
		foreach ($stickyifs as $stickyif) {
637
			$realif = get_real_interface($stickyif);
638
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
639
		}
640
	}
641
	if (!empty($bridge['private'])) {
642
		$privateifs = explode(',', $bridge['private']);
643
		foreach ($privateifs as $privateif) {
644
			$realif = get_real_interface($privateif);
645
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
646
		}
647
	}
648

    
649
	if ($bridge['bridgeif']) {
650
		interfaces_bring_up($bridge['bridgeif']);
651
	} else {
652
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
653
	}
654
}
655

    
656
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
657

    
658
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
659
		return;
660
	}
661

    
662
	if ($flagsapplied == false) {
663
		$mtu = get_interface_mtu($bridgeif);
664
		$mtum = get_interface_mtu($interface);
665
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
666
			pfSense_interface_mtu($interface, $mtu);
667
		}
668

    
669
		hardware_offloading_applyflags($interface);
670
		interfaces_bring_up($interface);
671
	}
672

    
673
	pfSense_bridge_add_member($bridgeif, $interface);
674
}
675

    
676
function interfaces_lagg_configure($realif = "") {
677
	global $config, $g;
678
	if (platform_booting()) {
679
		echo gettext("Configuring LAGG interfaces...");
680
	}
681
	$i = 0;
682
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
683
		foreach ($config['laggs']['lagg'] as $lagg) {
684
			if (empty($lagg['laggif'])) {
685
				$lagg['laggif'] = "lagg{$i}";
686
			}
687
			if (!empty($realif) && $realif != $lagg['laggif']) {
688
				continue;
689
			}
690
			/* XXX: Maybe we should report any errors?! */
691
			interface_lagg_configure($lagg);
692
			$i++;
693
		}
694
	}
695
	if (platform_booting()) {
696
		echo gettext("done.") . "\n";
697
	}
698
}
699

    
700
function interface_lagg_configure($lagg) {
701
	global $config, $g;
702

    
703
	if (!is_array($lagg)) {
704
		return -1;
705
	}
706

    
707
	$members = explode(',', $lagg['members']);
708
	if (!count($members)) {
709
		return -1;
710
	}
711

    
712
	if (platform_booting() || !(empty($lagg['laggif']))) {
713
		pfSense_interface_destroy($lagg['laggif']);
714
		pfSense_interface_create($lagg['laggif']);
715
		$laggif = $lagg['laggif'];
716
	} else {
717
		$laggif = pfSense_interface_create("lagg");
718
	}
719

    
720
	/* Check if MTU was defined for this lagg interface */
721
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
722
	if ($lagg_mtu == 0) {
723
		/* Calculate smaller mtu and enforce it */
724
		$smallermtu = 0;
725
		foreach ($members as $member) {
726
			$mtu = get_interface_mtu($member);
727
			if ($smallermtu == 0 && !empty($mtu)) {
728
				$smallermtu = $mtu;
729
			} else if (!empty($mtu) && $mtu < $smallermtu) {
730
				$smallermtu = $mtu;
731
			}
732
		}
733
		$lagg_mtu = $smallermtu;
734
	}
735

    
736
	/* Just in case anything is not working well */
737
	if ($lagg_mtu == 0) {
738
		$lagg_mtu = 1500;
739
	}
740

    
741
	foreach ($members as $member) {
742
		if (!does_interface_exist($member)) {
743
			continue;
744
		}
745
		/* make sure the parent interface is up */
746
		pfSense_interface_mtu($member, $lagg_mtu);
747
		interfaces_bring_up($member);
748
		hardware_offloading_applyflags($member);
749
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
750
	}
751
	pfSense_interface_capabilities($laggif, -$flags_off);
752
	pfSense_interface_capabilities($laggif, $flags_on);
753

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

    
756
	interfaces_bring_up($laggif);
757

    
758
	return $laggif;
759
}
760

    
761
function interfaces_gre_configure($checkparent = 0, $realif = "") {
762
	global $config;
763

    
764
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
765
		foreach ($config['gres']['gre'] as $i => $gre) {
766
			if (empty($gre['greif'])) {
767
				$gre['greif'] = "gre{$i}";
768
			}
769
			if (!empty($realif) && $realif != $gre['greif']) {
770
				continue;
771
			}
772

    
773
			if ($checkparent == 1) {
774
				if (substr($gre['if'], 0, 4) == '_vip') {
775
					continue;
776
				}
777
				if (substr($gre['if'], 0, 5) == '_lloc') {
778
					continue;
779
				}
780
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6") {
781
					continue;
782
				}
783
			} else if ($checkparent == 2) {
784
				if ((substr($gre['if'], 0, 4) != '_vip' && substr($gre['if'], 0, 5) != '_lloc') &&
785
				    (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")) {
786
					continue;
787
				}
788
			}
789
			/* XXX: Maybe we should report any errors?! */
790
			interface_gre_configure($gre);
791
		}
792
	}
793
}
794

    
795
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
796
function interface_gre_configure(&$gre, $grekey = "") {
797
	global $config, $g;
798

    
799
	if (!is_array($gre)) {
800
		return -1;
801
	}
802

    
803
	$realif = get_real_interface($gre['if']);
804
	$realifip = get_interface_ip($gre['if']);
805
	$realifip6 = get_interface_ipv6($gre['if']);
806

    
807
	/* make sure the parent interface is up */
808
	interfaces_bring_up($realif);
809

    
810
	if (platform_booting() || !(empty($gre['greif']))) {
811
		pfSense_interface_destroy($gre['greif']);
812
		pfSense_interface_create($gre['greif']);
813
		$greif = $gre['greif'];
814
	} else {
815
		$greif = pfSense_interface_create("gre");
816
	}
817

    
818
	/* Do not change the order here for more see gre(4) NOTES section. */
819
	if (is_ipaddrv6($gre['remote-addr'])) {
820
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
821
	} else {
822
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
823
	}
824
	if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
825
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
826
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
827
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
828
	} else {
829
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
830
	}
831
	if (isset($gre['link0'])) {
832
		pfSense_interface_flags($greif, IFF_LINK0);
833
	}
834
	if (isset($gre['link1'])) {
835
		pfSense_interface_flags($greif, IFF_LINK1);
836
	}
837
	if (isset($gre['link2'])) {
838
		pfSense_interface_flags($greif, IFF_LINK2);
839
	}
840

    
841
	if ($greif) {
842
		interfaces_bring_up($greif);
843
	} else {
844
		log_error(gettext("Could not bring greif up -- variable not defined."));
845
	}
846

    
847
	if (isset($gre['link1']) && $gre['link1']) {
848
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
849
	}
850
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
851
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
852
	}
853
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
854
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
855
	}
856

    
857
	interfaces_bring_up($greif);
858

    
859
	return $greif;
860
}
861

    
862
function interfaces_gif_configure($checkparent = 0, $realif = "") {
863
	global $config;
864

    
865
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
866
		foreach ($config['gifs']['gif'] as $i => $gif) {
867
			if (empty($gif['gifif'])) {
868
				$gre['gifif'] = "gif{$i}";
869
			}
870
			if (!empty($realif) && $realif != $gif['gifif']) {
871
				continue;
872
			}
873

    
874
			if ($checkparent == 1) {
875
				if (substr($gif['if'], 0, 4) == '_vip') {
876
					continue;
877
				}
878
				if (substr($gif['if'], 0, 5) == '_lloc') {
879
					continue;
880
				}
881
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
882
					continue;
883
				}
884
			}
885
			else if ($checkparent == 2) {
886
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
887
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
888
					continue;
889
				}
890
			}
891
			/* XXX: Maybe we should report any errors?! */
892
			interface_gif_configure($gif);
893
		}
894
	}
895
}
896

    
897
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
898
function interface_gif_configure(&$gif, $gifkey = "") {
899
	global $config, $g;
900

    
901
	if (!is_array($gif)) {
902
		return -1;
903
	}
904

    
905
	$realif = get_real_interface($gif['if']);
906
	$ipaddr = get_interface_ip($gif['if']);
907

    
908
	if (is_ipaddrv4($gif['remote-addr'])) {
909
		if (is_ipaddrv4($ipaddr)) {
910
			$realifip = $ipaddr;
911
		} else {
912
			$realifip = get_interface_ip($gif['if']);
913
		}
914
		$realifgw = get_interface_gateway($gif['if']);
915
	} else if (is_ipaddrv6($gif['remote-addr'])) {
916
		if (is_ipaddrv6($ipaddr)) {
917
			$realifip = $ipaddr;
918
		} else {
919
			$realifip = get_interface_ipv6($gif['if']);
920
		}
921
		$realifgw = get_interface_gateway_v6($gif['if']);
922
	}
923
	/* make sure the parent interface is up */
924
	if ($realif) {
925
		interfaces_bring_up($realif);
926
	} else {
927
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
928
	}
929

    
930
	if (platform_booting() || !(empty($gif['gifif']))) {
931
		pfSense_interface_destroy($gif['gifif']);
932
		pfSense_interface_create($gif['gifif']);
933
		$gifif = $gif['gifif'];
934
	} else {
935
		$gifif = pfSense_interface_create("gif");
936
	}
937

    
938
	/* Do not change the order here for more see gif(4) NOTES section. */
939
	if (is_ipaddrv6($gif['remote-addr'])) {
940
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
941
	} else {
942
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
943
	}
944
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
945
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
946
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
947
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
948
	} else {
949
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
950
	}
951
	if (isset($gif['link0'])) {
952
		pfSense_interface_flags($gifif, IFF_LINK0);
953
	}
954
	if (isset($gif['link1'])) {
955
		pfSense_interface_flags($gifif, IFF_LINK1);
956
	}
957
	if ($gifif) {
958
		interfaces_bring_up($gifif);
959
	} else {
960
		log_error(gettext("could not bring gifif up -- variable not defined"));
961
	}
962

    
963
	if (!platform_booting()) {
964
		$iflist = get_configured_interface_list();
965
		foreach ($iflist as $ifname) {
966
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
967
				if (get_interface_gateway($ifname)) {
968
					system_routing_configure($ifname);
969
					break;
970
				}
971
				if (get_interface_gateway_v6($ifname)) {
972
					system_routing_configure($ifname);
973
					break;
974
				}
975
			}
976
		}
977
	}
978

    
979

    
980
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
981
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
982
	}
983
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
984
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
985
	}
986

    
987
	if (is_ipaddrv4($realifgw)) {
988
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
989
	}
990
	if (is_ipaddrv6($realifgw)) {
991
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
992
	}
993

    
994
	interfaces_bring_up($gifif);
995

    
996
	return $gifif;
997
}
998

    
999
function interfaces_configure() {
1000
	global $config, $g;
1001

    
1002
	/* Set up our loopback interface */
1003
	interfaces_loopback_configure();
1004

    
1005
	/* create the unconfigured wireless clones */
1006
	interfaces_create_wireless_clones();
1007

    
1008
	/* set up LAGG virtual interfaces */
1009
	interfaces_lagg_configure();
1010

    
1011
	/* set up VLAN virtual interfaces */
1012
	interfaces_vlan_configure();
1013

    
1014
	interfaces_qinq_configure();
1015

    
1016
	$iflist = get_configured_interface_with_descr();
1017
	$delayed_list = array();
1018
	$bridge_list = array();
1019
	$track6_list = array();
1020

    
1021
	/* This is needed to speedup interfaces on bootup. */
1022
	$reload = false;
1023
	if (!platform_booting()) {
1024
		$reload = true;
1025
	}
1026

    
1027
	foreach ($iflist as $if => $ifname) {
1028
		$realif = $config['interfaces'][$if]['if'];
1029
		if (strstr($realif, "bridge")) {
1030
			$bridge_list[$if] = $ifname;
1031
		} else if (strstr($realif, "gre")) {
1032
			$delayed_list[$if] = $ifname;
1033
		} else if (strstr($realif, "gif")) {
1034
			$delayed_list[$if] = $ifname;
1035
		} else if (strstr($realif, "ovpn")) {
1036
			//echo "Delaying OpenVPN interface configuration...done.\n";
1037
			continue;
1038
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1039
			$track6_list[$if] = $ifname;
1040
		} else {
1041
			if (platform_booting()) {
1042
				printf(gettext("Configuring %s interface..."), $ifname);
1043
			}
1044

    
1045
			if ($g['debug']) {
1046
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1047
			}
1048
			interface_configure($if, $reload);
1049
			if (platform_booting()) {
1050
				echo gettext("done.") . "\n";
1051
			}
1052
		}
1053
	}
1054

    
1055
	/*
1056
	 * NOTE: The following function parameter consists of
1057
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1058
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1059
	 */
1060

    
1061
	/* set up GRE virtual interfaces */
1062
	interfaces_gre_configure(1);
1063

    
1064
	/* set up GIF virtual interfaces */
1065
	interfaces_gif_configure(1);
1066

    
1067
	/* set up BRIDGe virtual interfaces */
1068
	interfaces_bridge_configure(1);
1069

    
1070
	foreach ($track6_list as $if => $ifname) {
1071
		if (platform_booting()) {
1072
			printf(gettext("Configuring %s interface..."), $ifname);
1073
		}
1074
		if ($g['debug']) {
1075
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1076
		}
1077

    
1078
		interface_configure($if, $reload);
1079

    
1080
		if (platform_booting()) {
1081
			echo gettext("done.") . "\n";
1082
		}
1083
	}
1084

    
1085
	/* bring up vip interfaces */
1086
	interfaces_vips_configure();
1087

    
1088
	/* set up GRE virtual interfaces */
1089
	interfaces_gre_configure(2);
1090

    
1091
	/* set up GIF virtual interfaces */
1092
	interfaces_gif_configure(2);
1093

    
1094
	foreach ($delayed_list as $if => $ifname) {
1095
		if (platform_booting()) {
1096
			printf(gettext("Configuring %s interface..."), $ifname);
1097
		}
1098
		if ($g['debug']) {
1099
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1100
		}
1101

    
1102
		interface_configure($if, $reload);
1103

    
1104
		if (platform_booting()) {
1105
			echo gettext("done.") . "\n";
1106
		}
1107
	}
1108

    
1109
	/* set up BRIDGe virtual interfaces */
1110
	interfaces_bridge_configure(2);
1111

    
1112
	foreach ($bridge_list as $if => $ifname) {
1113
		if (platform_booting()) {
1114
			printf(gettext("Configuring %s interface..."), $ifname);
1115
		}
1116
		if ($g['debug']) {
1117
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1118
		}
1119

    
1120
		interface_configure($if, $reload);
1121

    
1122
		if (platform_booting()) {
1123
			echo gettext("done.") . "\n";
1124
		}
1125
	}
1126

    
1127
	/* configure interface groups */
1128
	interfaces_group_setup();
1129

    
1130
	if (!platform_booting()) {
1131
		/* reconfigure static routes (kernel may have deleted them) */
1132
		system_routing_configure();
1133

    
1134
		/* reload IPsec tunnels */
1135
		vpn_ipsec_configure();
1136

    
1137
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1138
		services_dhcpd_configure();
1139

    
1140
		/* restart dnsmasq or unbound */
1141
		if (isset($config['dnsmasq']['enable'])) {
1142
			services_dnsmasq_configure();
1143
		} elseif (isset($config['unbound']['enable'])) {
1144
			services_unbound_configure();
1145
		}
1146
	}
1147

    
1148
	return 0;
1149
}
1150

    
1151
function interface_reconfigure($interface = "wan", $reloadall = false) {
1152
	interface_bring_down($interface);
1153
	interface_configure($interface, $reloadall);
1154
}
1155

    
1156
function interface_vip_bring_down($vip) {
1157
	global $g;
1158

    
1159
	if (strpos($vip['interface'], '_vip')) {
1160
		if (is_ipaddrv6($vip['subnet'])) {
1161
			$family = 'inet6';
1162
		} else {
1163
			$family = 'inet';
1164
		}
1165

    
1166
		$carpvip = get_configured_carp_interface_list($vip['interface'], $family, 'vip');
1167
		$iface = $carpvip['interface'];
1168
	} else {
1169
		$iface = $vip['interface'];
1170
	}
1171

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

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

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

    
1208
	if ($g['debug']) {
1209
		log_error("Calling interface down for interface {$interface}, destroy is " . (($destroy) ? 'true' : 'false'));
1210
	}
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
				}
1272
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1273
			}
1274
			break;
1275
		default:
1276
			if (does_interface_exist("$realif")) {
1277
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1278
				interface_ipalias_cleanup($interface);
1279
				if ($destroy == true) {
1280
					pfSense_interface_flags($realif, -IFF_UP);
1281
				}
1282
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1283
			}
1284
			break;
1285
	}
1286

    
1287
	$track6 = array();
1288
	switch ($ifcfg['ipaddrv6']) {
1289
		case "slaac":
1290
		case "dhcp6":
1291
			$pidv6 = find_dhcp6c_process($realif);
1292
			if ($pidv6) {
1293
				posix_kill($pidv6, SIGTERM);
1294
			}
1295
			sleep(3);
1296
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1297
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1298
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1299
			if (does_interface_exist($realifv6)) {
1300
				$ip6 = find_interface_ipv6($realifv6);
1301
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1302
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1303
				}
1304
				interface_ipalias_cleanup($interface, "inet6");
1305
				if ($destroy == true) {
1306
					pfSense_interface_flags($realif, -IFF_UP);
1307
				}
1308
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1309
			}
1310
			$track6 = link_interface_to_track6($interface);
1311
			break;
1312
		case "6rd":
1313
		case "6to4":
1314
			$realif = "{$interface}_stf";
1315
			if (does_interface_exist("$realif")) {
1316
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1317
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1318
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1319
					$destroy = true;
1320
				} else {
1321
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1322
					$ip6 = get_interface_ipv6($interface);
1323
					if (is_ipaddrv6($ip6)) {
1324
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1325
					}
1326
				}
1327
				interface_ipalias_cleanup($interface, "inet6");
1328
				if ($destroy == true) {
1329
					pfSense_interface_flags($realif, -IFF_UP);
1330
				}
1331
			}
1332
			$track6 = link_interface_to_track6($interface);
1333
			break;
1334
		default:
1335
			if (does_interface_exist("$realif")) {
1336
				$ip6 = get_interface_ipv6($interface);
1337
				if (is_ipaddrv6($ip6)) {
1338
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1339
				}
1340
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1341
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1342
				}
1343
				interface_ipalias_cleanup($interface, "inet6");
1344
				if ($destroy == true) {
1345
					pfSense_interface_flags($realif, -IFF_UP);
1346
				}
1347
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1348
			}
1349
			$track6 = link_interface_to_track6($interface);
1350
			break;
1351
	}
1352

    
1353
	if (!empty($track6) && is_array($track6)) {
1354
		if (!function_exists('services_dhcpd_configure')) {
1355
			require_once('services.inc');
1356
		}
1357
		/* Bring down radvd and dhcp6 on these interfaces */
1358
		services_dhcpd_configure('inet6', $track6);
1359
	}
1360

    
1361
	$old_router = '';
1362
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1363
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1364
	}
1365

    
1366
	/* remove interface up file if it exists */
1367
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1368
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1369
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1370
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1371
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1372
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1373
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1374

    
1375
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1376
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1377
	if (is_array($ifcfg['wireless'])) {
1378
		kill_hostapd($realif);
1379
		mwexec(kill_wpasupplicant($realif));
1380
	}
1381

    
1382
	if ($destroy == true) {
1383
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1384
			pfSense_interface_destroy($realif);
1385
		}
1386
	}
1387

    
1388
	return;
1389
}
1390

    
1391
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1392
	global $config;
1393
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1394
		unset($config["virtualip_carp_maintenancemode"]);
1395
		write_config("Leave CARP maintenance mode");
1396
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1397
		$config["virtualip_carp_maintenancemode"] = true;
1398
		write_config("Enter CARP maintenance mode");
1399
	}
1400

    
1401
	$viparr = &$config['virtualip']['vip'];
1402
	foreach ($viparr as $vip) {
1403
		if ($vip['mode'] == "carp") {
1404
			interface_carp_configure($vip);
1405
		}
1406
	}
1407
}
1408

    
1409
function interface_isppp_type($interface) {
1410
	global $config;
1411

    
1412
	if (!is_array($config['interfaces'][$interface])) {
1413
		return false;
1414
	}
1415

    
1416
	switch ($config['interfaces'][$interface]['ipaddr']) {
1417
		case 'pptp':
1418
		case 'l2tp':
1419
		case 'pppoe':
1420
		case 'ppp':
1421
			return true;
1422
			break;
1423
		default:
1424
			return false;
1425
			break;
1426
	}
1427
}
1428

    
1429
function interfaces_ptpid_used($ptpid) {
1430
	global $config;
1431

    
1432
	if (is_array($config['ppps']['ppp'])) {
1433
		foreach ($config['ppps']['ppp'] as & $settings) {
1434
			if ($ptpid == $settings['ptpid']) {
1435
				return true;
1436
			}
1437
		}
1438
	}
1439

    
1440
	return false;
1441
}
1442

    
1443
function interfaces_ptpid_next() {
1444

    
1445
	$ptpid = 0;
1446
	while (interfaces_ptpid_used($ptpid)) {
1447
		$ptpid++;
1448
	}
1449

    
1450
	return $ptpid;
1451
}
1452

    
1453
function getMPDCRONSettings($pppif) {
1454
	global $config;
1455

    
1456
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1457
	if (is_array($config['cron']['item'])) {
1458
		foreach ($config['cron']['item'] as $i => $item) {
1459
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1460
				return array("ID" => $i, "ITEM" => $item);
1461
			}
1462
		}
1463
	}
1464

    
1465
	return NULL;
1466
}
1467

    
1468
function handle_pppoe_reset($post_array) {
1469
	global $config, $g;
1470

    
1471
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1472
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1473

    
1474
	if (!is_array($config['cron']['item'])) {
1475
		$config['cron']['item'] = array();
1476
	}
1477

    
1478
	$itemhash = getMPDCRONSettings($pppif);
1479

    
1480
	// reset cron items if necessary and return
1481
	if (empty($post_array['pppoe-reset-type'])) {
1482
		if (isset($itemhash)) {
1483
			unset($config['cron']['item'][$itemhash['ID']]);
1484
		}
1485
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1486
		return;
1487
	}
1488

    
1489
	if (empty($itemhash)) {
1490
		$itemhash = array();
1491
	}
1492
	$item = array();
1493
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1494
		$item['minute'] = $post_array['pppoe_resetminute'];
1495
		$item['hour'] = $post_array['pppoe_resethour'];
1496
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1497
			$date = explode("/", $post_array['pppoe_resetdate']);
1498
			$item['mday'] = $date[1];
1499
			$item['month'] = $date[0];
1500
		} else {
1501
			$item['mday'] = "*";
1502
			$item['month'] = "*";
1503
		}
1504
		$item['wday'] = "*";
1505
		$item['who'] = "root";
1506
		$item['command'] = $cron_cmd_file;
1507
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1508
		switch ($post_array['pppoe_pr_preset_val']) {
1509
			case "monthly":
1510
				$item['minute'] = "0";
1511
				$item['hour'] = "0";
1512
				$item['mday'] = "1";
1513
				$item['month'] = "*";
1514
				$item['wday'] = "*";
1515
				break;
1516
			case "weekly":
1517
				$item['minute'] = "0";
1518
				$item['hour'] = "0";
1519
				$item['mday'] = "*";
1520
				$item['month'] = "*";
1521
				$item['wday'] = "0";
1522
				break;
1523
			case "daily":
1524
				$item['minute'] = "0";
1525
				$item['hour'] = "0";
1526
				$item['mday'] = "*";
1527
				$item['month'] = "*";
1528
				$item['wday'] = "*";
1529
				break;
1530
			case "hourly":
1531
				$item['minute'] = "0";
1532
				$item['hour'] = "*";
1533
				$item['mday'] = "*";
1534
				$item['month'] = "*";
1535
				$item['wday'] = "*";
1536
				break;
1537
		} // end switch
1538
		$item['who'] = "root";
1539
		$item['command'] = $cron_cmd_file;
1540
	}
1541
	if (empty($item)) {
1542
		return;
1543
	}
1544
	if (isset($itemhash['ID'])) {
1545
		$config['cron']['item'][$itemhash['ID']] = $item;
1546
	} else {
1547
		$config['cron']['item'][] = $item;
1548
	}
1549
}
1550

    
1551
/*
1552
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1553
 * It writes the mpd config file to /var/etc every time the link is opened.
1554
 */
1555
function interface_ppps_configure($interface) {
1556
	global $config, $g;
1557

    
1558
	/* Return for unassigned interfaces. This is a minimum requirement. */
1559
	if (empty($config['interfaces'][$interface])) {
1560
		return 0;
1561
	}
1562
	$ifcfg = $config['interfaces'][$interface];
1563
	if (!isset($ifcfg['enable'])) {
1564
		return 0;
1565
	}
1566

    
1567
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1568
	if (!is_dir("/var/spool/lock")) {
1569
		mkdir("/var/spool/lock", 0777, true);
1570
	}
1571
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1572
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1573
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1574
	}
1575

    
1576
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1577
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1578
			if ($ifcfg['if'] == $ppp['if']) {
1579
				break;
1580
			}
1581
		}
1582
	}
1583
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
1584
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1585
		return 0;
1586
	}
1587
	$pppif = $ifcfg['if'];
1588
	if ($ppp['type'] == "ppp") {
1589
		$type = "modem";
1590
	} else {
1591
		$type = $ppp['type'];
1592
	}
1593
	$upper_type = strtoupper($ppp['type']);
1594

    
1595
	/* XXX: This does not make sense and may create trouble
1596
	 * comment it for now to be removed later on.
1597
	if (platform_booting()) {
1598
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1599
		echo "starting {$pppif} link...";
1600
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1601
			return 0;
1602
	}
1603
	*/
1604

    
1605
	$ports = explode(',', $ppp['ports']);
1606
	if ($type != "modem") {
1607
		foreach ($ports as $pid => $port) {
1608
			$ports[$pid] = get_real_interface($port);
1609
			if (empty($ports[$pid])) {
1610
				return 0;
1611
			}
1612
		}
1613
	}
1614
	$localips = explode(',', $ppp['localip']);
1615
	$gateways = explode(',', $ppp['gateway']);
1616
	$subnets = explode(',', $ppp['subnet']);
1617

    
1618
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1619
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1620
	 */
1621
	foreach ($ports as $pid => $port) {
1622
		switch ($ppp['type']) {
1623
			case "pppoe":
1624
				/* Bring the parent interface up */
1625
				interfaces_bring_up($port);
1626
				pfSense_ngctl_attach(".", $port);
1627
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1628
				mwexec("/usr/sbin/ngctl msg {$port}: setautosrc 1");
1629
				break;
1630
			case "pptp":
1631
			case "l2tp":
1632
				/* configure interface */
1633
				if (is_ipaddr($localips[$pid])) {
1634
					// Manually configure interface IP/subnet
1635
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1636
					interfaces_bring_up($port);
1637
				} else if (empty($localips[$pid])) {
1638
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1639
				}
1640

    
1641
				if (!is_ipaddr($localips[$pid])) {
1642
					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!");
1643
					$localips[$pid] = "0.0.0.0";
1644
				}
1645
				if (!is_ipaddr($gateways[$pid])) {
1646
					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));
1647
					return 0;
1648
				}
1649
				pfSense_ngctl_attach(".", $port);
1650
				break;
1651
			case "ppp":
1652
				if (!file_exists("{$port}")) {
1653
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1654
					return 0;
1655
				}
1656
				break;
1657
			default:
1658
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1659
				break;
1660
		}
1661
	}
1662

    
1663
	if (is_array($ports) && count($ports) > 1) {
1664
		$multilink = "enable";
1665
	} else {
1666
		$multilink = "disable";
1667
	}
1668

    
1669
	if ($type == "modem") {
1670
		if (is_ipaddr($ppp['localip'])) {
1671
			$localip = $ppp['localip'];
1672
		} else {
1673
			$localip = '0.0.0.0';
1674
		}
1675

    
1676
		if (is_ipaddr($ppp['gateway'])) {
1677
			$gateway = $ppp['gateway'];
1678
		} else {
1679
			$gateway = "10.64.64.{$pppid}";
1680
		}
1681
		$ranges = "{$localip}/0 {$gateway}/0";
1682

    
1683
		if (empty($ppp['apnum'])) {
1684
			$ppp['apnum'] = 1;
1685
		}
1686
	} else {
1687
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1688
	}
1689

    
1690
	if (isset($ppp['ondemand'])) {
1691
		$ondemand = "enable";
1692
	} else {
1693
		$ondemand = "disable";
1694
	}
1695
	if (!isset($ppp['idletimeout'])) {
1696
		$ppp['idletimeout'] = 0;
1697
	}
1698

    
1699
	if (empty($ppp['username']) && $type == "modem") {
1700
		$ppp['username'] = "user";
1701
		$ppp['password'] = "none";
1702
	}
1703
	if (empty($ppp['password']) && $type == "modem") {
1704
		$passwd = "none";
1705
	} else {
1706
		$passwd = base64_decode($ppp['password']);
1707
	}
1708

    
1709
	$bandwidths = explode(',', $ppp['bandwidth']);
1710
	$defaultmtu = "1492";
1711
	if (!empty($ifcfg['mtu'])) {
1712
		$defaultmtu = intval($ifcfg['mtu']);
1713
	}
1714
	$mtus = explode(',', $ppp['mtu']);
1715
	$mrus = explode(',', $ppp['mru']);
1716

    
1717
	if (isset($ppp['mrru'])) {
1718
		$mrrus = explode(',', $ppp['mrru']);
1719
	}
1720

    
1721
	// Construct the mpd.conf file
1722
	$mpdconf = <<<EOD
1723
startup:
1724
	# configure the console
1725
	set console close
1726
	# configure the web server
1727
	set web close
1728

    
1729
default:
1730
{$ppp['type']}client:
1731
	create bundle static {$interface}
1732
	set bundle enable ipv6cp
1733
	set iface name {$pppif}
1734

    
1735
EOD;
1736
	$setdefaultgw = false;
1737
	$founddefaultgw = false;
1738
	if (is_array($config['gateways']['gateway_item'])) {
1739
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1740
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1741
				$setdefaultgw = true;
1742
				break;
1743
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1744
				$founddefaultgw = true;
1745
				break;
1746
			}
1747
		}
1748
	}
1749

    
1750
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1751
		$setdefaultgw = true;
1752
		$mpdconf .= <<<EOD
1753
	set iface route default
1754

    
1755
EOD;
1756
	}
1757
	$mpdconf .= <<<EOD
1758
	set iface {$ondemand} on-demand
1759
	set iface idle {$ppp['idletimeout']}
1760

    
1761
EOD;
1762

    
1763
	if (isset($ppp['ondemand'])) {
1764
		$mpdconf .= <<<EOD
1765
	set iface addrs 10.10.1.1 10.10.1.2
1766

    
1767
EOD;
1768
	}
1769

    
1770
	if (isset($ppp['tcpmssfix'])) {
1771
		$tcpmss = "disable";
1772
	} else {
1773
		$tcpmss = "enable";
1774
	}
1775
	$mpdconf .= <<<EOD
1776
	set iface {$tcpmss} tcpmssfix
1777

    
1778
EOD;
1779

    
1780
	$mpdconf .= <<<EOD
1781
	set iface up-script /usr/local/sbin/ppp-linkup
1782
	set iface down-script /usr/local/sbin/ppp-linkdown
1783
	set ipcp ranges {$ranges}
1784

    
1785
EOD;
1786
	if (isset($ppp['vjcomp'])) {
1787
		$mpdconf .= <<<EOD
1788
	set ipcp no vjcomp
1789

    
1790
EOD;
1791
	}
1792

    
1793
	if (isset($config['system']['dnsallowoverride'])) {
1794
		$mpdconf .= <<<EOD
1795
	set ipcp enable req-pri-dns
1796
	set ipcp enable req-sec-dns
1797

    
1798
EOD;
1799
	}
1800

    
1801
	if (!isset($ppp['verbose_log'])) {
1802
		$mpdconf .= <<<EOD
1803
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1804

    
1805
EOD;
1806
	}
1807

    
1808
	foreach ($ports as $pid => $port) {
1809
		$port = get_real_interface($port);
1810
		$mpdconf .= <<<EOD
1811

    
1812
	create link static {$interface}_link{$pid} {$type}
1813
	set link action bundle {$interface}
1814
	set link {$multilink} multilink
1815
	set link keep-alive 10 60
1816
	set link max-redial 0
1817

    
1818
EOD;
1819
		if (isset($ppp['shortseq'])) {
1820
			$mpdconf .= <<<EOD
1821
	set link no shortseq
1822

    
1823
EOD;
1824
		}
1825

    
1826
		if (isset($ppp['acfcomp'])) {
1827
			$mpdconf .= <<<EOD
1828
	set link no acfcomp
1829

    
1830
EOD;
1831
		}
1832

    
1833
		if (isset($ppp['protocomp'])) {
1834
			$mpdconf .= <<<EOD
1835
	set link no protocomp
1836

    
1837
EOD;
1838
		}
1839

    
1840
		$mpdconf .= <<<EOD
1841
	set link disable chap pap
1842
	set link accept chap pap eap
1843
	set link disable incoming
1844

    
1845
EOD;
1846

    
1847

    
1848
		if (!empty($bandwidths[$pid])) {
1849
			$mpdconf .= <<<EOD
1850
	set link bandwidth {$bandwidths[$pid]}
1851

    
1852
EOD;
1853
		}
1854

    
1855
		if (empty($mtus[$pid])) {
1856
			$mtus[$pid] = $defaultmtu;
1857
		}
1858
		if ($type == "pppoe") {
1859
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
1860
				$mtus[$pid] = get_interface_mtu($port) - 8;
1861
			}
1862
		}
1863
		if (! ($type == "pppoe" && $mtus[$pid] > 1492) ) {
1864
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
1865
			$mpdconf .= <<<EOD
1866
	set link mtu {$mtus[$pid]}
1867

    
1868
EOD;
1869
		}
1870

    
1871
		if (!empty($mrus[$pid])) {
1872
			$mpdconf .= <<<EOD
1873
	set link mru {$mrus[$pid]}
1874

    
1875
EOD;
1876
		}
1877

    
1878
		if (!empty($mrrus[$pid])) {
1879
			$mpdconf .= <<<EOD
1880
	set link mrru {$mrrus[$pid]}
1881

    
1882
EOD;
1883
		}
1884

    
1885
		$mpdconf .= <<<EOD
1886
	set auth authname "{$ppp['username']}"
1887
	set auth password {$passwd}
1888

    
1889
EOD;
1890
		if ($type == "modem") {
1891
			$mpdconf .= <<<EOD
1892
	set modem device {$ppp['ports']}
1893
	set modem script DialPeer
1894
	set modem idle-script Ringback
1895
	set modem watch -cd
1896
	set modem var \$DialPrefix "DT"
1897
	set modem var \$Telephone "{$ppp['phone']}"
1898

    
1899
EOD;
1900
		}
1901
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1902
			$mpdconf .= <<<EOD
1903
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1904

    
1905
EOD;
1906
		}
1907
		if (isset($ppp['initstr']) && $type == "modem") {
1908
			$initstr = base64_decode($ppp['initstr']);
1909
			$mpdconf .= <<<EOD
1910
	set modem var \$InitString "{$initstr}"
1911

    
1912
EOD;
1913
		}
1914
		if (isset($ppp['simpin']) && $type == "modem") {
1915
			if ($ppp['pin-wait'] == "") {
1916
				$ppp['pin-wait'] = 0;
1917
			}
1918
			$mpdconf .= <<<EOD
1919
	set modem var \$SimPin "{$ppp['simpin']}"
1920
	set modem var \$PinWait "{$ppp['pin-wait']}"
1921

    
1922
EOD;
1923
		}
1924
		if (isset($ppp['apn']) && $type == "modem") {
1925
			$mpdconf .= <<<EOD
1926
	set modem var \$APN "{$ppp['apn']}"
1927
	set modem var \$APNum "{$ppp['apnum']}"
1928

    
1929
EOD;
1930
		}
1931
		if ($type == "pppoe") {
1932
			// Send a null service name if none is set.
1933
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1934
			$mpdconf .= <<<EOD
1935
	set pppoe service "{$provider}"
1936

    
1937
EOD;
1938
		}
1939
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
1940
			$mpdconf .= <<<EOD
1941
	set pppoe max-payload {$mtus[$pid]}
1942

    
1943
EOD;
1944
		}
1945
		if ($type == "pppoe") {
1946
			$mpdconf .= <<<EOD
1947
	set pppoe iface {$port}
1948

    
1949
EOD;
1950
		}
1951

    
1952
		if ($type == "pptp" || $type == "l2tp") {
1953
			$mpdconf .= <<<EOD
1954
	set {$type} self {$localips[$pid]}
1955
	set {$type} peer {$gateways[$pid]}
1956

    
1957
EOD;
1958
		}
1959

    
1960
		$mpdconf .= "\topen\n";
1961
	} //end foreach ($port)
1962

    
1963

    
1964
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1965
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
1966
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1967
	} else {
1968
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1969
		if (!$fd) {
1970
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1971
			return 0;
1972
		}
1973
		// Write out mpd_ppp.conf
1974
		fwrite($fd, $mpdconf);
1975
		fclose($fd);
1976
		unset($mpdconf);
1977
	}
1978

    
1979
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1980
	if (isset($ppp['uptime'])) {
1981
		if (!file_exists("/conf/{$pppif}.log")) {
1982
			conf_mount_rw();
1983
			file_put_contents("/conf/{$pppif}.log", '');
1984
			conf_mount_ro();
1985
		}
1986
	} else {
1987
		if (file_exists("/conf/{$pppif}.log")) {
1988
			conf_mount_rw();
1989
			@unlink("/conf/{$pppif}.log");
1990
			conf_mount_ro();
1991
		}
1992
	}
1993

    
1994
	/* clean up old lock files */
1995
	foreach ($ports as $port) {
1996
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
1997
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1998
		}
1999
	}
2000

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

    
2005
	// Check for PPPoE periodic reset request
2006
	if ($type == "pppoe") {
2007
		if (!empty($ppp['pppoe-reset-type'])) {
2008
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2009
		} else {
2010
			interface_setup_pppoe_reset_file($ppp['if']);
2011
		}
2012
	}
2013
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
2014
	$i = 0;
2015
	while ($i < 3) {
2016
		sleep(10);
2017
		if (does_interface_exist($ppp['if'], true)) {
2018
			break;
2019
		}
2020
		$i++;
2021
	}
2022

    
2023
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2024
	/* We should be able to launch the right version for each modem */
2025
	/* We can also guess the mondev from the manufacturer */
2026
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2027
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2028
	foreach ($ports as $port) {
2029
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2030
			$mondev = substr(basename($port), 0, -1);
2031
			$devlist = glob("/dev/{$mondev}?");
2032
			$mondev = basename(end($devlist));
2033
		}
2034
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2035
			$mondev = substr(basename($port), 0, -1) . "1";
2036
		}
2037
		if ($mondev != '') {
2038
			log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
2039
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2040
		}
2041
	}
2042

    
2043
	return 1;
2044
}
2045

    
2046
function interfaces_sync_setup() {
2047
	global $g, $config;
2048

    
2049
	if (isset($config['system']['developerspew'])) {
2050
		$mt = microtime();
2051
		echo "interfaces_sync_setup() being called $mt\n";
2052
	}
2053

    
2054
	if (platform_booting()) {
2055
		echo gettext("Configuring CARP settings...");
2056
		mute_kernel_msgs();
2057
	}
2058

    
2059
	/* suck in configuration items */
2060
	if ($config['hasync']) {
2061
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2062
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2063
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2064
	} else {
2065
		unset($pfsyncinterface);
2066
		unset($pfsyncenabled);
2067
	}
2068

    
2069
	set_sysctl(array(
2070
		"net.inet.carp.preempt" => "1",
2071
		"net.inet.carp.log" => "1")
2072
	);
2073

    
2074
	if (!empty($pfsyncinterface)) {
2075
		$carp_sync_int = get_real_interface($pfsyncinterface);
2076
	} else {
2077
		unset($carp_sync_int);
2078
	}
2079

    
2080
	/* setup pfsync interface */
2081
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2082
		if (is_ipaddr($pfsyncpeerip)) {
2083
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2084
		} else {
2085
			$syncpeer = "-syncpeer";
2086
		}
2087

    
2088
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2089
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2090

    
2091
		sleep(1);
2092

    
2093
		/* 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
2094
		 * for existing sessions.
2095
		 */
2096
		log_error("waiting for pfsync...");
2097
		$i = 0;
2098
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2099
			$i++;
2100
			sleep(1);
2101
		}
2102
		log_error("pfsync done in $i seconds.");
2103
		log_error("Configuring CARP settings finalize...");
2104
	} else {
2105
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2106
	}
2107

    
2108
	if ($config['virtualip']['vip']) {
2109
		set_single_sysctl("net.inet.carp.allow", "1");
2110
	} else {
2111
		set_single_sysctl("net.inet.carp.allow", "0");
2112
	}
2113

    
2114
	if (platform_booting()) {
2115
		unmute_kernel_msgs();
2116
		echo gettext("done.") . "\n";
2117
	}
2118
}
2119

    
2120
function interface_proxyarp_configure($interface = "") {
2121
	global $config, $g;
2122
	if (isset($config['system']['developerspew'])) {
2123
		$mt = microtime();
2124
		echo "interface_proxyarp_configure() being called $mt\n";
2125
	}
2126

    
2127
	/* kill any running choparp */
2128
	if (empty($interface)) {
2129
		killbyname("choparp");
2130
	} else {
2131
		$vipif = get_real_interface($interface);
2132
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2133
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2134
		}
2135
	}
2136

    
2137
	$paa = array();
2138
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2139

    
2140
		/* group by interface */
2141
		foreach ($config['virtualip']['vip'] as $vipent) {
2142
			if ($vipent['mode'] === "proxyarp") {
2143
				if ($vipent['interface']) {
2144
					$proxyif = $vipent['interface'];
2145
				} else {
2146
					$proxyif = "wan";
2147
				}
2148

    
2149
				if (!empty($interface) && $interface != $proxyif) {
2150
					continue;
2151
				}
2152

    
2153
				if (!is_array($paa[$proxyif])) {
2154
					$paa[$proxyif] = array();
2155
				}
2156

    
2157
				$paa[$proxyif][] = $vipent;
2158
			}
2159
		}
2160
	}
2161

    
2162
	if (!empty($interface)) {
2163
		if (is_array($paa[$interface])) {
2164
			$paaifip = get_interface_ip($interface);
2165
			if (!is_ipaddr($paaifip)) {
2166
				return;
2167
			}
2168
			$args = get_real_interface($interface) . " auto";
2169
			foreach ($paa[$interface] as $paent) {
2170
				if (isset($paent['subnet'])) {
2171
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2172
				} else if (isset($paent['range'])) {
2173
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2174
				}
2175
			}
2176
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2177
		}
2178
	} else if (count($paa) > 0) {
2179
		foreach ($paa as $paif => $paents) {
2180
			$paaifip = get_interface_ip($paif);
2181
			if (!is_ipaddr($paaifip)) {
2182
				continue;
2183
			}
2184
			$args = get_real_interface($paif) . " auto";
2185
			foreach ($paents as $paent) {
2186
				if (isset($paent['subnet'])) {
2187
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2188
				} else if (isset($paent['range'])) {
2189
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2190
				}
2191
			}
2192
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2193
		}
2194
	}
2195
}
2196

    
2197
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2198
	global $g, $config;
2199

    
2200
	if (is_array($config['virtualip']['vip'])) {
2201
		foreach ($config['virtualip']['vip'] as $vip) {
2202
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2203
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet'])) {
2204
					interface_vip_bring_down($vip);
2205
				} else if ($inet == "inet4" && is_ipaddrv4($vip['subnet'])) {
2206
					interface_vip_bring_down($vip);
2207
				}
2208
			}
2209
		}
2210
	}
2211
}
2212

    
2213
function interfaces_vips_configure($interface = "") {
2214
	global $g, $config;
2215
	if (isset($config['system']['developerspew'])) {
2216
		$mt = microtime();
2217
		echo "interfaces_vips_configure() being called $mt\n";
2218
	}
2219
	$paa = array();
2220
	if (is_array($config['virtualip']['vip'])) {
2221
		$carp_setuped = false;
2222
		$anyproxyarp = false;
2223
		foreach ($config['virtualip']['vip'] as $vip) {
2224
			switch ($vip['mode']) {
2225
				case "proxyarp":
2226
					/* nothing it is handled on interface_proxyarp_configure() */
2227
					if ($interface <> "" && $vip['interface'] <> $interface) {
2228
						continue;
2229
					}
2230
					$anyproxyarp = true;
2231
					break;
2232
				case "ipalias":
2233
					if ($interface <> "" && $vip['interface'] <> $interface) {
2234
						continue;
2235
					}
2236
					interface_ipalias_configure($vip);
2237
					break;
2238
				case "carp":
2239
					if ($interface <> "" && $vip['interface'] <> $interface) {
2240
						continue;
2241
					}
2242
					if ($carp_setuped == false) {
2243
						$carp_setuped = true;
2244
					}
2245
					interface_carp_configure($vip);
2246
					break;
2247
			}
2248
		}
2249
		if ($carp_setuped == true) {
2250
			interfaces_sync_setup();
2251
		}
2252
		if ($anyproxyarp == true) {
2253
			interface_proxyarp_configure();
2254
		}
2255
	}
2256
}
2257

    
2258
function interface_ipalias_configure(&$vip) {
2259
	global $config;
2260

    
2261
	if ($vip['mode'] != 'ipalias') {
2262
		return;
2263
	}
2264

    
2265
	if ($vip['interface'] != 'lo0' && stripos($vip['interface'], '_vip') === false) {
2266
		if (!isset($config['interfaces'][$vip['interface']])) {
2267
			return;
2268
		}
2269

    
2270
		if (!isset($config['interfaces'][$vip['interface']]['enable'])) {
2271
			return;
2272
		}
2273
	}
2274

    
2275
	$af = 'inet';
2276
	if (is_ipaddrv6($vip['subnet'])) {
2277
		$af = 'inet6';
2278
	}
2279
	$iface = $vip['interface'];
2280
	$vipadd = '';
2281
	if (strpos($vip['interface'], '_vip')) {
2282
		$carpvip = get_configured_carp_interface_list($vip['interface'], $af, 'vip');
2283
		$iface = $carpvip['interface'];
2284
		$vipadd = "vhid {$carpvip['vhid']}";
2285
	}
2286
	$if = get_real_interface($iface);
2287
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vipadd}");
2288
	unset($iface, $af, $if, $carpvip, $vipadd);
2289
}
2290

    
2291
function interface_reload_carps($cif) {
2292
	global $config;
2293

    
2294
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2295
	if (empty($carpifs)) {
2296
		return;
2297
	}
2298

    
2299
	$carps = explode(" ", $carpifs);
2300
	if (is_array($config['virtualip']['vip'])) {
2301
		$viparr = &$config['virtualip']['vip'];
2302
		foreach ($viparr as $vip) {
2303
			if (in_array($vip['carpif'], $carps)) {
2304
				switch ($vip['mode']) {
2305
					case "carp":
2306
						interface_vip_bring_down($vip);
2307
						sleep(1);
2308
						interface_carp_configure($vip);
2309
						break;
2310
					case "ipalias":
2311
						interface_vip_bring_down($vip);
2312
						sleep(1);
2313
						interface_ipalias_configure($vip);
2314
						break;
2315
				}
2316
			}
2317
		}
2318
	}
2319
}
2320

    
2321
function interface_carp_configure(&$vip) {
2322
	global $config, $g;
2323
	if (isset($config['system']['developerspew'])) {
2324
		$mt = microtime();
2325
		echo "interface_carp_configure() being called $mt\n";
2326
	}
2327

    
2328
	if ($vip['mode'] != "carp") {
2329
		return;
2330
	}
2331

    
2332
	/* NOTE: Maybe its useless nowadays */
2333
	$realif = get_real_interface($vip['interface']);
2334
	if (!does_interface_exist($realif)) {
2335
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2336
		return;
2337
	}
2338

    
2339
	$vip_password = $vip['password'];
2340
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2341
	if ($vip['password'] != "") {
2342
		$password = " pass {$vip_password}";
2343
	}
2344

    
2345
	$advbase = "";
2346
	if (!empty($vip['advbase'])) {
2347
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2348
	}
2349

    
2350
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2351
	if ($carp_maintenancemode) {
2352
		$advskew = "advskew 254";
2353
	} else {
2354
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2355
	}
2356

    
2357
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) . " {$advskew} {$advbase} {$password}");
2358

    
2359
	if (is_ipaddrv4($vip['subnet'])) {
2360
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2361
	} else if (is_ipaddrv6($vip['subnet'])) {
2362
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2363
	}
2364

    
2365
	return $realif;
2366
}
2367

    
2368
function interface_wireless_clone($realif, $wlcfg) {
2369
	global $config, $g;
2370
	/*   Check to see if interface has been cloned as of yet.
2371
	 *   If it has not been cloned then go ahead and clone it.
2372
	 */
2373
	$needs_clone = false;
2374
	if (is_array($wlcfg['wireless'])) {
2375
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2376
	} else {
2377
		$wlcfg_mode = $wlcfg['mode'];
2378
	}
2379
	switch ($wlcfg_mode) {
2380
		case "hostap":
2381
			$mode = "wlanmode hostap";
2382
			break;
2383
		case "adhoc":
2384
			$mode = "wlanmode adhoc";
2385
			break;
2386
		default:
2387
			$mode = "";
2388
			break;
2389
	}
2390
	$baseif = interface_get_wireless_base($wlcfg['if']);
2391
	if (does_interface_exist($realif)) {
2392
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2393
		$ifconfig_str = implode($output);
2394
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2395
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2396
			$needs_clone = true;
2397
		}
2398
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2399
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2400
			$needs_clone = true;
2401
		}
2402
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2403
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2404
			$needs_clone = true;
2405
		}
2406
	} else {
2407
		$needs_clone = true;
2408
	}
2409

    
2410
	if ($needs_clone == true) {
2411
		/* remove previous instance if it exists */
2412
		if (does_interface_exist($realif)) {
2413
			pfSense_interface_destroy($realif);
2414
		}
2415

    
2416
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2417
		// Create the new wlan interface. FreeBSD returns the new interface name.
2418
		// example:  wlan2
2419
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2420
		if ($ret <> 0) {
2421
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2422
			return false;
2423
		}
2424
		$newif = trim($out[0]);
2425
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2426
		pfSense_interface_rename($newif, $realif);
2427
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2428
	}
2429
	return true;
2430
}
2431

    
2432
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2433
	global $config, $g;
2434

    
2435
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2436
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2437
				 'regdomain', 'regcountry', 'reglocation');
2438

    
2439
	if (!is_interface_wireless($ifcfg['if'])) {
2440
		return;
2441
	}
2442

    
2443
	$baseif = interface_get_wireless_base($ifcfg['if']);
2444

    
2445
	// Sync shared settings for assigned clones
2446
	$iflist = get_configured_interface_list(false, true);
2447
	foreach ($iflist as $if) {
2448
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2449
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2450
				foreach ($shared_settings as $setting) {
2451
					if ($sync_changes) {
2452
						if (isset($ifcfg['wireless'][$setting])) {
2453
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2454
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2455
							unset($config['interfaces'][$if]['wireless'][$setting]);
2456
						}
2457
					} else {
2458
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2459
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2460
						} else if (isset($ifcfg['wireless'][$setting])) {
2461
							unset($ifcfg['wireless'][$setting]);
2462
						}
2463
					}
2464
				}
2465
				if (!$sync_changes) {
2466
					break;
2467
				}
2468
			}
2469
		}
2470
	}
2471

    
2472
	// Read or write settings at shared area
2473
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2474
		foreach ($shared_settings as $setting) {
2475
			if ($sync_changes) {
2476
				if (isset($ifcfg['wireless'][$setting])) {
2477
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2478
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2479
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2480
				}
2481
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2482
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2483
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2484
				} else if (isset($ifcfg['wireless'][$setting])) {
2485
					unset($ifcfg['wireless'][$setting]);
2486
				}
2487
			}
2488
		}
2489
	}
2490

    
2491
	// Sync the mode on the clone creation page with the configured mode on the interface
2492
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2493
		foreach ($config['wireless']['clone'] as &$clone) {
2494
			if ($clone['cloneif'] == $ifcfg['if']) {
2495
				if ($sync_changes) {
2496
					$clone['mode'] = $ifcfg['wireless']['mode'];
2497
				} else {
2498
					$ifcfg['wireless']['mode'] = $clone['mode'];
2499
				}
2500
				break;
2501
			}
2502
		}
2503
		unset($clone);
2504
	}
2505
}
2506

    
2507
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2508
	global $config, $g;
2509

    
2510
	/*    open up a shell script that will be used to output the commands.
2511
	 *    since wireless is changing a lot, these series of commands are fragile
2512
	 *    and will sometimes need to be verified by a operator by executing the command
2513
	 *    and returning the output of the command to the developers for inspection.  please
2514
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2515
	 */
2516

    
2517
	// Remove script file
2518
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2519

    
2520
	// Clone wireless nic if needed.
2521
	interface_wireless_clone($if, $wl);
2522

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

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

    
2530
	$wlan_setup_log = fopen("{$g['tmp_path']}/{$if}_setup.log", "w");
2531

    
2532
	/* set values for /path/program */
2533
	$hostapd = "/usr/sbin/hostapd";
2534
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2535
	$ifconfig = "/sbin/ifconfig";
2536
	$sysctl = "/sbin/sysctl";
2537
	$killall = "/usr/bin/killall";
2538

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

    
2541
	$wlcmd = array();
2542
	$wl_sysctl = array();
2543
	/* Make sure it's up */
2544
	$wlcmd[] = "up";
2545
	/* Set a/b/g standard */
2546
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2547
	/* skip mode entirely for "auto" */
2548
	if ($wlcfg['standard'] != "auto") {
2549
		$wlcmd[] = "mode " . escapeshellarg($standard);
2550
	}
2551

    
2552
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2553
	 * to prevent massive packet loss under certain conditions. */
2554
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2555
		$wlcmd[] = "-ampdu";
2556
	}
2557

    
2558
	/* Set ssid */
2559
	if ($wlcfg['ssid']) {
2560
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2561
	}
2562

    
2563
	/* Set 802.11g protection mode */
2564
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2565

    
2566
	/* set wireless channel value */
2567
	if (isset($wlcfg['channel'])) {
2568
		if ($wlcfg['channel'] == "0") {
2569
			$wlcmd[] = "channel any";
2570
		} else {
2571
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2572
		}
2573
	}
2574

    
2575
	/* Set antenna diversity value */
2576
	if (isset($wlcfg['diversity'])) {
2577
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2578
	}
2579

    
2580
	/* Set txantenna value */
2581
	if (isset($wlcfg['txantenna'])) {
2582
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2583
	}
2584

    
2585
	/* Set rxantenna value */
2586
	if (isset($wlcfg['rxantenna'])) {
2587
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2588
	}
2589

    
2590
	/* set Distance value */
2591
	if ($wlcfg['distance']) {
2592
		$distance = escapeshellarg($wlcfg['distance']);
2593
	}
2594

    
2595
	/* Set wireless hostap mode */
2596
	if ($wlcfg['mode'] == "hostap") {
2597
		$wlcmd[] = "mediaopt hostap";
2598
	} else {
2599
		$wlcmd[] = "-mediaopt hostap";
2600
	}
2601

    
2602
	/* Set wireless adhoc mode */
2603
	if ($wlcfg['mode'] == "adhoc") {
2604
		$wlcmd[] = "mediaopt adhoc";
2605
	} else {
2606
		$wlcmd[] = "-mediaopt adhoc";
2607
	}
2608

    
2609
	/* Not necessary to set BSS mode as this is default if adhoc and/or hostap is NOT set */
2610

    
2611
	/* handle hide ssid option */
2612
	if (isset($wlcfg['hidessid']['enable'])) {
2613
		$wlcmd[] = "hidessid";
2614
	} else {
2615
		$wlcmd[] = "-hidessid";
2616
	}
2617

    
2618
	/* handle pureg (802.11g) only option */
2619
	if (isset($wlcfg['pureg']['enable'])) {
2620
		$wlcmd[] = "mode 11g pureg";
2621
	} else {
2622
		$wlcmd[] = "-pureg";
2623
	}
2624

    
2625
	/* handle puren (802.11n) only option */
2626
	if (isset($wlcfg['puren']['enable'])) {
2627
		$wlcmd[] = "puren";
2628
	} else {
2629
		$wlcmd[] = "-puren";
2630
	}
2631

    
2632
	/* enable apbridge option */
2633
	if (isset($wlcfg['apbridge']['enable'])) {
2634
		$wlcmd[] = "apbridge";
2635
	} else {
2636
		$wlcmd[] = "-apbridge";
2637
	}
2638

    
2639
	/* handle turbo option */
2640
	if (isset($wlcfg['turbo']['enable'])) {
2641
		$wlcmd[] = "mediaopt turbo";
2642
	} else {
2643
		$wlcmd[] = "-mediaopt turbo";
2644
	}
2645

    
2646
	/* handle txpower setting */
2647
	// or don't. this has issues at the moment.
2648
	/*
2649
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2650
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2651
	}*/
2652

    
2653
	/* handle wme option */
2654
	if (isset($wlcfg['wme']['enable'])) {
2655
		$wlcmd[] = "wme";
2656
	} else {
2657
		$wlcmd[] = "-wme";
2658
	}
2659

    
2660
	/* Enable wpa if it's configured. No WEP support anymore. */
2661
	if (isset($wlcfg['wpa']['enable'])) {
2662
		$wlcmd[] = "authmode wpa wepmode off ";
2663
	} else {
2664
		$wlcmd[] = "authmode open wepmode off ";
2665
	}
2666

    
2667
	kill_hostapd($if);
2668
	mwexec(kill_wpasupplicant("{$if}"));
2669

    
2670
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2671
	conf_mount_rw();
2672

    
2673
	switch ($wlcfg['mode']) {
2674
		case 'bss':
2675
			if (isset($wlcfg['wpa']['enable'])) {
2676
				$wpa .= <<<EOD
2677
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2678
ctrl_interface_group=0
2679
ap_scan=1
2680
#fast_reauth=1
2681
network={
2682
ssid="{$wlcfg['ssid']}"
2683
scan_ssid=1
2684
priority=5
2685
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2686
psk="{$wlcfg['wpa']['passphrase']}"
2687
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2688
group={$wlcfg['wpa']['wpa_pairwise']}
2689
}
2690
EOD;
2691

    
2692
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2693
				unset($wpa);
2694
			}
2695
			break;
2696
		case 'hostap':
2697
			if (!empty($wlcfg['wpa']['passphrase'])) {
2698
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2699
			} else {
2700
				$wpa_passphrase = "";
2701
			}
2702
			if (isset($wlcfg['wpa']['enable'])) {
2703
				$wpa .= <<<EOD
2704
interface={$if}
2705
driver=bsd
2706
logger_syslog=-1
2707
logger_syslog_level=0
2708
logger_stdout=-1
2709
logger_stdout_level=0
2710
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2711
ctrl_interface={$g['varrun_path']}/hostapd
2712
ctrl_interface_group=wheel
2713
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2714
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2715
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2716
ssid={$wlcfg['ssid']}
2717
debug={$wlcfg['wpa']['debug_mode']}
2718
wpa={$wlcfg['wpa']['wpa_mode']}
2719
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2720
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2721
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2722
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2723
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2724
{$wpa_passphrase}
2725

    
2726
EOD;
2727

    
2728
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2729
					$wpa .= <<<EOD
2730
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2731
rsn_preauth=1
2732
rsn_preauth_interfaces={$if}
2733

    
2734
EOD;
2735
				}
2736
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2737
					$wpa .= "ieee8021x=1\n";
2738

    
2739
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2740
						$auth_server_port = "1812";
2741
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2742
							$auth_server_port = intval($wlcfg['auth_server_port']);
2743
						}
2744
						$wpa .= <<<EOD
2745

    
2746
auth_server_addr={$wlcfg['auth_server_addr']}
2747
auth_server_port={$auth_server_port}
2748
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2749

    
2750
EOD;
2751
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2752
							$auth_server_port2 = "1812";
2753
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2754
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2755
							}
2756

    
2757
							$wpa .= <<<EOD
2758
auth_server_addr={$wlcfg['auth_server_addr2']}
2759
auth_server_port={$auth_server_port2}
2760
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2761

    
2762
EOD;
2763
						}
2764
					}
2765
				}
2766

    
2767
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2768
				unset($wpa);
2769
			}
2770
			break;
2771
	}
2772

    
2773
	/*
2774
	 *    all variables are set, lets start up everything
2775
	 */
2776

    
2777
	$baseif = interface_get_wireless_base($if);
2778
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2779
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2780

    
2781
	/* set sysctls for the wireless interface */
2782
	if (!empty($wl_sysctl)) {
2783
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2784
		foreach ($wl_sysctl as $wl_sysctl_line) {
2785
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2786
		}
2787
	}
2788

    
2789
	/* set ack timers according to users preference (if he/she has any) */
2790
	if ($distance) {
2791
		fwrite($fd_set, "# Enable ATH distance settings\n");
2792
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2793
	}
2794

    
2795
	if (isset($wlcfg['wpa']['enable'])) {
2796
		if ($wlcfg['mode'] == "bss") {
2797
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2798
		}
2799
		if ($wlcfg['mode'] == "hostap") {
2800
			/* add line to script to restore old mac to make hostapd happy */
2801
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2802
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2803
				if (is_macaddr($if_oldmac)) {
2804
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2805
						" link " . escapeshellarg($if_oldmac) . "\n");
2806
				}
2807
			}
2808

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

    
2811
			/* add line to script to restore spoofed mac after running hostapd */
2812
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2813
				if ($wl['spoofmac']) {
2814
					$if_curmac = $wl['spoofmac'];
2815
				} else {
2816
					$if_curmac = get_interface_mac($if);
2817
				}
2818
				if (is_macaddr($if_curmac)) {
2819
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2820
						" link " . escapeshellarg($if_curmac) . "\n");
2821
				}
2822
			}
2823
		}
2824
	}
2825

    
2826
	fclose($fd_set);
2827
	conf_mount_ro();
2828

    
2829
	/* Making sure regulatory settings have actually changed
2830
	 * before applying, because changing them requires bringing
2831
	 * down all wireless networks on the interface. */
2832
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2833
	$ifconfig_str = implode($output);
2834
	unset($output);
2835
	$reg_changing = false;
2836

    
2837
	/* special case for the debug country code */
2838
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
2839
		$reg_changing = true;
2840
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
2841
		$reg_changing = true;
2842
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
2843
		$reg_changing = true;
2844
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
2845
		$reg_changing = true;
2846
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
2847
		$reg_changing = true;
2848
	}
2849

    
2850
	if ($reg_changing) {
2851
		/* set regulatory domain */
2852
		if ($wlcfg['regdomain']) {
2853
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2854
		}
2855

    
2856
		/* set country */
2857
		if ($wlcfg['regcountry']) {
2858
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2859
		}
2860

    
2861
		/* set location */
2862
		if ($wlcfg['reglocation']) {
2863
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2864
		}
2865

    
2866
		$wlregcmd_args = implode(" ", $wlregcmd);
2867

    
2868
		/* build a complete list of the wireless clones for this interface */
2869
		$clone_list = array();
2870
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2871
			$clone_list[] = interface_get_wireless_clone($baseif);
2872
		}
2873
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2874
			foreach ($config['wireless']['clone'] as $clone) {
2875
				if ($clone['if'] == $baseif) {
2876
					$clone_list[] = $clone['cloneif'];
2877
				}
2878
			}
2879
		}
2880

    
2881
		/* find which clones are up and bring them down */
2882
		$clones_up = array();
2883
		foreach ($clone_list as $clone_if) {
2884
			$clone_status = pfSense_get_interface_addresses($clone_if);
2885
			if ($clone_status['status'] == 'up') {
2886
				$clones_up[] = $clone_if;
2887
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2888
			}
2889
		}
2890

    
2891
		/* apply the regulatory settings */
2892
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2893
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2894

    
2895
		/* bring the clones back up that were previously up */
2896
		foreach ($clones_up as $clone_if) {
2897
			interfaces_bring_up($clone_if);
2898

    
2899
			/*
2900
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2901
			 * is in infrastructure mode, and WPA is enabled.
2902
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2903
			 */
2904
			if ($clone_if != $if) {
2905
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2906
				if ((!empty($friendly_if)) &&
2907
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
2908
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
2909
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2910
				}
2911
			}
2912
		}
2913
	}
2914

    
2915
	/* 20150318 cmb - Note: the below no longer appears to be true on FreeBSD 10.x, so don't set
2916
	 * mode twice (for now at least). This can be removed entirely in the future if no problems are found
2917

    
2918
	 * The mode must be specified in a separate command before ifconfig
2919
	 * will allow the mode and channel at the same time in the next. */
2920
	//mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2921
	//fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
2922

    
2923
	/* configure wireless */
2924
	$wlcmd_args = implode(" ", $wlcmd);
2925
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2926
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
2927
	fclose($wlan_setup_log);
2928

    
2929
	unset($wlcmd_args, $wlcmd);
2930

    
2931

    
2932
	sleep(1);
2933
	/* execute hostapd and wpa_supplicant if required in shell */
2934
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2935

    
2936
	return 0;
2937

    
2938
}
2939

    
2940
function kill_hostapd($interface) {
2941
	global $g;
2942

    
2943
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
2944
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2945
	}
2946
}
2947

    
2948
function kill_wpasupplicant($interface) {
2949
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2950
}
2951

    
2952
function find_dhclient_process($interface) {
2953
	if ($interface) {
2954
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2955
	} else {
2956
		$pid = 0;
2957
	}
2958

    
2959
	return intval($pid);
2960
}
2961

    
2962
function kill_dhclient_process($interface) {
2963
	if (empty($interface) || !does_interface_exist($interface)) {
2964
		return;
2965
	}
2966

    
2967
	$i = 0;
2968
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2969
		/* 3rd time make it die for sure */
2970
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2971
		posix_kill($pid, $sig);
2972
		sleep(1);
2973
		$i++;
2974
	}
2975
	unset($i);
2976
}
2977

    
2978
function find_dhcp6c_process($interface) {
2979
	global $g;
2980

    
2981
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
2982
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2983
	} else {
2984
		return(false);
2985
	}
2986

    
2987
	return intval($pid);
2988
}
2989

    
2990
function interface_virtual_create($interface) {
2991
	global $config;
2992

    
2993
	if (strstr($interface, "_vlan")) {
2994
		interfaces_vlan_configure($vlan);
2995
	} else if (substr($interface, 0, 3) == "gre") {
2996
		interfaces_gre_configure(0, $interface);
2997
	} else if (substr($interface, 0, 3) == "gif") {
2998
		interfaces_gif_configure(0, $interface);
2999
	} else if (substr($interface, 0, 5) == "ovpns") {
3000
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3001
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3002
				if ($interface == "ovpns{$server['vpnid']}") {
3003
					if (!function_exists('openvpn_resync')) {
3004
						require_once('openvpn.inc');
3005
					}
3006
					log_error("OpenVPN: Resync server {$server['description']}");
3007
					openvpn_resync('server', $server);
3008
				}
3009
			}
3010
			unset($server);
3011
		}
3012
	} else if (substr($interface, 0, 5) == "ovpnc") {
3013
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3014
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3015
				if ($interface == "ovpnc{$client['vpnid']}") {
3016
					if (!function_exists('openvpn_resync')) {
3017
						require_once('openvpn.inc');
3018
					}
3019
					log_error("OpenVPN: Resync server {$client['description']}");
3020
					openvpn_resync('client', $client);
3021
				}
3022
			}
3023
			unset($client);
3024
		}
3025
	} else if (substr($interface, 0, 4) == "lagg") {
3026
		interfaces_lagg_configure($interface);
3027
	} else if (substr($interface, 0, 6) == "bridge") {
3028
		interfaces_bridge_configure(0, $interface);
3029
	}
3030
}
3031

    
3032
function interface_vlan_mtu_configured($realhwif, $mtu) {
3033
	global $config;
3034

    
3035
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3036
		foreach ($config['vlans']['vlan'] as $vlan) {
3037
			if ($vlan['if'] != $realhwif) {
3038
				continue;
3039
			}
3040
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3041
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3042
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu) {
3043
					$mtu = $config['interfaces'][$assignedport]['mtu'];
3044
				}
3045
			}
3046
			$pppoe_mtu = interface_mtu_wanted_for_pppoe($vlan['vlanif']);
3047
			if ($pppoe_mtu > $mtu) {
3048
				$mtu = $pppoe_mtu;
3049
			}
3050
		}
3051
	}
3052

    
3053
	return $mtu;
3054
}
3055

    
3056
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
3057
	global $config;
3058

    
3059
	if (!is_array($vlanifs)) {
3060
		return;
3061
	}
3062

    
3063
	/* All vlans need to use the same mtu value as their parent. */
3064
	foreach ($vlanifs as $vlan) {
3065
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3066
		$pppoe_mtu = interface_mtu_wanted_for_pppoe($vlan['vlanif']);
3067
		if (!empty($assignedport)) {
3068
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
3069
				pfSense_interface_mtu($vlan['vlanif'], $config['interfaces'][$assignedport]['mtu']);
3070
			} else if ($pppoe_mtu != 0) {
3071
				pfSense_interface_mtu($vlan['vlanif'], $pppoe_mtu);
3072
			} else {
3073
				if (get_interface_mtu($vlan['vlanif']) != (($mtu > 1500) ? 1500 : $mtu)) {
3074
					pfSense_interface_mtu($vlan['vlanif'], (($mtu > 1500) ? 1500 : $mtu));
3075
				}
3076
			}
3077
		} else {
3078
			if ($pppoe_mtu != 0) {
3079
				pfSense_interface_mtu($vlan['vlanif'], $pppoe_mtu);
3080
			} else if (get_interface_mtu($vlan['vlanif']) != (($mtu > 1500) ? 1500 : $mtu)) {
3081
				pfSense_interface_mtu($vlan['vlanif'], (($mtu > 1500) ? 1500 : $mtu));
3082
			}
3083
		}
3084
	}
3085
}
3086

    
3087
function interface_mtu_wanted_for_pppoe($realif) {
3088
	global $config;
3089

    
3090
	$mtu = 0;
3091

    
3092
	if (is_array($config['ppps']) && is_array($config['ppps']['ppp'])) {
3093
		foreach ($config['ppps']['ppp'] as $ppp) {
3094
			if ($ppp['type'] == "pppoe") {
3095
				$ports = explode(',',$ppp['ports']);
3096
				$mtu_wanted = 1500;
3097
				foreach ($ports as $pid => $port) {
3098
					if (get_real_interface($port) == $realif) {
3099
						// use the MTU configured on the interface ...
3100
						if (is_array($config['interfaces'])) {
3101
							foreach ($config['interfaces'] as $interface) {
3102
								if ($interface['if'] != $ppp['if']) {
3103
									continue;
3104
								}
3105
								if (!empty($interface['mtu'])) {
3106
									$mtu_wanted = intval($interface['mtu']) + 8;
3107
								}
3108
							}
3109
						}
3110
						// ... unless there is an MTU configured on the port in question
3111
						if (!empty($ppp['mtu'])) {
3112
							$mtus = explode(',',$ppp['mtu']);
3113
							if (!empty($mtus[$pid])) {
3114
								$mtu_wanted = intval($mtus[$pid]) + 8;
3115
							}
3116
						}
3117
						if ($mtu_wanted > $mtu) {
3118
							$mtu = $mtu_wanted;
3119
						}
3120
					}
3121
				}
3122
			}
3123
		}
3124
	}
3125

    
3126
	return $mtu;
3127
}
3128

    
3129
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3130
	global $config, $g;
3131
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3132
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3133

    
3134
	$wancfg = $config['interfaces'][$interface];
3135

    
3136
	if (!isset($wancfg['enable'])) {
3137
		return;
3138
	}
3139

    
3140
	$realif = get_real_interface($interface);
3141
	$realhwif_array = get_parent_interface($interface);
3142
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3143
	$realhwif = $realhwif_array[0];
3144

    
3145
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3146
		/* remove all IPv4 and IPv6 addresses */
3147
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3148
		if (is_array($tmpifaces)) {
3149
			foreach ($tmpifaces as $tmpiface) {
3150
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3151
					if (!is_linklocal($tmpiface)) {
3152
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3153
					}
3154
				} else {
3155
					if (is_subnetv4($tmpiface)) {
3156
						$tmpip = explode('/', $tmpiface);
3157
						$tmpip = $tmpip[0];
3158
					} else {
3159
						$tmpip = $tmpiface;
3160
					}
3161
					pfSense_interface_deladdress($realif, $tmpip);
3162
				}
3163
			}
3164
		}
3165

    
3166
		/* only bring down the interface when both v4 and v6 are set to NONE */
3167
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3168
			interface_bring_down($interface);
3169
		}
3170
	}
3171

    
3172
	$interface_to_check = $realif;
3173
	if (interface_isppp_type($interface)) {
3174
		$interface_to_check = $realhwif;
3175
	}
3176

    
3177
	/* Need to check that the interface exists or not in the case where its coming back from disabled state see #3270 */
3178
	if (!platform_booting() && (in_array(substr($realif, 0, 3), array("gre", "gif")) || !does_interface_exist($interface_to_check))) {
3179
		interface_virtual_create($interface_to_check);
3180
	}
3181

    
3182
	/* Disable Accepting router advertisements unless specifically requested */
3183
	if ($g['debug']) {
3184
		log_error("Deny router advertisements for interface {$interface}");
3185
	}
3186
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3187

    
3188
	/* wireless configuration? */
3189
	if (is_array($wancfg['wireless'])) {
3190
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3191
	}
3192

    
3193
	$mac = get_interface_mac($realhwif);
3194
	/*
3195
	 * Don't try to reapply the spoofed MAC if it's already applied.
3196
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3197
	 * the interface config again, which attempts to spoof the MAC again,
3198
	 * which cycles the link again...
3199
	 */
3200
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
3201
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3202
			" link " . escapeshellarg($wancfg['spoofmac']));
3203
	} else {
3204

    
3205
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3206
			/*   this is not a valid mac address.  generate a
3207
			 *   temporary mac address so the machine can get online.
3208
			 */
3209
			echo gettext("Generating new MAC address.");
3210
			$random_mac = generate_random_mac_address();
3211
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3212
				" link " . escapeshellarg($random_mac));
3213
			$wancfg['spoofmac'] = $random_mac;
3214
			write_config();
3215
			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");
3216
		}
3217
	}
3218

    
3219
	/* media */
3220
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3221
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3222
		if ($wancfg['media']) {
3223
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3224
		}
3225
		if ($wancfg['mediaopt']) {
3226
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3227
		}
3228
		mwexec($cmd);
3229
	}
3230

    
3231
	/* Apply hw offloading policies as configured */
3232
	enable_hardware_offloading($interface);
3233

    
3234
	/* invalidate interface/ip/sn cache */
3235
	get_interface_arr(true);
3236
	unset($interface_ip_arr_cache[$realif]);
3237
	unset($interface_sn_arr_cache[$realif]);
3238
	unset($interface_ipv6_arr_cache[$realif]);
3239
	unset($interface_snv6_arr_cache[$realif]);
3240

    
3241
	$tunnelif = substr($realif, 0, 3);
3242

    
3243
	if (does_interface_exist($wancfg['if'])) {
3244
		interfaces_bring_up($wancfg['if']);
3245
	}
3246

    
3247
	$mtuif = $realif;
3248
	$mtuhwif = $realhwif;
3249
	$wantedmtu = 0;
3250

    
3251
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3252
	if (interface_isppp_type($interface)) {
3253
		$mtuif = $realhwif;
3254
		$mtuhwif_array = get_parent_interface($mtuif);
3255
		$mtuhwif = $mtuhwif_array[0];
3256
		$parent_mtu_configured = false;
3257
		if (is_array($config['interfaces'])) {
3258
			foreach ($config['interfaces'] as $tmpinterface) {
3259
				if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3260
					$parent_mtu_configured = true;
3261
					break;
3262
				}
3263
			}
3264
		}
3265
		if (!$parent_mtu_configured) {
3266
			$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3267
		}
3268
	}
3269

    
3270
	if (is_array($config['interfaces'])) {
3271
		foreach ($config['interfaces'] as $tmpinterface) {
3272
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3273
				$wantedmtu = $tmpinterface['mtu'];
3274
				break;
3275
			}
3276
		}
3277
	}
3278

    
3279
	// Set the MTU to 1500 if no explicit MTU configured
3280
	if ($wantedmtu == 0) {
3281
		$wantedmtu = 1500; /* Default */
3282
	}
3283

    
3284
	if (stristr($mtuif, "_vlan")) {
3285
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3286
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3287
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3288
			if ($wancfg['mtu'] > $parentmtu) {
3289
				log_error("There is a conflict on MTU between parent {$mtuhwif} and VLAN({$mtuif})");
3290
			}
3291
		} else {
3292
			$parentmtu = 0;
3293
		}
3294

    
3295
		$parentmtu = interface_vlan_mtu_configured($mtuhwif, $parentmtu);
3296

    
3297
		if (get_interface_mtu($mtuhwif) != $parentmtu) {
3298
			pfSense_interface_mtu($mtuhwif, $parentmtu);
3299
		}
3300

    
3301
		/* All vlans need to use the same mtu value as their parent. */
3302
		interface_vlan_adapt_mtu(link_interface_to_vlans($mtuhwif), $parentmtu);
3303
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3304
		/* LAGG interface must be destroyed and re-created to change MTU */
3305
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3306
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3307
				foreach ($config['laggs']['lagg'] as $lagg) {
3308
					if ($lagg['laggif'] == $mtuif) {
3309
						interface_lagg_configure($lagg);
3310
						break;
3311
					}
3312
				}
3313
			}
3314
		}
3315
	} else {
3316
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3317
			pfSense_interface_mtu($mtuif, $wantedmtu);
3318
		}
3319

    
3320
		/* This case is needed when the parent of vlans is being configured */
3321
		$vlans = link_interface_to_vlans($mtuif);
3322
		if (is_array($vlans)) {
3323
			interface_vlan_adapt_mtu($vlans, $wantedmtu);
3324
		}
3325
		unset($vlans);
3326
	}
3327
	/* XXX: What about gre/gif/.. ? */
3328

    
3329
	switch ($wancfg['ipaddr']) {
3330
		case 'dhcp':
3331
			interface_dhcp_configure($interface);
3332
			break;
3333
		case 'pppoe':
3334
		case 'l2tp':
3335
		case 'pptp':
3336
		case 'ppp':
3337
			interface_ppps_configure($interface);
3338
			break;
3339
		default:
3340
			/* XXX: Kludge for now related to #3280 */
3341
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3342
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3343
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3344
				}
3345
			}
3346
			break;
3347
	}
3348

    
3349
	switch ($wancfg['ipaddrv6']) {
3350
		case 'slaac':
3351
		case 'dhcp6':
3352
			interface_dhcpv6_configure($interface, $wancfg);
3353
			break;
3354
		case '6rd':
3355
			interface_6rd_configure($interface, $wancfg);
3356
			break;
3357
		case '6to4':
3358
			interface_6to4_configure($interface, $wancfg);
3359
			break;
3360
		case 'track6':
3361
			interface_track6_configure($interface, $wancfg, $linkupevent);
3362
			break;
3363
		default:
3364
			/* XXX: Kludge for now related to #3280 */
3365
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3366
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3367
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3368
					// FIXME: Add IPv6 Support to the pfSense module
3369
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3370
				}
3371
			}
3372
			break;
3373
	}
3374

    
3375
	interface_netgraph_needed($interface);
3376

    
3377
	if (!platform_booting()) {
3378
		link_interface_to_vips($interface, "update");
3379

    
3380
		if ($tunnelif != 'gre') {
3381
			unset($gre);
3382
			$gre = link_interface_to_gre($interface);
3383
			if (!empty($gre)) {
3384
				array_walk($gre, 'interface_gre_configure');
3385
			}
3386
		}
3387

    
3388
		if ($tunnelif != 'gif') {
3389
			unset($gif);
3390
			$gif = link_interface_to_gif ($interface);
3391
			if (!empty($gif)) {
3392
				array_walk($gif, 'interface_gif_configure');
3393
			}
3394
		}
3395

    
3396
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3397
			unset($bridgetmp);
3398
			$bridgetmp = link_interface_to_bridge($interface);
3399
			if (!empty($bridgetmp)) {
3400
				interface_bridge_add_member($bridgetmp, $realif);
3401
			}
3402
		}
3403

    
3404
		$grouptmp = link_interface_to_group($interface);
3405
		if (!empty($grouptmp)) {
3406
			array_walk($grouptmp, 'interface_group_add_member');
3407
		}
3408

    
3409
		if ($interface == "lan") {
3410
			/* make new hosts file */
3411
			system_hosts_generate();
3412
		}
3413

    
3414
		if ($reloadall == true) {
3415

    
3416
			/* reconfigure static routes (kernel may have deleted them) */
3417
			system_routing_configure($interface);
3418

    
3419
			/* reload ipsec tunnels */
3420
			send_event("service reload ipsecdns");
3421

    
3422
			/* restart dnsmasq or unbound */
3423
			if (isset($config['dnsmasq']['enable'])) {
3424
				services_dnsmasq_configure();
3425
			} elseif (isset($config['unbound']['enable'])) {
3426
				services_unbound_configure();
3427
			}
3428

    
3429
			/* update dyndns */
3430
			send_event("service reload dyndns {$interface}");
3431

    
3432
			/* reload captive portal */
3433
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3434
				require_once('captiveportal.inc');
3435
			}
3436
			captiveportal_init_rules_byinterface($interface);
3437
		}
3438
	}
3439

    
3440
	interfaces_staticarp_configure($interface);
3441
	return 0;
3442
}
3443

    
3444
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3445
	global $config, $g;
3446

    
3447
	if (!is_array($wancfg)) {
3448
		return;
3449
	}
3450

    
3451
	if (!isset($wancfg['enable'])) {
3452
		return;
3453
	}
3454

    
3455
	/* If the interface is not configured via another, exit */
3456
	if (empty($wancfg['track6-interface'])) {
3457
		return;
3458
	}
3459

    
3460
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3461
	$realif = get_real_interface($interface);
3462
	$linklocal = find_interface_ipv6_ll($realif);
3463
	if (!empty($linklocal)) {
3464
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3465
	}
3466
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3467
	/* XXX: Probably should remove? */
3468
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3469

    
3470
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3471
	if (!isset($trackcfg['enable'])) {
3472
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3473
		return;
3474
	}
3475

    
3476
	switch ($trackcfg['ipaddrv6']) {
3477
		case "6to4":
3478
			if ($g['debug']) {
3479
				log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3480
			}
3481
			interface_track6_6to4_configure($interface, $wancfg);
3482
			break;
3483
		case "6rd":
3484
			if ($g['debug']) {
3485
				log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3486
			}
3487
			interface_track6_6rd_configure($interface, $wancfg);
3488
			break;
3489
		case "dhcp6":
3490
			if ($linkupevent == true) {
3491
				/*
3492
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
3493
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3494
				 *
3495
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
3496
				 */
3497
				$parentrealif = get_real_interface($wancfg['track6-interface']);
3498
				$pidv6 = find_dhcp6c_process($parentrealif);
3499
				if ($pidv6) {
3500
					posix_kill($pidv6, SIGHUP);
3501
				}
3502
			}
3503
			break;
3504
	}
3505

    
3506
	if ($linkupevent == false) {
3507
		if (!function_exists('services_dhcpd_configure')) {
3508
			require_once("services.inc");
3509
		}
3510

    
3511
		if (isset($config['unbound']['enable'])) {
3512
			services_unbound_configure();
3513
		}
3514

    
3515
		services_dhcpd_configure("inet6");
3516
	}
3517

    
3518
	return 0;
3519
}
3520

    
3521
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3522
	global $config, $g;
3523
	global $interface_ipv6_arr_cache;
3524
	global $interface_snv6_arr_cache;
3525

    
3526
	if (!is_array($lancfg)) {
3527
		return;
3528
	}
3529

    
3530
	/* If the interface is not configured via another, exit */
3531
	if (empty($lancfg['track6-interface'])) {
3532
		return;
3533
	}
3534

    
3535
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3536
	if (empty($wancfg)) {
3537
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3538
		return;
3539
	}
3540

    
3541
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3542
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3543
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not valid, not configuring 6RD tunnel");
3544
		return;
3545
	}
3546
	$hexwanv4 = return_hex_ipv4($ip4address);
3547

    
3548
	/* create the long prefix notation for math, save the prefix length */
3549
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3550
	$rd6prefixlen = $rd6prefix[1];
3551
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3552

    
3553
	/* binary presentation of the prefix for all 128 bits. */
3554
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3555

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

    
3561
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3562
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3563
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3564
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3565
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3566
	/* fill the rest out with zeros */
3567
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3568

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

    
3572
	$lanif = get_real_interface($interface);
3573
	$oip = find_interface_ipv6($lanif);
3574
	if (is_ipaddrv6($oip)) {
3575
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3576
	}
3577
	unset($interface_ipv6_arr_cache[$lanif]);
3578
	unset($interface_snv6_arr_cache[$lanif]);
3579
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3580
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3581

    
3582
	return 0;
3583
}
3584

    
3585
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3586
	global $config, $g;
3587
	global $interface_ipv6_arr_cache;
3588
	global $interface_snv6_arr_cache;
3589

    
3590
	if (!is_array($lancfg)) {
3591
		return;
3592
	}
3593

    
3594
	/* If the interface is not configured via another, exit */
3595
	if (empty($lancfg['track6-interface'])) {
3596
		return;
3597
	}
3598

    
3599
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3600
	if (empty($wancfg)) {
3601
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3602
		return;
3603
	}
3604

    
3605
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3606
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3607
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3608
		return;
3609
	}
3610
	$hexwanv4 = return_hex_ipv4($ip4address);
3611

    
3612
	/* create the long prefix notation for math, save the prefix length */
3613
	$sixto4prefix = "2002::";
3614
	$sixto4prefixlen = 16;
3615
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3616

    
3617
	/* binary presentation of the prefix for all 128 bits. */
3618
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3619

    
3620
	/* just save the left prefix length bits */
3621
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3622
	/* add the v4 address */
3623
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3624
	/* add the custom prefix id */
3625
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3626
	/* fill the rest out with zeros */
3627
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3628

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

    
3632
	$lanif = get_real_interface($interface);
3633
	$oip = find_interface_ipv6($lanif);
3634
	if (is_ipaddrv6($oip)) {
3635
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3636
	}
3637
	unset($interface_ipv6_arr_cache[$lanif]);
3638
	unset($interface_snv6_arr_cache[$lanif]);
3639
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3640
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3641

    
3642
	return 0;
3643
}
3644

    
3645
function interface_6rd_configure($interface = "wan", $wancfg) {
3646
	global $config, $g;
3647

    
3648
	/* because this is a tunnel interface we can only function
3649
	 *	with a public IPv4 address on the interface */
3650

    
3651
	if (!is_array($wancfg)) {
3652
		return;
3653
	}
3654

    
3655
	if (!is_module_loaded('if_stf.ko')) {
3656
		mwexec('/sbin/kldload if_stf.ko');
3657
	}
3658

    
3659
	$wanif = get_real_interface($interface);
3660
	$ip4address = find_interface_ip($wanif);
3661
	if (!is_ipaddrv4($ip4address)) {
3662
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3663
		return false;
3664
	}
3665
	$hexwanv4 = return_hex_ipv4($ip4address);
3666

    
3667
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3668
		$wancfg['prefix-6rd-v4plen'] = 0;
3669
	}
3670

    
3671
	/* create the long prefix notation for math, save the prefix length */
3672
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3673
	$rd6prefixlen = $rd6prefix[1];
3674
	$brgw = explode('.', $wancfg['gateway-6rd']);
3675
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3676
	$rd6brgw .= str_pad(decbin($brgw[0]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[1]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[2]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[3]), 8, '0', STR_PAD_LEFT);
3677
	if (strlen($rd6brgw) < 128) {
3678
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3679
	}
3680
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3681
	unset($brgw);
3682
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3683

    
3684
	/* binary presentation of the prefix for all 128 bits. */
3685
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3686

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

    
3694
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3695
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3696

    
3697

    
3698
	/* XXX: need to extend to support variable prefix size for v4 */
3699
	if (!is_module_loaded("if_stf")) {
3700
		mwexec("/sbin/kldload if_stf.ko");
3701
	}
3702
	$stfiface = "{$interface}_stf";
3703
	if (does_interface_exist($stfiface)) {
3704
		pfSense_interface_destroy($stfiface);
3705
	}
3706
	$tmpstfiface = pfSense_interface_create("stf");
3707
	pfSense_interface_rename($tmpstfiface, $stfiface);
3708
	pfSense_interface_flags($stfiface, IFF_LINK2);
3709
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3710
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3711
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3712
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3713
	}
3714
	if ($g['debug']) {
3715
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3716
	}
3717

    
3718
	/* write out a default router file */
3719
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3720
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3721

    
3722
	$ip4gateway = get_interface_gateway($interface);
3723
	if (is_ipaddrv4($ip4gateway)) {
3724
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3725
	}
3726

    
3727
	/* configure dependent interfaces */
3728
	if (!platform_booting()) {
3729
		link_interface_to_track6($interface, "update");
3730
	}
3731

    
3732
	return 0;
3733
}
3734

    
3735
function interface_6to4_configure($interface = "wan", $wancfg) {
3736
	global $config, $g;
3737

    
3738
	/* because this is a tunnel interface we can only function
3739
	 *	with a public IPv4 address on the interface */
3740

    
3741
	if (!is_array($wancfg)) {
3742
		return;
3743
	}
3744

    
3745
	$wanif = get_real_interface($interface);
3746
	$ip4address = find_interface_ip($wanif);
3747
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3748
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3749
		return false;
3750
	}
3751

    
3752
	/* create the long prefix notation for math, save the prefix length */
3753
	$stfprefixlen = 16;
3754
	$stfprefix = Net_IPv6::uncompress("2002::");
3755
	$stfarr = explode(":", $stfprefix);
3756
	$v4prefixlen = "0";
3757

    
3758
	/* we need the hex form of the interface IPv4 address */
3759
	$ip4arr = explode(".", $ip4address);
3760
	$hexwanv4 = "";
3761
	foreach ($ip4arr as $octet) {
3762
		$hexwanv4 .= sprintf("%02x", $octet);
3763
	}
3764

    
3765
	/* we need the hex form of the broker IPv4 address */
3766
	$ip4arr = explode(".", "192.88.99.1");
3767
	$hexbrv4 = "";
3768
	foreach ($ip4arr as $octet) {
3769
		$hexbrv4 .= sprintf("%02x", $octet);
3770
	}
3771

    
3772
	/* binary presentation of the prefix for all 128 bits. */
3773
	$stfprefixbin = "";
3774
	foreach ($stfarr as $element) {
3775
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3776
	}
3777
	/* just save the left prefix length bits */
3778
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3779

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

    
3784
	/* for the local subnet too. */
3785
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3786
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3787

    
3788
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3789
	$stfbrarr = array();
3790
	$stfbrbinarr = array();
3791
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3792
	foreach ($stfbrbinarr as $bin) {
3793
		$stfbrarr[] = dechex(bindec($bin));
3794
	}
3795
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3796

    
3797
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3798
	$stflanarr = array();
3799
	$stflanbinarr = array();
3800
	$stflanbinarr = str_split($stflanbin, 16);
3801
	foreach ($stflanbinarr as $bin) {
3802
		$stflanarr[] = dechex(bindec($bin));
3803
	}
3804
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3805
	$stflanarr[7] = 1;
3806
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3807

    
3808
	/* setup the stf interface */
3809
	if (!is_module_loaded("if_stf")) {
3810
		mwexec("/sbin/kldload if_stf.ko");
3811
	}
3812
	$stfiface = "{$interface}_stf";
3813
	if (does_interface_exist($stfiface)) {
3814
		pfSense_interface_destroy($stfiface);
3815
	}
3816
	$tmpstfiface = pfSense_interface_create("stf");
3817
	pfSense_interface_rename($tmpstfiface, $stfiface);
3818
	pfSense_interface_flags($stfiface, IFF_LINK2);
3819
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3820

    
3821
	if ($g['debug']) {
3822
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3823
	}
3824

    
3825
	/* write out a default router file */
3826
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3827
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3828

    
3829
	$ip4gateway = get_interface_gateway($interface);
3830
	if (is_ipaddrv4($ip4gateway)) {
3831
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3832
	}
3833

    
3834
	if (!platform_booting()) {
3835
		link_interface_to_track6($interface, "update");
3836
	}
3837

    
3838
	return 0;
3839
}
3840

    
3841
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3842
	global $config, $g;
3843

    
3844
	if (!is_array($wancfg)) {
3845
		return;
3846
	}
3847

    
3848
	$wanif = get_real_interface($interface, "inet6");
3849
	$dhcp6cconf = "";
3850

    
3851
	if ($wancfg['adv_dhcp6_config_file_override']) {
3852
		// DHCP6 Config File Override
3853
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3854
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3855
		// DHCP6 Config File Advanced
3856
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3857
	} else {
3858
		// DHCP6 Config File Basic
3859
		$dhcp6cconf .= "interface {$wanif} {\n";
3860

    
3861
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3862
		if ($wancfg['ipaddrv6'] == "slaac") {
3863
			$dhcp6cconf .= "\tinformation-only;\n";
3864
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3865
			$dhcp6cconf .= "\trequest domain-name;\n";
3866
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3867
			$dhcp6cconf .= "};\n";
3868
		} else {
3869
			$trackiflist = array();
3870
			$iflist = link_interface_to_track6($interface);
3871
			foreach ($iflist as $ifname => $ifcfg) {
3872
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3873
					$trackiflist[$ifname] = $ifcfg;
3874
				}
3875
			}
3876

    
3877
			/* skip address request if this is set */
3878
			if (!isset($wancfg['dhcp6prefixonly'])) {
3879
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3880
			}
3881
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3882
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3883
			}
3884

    
3885
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3886
			$dhcp6cconf .= "\trequest domain-name;\n";
3887
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3888
			$dhcp6cconf .= "};\n";
3889

    
3890
			if (!isset($wancfg['dhcp6prefixonly'])) {
3891
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3892
			}
3893

    
3894
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3895
				/* Setup the prefix delegation */
3896
				$dhcp6cconf .= "id-assoc pd 0 {\n";
3897
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3898
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
3899
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
3900
				}
3901
				foreach ($trackiflist as $friendly => $ifcfg) {
3902
					if ($g['debug']) {
3903
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3904
					}
3905
					$realif = get_real_interface($friendly);
3906
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
3907
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
3908
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3909
					$dhcp6cconf .= "\t};\n";
3910
				}
3911
				unset($preflen, $iflist, $ifcfg, $ifname);
3912
				$dhcp6cconf .= "};\n";
3913
			}
3914
			unset($trackiflist);
3915
		}
3916
	}
3917

    
3918
	/* wide-dhcp6c works for now. */
3919
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3920
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3921
		unset($dhcp6cconf);
3922
		return 1;
3923
	}
3924
	unset($dhcp6cconf);
3925

    
3926
	$dhcp6cscript = "#!/bin/sh\n";
3927
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3928
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3929
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3930
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3931
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3932
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3933
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3934
		unset($dhcp6cscript);
3935
		return 1;
3936
	}
3937
	unset($dhcp6cscript);
3938
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3939

    
3940
	$rtsoldscript = "#!/bin/sh\n";
3941
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3942
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3943
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3944
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Recieved RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
3945
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3946
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3947
	$rtsoldscript .= "\t/bin/sleep 1\n";
3948
	$rtsoldscript .= "fi\n";
3949
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3950
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3951
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3952
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3953
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3954
		unset($rtsoldscript);
3955
		return 1;
3956
	}
3957
	unset($rtsoldscript);
3958
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3959

    
3960
	/* accept router advertisements for this interface */
3961
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3962
	log_error("Accept router advertisements on interface {$wanif} ");
3963
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3964

    
3965
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3966
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3967
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3968
		sleep(2);
3969
	}
3970
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3971

    
3972
	/* NOTE: will be called from rtsold invoked script
3973
	 * link_interface_to_track6($interface, "update");
3974
	 */
3975

    
3976
	return 0;
3977
}
3978

    
3979
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3980
	global $g;
3981

    
3982
	$send_options = "";
3983
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3984
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_send_options']);
3985
		foreach ($options as $option) {
3986
			$send_options .= "\tsend " . trim($option) . ";\n";
3987
		}
3988
	}
3989

    
3990
	$request_options = "";
3991
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3992
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_request_options']);
3993
		foreach ($options as $option) {
3994
			$request_options .= "\trequest " . trim($option) . ";\n";
3995
		}
3996
	}
3997

    
3998
	$information_only = "";
3999
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4000
		$information_only = "\tinformation-only;\n";
4001
	}
4002

    
4003
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4004
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4005
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4006
	}
4007

    
4008
	$interface_statement  = "interface";
4009
	$interface_statement .= " {$wanif}";
4010
	$interface_statement .= " {\n";
4011
	$interface_statement .= "$send_options";
4012
	$interface_statement .= "$request_options";
4013
	$interface_statement .= "$information_only";
4014
	$interface_statement .= "$script";
4015
	$interface_statement .= "};\n";
4016

    
4017
	$id_assoc_statement_address = "";
4018
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4019
		$id_assoc_statement_address .= "id-assoc";
4020
		$id_assoc_statement_address .= " na";
4021
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4022
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4023
		}
4024
		$id_assoc_statement_address .= " { ";
4025

    
4026
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4027
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4028
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4029
			$id_assoc_statement_address .= "\n\taddress";
4030
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4031
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4032
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4033
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4034
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4035
			}
4036
			$id_assoc_statement_address .= ";\n";
4037
		}
4038

    
4039
		$id_assoc_statement_address .= "};\n";
4040
	}
4041

    
4042
	$id_assoc_statement_prefix = "";
4043
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4044
		$id_assoc_statement_prefix .= "id-assoc";
4045
		$id_assoc_statement_prefix .= " pd";
4046
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4047
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4048
		}
4049
		$id_assoc_statement_prefix .= " { ";
4050

    
4051
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4052
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4053
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4054
			$id_assoc_statement_prefix .= "\n\tprefix";
4055
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4056
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4057
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4058
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4059
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4060
			}
4061
			$id_assoc_statement_prefix .= ";";
4062
		}
4063

    
4064
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4065
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4066
			$id_assoc_statement_prefix .= " {$wanif}";
4067
			$id_assoc_statement_prefix .= " {\n";
4068
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4069
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4070
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4071
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4072
			}
4073
			$id_assoc_statement_prefix .= "\t};";
4074
		}
4075

    
4076
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4077
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4078
			$id_assoc_statement_prefix .= "\n";
4079
		}
4080

    
4081
		$id_assoc_statement_prefix .= "};\n";
4082
	}
4083

    
4084
	$authentication_statement = "";
4085
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4086
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4087
		$authentication_statement .= "authentication";
4088
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4089
		$authentication_statement .= " {\n";
4090
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4091
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4092
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4093
		}
4094
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4095
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4096
		}
4097
		$authentication_statement .= "};\n";
4098
	}
4099

    
4100
	$key_info_statement = "";
4101
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4102
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4103
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4104
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4105
		$key_info_statement .= "keyinfo";
4106
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4107
		$key_info_statement .= " {\n";
4108
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4109
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4110
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4111
		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'])) {
4112
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4113
		}
4114
		$key_info_statement .= "};\n";
4115
	}
4116

    
4117
	$dhcp6cconf  = $interface_statement;
4118
	$dhcp6cconf .= $id_assoc_statement_address;
4119
	$dhcp6cconf .= $id_assoc_statement_prefix;
4120
	$dhcp6cconf .= $authentication_statement;
4121
	$dhcp6cconf .= $key_info_statement;
4122

    
4123
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4124

    
4125
	return $dhcp6cconf;
4126
}
4127

    
4128

    
4129
function DHCP6_Config_File_Override($wancfg, $wanif) {
4130

    
4131
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4132

    
4133
	if ($dhcp6cconf === false) {
4134
		log_error("Error: cannot open {$wancfg['adv_dhcp6_config_file_override_path']} in DHCP6_Config_File_Override() for reading.\n");
4135
		return '';
4136
	} else {
4137
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4138
	}
4139
}
4140

    
4141

    
4142
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4143

    
4144
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4145

    
4146
	return $dhcp6cconf;
4147
}
4148

    
4149

    
4150
function interface_dhcp_configure($interface = "wan") {
4151
	global $config, $g;
4152

    
4153
	$wancfg = $config['interfaces'][$interface];
4154
	$wanif = $wancfg['if'];
4155
	if (empty($wancfg)) {
4156
		$wancfg = array();
4157
	}
4158

    
4159
	/* generate dhclient_wan.conf */
4160
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4161
	if (!$fd) {
4162
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
4163
		return 1;
4164
	}
4165

    
4166
	if ($wancfg['dhcphostname']) {
4167
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4168
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4169
	} else {
4170
		$dhclientconf_hostname = "";
4171
	}
4172

    
4173
	$wanif = get_real_interface($interface);
4174
	if (empty($wanif)) {
4175
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4176
		return 0;
4177
	}
4178
	$dhclientconf = "";
4179

    
4180
	$dhclientconf .= <<<EOD
4181
interface "{$wanif}" {
4182
timeout 60;
4183
retry 15;
4184
select-timeout 0;
4185
initial-interval 1;
4186
	{$dhclientconf_hostname}
4187
	script "/sbin/dhclient-script";
4188
EOD;
4189

    
4190
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4191
		$dhclientconf .= <<<EOD
4192

    
4193
	reject {$wancfg['dhcprejectfrom']};
4194
EOD;
4195
	}
4196
	$dhclientconf .= <<<EOD
4197

    
4198
}
4199

    
4200
EOD;
4201

    
4202
	// DHCP Config File Advanced
4203
	if ($wancfg['adv_dhcp_config_advanced']) {
4204
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4205
	}
4206

    
4207
	if (is_ipaddr($wancfg['alias-address'])) {
4208
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4209
		$dhclientconf .= <<<EOD
4210
alias {
4211
	interface "{$wanif}";
4212
	fixed-address {$wancfg['alias-address']};
4213
	option subnet-mask {$subnetmask};
4214
}
4215

    
4216
EOD;
4217
	}
4218

    
4219
	// DHCP Config File Override
4220
	if ($wancfg['adv_dhcp_config_file_override']) {
4221
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4222
	}
4223

    
4224
	fwrite($fd, $dhclientconf);
4225
	fclose($fd);
4226

    
4227
	/* bring wan interface up before starting dhclient */
4228
	if ($wanif) {
4229
		interfaces_bring_up($wanif);
4230
	} else {
4231
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4232
	}
4233

    
4234
	/* Make sure dhclient is not running */
4235
	kill_dhclient_process($wanif);
4236

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

    
4240
	return 0;
4241
}
4242

    
4243
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4244

    
4245
	$hostname = "";
4246
	if ($wancfg['dhcphostname'] != '') {
4247
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4248
	}
4249

    
4250
	/* DHCP Protocol Timings */
4251
	$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");
4252
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4253
		$pt_variable = "{$Protocol_Timing}";
4254
		${$pt_variable} = "";
4255
		if ($wancfg[$Protocol_Timing] != "") {
4256
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4257
		}
4258
	}
4259

    
4260
	$send_options = "";
4261
	if ($wancfg['adv_dhcp_send_options'] != '') {
4262
		$options = explode(',', $wancfg['adv_dhcp_send_options']);
4263
		foreach ($options as $option) {
4264
			$send_options .= "\tsend " . trim($option) . ";\n";
4265
		}
4266
	}
4267

    
4268
	$request_options = "";
4269
	if ($wancfg['adv_dhcp_request_options'] != '') {
4270
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4271
	}
4272

    
4273
	$required_options = "";
4274
	if ($wancfg['adv_dhcp_required_options'] != '') {
4275
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4276
	}
4277

    
4278
	$option_modifiers = "";
4279
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4280
		$modifiers = explode(',', $wancfg['adv_dhcp_option_modifiers']);
4281
		foreach ($modifiers as $modifier) {
4282
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4283
		}
4284
	}
4285

    
4286
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4287
	$dhclientconf .= "\n";
4288
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4289
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4290
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4291
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4292
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4293
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4294
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4295
	$dhclientconf .= "\n";
4296
	$dhclientconf .= "# DHCP Protocol Options\n";
4297
	$dhclientconf .= "{$hostname}";
4298
	$dhclientconf .= "{$send_options}";
4299
	$dhclientconf .= "{$request_options}";
4300
	$dhclientconf .= "{$required_options}";
4301
	$dhclientconf .= "{$option_modifiers}";
4302
	$dhclientconf .= "\n";
4303
	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4304
	$dhclientconf .= "}\n";
4305

    
4306
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4307

    
4308
	return $dhclientconf;
4309
}
4310

    
4311

    
4312
function DHCP_Config_File_Override($wancfg, $wanif) {
4313

    
4314
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4315

    
4316
	if ($dhclientconf === false) {
4317
		log_error("Error: cannot open {$wancfg['adv_dhcp_config_file_override_path']} in DHCP_Config_File_Override() for reading.\n");
4318
		return '';
4319
	} else {
4320
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4321
	}
4322
}
4323

    
4324

    
4325
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4326

    
4327
	/* Apply Interface Substitutions */
4328
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4329

    
4330
	/* Apply Hostname Substitutions */
4331
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4332

    
4333
	/* Arrays of MAC Address Types, Cases, Delimiters */
4334
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4335
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4336
	$various_mac_cases      = array("U", "L");
4337
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4338

    
4339
	/* Apply MAC Address Substitutions */
4340
	foreach ($various_mac_types as $various_mac_type) {
4341
		foreach ($various_mac_cases as $various_mac_case) {
4342
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4343

    
4344
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4345
				if ($res !== false) {
4346

    
4347
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4348
					if ("$various_mac_case" == "U") {
4349
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4350
					}
4351
					if ("$various_mac_case" == "L") {
4352
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4353
					}
4354

    
4355
					if ("$various_mac_type" == "mac_addr_hex") {
4356
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4357
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4358
						$dhcpclientconf_mac_hex = "";
4359
						$delimiter = "";
4360
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4361
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4362
							$delimiter = ":";
4363
						}
4364
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4365
					}
4366

    
4367
					/* MAC Address Delimiter Substitutions */
4368
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4369

    
4370
					/* Apply MAC Address Substitutions */
4371
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4372
				}
4373
			}
4374
		}
4375
	}
4376

    
4377
	return $dhclientconf;
4378
}
4379

    
4380
function interfaces_group_setup() {
4381
	global $config;
4382

    
4383
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4384
		return;
4385
	}
4386

    
4387
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4388
		interface_group_setup($groupar);
4389
	}
4390

    
4391
	return;
4392
}
4393

    
4394
function interface_group_setup(&$groupname /* The parameter is an array */) {
4395
	global $config;
4396

    
4397
	if (!is_array($groupname)) {
4398
		return;
4399
	}
4400
	$members = explode(" ", $groupname['members']);
4401
	foreach ($members as $ifs) {
4402
		$realif = get_real_interface($ifs);
4403
		if ($realif && does_interface_exist($realif)) {
4404
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4405
		}
4406
	}
4407

    
4408
	return;
4409
}
4410

    
4411
function is_interface_group($if) {
4412
	global $config;
4413

    
4414
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4415
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4416
			if ($groupentry['ifname'] === $if) {
4417
				return true;
4418
			}
4419
		}
4420
	}
4421

    
4422
	return false;
4423
}
4424

    
4425
function interface_group_add_member($interface, $groupname) {
4426
	$interface = get_real_interface($interface);
4427
	if (does_interface_exist($interface)) {
4428
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4429
	}
4430
}
4431

    
4432
/* COMPAT Function */
4433
function convert_friendly_interface_to_real_interface_name($interface) {
4434
	return get_real_interface($interface);
4435
}
4436

    
4437
/* COMPAT Function */
4438
function get_real_wan_interface($interface = "wan") {
4439
	return get_real_interface($interface);
4440
}
4441

    
4442
/* COMPAT Function */
4443
function get_current_wan_address($interface = "wan") {
4444
	return get_interface_ip($interface);
4445
}
4446

    
4447
/*
4448
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4449
 */
4450
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4451
	global $config;
4452

    
4453
	if (stripos($interface, "_vip")) {
4454
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
4455
			if ($vip['mode'] == "carp") {
4456
				if ($interface == "_vip{$vip['uniqid']}") {
4457
					return $vip['interface'];
4458
				}
4459
			}
4460
		}
4461
	}
4462

    
4463
	/* XXX: For speed reasons reference directly the interface array */
4464
	$ifdescrs = &$config['interfaces'];
4465
	//$ifdescrs = get_configured_interface_list(false, true);
4466

    
4467
	foreach ($ifdescrs as $if => $ifname) {
4468
		if ($if == $interface || $ifname['if'] == $interface) {
4469
			return $if;
4470
		}
4471

    
4472
		if (get_real_interface($if) == $interface) {
4473
			return $if;
4474
		}
4475

    
4476
		if ($checkparent == false) {
4477
			continue;
4478
		}
4479

    
4480
		$int = get_parent_interface($if, true);
4481
		if (is_array($int)) {
4482
			foreach ($int as $iface) {
4483
				if ($iface == $interface) {
4484
					return $if;
4485
				}
4486
			}
4487
		}
4488
	}
4489

    
4490
	if ($interface == "enc0") {
4491
		return 'IPsec';
4492
	}
4493
}
4494

    
4495
/* attempt to resolve interface to friendly descr */
4496
function convert_friendly_interface_to_friendly_descr($interface) {
4497
	global $config;
4498

    
4499
	switch ($interface) {
4500
		case "l2tp":
4501
			$ifdesc = "L2TP";
4502
			break;
4503
		case "pptp":
4504
			$ifdesc = "PPTP";
4505
			break;
4506
		case "pppoe":
4507
			$ifdesc = "PPPoE";
4508
			break;
4509
		case "openvpn":
4510
			$ifdesc = "OpenVPN";
4511
			break;
4512
		case "enc0":
4513
		case "ipsec":
4514
		case "IPsec":
4515
			$ifdesc = "IPsec";
4516
			break;
4517
		default:
4518
			if (isset($config['interfaces'][$interface])) {
4519
				if (empty($config['interfaces'][$interface]['descr'])) {
4520
					$ifdesc = strtoupper($interface);
4521
				} else {
4522
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4523
				}
4524
				break;
4525
			} else if (substr($interface, 0, 4) == '_vip') {
4526
				if (is_array($config['virtualip']['vip'])) {
4527
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
4528
						if ($vip['mode'] == "carp") {
4529
							if ($interface == "_vip{$vip['uniqid']}") {
4530
								return "{$vip['subnet']} - {$vip['descr']}";
4531
							}
4532
						}
4533
					}
4534
				}
4535
			} else if (substr($interface, 0, 5) == '_lloc') {
4536
				return get_interface_linklocal($interface);
4537
			} else {
4538
				/* if list */
4539
				$ifdescrs = get_configured_interface_with_descr(false, true);
4540
				foreach ($ifdescrs as $if => $ifname) {
4541
					if ($if == $interface || $ifname == $interface) {
4542
						return $ifname;
4543
					}
4544
				}
4545
			}
4546
			break;
4547
	}
4548

    
4549
	return $ifdesc;
4550
}
4551

    
4552
function convert_real_interface_to_friendly_descr($interface) {
4553

    
4554
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4555

    
4556
	if (!empty($ifdesc)) {
4557
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4558
	}
4559

    
4560
	return $interface;
4561
}
4562

    
4563
/*
4564
 *  get_parent_interface($interface):
4565
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4566
 *				or virtual interface (i.e. vlan)
4567
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4568
 *			-- returns $interface passed in if $interface parent is not found
4569
 *			-- returns empty array if an invalid interface is passed
4570
 *	(Only handles ppps and vlans now.)
4571
 */
4572
function get_parent_interface($interface, $avoidrecurse = false) {
4573
	global $config;
4574

    
4575
	$parents = array();
4576
	//Check that we got a valid interface passed
4577
	$realif = get_real_interface($interface);
4578
	if ($realif == NULL) {
4579
		return $parents;
4580
	}
4581

    
4582
	// If we got a real interface, find it's friendly assigned name
4583
	if ($interface == $realif && $avoidrecurse == false) {
4584
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4585
	}
4586

    
4587
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4588
		$ifcfg = $config['interfaces'][$interface];
4589
		switch ($ifcfg['ipaddr']) {
4590
			case "ppp":
4591
			case "pppoe":
4592
			case "pptp":
4593
			case "l2tp":
4594
				if (empty($parents)) {
4595
					if (is_array($config['ppps']['ppp'])) {
4596
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4597
							if ($ifcfg['if'] == $ppp['if']) {
4598
								$ports = explode(',', $ppp['ports']);
4599
								foreach ($ports as $pid => $parent_if) {
4600
									$parents[$pid] = get_real_interface($parent_if);
4601
								}
4602
								break;
4603
							}
4604
						}
4605
					}
4606
				}
4607
				break;
4608
			case "dhcp":
4609
			case "static":
4610
			default:
4611
				// Handle _vlans
4612
				if (strpos($realif, '_vlan') !== FALSE) {
4613
					if (is_array($config['vlans']['vlan'])) {
4614
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4615
							if ($ifcfg['if'] == $vlan['vlanif']) {
4616
								$parents[0] = $vlan['if'];
4617
								break;
4618
							}
4619
						}
4620
					}
4621
				}
4622
				break;
4623
		}
4624
	}
4625

    
4626
	if (empty($parents)) {
4627
		// Handle _vlans not assigned to an interface
4628
		if (strpos($realif, '_vlan') !== FALSE) {
4629
			if (is_array($config['vlans']['vlan'])) {
4630
				foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4631
					if ($realif == $vlan['vlanif']) {
4632
						$parents[0] = $vlan['if'];
4633
						break;
4634
					}
4635
				}
4636
			}
4637
		}
4638
	}
4639

    
4640
	if (empty($parents)) {
4641
		$parents[0] = $realif;
4642
	}
4643

    
4644
	return $parents;
4645
}
4646

    
4647
function interface_is_wireless_clone($wlif) {
4648
	if (!stristr($wlif, "_wlan")) {
4649
		return false;
4650
	} else {
4651
		return true;
4652
	}
4653
}
4654

    
4655
function interface_get_wireless_base($wlif) {
4656
	if (!stristr($wlif, "_wlan")) {
4657
		return $wlif;
4658
	} else {
4659
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4660
	}
4661
}
4662

    
4663
function interface_get_wireless_clone($wlif) {
4664
	if (!stristr($wlif, "_wlan")) {
4665
		return $wlif . "_wlan0";
4666
	} else {
4667
		return $wlif;
4668
	}
4669
}
4670

    
4671
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4672
	global $config, $g;
4673

    
4674
	$wanif = NULL;
4675

    
4676
	switch ($interface) {
4677
		case "l2tp":
4678
			$wanif = "l2tp";
4679
			break;
4680
		case "pptp":
4681
			$wanif = "pptp";
4682
			break;
4683
		case "pppoe":
4684
			$wanif = "pppoe";
4685
			break;
4686
		case "openvpn":
4687
			$wanif = "openvpn";
4688
			break;
4689
		case "IPsec":
4690
		case "ipsec":
4691
		case "enc0":
4692
			$wanif = "enc0";
4693
			break;
4694
		case "ppp":
4695
			$wanif = "ppp";
4696
			break;
4697
		default:
4698
			if (substr($interface, 0, 4) == '_vip') {
4699
				$wanif = get_configured_carp_interface_list($interface, $family, 'iface');
4700
				if (!empty($wanif)) {
4701
					$wanif = get_real_interface($wanif, $family);
4702
				}
4703
				break;
4704
			} else if (substr($interface, 0, 5) == '_lloc') {
4705
				$interface = substr($interface, 5);
4706
			} else if (does_interface_exist($interface, $flush)) {
4707
				/*
4708
				 * If a real interface was already passed simply
4709
				 * pass the real interface back.  This encourages
4710
				 * the usage of this function in more cases so that
4711
				 * we can combine logic for more flexibility.
4712
				 */
4713
				$wanif = $interface;
4714
				break;
4715
			}
4716

    
4717
			if (empty($config['interfaces'][$interface])) {
4718
				break;
4719
			}
4720

    
4721
			$cfg = &$config['interfaces'][$interface];
4722

    
4723
			if ($family == "inet6") {
4724
				switch ($cfg['ipaddrv6']) {
4725
					case "6rd":
4726
					case "6to4":
4727
						$wanif = "{$interface}_stf";
4728
						break;
4729
					case 'pppoe':
4730
					case 'ppp':
4731
					case 'l2tp':
4732
					case 'pptp':
4733
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4734
							$wanif = interface_get_wireless_clone($cfg['if']);
4735
						} else {
4736
							$wanif = $cfg['if'];
4737
						}
4738
						break;
4739
					default:
4740
						switch ($cfg['ipaddr']) {
4741
							case 'pppoe':
4742
							case 'ppp':
4743
							case 'l2tp':
4744
							case 'pptp':
4745
								if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false) {
4746
									$wanif = $cfg['if'];
4747
								} else {
4748
									$parents = get_parent_interface($interface);
4749
									if (!empty($parents[0])) {
4750
										$wanif = $parents[0];
4751
									} else {
4752
										$wanif = $cfg['if'];
4753
									}
4754
								}
4755
								break;
4756
							default:
4757
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4758
									$wanif = interface_get_wireless_clone($cfg['if']);
4759
								} else {
4760
									$wanif = $cfg['if'];
4761
								}
4762
								break;
4763
						}
4764
						break;
4765
				}
4766
			} else {
4767
				// Wireless cloned NIC support (FreeBSD 8+)
4768
				// interface name format: $parentnic_wlanparentnic#
4769
				// example: ath0_wlan0
4770
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4771
					$wanif = interface_get_wireless_clone($cfg['if']);
4772
				} else {
4773
					$wanif = $cfg['if'];
4774
				}
4775
			}
4776
			break;
4777
	}
4778

    
4779
	return $wanif;
4780
}
4781

    
4782
/* Guess the physical interface by providing a IP address */
4783
function guess_interface_from_ip($ipaddress) {
4784

    
4785
	$family = '';
4786
	if (is_ipaddrv4($ipaddress)) {
4787
		$family = 'inet';
4788
	}
4789
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4790
		$family = 'inet6';
4791
	}
4792

    
4793
	if (empty($family)) {
4794
		return false;
4795
	}
4796

    
4797
	/* create a route table we can search */
4798
	$output = '';
4799
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4800
	$output[0] = trim($output[0], " \n");
4801
	if (!empty($output[0])) {
4802
		return $output[0];
4803
	}
4804

    
4805
	return false;
4806
}
4807

    
4808
/*
4809
 * find_ip_interface($ip): return the interface where an ip is defined
4810
 *   (or if $bits is specified, where an IP within the subnet is defined)
4811
 */
4812
function find_ip_interface($ip, $bits = null) {
4813
	if (!is_ipaddr($ip)) {
4814
		return false;
4815
	}
4816

    
4817
	$isv6ip = is_ipaddrv6($ip);
4818

    
4819
	/* if list */
4820
	$ifdescrs = get_configured_interface_list();
4821

    
4822
	foreach ($ifdescrs as $ifdescr => $ifname) {
4823
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4824
		if (is_null($ifip)) {
4825
			continue;
4826
		}
4827
		if (is_null($bits)) {
4828
			if ($ip == $ifip) {
4829
				$int = get_real_interface($ifname);
4830
				return $int;
4831
			}
4832
		} else {
4833
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4834
				$int = get_real_interface($ifname);
4835
				return $int;
4836
			}
4837
		}
4838
	}
4839

    
4840
	return false;
4841
}
4842

    
4843
/*
4844
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4845
 *   (or if $bits is specified, where an IP within the subnet is found)
4846
 */
4847
function find_virtual_ip_alias($ip, $bits = null) {
4848
	global $config;
4849

    
4850
	if (!is_array($config['virtualip']['vip'])) {
4851
		return false;
4852
	}
4853
	if (!is_ipaddr($ip)) {
4854
		return false;
4855
	}
4856

    
4857
	$isv6ip = is_ipaddrv6($ip);
4858

    
4859
	foreach ($config['virtualip']['vip'] as $vip) {
4860
		if ($vip['mode'] === "ipalias") {
4861
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
4862
				continue;
4863
			}
4864
			if (is_null($bits)) {
4865
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4866
					return $vip;
4867
				}
4868
			} else {
4869
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
4870
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4871
					return $vip;
4872
				}
4873
			}
4874
		}
4875
	}
4876
	return false;
4877
}
4878

    
4879
/*
4880
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4881
 */
4882
function find_number_of_created_carp_interfaces() {
4883
	return `/sbin/ifconfig | /usr/bin/grep "carp:" | /usr/bin/wc -l`;
4884
}
4885

    
4886
/*
4887
 * find_carp_interface($ip): return the carp interface where an ip is defined
4888
 */
4889
function find_carp_interface($ip) {
4890
	global $config;
4891
	if (is_array($config['virtualip']['vip'])) {
4892
		foreach ($config['virtualip']['vip'] as $vip) {
4893
			if ($vip['mode'] == "carp") {
4894
				if (is_ipaddrv4($ip)) {
4895
					$carp_ip = get_interface_ip($vip['interface']);
4896
				}
4897
				if (is_ipaddrv6($ip)) {
4898
					$carp_ip = get_interface_ipv6($vip['interface']);
4899
				}
4900
				exec("/sbin/ifconfig", $output, $return);
4901
				foreach ($output as $line) {
4902
					$elements = preg_split("/[ ]+/i", $line);
4903
					if (strstr($elements[0], "vip")) {
4904
						$curif = str_replace(":", "", $elements[0]);
4905
					}
4906
					if (stristr($line, $ip)) {
4907
						$if = $curif;
4908
						continue;
4909
					}
4910
				}
4911

    
4912
				if ($if) {
4913
					return $if;
4914
				}
4915
			}
4916
		}
4917
	}
4918
}
4919

    
4920
function link_carp_interface_to_parent($interface) {
4921
	global $config;
4922

    
4923
	if (empty($interface)) {
4924
		return;
4925
	}
4926

    
4927
	$carp_ip = get_interface_ip($interface);
4928
	$carp_ipv6 = get_interface_ipv6($interface);
4929

    
4930
	if ((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6))) {
4931
		return;
4932
	}
4933

    
4934
	/* if list */
4935
	$ifdescrs = get_configured_interface_list();
4936
	foreach ($ifdescrs as $ifdescr => $ifname) {
4937
		/* check IPv4 */
4938
		if (is_ipaddrv4($carp_ip)) {
4939
			$interfaceip = get_interface_ip($ifname);
4940
			$subnet_bits = get_interface_subnet($ifname);
4941
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4942
			if (ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}")) {
4943
				return $ifname;
4944
			}
4945
		}
4946
		/* Check IPv6 */
4947
		if (is_ipaddrv6($carp_ipv6)) {
4948
			$interfaceipv6 = get_interface_ipv6($ifname);
4949
			$prefixlen = get_interface_subnetv6($ifname);
4950
			if (ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}")) {
4951
				return $ifname;
4952
			}
4953
		}
4954
	}
4955
	return "";
4956
}
4957

    
4958

    
4959
/****f* interfaces/link_ip_to_carp_interface
4960
 * NAME
4961
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4962
 * INPUTS
4963
 *   $ip
4964
 * RESULT
4965
 *   $carp_ints
4966
 ******/
4967
function link_ip_to_carp_interface($ip) {
4968
	global $config;
4969

    
4970
	if (!is_ipaddr($ip)) {
4971
		return;
4972
	}
4973

    
4974
	$carp_ints = "";
4975
	if (is_array($config['virtualip']['vip'])) {
4976
		$first = 0;
4977
		$carp_int = array();
4978
		foreach ($config['virtualip']['vip'] as $vip) {
4979
			if ($vip['mode'] == "carp") {
4980
				$carp_ip = $vip['subnet'];
4981
				$carp_sn = $vip['subnet_bits'];
4982
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4983
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4984
					$carp_int[] = get_real_interface($vip['interface']);
4985
				}
4986
			}
4987
		}
4988
		if (!empty($carp_int)) {
4989
			$carp_ints = implode(" ", array_unique($carp_int));
4990
		}
4991
	}
4992

    
4993
	return $carp_ints;
4994
}
4995

    
4996
function link_interface_to_track6($int, $action = "") {
4997
	global $config;
4998

    
4999
	if (empty($int)) {
5000
		return;
5001
	}
5002

    
5003
	if (is_array($config['interfaces'])) {
5004
		$list = array();
5005
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5006
			if (!isset($ifcfg['enable'])) {
5007
				continue;
5008
			}
5009
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5010
				if ($action == "update") {
5011
					interface_track6_configure($ifname, $ifcfg);
5012
				} else if ($action == "") {
5013
					$list[$ifname] = $ifcfg;
5014
				}
5015
			}
5016
		}
5017
		return $list;
5018
	}
5019
}
5020

    
5021
function interface_find_child_cfgmtu($realiface) {
5022
	global $config;
5023

    
5024
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5025
	$vlans = link_interface_to_vlans($realiface);
5026
	$bridge = link_interface_to_bridge($realiface);
5027
	if (!empty($interface)) {
5028
		$gifs = link_interface_to_gif($interface);
5029
		$gres = link_interface_to_gre($interface);
5030
	} else {
5031
		$gifs = array();
5032
		$gres = array();
5033
	}
5034

    
5035
	$mtu = 0;
5036
	if (is_array($vlans)) {
5037
		foreach ($vlans as $vlan) {
5038
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5039
			if (empty($ifass)) {
5040
				continue;
5041
			}
5042
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5043
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5044
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5045
				}
5046
			}
5047
		}
5048
	}
5049
	if (is_array($gifs)) {
5050
		foreach ($gifs as $vlan) {
5051
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['gifif']);
5052
			if (empty($ifass)) {
5053
				continue;
5054
			}
5055
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5056
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5057
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5058
				}
5059
			}
5060
		}
5061
	}
5062
	if (is_array($gres)) {
5063
		foreach ($gres as $vlan) {
5064
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['greif']);
5065
			if (empty($ifass)) {
5066
				continue;
5067
			}
5068
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5069
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5070
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5071
				}
5072
			}
5073
		}
5074
	}
5075
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5076
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5077
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5078
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5079
		}
5080
	}
5081
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5082

    
5083
	return $mtu;
5084
}
5085

    
5086
function link_interface_to_vlans($int, $action = "") {
5087
	global $config;
5088

    
5089
	if (empty($int)) {
5090
		return;
5091
	}
5092

    
5093
	if (is_array($config['vlans']['vlan'])) {
5094
		$ifaces = array();
5095
		foreach ($config['vlans']['vlan'] as $vlan) {
5096
			if ($int == $vlan['if']) {
5097
				if ($action == "update") {
5098
					interfaces_bring_up($int);
5099
				} else {
5100
					$ifaces[$vlan['tag']] = $vlan;
5101
				}
5102
			}
5103
		}
5104
		if (!empty($ifaces)) {
5105
			return $ifaces;
5106
		}
5107
	}
5108
}
5109

    
5110
function link_interface_to_vips($int, $action = "", $vhid = '') {
5111
	global $config;
5112

    
5113
	if (is_array($config['virtualip']['vip'])) {
5114
		$result = array();
5115
		foreach ($config['virtualip']['vip'] as $vip) {
5116
			if ($int == $vip['interface']) {
5117
				if ($action == "update") {
5118
					interfaces_vips_configure($int);
5119
				} else {
5120
					if (empty($vhid) || ($vhid == $vip['vhid'])) {
5121
						$result[] = $vip;
5122
					}
5123
				}
5124
			}
5125
		}
5126
		return $result;
5127
	}
5128
}
5129

    
5130
/****f* interfaces/link_interface_to_bridge
5131
 * NAME
5132
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5133
 * INPUTS
5134
 *   $ip
5135
 * RESULT
5136
 *   bridge[0-99]
5137
 ******/
5138
function link_interface_to_bridge($int) {
5139
	global $config;
5140

    
5141
	if (is_array($config['bridges']['bridged'])) {
5142
		foreach ($config['bridges']['bridged'] as $bridge) {
5143
			if (in_array($int, explode(',', $bridge['members']))) {
5144
				return "{$bridge['bridgeif']}";
5145
			}
5146
		}
5147
	}
5148
}
5149

    
5150
function link_interface_to_group($int) {
5151
	global $config;
5152

    
5153
	$result = array();
5154

    
5155
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5156
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5157
			if (in_array($int, explode(" ", $group['members']))) {
5158
				$result[$group['ifname']] = $int;
5159
			}
5160
		}
5161
	}
5162

    
5163
	return $result;
5164
}
5165

    
5166
function link_interface_to_gre($interface) {
5167
	global $config;
5168

    
5169
	$result = array();
5170

    
5171
	if (is_array($config['gres']['gre'])) {
5172
		foreach ($config['gres']['gre'] as $gre) {
5173
			if ($gre['if'] == $interface) {
5174
				$result[] = $gre;
5175
			}
5176
		}
5177
	}
5178

    
5179
	return $result;
5180
}
5181

    
5182
function link_interface_to_gif($interface) {
5183
	global $config;
5184

    
5185
	$result = array();
5186

    
5187
	if (is_array($config['gifs']['gif'])) {
5188
		foreach ($config['gifs']['gif'] as $gif) {
5189
			if ($gif['if'] == $interface) {
5190
				$result[] = $gif;
5191
			}
5192
		}
5193
	}
5194

    
5195
	return $result;
5196
}
5197

    
5198
/*
5199
 * find_interface_ip($interface): return the interface ip (first found)
5200
 */
5201
function find_interface_ip($interface, $flush = false) {
5202
	global $interface_ip_arr_cache;
5203
	global $interface_sn_arr_cache;
5204

    
5205
	$interface = str_replace("\n", "", $interface);
5206

    
5207
	if (!does_interface_exist($interface)) {
5208
		return;
5209
	}
5210

    
5211
	/* Setup IP cache */
5212
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5213
		$ifinfo = pfSense_get_interface_addresses($interface);
5214
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5215
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5216
	}
5217

    
5218
	return $interface_ip_arr_cache[$interface];
5219
}
5220

    
5221
/*
5222
 * find_interface_ipv6($interface): return the interface ip (first found)
5223
 */
5224
function find_interface_ipv6($interface, $flush = false) {
5225
	global $interface_ipv6_arr_cache;
5226
	global $interface_snv6_arr_cache;
5227
	global $config;
5228

    
5229
	$interface = trim($interface);
5230
	$interface = get_real_interface($interface);
5231

    
5232
	if (!does_interface_exist($interface)) {
5233
		return;
5234
	}
5235

    
5236
	/* Setup IP cache */
5237
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5238
		$ifinfo = pfSense_get_interface_addresses($interface);
5239
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5240
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5241
	}
5242

    
5243
	return $interface_ipv6_arr_cache[$interface];
5244
}
5245

    
5246
/*
5247
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5248
 */
5249
function find_interface_ipv6_ll($interface, $flush = false) {
5250
	global $interface_llv6_arr_cache;
5251
	global $config;
5252

    
5253
	$interface = str_replace("\n", "", $interface);
5254

    
5255
	if (!does_interface_exist($interface)) {
5256
		return;
5257
	}
5258

    
5259
	/* Setup IP cache */
5260
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5261
		$ifinfo = pfSense_getall_interface_addresses($interface);
5262
		foreach ($ifinfo as $line) {
5263
			if (strstr($line, ":")) {
5264
				$parts = explode("/", $line);
5265
				if (is_linklocal($parts[0])) {
5266
					$ifinfo['linklocal'] = $parts[0];
5267
				}
5268
			}
5269
		}
5270
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5271
	}
5272
	return $interface_llv6_arr_cache[$interface];
5273
}
5274

    
5275
function find_interface_subnet($interface, $flush = false) {
5276
	global $interface_sn_arr_cache;
5277
	global $interface_ip_arr_cache;
5278

    
5279
	$interface = str_replace("\n", "", $interface);
5280
	if (does_interface_exist($interface) == false) {
5281
		return;
5282
	}
5283

    
5284
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5285
		$ifinfo = pfSense_get_interface_addresses($interface);
5286
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5287
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5288
	}
5289

    
5290
	return $interface_sn_arr_cache[$interface];
5291
}
5292

    
5293
function find_interface_subnetv6($interface, $flush = false) {
5294
	global $interface_snv6_arr_cache;
5295
	global $interface_ipv6_arr_cache;
5296

    
5297
	$interface = str_replace("\n", "", $interface);
5298
	if (does_interface_exist($interface) == false) {
5299
		return;
5300
	}
5301

    
5302
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5303
		$ifinfo = pfSense_get_interface_addresses($interface);
5304
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5305
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5306
	}
5307

    
5308
	return $interface_snv6_arr_cache[$interface];
5309
}
5310

    
5311
function ip_in_interface_alias_subnet($interface, $ipalias) {
5312
	global $config;
5313

    
5314
	if (empty($interface) || !is_ipaddr($ipalias)) {
5315
		return false;
5316
	}
5317
	if (is_array($config['virtualip']['vip'])) {
5318
		foreach ($config['virtualip']['vip'] as $vip) {
5319
			switch ($vip['mode']) {
5320
				case "ipalias":
5321
					if ($vip['interface'] <> $interface) {
5322
						break;
5323
					}
5324
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5325
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5326
						return true;
5327
					}
5328
					break;
5329
			}
5330
		}
5331
	}
5332

    
5333
	return false;
5334
}
5335

    
5336
function get_possible_listen_ips($include_ipv6_link_local=false) {
5337

    
5338
	$interfaces = get_configured_interface_with_descr();
5339
	foreach ($interfaces as $iface => $ifacename) {
5340
		if ($include_ipv6_link_local) {
5341
			/* This is to avoid going though added ll below */
5342
			if (substr($iface, 0, 5) == '_lloc') {
5343
				continue;
5344
			}
5345
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5346
			if (!empty($llip)) {
5347
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5348
			}
5349
		}
5350
	}
5351
	/* XXX: Maybe use array_merge below? */
5352
	$carplist = get_configured_carp_interface_list();
5353
	foreach ($carplist as $cif => $carpip) {
5354
		if (get_vip_descr($carpip)) {
5355
			$interfaces[$cif] = $carpip . ' (' . get_vip_descr($carpip) . ')';
5356
		} else {
5357
			$interfaces[$cif] = $carpip;
5358
		}
5359
	}
5360
	$aliaslist = get_configured_ip_aliases_list();
5361
	foreach ($aliaslist as $aliasip => $aliasif) {
5362
		if (get_vip_descr($aliasip)) {
5363
			$interfaces[$aliasip] = $aliasip . ' (' . get_vip_descr($aliasip) . ')';
5364
		} else {
5365
			$interfaces[$aliasip] = $aliasip;
5366
		}
5367
	}
5368

    
5369
	$interfaces['lo0'] = 'Localhost';
5370

    
5371
	return $interfaces;
5372
}
5373

    
5374
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5375
	global $config;
5376

    
5377
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5378
	foreach (array('server', 'client') as $mode) {
5379
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5380
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5381
				if (!isset($setting['disable'])) {
5382
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5383
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " ".$mode.": ".htmlspecialchars($setting['description']);
5384
				}
5385
			}
5386
		}
5387
	}
5388
	return $sourceips;
5389
}
5390

    
5391
function get_interface_ip($interface = "wan") {
5392

    
5393
	$realif = get_failover_interface($interface, 'inet');
5394
	if (!$realif) {
5395
		return null;
5396
	}
5397

    
5398
	if (substr($interface, 0, 4) == '_vip') {
5399
		return get_configured_carp_interface_list($interface, 'inet', 'ip');
5400
	} else if (substr($interface, 0, 5) == '_lloc') {
5401
		/* No link-local address for v4. */
5402
		return null;
5403
	}
5404

    
5405
	$curip = find_interface_ip($realif);
5406
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5407
		return $curip;
5408
	} else {
5409
		return null;
5410
	}
5411
}
5412

    
5413
function get_interface_ipv6($interface = "wan", $flush = false) {
5414
	global $config;
5415

    
5416
	$realif = get_failover_interface($interface, 'inet6');
5417
	if (!$realif) {
5418
		return null;
5419
	}
5420

    
5421
	if (substr($interface, 0, 4) == '_vip') {
5422
		return get_configured_carp_interface_list($interface, 'inet6', 'ip');
5423
	} else if (substr($interface, 0, 5) == '_lloc') {
5424
		return get_interface_linklocal($interface);
5425
	}
5426

    
5427
	if (is_array($config['interfaces'][$interface])) {
5428
		switch ($config['interfaces'][$interface]['ipaddr']) {
5429
			case 'pppoe':
5430
			case 'l2tp':
5431
			case 'pptp':
5432
			case 'ppp':
5433
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5434
					$realif = get_real_interface($interface, 'inet6', false);
5435
				}
5436
				break;
5437
		}
5438
	}
5439

    
5440
	$curip = find_interface_ipv6($realif, $flush);
5441
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5442
		return $curip;
5443
	} else {
5444
		/*
5445
		 * NOTE: On the case when only the prefix is requested,
5446
		 * the communication on WAN will be done over link-local.
5447
		 */
5448
		if (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
5449
			$curip = find_interface_ipv6_ll($realif, $flush);
5450
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5451
				return $curip;
5452
			}
5453
		}
5454
	}
5455
	return null;
5456
}
5457

    
5458
function get_interface_linklocal($interface = "wan") {
5459

    
5460
	$realif = get_failover_interface($interface, 'inet6');
5461
	if (!$realif) {
5462
		return null;
5463
	}
5464

    
5465
	if (substr($interface, 0, 4) == '_vip') {
5466
		$realif = get_real_interface($interface);
5467
	} else if (substr($interface, 0, 5) == '_lloc') {
5468
		$realif = get_real_interface(substr($interface, 5));
5469
	}
5470

    
5471
	$curip = find_interface_ipv6_ll($realif);
5472
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5473
		return $curip;
5474
	} else {
5475
		return null;
5476
	}
5477
}
5478

    
5479
function get_interface_subnet($interface = "wan") {
5480

    
5481
	if (substr($interface, 0, 4) == '_vip') {
5482
		return get_configured_carp_interface_list($interface, 'inet', 'subnet');
5483
	}
5484

    
5485
	$realif = get_real_interface($interface);
5486
	if (!$realif) {
5487
		return null;
5488
	}
5489

    
5490
	$cursn = find_interface_subnet($realif);
5491
	if (!empty($cursn)) {
5492
		return $cursn;
5493
	}
5494

    
5495
	return null;
5496
}
5497

    
5498
function get_interface_subnetv6($interface = "wan") {
5499

    
5500
	if (substr($interface, 0, 4) == '_vip') {
5501
		return get_configured_carp_interface_list($interface, 'inet6', 'subnet');
5502
	} else if (substr($interface, 0, 5) == '_lloc') {
5503
		$interface = substr($interface, 5);
5504
	}
5505

    
5506
	$realif = get_real_interface($interface, 'inet6');
5507
	if (!$realif) {
5508
		return null;
5509
	}
5510

    
5511
	$cursn = find_interface_subnetv6($realif);
5512
	if (!empty($cursn)) {
5513
		return $cursn;
5514
	}
5515

    
5516
	return null;
5517
}
5518

    
5519
/* return outside interfaces with a gateway */
5520
function get_interfaces_with_gateway() {
5521
	global $config;
5522

    
5523
	$ints = array();
5524

    
5525
	/* loop interfaces, check config for outbound */
5526
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5527
		switch ($ifname['ipaddr']) {
5528
			case "dhcp":
5529
			case "pppoe":
5530
			case "pptp":
5531
			case "l2tp":
5532
			case "ppp":
5533
				$ints[$ifdescr] = $ifdescr;
5534
				break;
5535
			default:
5536
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5537
				    !empty($ifname['gateway'])) {
5538
					$ints[$ifdescr] = $ifdescr;
5539
				}
5540
				break;
5541
		}
5542
	}
5543
	return $ints;
5544
}
5545

    
5546
/* return true if interface has a gateway */
5547
function interface_has_gateway($friendly) {
5548
	global $config;
5549

    
5550
	if (!empty($config['interfaces'][$friendly])) {
5551
		$ifname = &$config['interfaces'][$friendly];
5552
		switch ($ifname['ipaddr']) {
5553
			case "dhcp":
5554
			case "pppoe":
5555
			case "pptp":
5556
			case "l2tp":
5557
			case "ppp":
5558
				return true;
5559
			break;
5560
			default:
5561
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5562
					return true;
5563
				}
5564
				$tunnelif = substr($ifname['if'], 0, 3);
5565
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5566
					return true;
5567
				}
5568
				if (!empty($ifname['gateway'])) {
5569
					return true;
5570
				}
5571
			break;
5572
		}
5573
	}
5574

    
5575
	return false;
5576
}
5577

    
5578
/* return true if interface has a gateway */
5579
function interface_has_gatewayv6($friendly) {
5580
	global $config;
5581

    
5582
	if (!empty($config['interfaces'][$friendly])) {
5583
		$ifname = &$config['interfaces'][$friendly];
5584
		switch ($ifname['ipaddrv6']) {
5585
			case "slaac":
5586
			case "dhcp6":
5587
			case "6to4":
5588
			case "6rd":
5589
				return true;
5590
				break;
5591
			default:
5592
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5593
					return true;
5594
				}
5595
				$tunnelif = substr($ifname['if'], 0, 3);
5596
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5597
					return true;
5598
				}
5599
				if (!empty($ifname['gatewayv6'])) {
5600
					return true;
5601
				}
5602
				break;
5603
		}
5604
	}
5605

    
5606
	return false;
5607
}
5608

    
5609
/****f* interfaces/is_altq_capable
5610
 * NAME
5611
 *   is_altq_capable - Test if interface is capable of using ALTQ
5612
 * INPUTS
5613
 *   $int            - string containing interface name
5614
 * RESULT
5615
 *   boolean         - true or false
5616
 ******/
5617

    
5618
function is_altq_capable($int) {
5619
	/* Per:
5620
	 * http://www.freebsd.org/cgi/man.cgi?query=altq&apropos=0&sektion=0&manpath=FreeBSD+8.3-RELEASE&arch=default&format=html
5621
	 * Only the following drivers have ALTQ support
5622
	 * 20150328 - removed wireless drivers - ath, awi, bwn, iwi, ipw, ral, rum, run, wi - for now. redmine #4406
5623
	 */
5624
	$capable = array("ae", "age", "alc", "ale", "an", "aue", "axe", "bce",
5625
			"bfe", "bge", "bridge", "cas", "dc", "de", "ed", "em", "ep", "epair", "et", "fxp", "gem",
5626
			"hme", "hn", "igb", "ixgbe", "jme", "le", "lem", "msk", "mxge", "my", "nfe",
5627
			"nge", "npe", "nve", "re", "rl", "sf", "sge", "sis", "sk",
5628
			"ste", "stge", "ti", "txp", "udav", "ural", "vge", "vmx", "vr", "vte", "xl",
5629
			"ndis", "tun", "ovpns", "ovpnc", "vlan", "pppoe", "pptp", "ng",
5630
			"l2tp", "ppp", "vtnet");
5631

    
5632
	$int_family = remove_ifindex($int);
5633

    
5634
	if (in_array($int_family, $capable)) {
5635
		return true;
5636
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5637
		return true;
5638
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5639
		return true;
5640
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5641
		return true;
5642
	} else {
5643
		return false;
5644
	}
5645
}
5646

    
5647
/****f* interfaces/is_interface_wireless
5648
 * NAME
5649
 *   is_interface_wireless - Returns if an interface is wireless
5650
 * RESULT
5651
 *   $tmp       - Returns if an interface is wireless
5652
 ******/
5653
function is_interface_wireless($interface) {
5654
	global $config, $g;
5655

    
5656
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5657
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5658
		if (preg_match($g['wireless_regex'], $interface)) {
5659
			if (isset($config['interfaces'][$friendly])) {
5660
				$config['interfaces'][$friendly]['wireless'] = array();
5661
			}
5662
			return true;
5663
		}
5664
		return false;
5665
	} else {
5666
		return true;
5667
	}
5668
}
5669

    
5670
function get_wireless_modes($interface) {
5671
	/* return wireless modes and channels */
5672
	$wireless_modes = array();
5673

    
5674
	$cloned_interface = get_real_interface($interface);
5675

    
5676
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5677
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5678
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5679
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5680

    
5681
		$interface_channels = "";
5682
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5683
		$interface_channel_count = count($interface_channels);
5684

    
5685
		$c = 0;
5686
		while ($c < $interface_channel_count) {
5687
			$channel_line = explode(",", $interface_channels["$c"]);
5688
			$wireless_mode = trim($channel_line[0]);
5689
			$wireless_channel = trim($channel_line[1]);
5690
			if (trim($wireless_mode) != "") {
5691
				/* if we only have 11g also set 11b channels */
5692
				if ($wireless_mode == "11g") {
5693
					if (!isset($wireless_modes["11b"])) {
5694
						$wireless_modes["11b"] = array();
5695
					}
5696
				} else if ($wireless_mode == "11g ht") {
5697
					if (!isset($wireless_modes["11b"])) {
5698
						$wireless_modes["11b"] = array();
5699
					}
5700
					if (!isset($wireless_modes["11g"])) {
5701
						$wireless_modes["11g"] = array();
5702
					}
5703
					$wireless_mode = "11ng";
5704
				} else if ($wireless_mode == "11a ht") {
5705
					if (!isset($wireless_modes["11a"])) {
5706
						$wireless_modes["11a"] = array();
5707
					}
5708
					$wireless_mode = "11na";
5709
				}
5710
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5711
			}
5712
			$c++;
5713
		}
5714
	}
5715
	return($wireless_modes);
5716
}
5717

    
5718
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5719
function get_wireless_channel_info($interface) {
5720
	$wireless_channels = array();
5721

    
5722
	$cloned_interface = get_real_interface($interface);
5723

    
5724
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5725
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5726
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5727
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5728

    
5729
		$interface_channels = "";
5730
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5731

    
5732
		foreach ($interface_channels as $channel_line) {
5733
			$channel_line = explode(",", $channel_line);
5734
			if (!isset($wireless_channels[$channel_line[0]])) {
5735
				$wireless_channels[$channel_line[0]] = $channel_line;
5736
			}
5737
		}
5738
	}
5739
	return($wireless_channels);
5740
}
5741

    
5742
/****f* interfaces/get_interface_mtu
5743
 * NAME
5744
 *   get_interface_mtu - Return the mtu of an interface
5745
 * RESULT
5746
 *   $tmp       - Returns the mtu of an interface
5747
 ******/
5748
function get_interface_mtu($interface) {
5749
	$mtu = pfSense_interface_getmtu($interface);
5750
	return $mtu['mtu'];
5751
}
5752

    
5753
function get_interface_mac($interface) {
5754

    
5755
	$macinfo = pfSense_get_interface_addresses($interface);
5756
	return $macinfo["macaddr"];
5757
}
5758

    
5759
/****f* pfsense-utils/generate_random_mac_address
5760
 * NAME
5761
 *   generate_random_mac - generates a random mac address
5762
 * INPUTS
5763
 *   none
5764
 * RESULT
5765
 *   $mac - a random mac address
5766
 ******/
5767
function generate_random_mac_address() {
5768
	$mac = "02";
5769
	for ($x = 0; $x < 5; $x++) {
5770
		$mac .= ":" . dechex(rand(16, 255));
5771
	}
5772
	return $mac;
5773
}
5774

    
5775
/****f* interfaces/is_jumbo_capable
5776
 * NAME
5777
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5778
 * INPUTS
5779
 *   $int             - string containing interface name
5780
 * RESULT
5781
 *   boolean          - true or false
5782
 ******/
5783
function is_jumbo_capable($iface) {
5784
	$iface = trim($iface);
5785
	$capable = pfSense_get_interface_addresses($iface);
5786

    
5787
	if (isset($capable['caps']['vlanmtu'])) {
5788
		return true;
5789
	}
5790

    
5791
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5792
	if (substr($iface, 0, 4) == "lagg") {
5793
		return true;
5794
	}
5795

    
5796
	return false;
5797
}
5798

    
5799
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5800
	global $g;
5801

    
5802
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5803

    
5804
	if (!empty($iface) && !empty($pppif)) {
5805
		$cron_cmd = <<<EOD
5806
#!/bin/sh
5807
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5808
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5809

    
5810
EOD;
5811

    
5812
		@file_put_contents($cron_file, $cron_cmd);
5813
		chmod($cron_file, 0755);
5814
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5815
	} else {
5816
		unlink_if_exists($cron_file);
5817
	}
5818
}
5819

    
5820
function get_interface_default_mtu($type = "ethernet") {
5821
	switch ($type) {
5822
		case "gre":
5823
			return 1476;
5824
			break;
5825
		case "gif":
5826
			return 1280;
5827
			break;
5828
		case "tun":
5829
		case "vlan":
5830
		case "tap":
5831
		case "ethernet":
5832
		default:
5833
			return 1500;
5834
			break;
5835
	}
5836

    
5837
	/* Never reached */
5838
	return 1500;
5839
}
5840

    
5841
function get_vip_descr($ipaddress) {
5842
	global $config;
5843

    
5844
	foreach ($config['virtualip']['vip'] as $vip) {
5845
		if ($vip['subnet'] == $ipaddress) {
5846
			return ($vip['descr']);
5847
		}
5848
	}
5849
	return "";
5850
}
5851

    
5852
function interfaces_staticarp_configure($if) {
5853
	global $config, $g;
5854
	if (isset($config['system']['developerspew'])) {
5855
		$mt = microtime();
5856
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5857
	}
5858

    
5859
	$ifcfg = $config['interfaces'][$if];
5860

    
5861
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5862
		return 0;
5863
	}
5864

    
5865
	/* Enable staticarp, if enabled */
5866
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5867
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5868
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5869
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5870
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5871
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5872
			}
5873
		}
5874
	} else {
5875
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5876
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5877
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5878
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5879
				if (isset($arpent['arp_table_static_entry'])) {
5880
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5881
				}
5882
			}
5883
		}
5884
	}
5885

    
5886
	return 0;
5887
}
5888

    
5889
function get_failover_interface($interface, $family = "all") {
5890
	global $config;
5891

    
5892
	/* shortcut to get_real_interface if we find it in the config */
5893
	if (is_array($config['interfaces'][$interface])) {
5894
		return get_real_interface($interface, $family);
5895
	}
5896

    
5897
	/* compare against gateway groups */
5898
	$a_groups = return_gateway_groups_array();
5899
	if (is_array($a_groups[$interface])) {
5900
		/* we found a gateway group, fetch the interface or vip */
5901
		if (!empty($a_groups[$interface][0]['vip'])) {
5902
			return $a_groups[$interface][0]['vip'];
5903
		} else {
5904
			return $a_groups[$interface][0]['int'];
5905
		}
5906
	}
5907
	/* fall through to get_real_interface */
5908
	/* XXX: Really needed? */
5909
	return get_real_interface($interface, $family);
5910
}
5911

    
5912
function remove_ifindex($ifname) {
5913
	return preg_replace("/[0-9]+$/", "", $ifname);
5914
}
5915

    
5916
?>
(25-25/65)