Project

General

Profile

Bug #6227 » interfaces.inc

Chris Rowe, 04/21/2016 02:01 PM

 
1
<?php
2
/* ====================================================================
3
 *  Copyright (c)  2004-2015  Electric Sheep Fencing, LLC. All rights reserved.
4
 *
5
 *  Some or all of this file is based on the m0n0wall project which is
6
 *  Copyright (c)  2004 Manuel Kasper (BSD 2 clause)
7
 *
8
 *  Redistribution and use in source and binary forms, with or without modification,
9
 *  are permitted provided that the following conditions are met:
10
 *
11
 *  1. Redistributions of source code must retain the above copyright notice,
12
 *      this list of conditions and the following disclaimer.
13
 *
14
 *  2. Redistributions in binary form must reproduce the above copyright
15
 *      notice, this list of conditions and the following disclaimer in
16
 *      the documentation and/or other materials provided with the
17
 *      distribution.
18
 *
19
 *  3. All advertising materials mentioning features or use of this software
20
 *      must display the following acknowledgment:
21
 *      "This product includes software developed by the pfSense Project
22
 *       for use in the pfSense software distribution. (http://www.pfsense.org/).
23
 *
24
 *  4. The names "pfSense" and "pfSense Project" must not be used to
25
 *       endorse or promote products derived from this software without
26
 *       prior written permission. For written permission, please contact
27
 *       coreteam@pfsense.org.
28
 *
29
 *  5. Products derived from this software may not be called "pfSense"
30
 *      nor may "pfSense" appear in their names without prior written
31
 *      permission of the Electric Sheep Fencing, LLC.
32
 *
33
 *  6. Redistributions of any form whatsoever must retain the following
34
 *      acknowledgment:
35
 *
36
 *  "This product includes software developed by the pfSense Project
37
 *  for use in the pfSense software distribution (http://www.pfsense.org/).
38
 *
39
 *  THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
40
 *  EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42
 *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
43
 *  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45
 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
 *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48
 *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50
 *  OF THE POSSIBILITY OF SUCH DAMAGE.
51
 *
52
 *  ====================================================================
53
 *
54
 * function interfaces_wireless_configure is Copyright (C) 2005 Espen Johansen
55
 *
56
 */
57

    
58
/* include all configuration functions */
59
require_once("globals.inc");
60
require_once("util.inc");
61
require_once("gwlb.inc");
62

    
63
function interfaces_bring_up($interface) {
64
	if (!$interface) {
65
		log_error(gettext("interfaces_bring_up() was called but no variable defined."));
66
		log_error("Backtrace: " . debug_backtrace());
67
		return;
68
	}
69
	pfSense_interface_flags($interface, IFF_UP);
70
}
71

    
72
/*
73
 * Return the interface array
74
 */
75
function get_interface_arr($flush = false) {
76
	global $interface_arr_cache;
77

    
78
	/* If the cache doesn't exist, build it */
79
	if (!isset($interface_arr_cache) or $flush) {
80
		$interface_arr_cache = pfSense_interface_listget();
81
	}
82

    
83
	return $interface_arr_cache;
84
}
85

    
86
/*
87
 * does_interface_exist($interface): return true or false if a interface is
88
 * detected.
89
 */
90
function does_interface_exist($interface, $flush = true) {
91
	global $config;
92

    
93
	if (!$interface) {
94
		return false;
95
	}
96

    
97
	$ints = get_interface_arr($flush);
98
	if (in_array($interface, $ints)) {
99
		return true;
100
	} else {
101
		return false;
102
	}
103
}
104

    
105
/*
106
 * does_vip_exist($vip): return true or false if a vip is
107
 * configured.
108
 */
109
function does_vip_exist($vip) {
110
	global $config;
111

    
112
	if (!$vip) {
113
		return false;
114
	}
115

    
116

    
117
	switch ($vip['mode']) {
118
		case "carp":
119
		case "ipalias":
120
			/* XXX: Make proper checks? */
121
			$realif = get_real_interface($vip['interface']);
122
			if (!does_interface_exist($realif)) {
123
				return false;
124
			}
125
			break;
126
		case "proxyarp":
127
			/* XXX: Implement this */
128
		default:
129
			return false;
130
	}
131

    
132
	$ifacedata = pfSense_getall_interface_addresses($realif);
133
	foreach ($ifacedata as $vipips) {
134
		if ($vipips == "{$vip['subnet']}/{$vip['subnet_bits']}") {
135
			return true;
136
		}
137
	}
138

    
139
	return false;
140
}
141

    
142
function interface_netgraph_needed($interface = "wan") {
143
	global $config;
144

    
145
	$found = false;
146
	if (!empty($config['l2tp']) &&
147
	    $config['l2tp']['mode'] == "server") {
148
		$found = true;
149
	}
150
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
151
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
152
			if ($pppoe['mode'] != "server") {
153
				continue;
154
			}
155
			if ($pppoe['interface'] == $interface) {
156
				$found = true;
157
				break;
158
			}
159
		}
160
	}
161
	if ($found == false) {
162
		$found = interface_isppp_type($interface);
163
	}
164

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

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

    
200
function interfaces_loopback_configure() {
201
	global $g;
202

    
203
	if (platform_booting()) {
204
		echo gettext("Configuring loopback interface...");
205
	}
206
	pfSense_interface_setaddress("lo0", "127.0.0.1");
207
	interfaces_bring_up("lo0");
208
	if (platform_booting()) {
209
		echo gettext("done.") . "\n";
210
	}
211
	return 0;
212
}
213

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

    
228
			/* XXX: Maybe we should report any errors?! */
229
			interface_vlan_configure($vlan);
230
		}
231
	}
232
	if (platform_booting()) {
233
		echo gettext("done.") . "\n";
234
	}
235
}
236

    
237
function interface_vlan_configure(&$vlan) {
238
	global $config, $g;
239

    
240
	if (!is_array($vlan)) {
241
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
242
		return;
243
	}
244
	$if = $vlan['if'];
245
	if (empty($if)) {
246
		log_error(gettext("interface_vlan_configure called with if undefined."));
247
		return;
248
	}
249

    
250
	$vlanif = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
251
	$tag = $vlan['tag'];
252
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
253

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

    
259
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
260
		pfSense_interface_destroy($vlanif);
261
	}
262

    
263
	$tmpvlanif = pfSense_interface_create("vlan");
264
	pfSense_interface_rename($tmpvlanif, $vlanif);
265
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
266

    
267
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
268

    
269
	interfaces_bring_up($vlanif);
270

    
271
	/* invalidate interface cache */
272
	get_interface_arr(true);
273

    
274
	/* configure interface if assigned */
275
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
276
	if ($assignedif) {
277
		if (isset($config['interfaces'][$assignedif]['enable'])) {
278
			interface_configure($assignedif, true);
279
		}
280
	}
281

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

    
285
	return $vlanif;
286
}
287

    
288
function interface_qinq_configure(&$vlan, $fd = NULL) {
289
	global $config, $g;
290

    
291
	if (!is_array($vlan)) {
292
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
293
		return;
294
	}
295

    
296
	$qinqif = $vlan['if'];
297
	$tag = $vlan['tag'];
298
	if (empty($qinqif)) {
299
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
300
		return;
301
	}
302

    
303
	if (!does_interface_exist($qinqif)) {
304
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
305
		return;
306
	}
307

    
308
	$vlanif = interface_vlan_configure($vlan);
309

    
310
	if ($fd == NULL) {
311
		$exec = true;
312
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
313
	} else {
314
		$exec = false;
315
	}
316
	/* make sure the parent is converted to ng_vlan(4) and is up */
317
	interfaces_bring_up($qinqif);
318

    
319
	pfSense_ngctl_attach(".", $qinqif);
320
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
321
		fwrite($fd, "shutdown {$vlanif}qinq:\n");
322
		exec("/usr/sbin/ngctl msg {$vlanif}qinq: gettable", $result);
323
		if (empty($result)) {
324
			fwrite($fd, "mkpeer {$vlanif}: vlan lower downstream\n");
325
			fwrite($fd, "name {$vlanif}:lower {$vlanif}qinq\n");
326
			fwrite($fd, "connect {$vlanif}: {$vlanif}qinq: upper nomatch\n");
327
		}
328
	} else {
329
		fwrite($fd, "mkpeer {$vlanif}: vlan lower downstream\n");
330
		fwrite($fd, "name {$vlanif}:lower {$vlanif}qinq\n");
331
		fwrite($fd, "connect {$vlanif}: {$vlanif}qinq: upper nomatch\n");
332
	}
333

    
334
	/* invalidate interface cache */
335
	get_interface_arr(true);
336

    
337
	if (!stristr($qinqif, "_vlan")) {
338
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
339
	}
340

    
341
	$macaddr = get_interface_mac($qinqif);
342
	if (!empty($vlan['members'])) {
343
		$members = explode(" ", $vlan['members']);
344
		foreach ($members as $qtag) {
345
			$qinq = array();
346
			$qinq['tag'] = $qtag;
347
			$qinq['if'] = $vlanif;
348
			interface_qinq2_configure($qinq, $fd, $macaddr);
349
		}
350
	}
351
	if ($exec == true) {
352
		fclose($fd);
353
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
354
	}
355

    
356
	interfaces_bring_up($qinqif);
357
	if (!empty($vlan['members'])) {
358
		$members = explode(" ", $vlan['members']);
359
		foreach ($members as $qif) {
360
			interfaces_bring_up("{$vlanif}_{$qif}");
361
		}
362
	}
363

    
364
	return $vlanif;
365
}
366

    
367
function interfaces_qinq_configure() {
368
	global $config, $g;
369
	if (platform_booting()) {
370
		echo gettext("Configuring QinQ interfaces...");
371
	}
372
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
373
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
374
			/* XXX: Maybe we should report any errors?! */
375
			interface_qinq_configure($qinq);
376
		}
377
	}
378
	if (platform_booting()) {
379
		echo gettext("done.") . "\n";
380
	}
381
}
382

    
383
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
384
	global $config, $g;
385

    
386
	if (!is_array($qinq)) {
387
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
388
		return;
389
	}
390

    
391
	$if = $qinq['if'];
392
	$tag = $qinq['tag'];
393
	$vlanif = "{$if}_{$tag}";
394
	if (empty($if)) {
395
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
396
		return;
397
	}
398

    
399
	fwrite($fd, "shutdown {$if}h{$tag}:\n");
400
	fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
401
	fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
402
	fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
403
	fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
404
	fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
405

    
406
	/* invalidate interface cache */
407
	get_interface_arr(true);
408

    
409
	return $vlanif;
410
}
411

    
412
function interfaces_create_wireless_clones() {
413
	global $config, $g;
414

    
415
	if (platform_booting()) {
416
		echo gettext("Creating wireless clone interfaces...");
417
	}
418

    
419
	$iflist = get_configured_interface_list();
420

    
421
	foreach ($iflist as $if) {
422
		$realif = $config['interfaces'][$if]['if'];
423
		if (is_interface_wireless($realif)) {
424
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
425
		}
426
	}
427

    
428
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
429
		foreach ($config['wireless']['clone'] as $clone) {
430
			if (empty($clone['cloneif'])) {
431
				continue;
432
			}
433
			if (does_interface_exist($clone['cloneif'])) {
434
				continue;
435
			}
436
			/* XXX: Maybe we should report any errors?! */
437
			interface_wireless_clone($clone['cloneif'], $clone);
438
		}
439
	}
440
	if (platform_booting()) {
441
		echo gettext("done.") . "\n";
442
	}
443

    
444
}
445

    
446
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
447
	global $config;
448

    
449
	$i = 0;
450
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
451
		foreach ($config['bridges']['bridged'] as $bridge) {
452
			if (empty($bridge['bridgeif'])) {
453
				$bridge['bridgeif'] = "bridge{$i}";
454
			}
455
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
456
				continue;
457
			}
458

    
459
			if ($checkmember == 1) {
460
				/* XXX: It should not be possible no? */
461
				if (strstr($bridge['if'], '_vip')) {
462
					continue;
463
				}
464
				$members = explode(',', $bridge['members']);
465
				foreach ($members as $member) {
466
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6") {
467
						continue 2;
468
					}
469
				}
470
			}
471
			else if ($checkmember == 2) {
472
				$members = explode(',', $bridge['members']);
473
				foreach ($members as $member) {
474
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6") {
475
						continue 2;
476
					}
477
				}
478
			}
479
			/* XXX: Maybe we should report any errors?! */
480
			interface_bridge_configure($bridge, $checkmember);
481
			$i++;
482
		}
483
	}
484
}
485

    
486
function interface_bridge_configure(&$bridge, $checkmember = 0) {
487
	global $config, $g;
488

    
489
	if (!is_array($bridge)) {
490
		return;
491
	}
492

    
493
	if (empty($bridge['members'])) {
494
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
495
		return;
496
	}
497

    
498
	$members = explode(',', $bridge['members']);
499
	if (!count($members)) {
500
		return;
501
	}
502

    
503
	/* Calculate smaller mtu and enforce it */
504
	$smallermtu = 0;
505
	$foundgif = false;
506
	foreach ($members as $member) {
507
		$realif = get_real_interface($member);
508
		$mtu = get_interface_mtu($realif);
509
		if (substr($realif, 0, 3) == "gif") {
510
			$foundgif = true;
511
			if ($checkmember == 1) {
512
				return;
513
			}
514
			if ($mtu <= 1500) {
515
				continue;
516
			}
517
		}
518
		if ($smallermtu == 0 && !empty($mtu)) {
519
			$smallermtu = $mtu;
520
		} else if (!empty($mtu) && $mtu < $smallermtu) {
521
			$smallermtu = $mtu;
522
		}
523
	}
524
	if ($foundgif == false && $checkmember == 2) {
525
		return;
526
	}
527

    
528
	/* Just in case anything is not working well */
529
	if ($smallermtu == 0) {
530
		$smallermtu = 1500;
531
	}
532

    
533
	if (!empty($bridge['bridgeif'])) {
534
		pfSense_interface_destroy($bridge['bridgeif']);
535
		pfSense_interface_create($bridge['bridgeif']);
536
		$bridgeif = escapeshellarg($bridge['bridgeif']);
537
	} else {
538
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
539
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
540
		$bridgeif = pfSense_interface_create("bridge");
541
		$bridge['bridgeif'] = $bridgeif;
542
	}
543

    
544
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
545
	if ($bridgemtu > $smallermtu) {
546
		$smallermtu = $bridgemtu;
547
	}
548

    
549
	$checklist = get_configured_interface_list();
550

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

    
568
	if (isset($bridge['enablestp'])) {
569
		interface_bridge_configure_stp($bridge);
570
	}
571

    
572
	interface_bridge_configure_advanced($bridge);
573

    
574
	if ($bridge['bridgeif']) {
575
		interfaces_bring_up($bridge['bridgeif']);
576
	} else {
577
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
578
	}
579
}
580

    
581
function interface_bridge_configure_stp($bridge) {
582
	if (isset($bridge['enablestp'])) {
583
		$bridgeif = $bridge['bridgeif'];
584
		/* configure spanning tree proto */
585
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
586

    
587
		if (!empty($bridge['stp'])) {
588
			$stpifs = explode(',', $bridge['stp']);
589
			foreach ($stpifs as $stpif) {
590
				$realif = get_real_interface($stpif);
591
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
592
			}
593
		}
594
		if (!empty($bridge['maxage'])) {
595
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
596
		}
597
		if (!empty($bridge['fwdelay'])) {
598
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
599
		}
600
		if (!empty($bridge['hellotime'])) {
601
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
602
		}
603
		if (!empty($bridge['priority'])) {
604
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
605
		}
606
		if (!empty($bridge['holdcnt'])) {
607
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
608
		}
609
		if (!empty($bridge['ifpriority'])) {
610
			$pconfig = explode(",", $bridge['ifpriority']);
611
			$ifpriority = array();
612
			foreach ($pconfig as $cfg) {
613
				$embcfg = explode_assoc(":", $cfg);
614
				foreach ($embcfg as $key => $value) {
615
					$ifpriority[$key] = $value;
616
				}
617
			}
618
			foreach ($ifpriority as $key => $value) {
619
				$realif = get_real_interface($key);
620
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
621
			}
622
		}
623
		if (!empty($bridge['ifpathcost'])) {
624
			$pconfig = explode(",", $bridge['ifpathcost']);
625
			$ifpathcost = array();
626
			foreach ($pconfig as $cfg) {
627
				$embcfg = explode_assoc(":", $cfg);
628
				foreach ($embcfg as $key => $value) {
629
					$ifpathcost[$key] = $value;
630
				}
631
			}
632
			foreach ($ifpathcost as $key => $value) {
633
				$realif = get_real_interface($key);
634
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
635
			}
636
		}
637
	}
638
}
639

    
640
function interface_bridge_configure_advanced($bridge) {
641
	$bridgeif = $bridge['bridgeif'];
642

    
643
	if ($bridge['maxaddr'] <> "") {
644
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
645
	}
646
	if ($bridge['timeout'] <> "") {
647
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
648
	}
649
	if (!empty($bridge['span'])) {
650
		$spanifs = explode(",", $bridge['span']);
651
		foreach ($spanifs as $spanif) {
652
			$realif = get_real_interface($spanif);
653
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
654
		}
655
	}
656
	if (!empty($bridge['edge'])) {
657
		$edgeifs = explode(',', $bridge['edge']);
658
		foreach ($edgeifs as $edgeif) {
659
			$realif = get_real_interface($edgeif);
660
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
661
		}
662
	}
663
	if (!empty($bridge['autoedge'])) {
664
		$edgeifs = explode(',', $bridge['autoedge']);
665
		foreach ($edgeifs as $edgeif) {
666
			$realif = get_real_interface($edgeif);
667
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
668
		}
669
	}
670
	if (!empty($bridge['ptp'])) {
671
		$ptpifs = explode(',', $bridge['ptp']);
672
		foreach ($ptpifs as $ptpif) {
673
			$realif = get_real_interface($ptpif);
674
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
675
		}
676
	}
677
	if (!empty($bridge['autoptp'])) {
678
		$ptpifs = explode(',', $bridge['autoptp']);
679
		foreach ($ptpifs as $ptpif) {
680
			$realif = get_real_interface($ptpif);
681
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
682
		}
683
	}
684
	if (!empty($bridge['static'])) {
685
		$stickyifs = explode(',', $bridge['static']);
686
		foreach ($stickyifs as $stickyif) {
687
			$realif = get_real_interface($stickyif);
688
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
689
		}
690
	}
691
	if (!empty($bridge['private'])) {
692
		$privateifs = explode(',', $bridge['private']);
693
		foreach ($privateifs as $privateif) {
694
			$realif = get_real_interface($privateif);
695
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
696
		}
697
	}
698
}
699

    
700
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
701
	global $config;
702

    
703
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
704
		return;
705
	}
706

    
707
	if ($flagsapplied == false) {
708
		$mtu = get_interface_mtu($bridgeif);
709
		$mtum = get_interface_mtu($interface);
710
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
711
			pfSense_interface_mtu($interface, $mtu);
712
		}
713

    
714
		hardware_offloading_applyflags($interface);
715
		interfaces_bring_up($interface);
716
	}
717

    
718
	pfSense_bridge_add_member($bridgeif, $interface);
719
	if (is_array($config['bridges']['bridged'])) {
720
		foreach ($config['bridges']['bridged'] as $bridge) {
721
			if ($bridgeif == $bridge['bridgeif']) {
722
				interface_bridge_configure_stp($bridge);
723
				interface_bridge_configure_advanced($bridge);
724
			}
725
		}
726
	}
727
}
728

    
729
function interfaces_lagg_configure($realif = "") {
730
	global $config, $g;
731
	if (platform_booting()) {
732
		echo gettext("Configuring LAGG interfaces...");
733
	}
734
	$i = 0;
735
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
736
		foreach ($config['laggs']['lagg'] as $lagg) {
737
			if (empty($lagg['laggif'])) {
738
				$lagg['laggif'] = "lagg{$i}";
739
			}
740
			if (!empty($realif) && $realif != $lagg['laggif']) {
741
				continue;
742
			}
743
			/* XXX: Maybe we should report any errors?! */
744
			interface_lagg_configure($lagg);
745
			$i++;
746
		}
747
	}
748
	if (platform_booting()) {
749
		echo gettext("done.") . "\n";
750
	}
751
}
752

    
753
function interface_lagg_configure($lagg) {
754
	global $config, $g;
755

    
756
	if (!is_array($lagg)) {
757
		return -1;
758
	}
759

    
760
	$members = explode(',', $lagg['members']);
761
	if (!count($members)) {
762
		return -1;
763
	}
764

    
765
	if (platform_booting() || !(empty($lagg['laggif']))) {
766
		pfSense_interface_destroy($lagg['laggif']);
767
		pfSense_interface_create($lagg['laggif']);
768
		$laggif = $lagg['laggif'];
769
	} else {
770
		$laggif = pfSense_interface_create("lagg");
771
	}
772

    
773
	/* Check if MTU was defined for this lagg interface */
774
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
775
	
776
	if ($lagg_mtu == 0 &&
777
	    is_array($config['interfaces'])) {
778
		foreach ($config['interfaces'] as $tmpinterface) {
779
			if ($tmpinterface['if'] == $lagg['laggif'] &&
780
			    !empty($tmpinterface['mtu'])) {
781
				$lagg_mtu = $tmpinterface['mtu'];
782
				break;
783
			}
784
		}
785
	}
786
	
787
	/* Just in case anything is not working well */
788
	if ($lagg_mtu == 0) {
789
		$lagg_mtu = 1500;
790
	}
791

    
792
	foreach ($members as $member) {
793
		if (!does_interface_exist($member)) {
794
			continue;
795
		}
796
		/* make sure the parent interface is up */
797
		pfSense_interface_mtu($member, $lagg_mtu);
798
		interfaces_bring_up($member);
799
		hardware_offloading_applyflags($member);
800
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
801
	}
802
	pfSense_interface_capabilities($laggif, -$flags_off);
803
	pfSense_interface_capabilities($laggif, $flags_on);
804

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

    
807
	interfaces_bring_up($laggif);
808

    
809
	return $laggif;
810
}
811

    
812
function interfaces_gre_configure($checkparent = 0, $realif = "") {
813
	global $config;
814

    
815
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
816
		foreach ($config['gres']['gre'] as $i => $gre) {
817
			if (empty($gre['greif'])) {
818
				$gre['greif'] = "gre{$i}";
819
			}
820
			if (!empty($realif) && $realif != $gre['greif']) {
821
				continue;
822
			}
823

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

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

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

    
854
	$realif = get_real_interface($gre['if']);
855
	$realifip = get_interface_ip($gre['if']);
856
	$realifip6 = get_interface_ipv6($gre['if']);
857

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

    
861
	if (platform_booting() || !(empty($gre['greif']))) {
862
		pfSense_interface_destroy($gre['greif']);
863
		pfSense_interface_create($gre['greif']);
864
		$greif = $gre['greif'];
865
	} else {
866
		$greif = pfSense_interface_create("gre");
867
	}
868

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

    
892
	if ($greif) {
893
		interfaces_bring_up($greif);
894
	} else {
895
		log_error(gettext("Could not bring greif up -- variable not defined."));
896
	}
897

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

    
908
	interfaces_bring_up($greif);
909

    
910
	return $greif;
911
}
912

    
913
function interfaces_gif_configure($checkparent = 0, $realif = "") {
914
	global $config;
915

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

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

    
948
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
949
function interface_gif_configure(&$gif, $gifkey = "") {
950
	global $config, $g;
951

    
952
	if (!is_array($gif)) {
953
		return -1;
954
	}
955

    
956
	$realif = get_real_interface($gif['if']);
957
	$ipaddr = get_interface_ip($gif['if']);
958

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

    
981
	if (platform_booting() || !(empty($gif['gifif']))) {
982
		pfSense_interface_destroy($gif['gifif']);
983
		pfSense_interface_create($gif['gifif']);
984
		$gifif = $gif['gifif'];
985
	} else {
986
		$gifif = pfSense_interface_create("gif");
987
	}
988

    
989
	/* Do not change the order here for more see gif(4) NOTES section. */
990
	if (is_ipaddrv6($gif['remote-addr'])) {
991
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
992
	} else {
993
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
994
	}
995
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
996
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
997
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
998
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
999
	} else {
1000
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1001
	}
1002
	if (isset($gif['link0'])) {
1003
		pfSense_interface_flags($gifif, IFF_LINK0);
1004
	}
1005
	if (isset($gif['link1'])) {
1006
		pfSense_interface_flags($gifif, IFF_LINK1);
1007
	}
1008
	if ($gifif) {
1009
		interfaces_bring_up($gifif);
1010
		$gifmtu = "";
1011
		$currentgifmtu = get_interface_mtu($gifif);
1012
		foreach ($config['interfaces'] as $tmpinterface) {
1013
			if ($tmpinterface['if'] == $gifif) {
1014
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1015
					$gifmtu = $tmpinterface['mtu'];
1016
				}
1017
			}
1018
		}
1019
		if (is_numericint($gifmtu)) {
1020
			if ($gifmtu != $currentgifmtu) {
1021
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1022
			}
1023
		}
1024
	} else {
1025
		log_error(gettext("could not bring gifif up -- variable not defined"));
1026
	}
1027

    
1028
	if (!platform_booting()) {
1029
		$iflist = get_configured_interface_list();
1030
		foreach ($iflist as $ifname) {
1031
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1032
				if (get_interface_gateway($ifname)) {
1033
					system_routing_configure($ifname);
1034
					break;
1035
				}
1036
				if (get_interface_gateway_v6($ifname)) {
1037
					system_routing_configure($ifname);
1038
					break;
1039
				}
1040
			}
1041
		}
1042
	}
1043

    
1044

    
1045
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1046
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1047
	}
1048
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1049
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1050
	}
1051

    
1052
	if (is_ipaddrv4($realifgw)) {
1053
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1054
	}
1055
	if (is_ipaddrv6($realifgw)) {
1056
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1057
	}
1058

    
1059
	interfaces_bring_up($gifif);
1060

    
1061
	return $gifif;
1062
}
1063

    
1064
function interfaces_configure() {
1065
	global $config, $g;
1066

    
1067
	/* Set up our loopback interface */
1068
	interfaces_loopback_configure();
1069

    
1070
	/* create the unconfigured wireless clones */
1071
	interfaces_create_wireless_clones();
1072

    
1073
	/* set up LAGG virtual interfaces */
1074
	interfaces_lagg_configure();
1075

    
1076
	/* set up VLAN virtual interfaces */
1077
	interfaces_vlan_configure();
1078

    
1079
	interfaces_qinq_configure();
1080

    
1081
	$iflist = get_configured_interface_with_descr();
1082
	$delayed_list = array();
1083
	$bridge_list = array();
1084
	$track6_list = array();
1085

    
1086
	/* This is needed to speedup interfaces on bootup. */
1087
	$reload = false;
1088
	if (!platform_booting()) {
1089
		$reload = true;
1090
	}
1091

    
1092
	foreach ($iflist as $if => $ifname) {
1093
		$realif = $config['interfaces'][$if]['if'];
1094
		if (strstr($realif, "bridge")) {
1095
			$bridge_list[$if] = $ifname;
1096
		} else if (strstr($realif, "gre")) {
1097
			$delayed_list[$if] = $ifname;
1098
		} else if (strstr($realif, "gif")) {
1099
			$delayed_list[$if] = $ifname;
1100
		} else if (strstr($realif, "ovpn")) {
1101
			//echo "Delaying OpenVPN interface configuration...done.\n";
1102
			continue;
1103
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1104
			$track6_list[$if] = $ifname;
1105
		} else {
1106
			if (platform_booting()) {
1107
				printf(gettext("Configuring %s interface..."), $ifname);
1108
			}
1109

    
1110
			if ($g['debug']) {
1111
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1112
			}
1113
			interface_configure($if, $reload);
1114
			if (platform_booting()) {
1115
				echo gettext("done.") . "\n";
1116
			}
1117
		}
1118
	}
1119

    
1120
	/*
1121
	 * NOTE: The following function parameter consists of
1122
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1123
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1124
	 */
1125

    
1126
	/* set up GRE virtual interfaces */
1127
	interfaces_gre_configure(1);
1128

    
1129
	/* set up GIF virtual interfaces */
1130
	interfaces_gif_configure(1);
1131

    
1132
	/* set up BRIDGe virtual interfaces */
1133
	interfaces_bridge_configure(1);
1134

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

    
1143
		interface_configure($if, $reload);
1144

    
1145
		if (platform_booting()) {
1146
			echo gettext("done.") . "\n";
1147
		}
1148
	}
1149

    
1150
	/* bring up vip interfaces */
1151
	interfaces_vips_configure();
1152

    
1153
	/* set up GRE virtual interfaces */
1154
	interfaces_gre_configure(2);
1155

    
1156
	/* set up GIF virtual interfaces */
1157
	interfaces_gif_configure(2);
1158

    
1159
	foreach ($delayed_list as $if => $ifname) {
1160
		if (platform_booting()) {
1161
			printf(gettext("Configuring %s interface..."), $ifname);
1162
		}
1163
		if ($g['debug']) {
1164
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1165
		}
1166

    
1167
		interface_configure($if, $reload);
1168

    
1169
		if (platform_booting()) {
1170
			echo gettext("done.") . "\n";
1171
		}
1172
	}
1173

    
1174
	/* set up BRIDGe virtual interfaces */
1175
	interfaces_bridge_configure(2);
1176

    
1177
	foreach ($bridge_list as $if => $ifname) {
1178
		if (platform_booting()) {
1179
			printf(gettext("Configuring %s interface..."), $ifname);
1180
		}
1181
		if ($g['debug']) {
1182
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1183
		}
1184

    
1185
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct. 
1186
		// redmine #3997
1187
		interface_reconfigure($if, $reload);
1188
		interfaces_vips_configure($if);
1189

    
1190
		if (platform_booting()) {
1191
			echo gettext("done.") . "\n";
1192
		}
1193
	}
1194

    
1195
	/* configure interface groups */
1196
	interfaces_group_setup();
1197

    
1198
	if (!platform_booting()) {
1199
		/* reconfigure static routes (kernel may have deleted them) */
1200
		system_routing_configure();
1201

    
1202
		/* reload IPsec tunnels */
1203
		vpn_ipsec_configure();
1204

    
1205
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1206
		services_dhcpd_configure();
1207

    
1208
		/* restart dnsmasq or unbound */
1209
		if (isset($config['dnsmasq']['enable'])) {
1210
			services_dnsmasq_configure();
1211
		} elseif (isset($config['unbound']['enable'])) {
1212
			services_unbound_configure();
1213
		}
1214
	}
1215

    
1216
	return 0;
1217
}
1218

    
1219
function interface_reconfigure($interface = "wan", $reloadall = false) {
1220
	interface_bring_down($interface);
1221
	interface_configure($interface, $reloadall);
1222
}
1223

    
1224
function interface_vip_bring_down($vip) {
1225
	global $g;
1226

    
1227
	$vipif = get_real_interface($vip['interface']);
1228
	switch ($vip['mode']) {
1229
		case "proxyarp":
1230
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1231
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1232
			}
1233
			break;
1234
		case "ipalias":
1235
			if (does_interface_exist($vipif)) {
1236
				if (is_ipaddrv6($vip['subnet'])) {
1237
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1238
				} else {
1239
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1240
				}
1241
			}
1242
			break;
1243
		case "carp":
1244
			/* XXX: Is enough to delete ip address? */
1245
			if (does_interface_exist($vipif)) {
1246
				if (is_ipaddrv6($vip['subnet'])) {
1247
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1248
				} else {
1249
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1250
				}
1251
			}
1252
			break;
1253
	}
1254
}
1255

    
1256
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1257
	global $config, $g;
1258

    
1259
	if (!isset($config['interfaces'][$interface])) {
1260
		return;
1261
	}
1262

    
1263
	if ($g['debug']) {
1264
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1265
	}
1266

    
1267
	/*
1268
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1269
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1270
	 * Keep this in mind while doing changes here!
1271
	 */
1272
	if ($ifacecfg === false) {
1273
		$ifcfg = $config['interfaces'][$interface];
1274
		$ppps = $config['ppps']['ppp'];
1275
		$realif = get_real_interface($interface);
1276
		$realifv6 = get_real_interface($interface, "inet6", true);
1277
	} elseif (!is_array($ifacecfg)) {
1278
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1279
		$ifcfg = $config['interfaces'][$interface];
1280
		$ppps = $config['ppps']['ppp'];
1281
		$realif = get_real_interface($interface);
1282
		$realifv6 = get_real_interface($interface, "inet6", true);
1283
	} else {
1284
		$ifcfg = $ifacecfg['ifcfg'];
1285
		$ppps = $ifacecfg['ppps'];
1286
		if (isset($ifacecfg['ifcfg']['realif'])) {
1287
			$realif = $ifacecfg['ifcfg']['realif'];
1288
			/* XXX: Any better way? */
1289
			$realifv6 = $realif;
1290
		} else {
1291
			$realif = get_real_interface($interface);
1292
			$realifv6 = get_real_interface($interface, "inet6", true);
1293
		}
1294
	}
1295

    
1296
	switch ($ifcfg['ipaddr']) {
1297
		case "ppp":
1298
		case "pppoe":
1299
		case "pptp":
1300
		case "l2tp":
1301
			if (is_array($ppps) && count($ppps)) {
1302
				foreach ($ppps as $pppid => $ppp) {
1303
					if ($realif == $ppp['if']) {
1304
						if (isset($ppp['ondemand']) && !$destroy) {
1305
							send_event("interface reconfigure {$interface}");
1306
							break;
1307
						}
1308
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1309
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1310
							sleep(2);
1311
						}
1312
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1313
						break;
1314
					}
1315
				}
1316
			}
1317
			break;
1318
		case "dhcp":
1319
			kill_dhclient_process($realif);
1320
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1321
			if (does_interface_exist("$realif")) {
1322
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1323
				interface_vip_cleanup($interface, "inet4");
1324
				if ($destroy == true) {
1325
					pfSense_interface_flags($realif, -IFF_UP);
1326
				}
1327
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1328
			}
1329
			break;
1330
		default:
1331
			if (does_interface_exist("$realif")) {
1332
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1333
				interface_vip_cleanup($interface, "inet4");
1334
				if ($destroy == true) {
1335
					pfSense_interface_flags($realif, -IFF_UP);
1336
				}
1337
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1338
			}
1339
			break;
1340
	}
1341

    
1342
	$track6 = array();
1343
	switch ($ifcfg['ipaddrv6']) {
1344
		case "slaac":
1345
		case "dhcp6":
1346
			$pidv6 = find_dhcp6c_process($realif);
1347
			if ($pidv6) {
1348
				posix_kill($pidv6, SIGTERM);
1349
			}
1350
			sleep(3);
1351
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1352
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1353
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1354
			if (does_interface_exist($realifv6)) {
1355
				$ip6 = find_interface_ipv6($realifv6);
1356
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1357
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1358
				}
1359
				interface_vip_cleanup($interface, "inet6");
1360
				if ($destroy == true) {
1361
					pfSense_interface_flags($realif, -IFF_UP);
1362
				}
1363
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1364
			}
1365
			$track6 = link_interface_to_track6($interface);
1366
			break;
1367
		case "6rd":
1368
		case "6to4":
1369
			$realif = "{$interface}_stf";
1370
			if (does_interface_exist("$realif")) {
1371
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1372
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1373
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1374
					$destroy = true;
1375
				} else {
1376
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1377
					$ip6 = get_interface_ipv6($interface);
1378
					if (is_ipaddrv6($ip6)) {
1379
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1380
					}
1381
				}
1382
				interface_vip_cleanup($interface, "inet6");
1383
				if ($destroy == true) {
1384
					pfSense_interface_flags($realif, -IFF_UP);
1385
				}
1386
			}
1387
			$track6 = link_interface_to_track6($interface);
1388
			break;
1389
		default:
1390
			if (does_interface_exist("$realif")) {
1391
				$ip6 = get_interface_ipv6($interface);
1392
				if (is_ipaddrv6($ip6)) {
1393
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1394
				}
1395
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1396
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1397
				}
1398
				interface_vip_cleanup($interface, "inet6");
1399
				if ($destroy == true) {
1400
					pfSense_interface_flags($realif, -IFF_UP);
1401
				}
1402
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1403
			}
1404
			$track6 = link_interface_to_track6($interface);
1405
			break;
1406
	}
1407

    
1408
	if (!empty($track6) && is_array($track6)) {
1409
		if (!function_exists('services_dhcpd_configure')) {
1410
			require_once('services.inc');
1411
		}
1412
		/* Bring down radvd and dhcp6 on these interfaces */
1413
		services_dhcpd_configure('inet6', $track6);
1414
	}
1415

    
1416
	$old_router = '';
1417
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1418
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1419
	}
1420

    
1421
	/* remove interface up file if it exists */
1422
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1423
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1424
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1425
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1426
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1427
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1428
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1429

    
1430
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1431
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1432
	if (is_array($ifcfg['wireless'])) {
1433
		kill_hostapd($realif);
1434
		mwexec(kill_wpasupplicant($realif));
1435
	}
1436

    
1437
	if ($destroy == true) {
1438
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1439
			pfSense_interface_destroy($realif);
1440
		}
1441
	}
1442

    
1443
	return;
1444
}
1445

    
1446
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1447
	global $config;
1448
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1449
		unset($config["virtualip_carp_maintenancemode"]);
1450
		write_config("Leave CARP maintenance mode");
1451
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1452
		$config["virtualip_carp_maintenancemode"] = true;
1453
		write_config(gettext("Enter CARP maintenance mode"));
1454
	}
1455

    
1456
	$viparr = &$config['virtualip']['vip'];
1457
	foreach ($viparr as $vip) {
1458
		if ($vip['mode'] == "carp") {
1459
			interface_carp_configure($vip);
1460
		}
1461
	}
1462
}
1463

    
1464
function interface_isppp_type($interface) {
1465
	global $config;
1466

    
1467
	if (!is_array($config['interfaces'][$interface])) {
1468
		return false;
1469
	}
1470

    
1471
	switch ($config['interfaces'][$interface]['ipaddr']) {
1472
		case 'pptp':
1473
		case 'l2tp':
1474
		case 'pppoe':
1475
		case 'ppp':
1476
			return true;
1477
			break;
1478
		default:
1479
			return false;
1480
			break;
1481
	}
1482
}
1483

    
1484
function interfaces_ptpid_used($ptpid) {
1485
	global $config;
1486

    
1487
	if (is_array($config['ppps']['ppp'])) {
1488
		foreach ($config['ppps']['ppp'] as & $settings) {
1489
			if ($ptpid == $settings['ptpid']) {
1490
				return true;
1491
			}
1492
		}
1493
	}
1494

    
1495
	return false;
1496
}
1497

    
1498
function interfaces_ptpid_next() {
1499

    
1500
	$ptpid = 0;
1501
	while (interfaces_ptpid_used($ptpid)) {
1502
		$ptpid++;
1503
	}
1504

    
1505
	return $ptpid;
1506
}
1507

    
1508
function getMPDCRONSettings($pppif) {
1509
	global $config;
1510

    
1511
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1512
	if (is_array($config['cron']['item'])) {
1513
		foreach ($config['cron']['item'] as $i => $item) {
1514
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1515
				return array("ID" => $i, "ITEM" => $item);
1516
			}
1517
		}
1518
	}
1519

    
1520
	return NULL;
1521
}
1522

    
1523
function handle_pppoe_reset($post_array) {
1524
	global $config, $g;
1525

    
1526
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1527
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1528

    
1529
	if (!is_array($config['cron']['item'])) {
1530
		$config['cron']['item'] = array();
1531
	}
1532

    
1533
	$itemhash = getMPDCRONSettings($pppif);
1534

    
1535
	// reset cron items if necessary and return
1536
	if (empty($post_array['pppoe-reset-type'])) {
1537
		if (isset($itemhash)) {
1538
			unset($config['cron']['item'][$itemhash['ID']]);
1539
		}
1540
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1541
		return;
1542
	}
1543

    
1544
	if (empty($itemhash)) {
1545
		$itemhash = array();
1546
	}
1547
	$item = array();
1548
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1549
		$item['minute'] = $post_array['pppoe_resetminute'];
1550
		$item['hour'] = $post_array['pppoe_resethour'];
1551
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1552
			$date = explode("/", $post_array['pppoe_resetdate']);
1553
			$item['mday'] = $date[1];
1554
			$item['month'] = $date[0];
1555
		} else {
1556
			$item['mday'] = "*";
1557
			$item['month'] = "*";
1558
		}
1559
		$item['wday'] = "*";
1560
		$item['who'] = "root";
1561
		$item['command'] = $cron_cmd_file;
1562
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1563
		switch ($post_array['pppoe_pr_preset_val']) {
1564
			case "monthly":
1565
				$item['minute'] = "0";
1566
				$item['hour'] = "0";
1567
				$item['mday'] = "1";
1568
				$item['month'] = "*";
1569
				$item['wday'] = "*";
1570
				break;
1571
			case "weekly":
1572
				$item['minute'] = "0";
1573
				$item['hour'] = "0";
1574
				$item['mday'] = "*";
1575
				$item['month'] = "*";
1576
				$item['wday'] = "0";
1577
				break;
1578
			case "daily":
1579
				$item['minute'] = "0";
1580
				$item['hour'] = "0";
1581
				$item['mday'] = "*";
1582
				$item['month'] = "*";
1583
				$item['wday'] = "*";
1584
				break;
1585
			case "hourly":
1586
				$item['minute'] = "0";
1587
				$item['hour'] = "*";
1588
				$item['mday'] = "*";
1589
				$item['month'] = "*";
1590
				$item['wday'] = "*";
1591
				break;
1592
		} // end switch
1593
		$item['who'] = "root";
1594
		$item['command'] = $cron_cmd_file;
1595
	}
1596
	if (empty($item)) {
1597
		return;
1598
	}
1599
	if (isset($itemhash['ID'])) {
1600
		$config['cron']['item'][$itemhash['ID']] = $item;
1601
	} else {
1602
		$config['cron']['item'][] = $item;
1603
	}
1604
}
1605

    
1606
/*
1607
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1608
 * It writes the mpd config file to /var/etc every time the link is opened.
1609
 */
1610
function interface_ppps_configure($interface) {
1611
	global $config, $g;
1612

    
1613
	/* Return for unassigned interfaces. This is a minimum requirement. */
1614
	if (empty($config['interfaces'][$interface])) {
1615
		return 0;
1616
	}
1617
	$ifcfg = $config['interfaces'][$interface];
1618
	if (!isset($ifcfg['enable'])) {
1619
		return 0;
1620
	}
1621

    
1622
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1623
	if (!is_dir("/var/spool/lock")) {
1624
		mkdir("/var/spool/lock", 0777, true);
1625
	}
1626
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1627
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1628
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1629
	}
1630

    
1631
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1632
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1633
			if ($ifcfg['if'] == $ppp['if']) {
1634
				break;
1635
			}
1636
		}
1637
	}
1638
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
1639
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1640
		return 0;
1641
	}
1642
	$pppif = $ifcfg['if'];
1643
	if ($ppp['type'] == "ppp") {
1644
		$type = "modem";
1645
	} else {
1646
		$type = $ppp['type'];
1647
	}
1648
	$upper_type = strtoupper($ppp['type']);
1649

    
1650
	/* XXX: This does not make sense and may create trouble
1651
	 * comment it for now to be removed later on.
1652
	if (platform_booting()) {
1653
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1654
		echo "starting {$pppif} link...";
1655
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1656
			return 0;
1657
	}
1658
	*/
1659

    
1660
	$ports = explode(',', $ppp['ports']);
1661
	if ($type != "modem") {
1662
		foreach ($ports as $pid => $port) {
1663
			$ports[$pid] = get_real_interface($port);
1664
			if (empty($ports[$pid])) {
1665
				return 0;
1666
			}
1667
		}
1668
	}
1669
	$localips = explode(',', $ppp['localip']);
1670
	$gateways = explode(',', $ppp['gateway']);
1671
	$subnets = explode(',', $ppp['subnet']);
1672

    
1673
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1674
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1675
	 */
1676
	foreach ($ports as $pid => $port) {
1677
		switch ($ppp['type']) {
1678
			case "pppoe":
1679
				/* Bring the parent interface up */
1680
				interfaces_bring_up($port);
1681
				pfSense_ngctl_attach(".", $port);
1682
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1683
				mwexec("/usr/sbin/ngctl msg {$port}: setautosrc 1");
1684
				break;
1685
			case "pptp":
1686
			case "l2tp":
1687
				/* configure interface */
1688
				if (is_ipaddr($localips[$pid])) {
1689
					// Manually configure interface IP/subnet
1690
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1691
					interfaces_bring_up($port);
1692
				} else if (empty($localips[$pid])) {
1693
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1694
				}
1695

    
1696
				if (!is_ipaddr($localips[$pid])) {
1697
					log_error(sprintf(gettext("Could not get a Local IP address for PPTP/L2TP link on %s in interfaces_ppps_configure. Using 0.0.0.0 ip!"), $port));
1698
					$localips[$pid] = "0.0.0.0";
1699
				}
1700
				if (!is_ipaddr($gateways[$pid])) {
1701
					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));
1702
					return 0;
1703
				}
1704
				pfSense_ngctl_attach(".", $port);
1705
				break;
1706
			case "ppp":
1707
				if (!file_exists("{$port}")) {
1708
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1709
					return 0;
1710
				}
1711
				break;
1712
			default:
1713
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1714
				break;
1715
		}
1716
	}
1717

    
1718
	if (is_array($ports) && count($ports) > 1) {
1719
		$multilink = "enable";
1720
	} else {
1721
		$multilink = "disable";
1722
	}
1723

    
1724
	if ($type == "modem") {
1725
		if (is_ipaddr($ppp['localip'])) {
1726
			$localip = $ppp['localip'];
1727
		} else {
1728
			$localip = '0.0.0.0';
1729
		}
1730

    
1731
		if (is_ipaddr($ppp['gateway'])) {
1732
			$gateway = $ppp['gateway'];
1733
		} else {
1734
			$gateway = "10.64.64.{$pppid}";
1735
		}
1736
		$ranges = "{$localip}/0 {$gateway}/0";
1737

    
1738
		if (empty($ppp['apnum'])) {
1739
			$ppp['apnum'] = 1;
1740
		}
1741
	} else {
1742
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1743
	}
1744

    
1745
	if (isset($ppp['ondemand'])) {
1746
		$ondemand = "enable";
1747
	} else {
1748
		$ondemand = "disable";
1749
	}
1750
	if (!isset($ppp['idletimeout'])) {
1751
		$ppp['idletimeout'] = 0;
1752
	}
1753

    
1754
	if (empty($ppp['username']) && $type == "modem") {
1755
		$ppp['username'] = "user";
1756
		$ppp['password'] = "none";
1757
	}
1758
	if (empty($ppp['password']) && $type == "modem") {
1759
		$passwd = "none";
1760
	} else {
1761
		$passwd = base64_decode($ppp['password']);
1762
	}
1763

    
1764
	$bandwidths = explode(',', $ppp['bandwidth']);
1765
	$defaultmtu = "1492";
1766
	if (!empty($ifcfg['mtu'])) {
1767
		$defaultmtu = intval($ifcfg['mtu']);
1768
	}
1769
	if (isset($ppp['mtu'])) {
1770
		$mtus = explode(',', $ppp['mtu']);
1771
	}
1772
	if (isset($ppp['mru'])) {
1773
		$mrus = explode(',', $ppp['mru']);
1774
	}
1775
	if (isset($ppp['mrru'])) {
1776
		$mrrus = explode(',', $ppp['mrru']);
1777
	}
1778

    
1779
	// Construct the mpd.conf file
1780
	$mpdconf = <<<EOD
1781
startup:
1782
	# configure the console
1783
	set console close
1784
	# configure the web server
1785
	set web close
1786

    
1787
default:
1788
{$ppp['type']}client:
1789
	create bundle static {$interface}
1790
	set bundle enable ipv6cp
1791
	set iface name {$pppif}
1792

    
1793
EOD;
1794
	$setdefaultgw = false;
1795
	$founddefaultgw = false;
1796
	if (is_array($config['gateways']['gateway_item'])) {
1797
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1798
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1799
				$setdefaultgw = true;
1800
				break;
1801
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1802
				$founddefaultgw = true;
1803
				break;
1804
			}
1805
		}
1806
	}
1807

    
1808
/* Omit this, we maintain the default route by other means, and it causes problems with
1809
 * default gateway switching. See redmine #1837
1810
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1811
		$setdefaultgw = true;
1812
		$mpdconf .= <<<EOD
1813
	set iface route default
1814

    
1815
EOD;
1816
	}
1817
*/
1818
	$mpdconf .= <<<EOD
1819
	set iface {$ondemand} on-demand
1820
	set iface idle {$ppp['idletimeout']}
1821

    
1822
EOD;
1823

    
1824
	if (isset($ppp['ondemand'])) {
1825
		$mpdconf .= <<<EOD
1826
	set iface addrs 10.10.1.1 10.10.1.2
1827

    
1828
EOD;
1829
	}
1830

    
1831
	if (isset($ppp['tcpmssfix'])) {
1832
		$tcpmss = "disable";
1833
	} else {
1834
		$tcpmss = "enable";
1835
	}
1836
	$mpdconf .= <<<EOD
1837
	set iface {$tcpmss} tcpmssfix
1838

    
1839
EOD;
1840

    
1841
	$mpdconf .= <<<EOD
1842
	set iface up-script /usr/local/sbin/ppp-linkup
1843
	set iface down-script /usr/local/sbin/ppp-linkdown
1844
	set ipcp ranges {$ranges}
1845

    
1846
EOD;
1847
	if (isset($ppp['vjcomp'])) {
1848
		$mpdconf .= <<<EOD
1849
	set ipcp no vjcomp
1850

    
1851
EOD;
1852
	}
1853

    
1854
	if (isset($config['system']['dnsallowoverride'])) {
1855
		$mpdconf .= <<<EOD
1856
	set ipcp enable req-pri-dns
1857
	set ipcp enable req-sec-dns
1858

    
1859
EOD;
1860
	}
1861

    
1862
	if (!isset($ppp['verbose_log'])) {
1863
		$mpdconf .= <<<EOD
1864
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1865

    
1866
EOD;
1867
	}
1868

    
1869
	foreach ($ports as $pid => $port) {
1870
		$port = get_real_interface($port);
1871
		$mpdconf .= <<<EOD
1872

    
1873
	create link static {$interface}_link{$pid} {$type}
1874
	set link action bundle {$interface}
1875
	set link {$multilink} multilink
1876
	set link keep-alive 10 60
1877
	set link max-redial 0
1878

    
1879
EOD;
1880
		if (isset($ppp['shortseq'])) {
1881
			$mpdconf .= <<<EOD
1882
	set link no shortseq
1883

    
1884
EOD;
1885
		}
1886

    
1887
		if (isset($ppp['acfcomp'])) {
1888
			$mpdconf .= <<<EOD
1889
	set link no acfcomp
1890

    
1891
EOD;
1892
		}
1893

    
1894
		if (isset($ppp['protocomp'])) {
1895
			$mpdconf .= <<<EOD
1896
	set link no protocomp
1897

    
1898
EOD;
1899
		}
1900

    
1901
		$mpdconf .= <<<EOD
1902
	set link disable chap pap
1903
	set link accept chap pap eap
1904
	set link disable incoming
1905

    
1906
EOD;
1907

    
1908

    
1909
		if (!empty($bandwidths[$pid])) {
1910
			$mpdconf .= <<<EOD
1911
	set link bandwidth {$bandwidths[$pid]}
1912

    
1913
EOD;
1914
		}
1915

    
1916
		if (empty($mtus[$pid])) {
1917
			$mtus[$pid] = $defaultmtu;
1918
		}
1919
		if ($type == "pppoe") {
1920
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
1921
				$mtus[$pid] = get_interface_mtu($port) - 8;
1922
			}
1923
		}
1924
		if (! ($type == "pppoe" && $mtus[$pid] > 1492) ) {
1925
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
1926
			$mpdconf .= <<<EOD
1927
	set link mtu {$mtus[$pid]}
1928

    
1929
EOD;
1930
		}
1931

    
1932
		if (!empty($mrus[$pid])) {
1933
			$mpdconf .= <<<EOD
1934
	set link mru {$mrus[$pid]}
1935

    
1936
EOD;
1937
		}
1938

    
1939
		if (!empty($mrrus[$pid])) {
1940
			$mpdconf .= <<<EOD
1941
	set link mrru {$mrrus[$pid]}
1942

    
1943
EOD;
1944
		}
1945

    
1946
		$mpdconf .= <<<EOD
1947
	set auth authname "{$ppp['username']}"
1948
	set auth password {$passwd}
1949

    
1950
EOD;
1951
		if ($type == "modem") {
1952
			$mpdconf .= <<<EOD
1953
	set modem device {$ppp['ports']}
1954
	set modem script DialPeer
1955
	set modem idle-script Ringback
1956
	set modem watch -cd
1957
	set modem var \$DialPrefix "DT"
1958
	set modem var \$Telephone "{$ppp['phone']}"
1959

    
1960
EOD;
1961
		}
1962
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1963
			$mpdconf .= <<<EOD
1964
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1965

    
1966
EOD;
1967
		}
1968
		if (isset($ppp['initstr']) && $type == "modem") {
1969
			$initstr = base64_decode($ppp['initstr']);
1970
			$mpdconf .= <<<EOD
1971
	set modem var \$InitString "{$initstr}"
1972

    
1973
EOD;
1974
		}
1975
		if (isset($ppp['simpin']) && $type == "modem") {
1976
			if ($ppp['pin-wait'] == "") {
1977
				$ppp['pin-wait'] = 0;
1978
			}
1979
			$mpdconf .= <<<EOD
1980
	set modem var \$SimPin "{$ppp['simpin']}"
1981
	set modem var \$PinWait "{$ppp['pin-wait']}"
1982

    
1983
EOD;
1984
		}
1985
		if (isset($ppp['apn']) && $type == "modem") {
1986
			$mpdconf .= <<<EOD
1987
	set modem var \$APN "{$ppp['apn']}"
1988
	set modem var \$APNum "{$ppp['apnum']}"
1989

    
1990
EOD;
1991
		}
1992
		if ($type == "pppoe") {
1993
			// Send a null service name if none is set.
1994
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1995
			$mpdconf .= <<<EOD
1996
	set pppoe service "{$provider}"
1997

    
1998
EOD;
1999
		}
2000
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
2001
			$mpdconf .= <<<EOD
2002
	set pppoe max-payload {$mtus[$pid]}
2003

    
2004
EOD;
2005
		}
2006
		if ($type == "pppoe") {
2007
			$mpdconf .= <<<EOD
2008
	set pppoe iface {$port}
2009

    
2010
EOD;
2011
		}
2012

    
2013
		if ($type == "pptp" || $type == "l2tp") {
2014
			$mpdconf .= <<<EOD
2015
	set {$type} self {$localips[$pid]}
2016
	set {$type} peer {$gateways[$pid]}
2017

    
2018
EOD;
2019
		}
2020

    
2021
		$mpdconf .= "\topen\n";
2022
	} //end foreach ($port)
2023

    
2024

    
2025
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2026
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2027
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2028
	} else {
2029
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2030
		if (!$fd) {
2031
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2032
			return 0;
2033
		}
2034
		// Write out mpd_ppp.conf
2035
		fwrite($fd, $mpdconf);
2036
		fclose($fd);
2037
		unset($mpdconf);
2038
	}
2039

    
2040
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2041
	if (isset($ppp['uptime'])) {
2042
		if (!file_exists("/conf/{$pppif}.log")) {
2043
			conf_mount_rw();
2044
			file_put_contents("/conf/{$pppif}.log", '');
2045
			conf_mount_ro();
2046
		}
2047
	} else {
2048
		if (file_exists("/conf/{$pppif}.log")) {
2049
			conf_mount_rw();
2050
			@unlink("/conf/{$pppif}.log");
2051
			conf_mount_ro();
2052
		}
2053
	}
2054

    
2055
	/* clean up old lock files */
2056
	foreach ($ports as $port) {
2057
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2058
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2059
		}
2060
	}
2061

    
2062
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2063
	/* random IPv6 interface identifier during boot. More details at */
2064
	/* https://forum.pfsense.org/index.php?topic=101967.msg570519#msg570519 */
2065
	if (platform_booting() && is_array($config['interfaces'])) {
2066
		$count = 0;
2067
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2068
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2069
				$tempaddr[$count]['if'] = $tempiface['if'];
2070
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2071
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2072
				$count++;
2073
			}
2074
			// Maximum /31 is is x.y.z.254/31
2075
			if ($count > 122) {
2076
				break;
2077
			}
2078
		}
2079
		unset($count);
2080
	}
2081

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

    
2086
	// Check for PPPoE periodic reset request
2087
	if ($type == "pppoe") {
2088
		if (!empty($ppp['pppoe-reset-type'])) {
2089
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2090
		} else {
2091
			interface_setup_pppoe_reset_file($ppp['if']);
2092
		}
2093
	}
2094
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
2095
	$i = 0;
2096
	while ($i < 3) {
2097
		sleep(10);
2098
		if (does_interface_exist($ppp['if'], true)) {
2099
			break;
2100
		}
2101
		$i++;
2102
	}
2103

    
2104
	/* Remove all temporary bogon IPv4 addresses */
2105
	if (is_array($tempaddr)) {
2106
		foreach ($tempaddr as $tempiface) {
2107
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2108
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2109
			}
2110
		}
2111
		unset ($tempaddr);
2112
	}
2113

    
2114
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2115
	/* We should be able to launch the right version for each modem */
2116
	/* We can also guess the mondev from the manufacturer */
2117
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2118
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2119
	foreach ($ports as $port) {
2120
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2121
			$mondev = substr(basename($port), 0, -1);
2122
			$devlist = glob("/dev/{$mondev}?");
2123
			$mondev = basename(end($devlist));
2124
		}
2125
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2126
			$mondev = substr(basename($port), 0, -1) . "1";
2127
		}
2128
		if ($mondev != '') {
2129
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2130
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2131
		}
2132
	}
2133

    
2134
	return 1;
2135
}
2136

    
2137
function interfaces_sync_setup() {
2138
	global $g, $config;
2139

    
2140
	if (isset($config['system']['developerspew'])) {
2141
		$mt = microtime();
2142
		echo "interfaces_sync_setup() being called $mt\n";
2143
	}
2144

    
2145
	if (platform_booting()) {
2146
		echo gettext("Configuring CARP settings...");
2147
		mute_kernel_msgs();
2148
	}
2149

    
2150
	/* suck in configuration items */
2151
	if ($config['hasync']) {
2152
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2153
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2154
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2155
	} else {
2156
		unset($pfsyncinterface);
2157
		unset($pfsyncenabled);
2158
	}
2159

    
2160
	set_sysctl(array(
2161
		"net.inet.carp.preempt" => "1",
2162
		"net.inet.carp.log" => "1")
2163
	);
2164

    
2165
	if (!empty($pfsyncinterface)) {
2166
		$carp_sync_int = get_real_interface($pfsyncinterface);
2167
	} else {
2168
		unset($carp_sync_int);
2169
	}
2170

    
2171
	/* setup pfsync interface */
2172
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2173
		if (is_ipaddr($pfsyncpeerip)) {
2174
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2175
		} else {
2176
			$syncpeer = "-syncpeer";
2177
		}
2178

    
2179
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2180
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2181

    
2182
		sleep(1);
2183

    
2184
		/* 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
2185
		 * for existing sessions.
2186
		 */
2187
		log_error(gettext("waiting for pfsync..."));
2188
		$i = 0;
2189
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2190
			$i++;
2191
			sleep(1);
2192
		}
2193
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2194
		log_error(gettext("Configuring CARP settings finalize..."));
2195
	} else {
2196
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2197
	}
2198

    
2199
	$carplist = get_configured_vip_list('all', VIP_CARP);
2200
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2201
		set_single_sysctl("net.inet.carp.allow", "1");
2202
	} else {
2203
		set_single_sysctl("net.inet.carp.allow", "0");
2204
	}
2205

    
2206
	if (platform_booting()) {
2207
		unmute_kernel_msgs();
2208
		echo gettext("done.") . "\n";
2209
	}
2210
}
2211

    
2212
function interface_proxyarp_configure($interface = "") {
2213
	global $config, $g;
2214
	if (isset($config['system']['developerspew'])) {
2215
		$mt = microtime();
2216
		echo "interface_proxyarp_configure() being called $mt\n";
2217
	}
2218

    
2219
	/* kill any running choparp */
2220
	if (empty($interface)) {
2221
		killbyname("choparp");
2222
	} else {
2223
		$vipif = get_real_interface($interface);
2224
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2225
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2226
		}
2227
	}
2228

    
2229
	$paa = array();
2230
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2231

    
2232
		/* group by interface */
2233
		foreach ($config['virtualip']['vip'] as $vipent) {
2234
			if ($vipent['mode'] === "proxyarp") {
2235
				if ($vipent['interface']) {
2236
					$proxyif = $vipent['interface'];
2237
				} else {
2238
					$proxyif = "wan";
2239
				}
2240

    
2241
				if (!empty($interface) && $interface != $proxyif) {
2242
					continue;
2243
				}
2244

    
2245
				if (!is_array($paa[$proxyif])) {
2246
					$paa[$proxyif] = array();
2247
				}
2248

    
2249
				$paa[$proxyif][] = $vipent;
2250
			}
2251
		}
2252
	}
2253

    
2254
	if (!empty($interface)) {
2255
		if (is_array($paa[$interface])) {
2256
			$paaifip = get_interface_ip($interface);
2257
			if (!is_ipaddr($paaifip)) {
2258
				return;
2259
			}
2260
			$args = get_real_interface($interface) . " auto";
2261
			foreach ($paa[$interface] as $paent) {
2262
				if (isset($paent['subnet'])) {
2263
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2264
				} else if (isset($paent['range'])) {
2265
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2266
				}
2267
			}
2268
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2269
		}
2270
	} else if (count($paa) > 0) {
2271
		foreach ($paa as $paif => $paents) {
2272
			$paaifip = get_interface_ip($paif);
2273
			if (!is_ipaddr($paaifip)) {
2274
				continue;
2275
			}
2276
			$args = get_real_interface($paif) . " auto";
2277
			foreach ($paents as $paent) {
2278
				if (isset($paent['subnet'])) {
2279
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2280
				} else if (isset($paent['range'])) {
2281
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2282
				}
2283
			}
2284
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2285
		}
2286
	}
2287
}
2288

    
2289
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2290
	global $g, $config;
2291

    
2292
	if (is_array($config['virtualip']['vip'])) {
2293
		foreach ($config['virtualip']['vip'] as $vip) {
2294

    
2295
			$iface = $vip['interface'];
2296
			if (substr($iface, 0, 4) == "_vip")
2297
				$iface = get_configured_vip_interface($vip['interface']);
2298
			if ($iface != $interface)
2299
				continue;
2300
			if ($type == VIP_CARP) {
2301
				if ($vip['mode'] != "carp")
2302
					continue;
2303
			} elseif ($type == VIP_IPALIAS) {
2304
				if ($vip['mode'] != "ipalias")
2305
					continue;
2306
			} else {
2307
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2308
					continue;
2309
			}
2310

    
2311
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2312
				interface_vip_bring_down($vip);
2313
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2314
				interface_vip_bring_down($vip);
2315
			else if ($inet == "all")
2316
				interface_vip_bring_down($vip);
2317
		}
2318
	}
2319
}
2320

    
2321
function interfaces_vips_configure($interface = "") {
2322
	global $g, $config;
2323
	if (isset($config['system']['developerspew'])) {
2324
		$mt = microtime();
2325
		echo "interfaces_vips_configure() being called $mt\n";
2326
	}
2327
	$paa = array();
2328
	if (is_array($config['virtualip']['vip'])) {
2329
		$carp_setuped = false;
2330
		$anyproxyarp = false;
2331
		foreach ($config['virtualip']['vip'] as $vip) {
2332
			switch ($vip['mode']) {
2333
				case "proxyarp":
2334
					/* nothing it is handled on interface_proxyarp_configure() */
2335
					if ($interface <> "" && $vip['interface'] <> $interface) {
2336
						continue;
2337
					}
2338
					$anyproxyarp = true;
2339
					break;
2340
				case "ipalias":
2341
					$iface = $vip['interface'];
2342
					if (substr($iface, 0, 4) == "_vip")
2343
						$iface = get_configured_vip_interface($vip['interface']);
2344
					if ($interface <> "" && $iface <> $interface) {
2345
						continue;
2346
					}
2347
					interface_ipalias_configure($vip);
2348
					break;
2349
				case "carp":
2350
					if ($interface <> "" && $vip['interface'] <> $interface) {
2351
						continue;
2352
					}
2353
					if ($carp_setuped == false) {
2354
						$carp_setuped = true;
2355
					}
2356
					interface_carp_configure($vip);
2357
					break;
2358
			}
2359
		}
2360
		if ($carp_setuped == true) {
2361
			interfaces_sync_setup();
2362
		}
2363
		if ($anyproxyarp == true) {
2364
			interface_proxyarp_configure();
2365
		}
2366
	}
2367
}
2368

    
2369
function interface_ipalias_configure(&$vip) {
2370
	global $config;
2371

    
2372
	if ($vip['mode'] != 'ipalias') {
2373
		return;
2374
	}
2375

    
2376
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2377
	if ($realif != "lo0") {
2378
		$if = convert_real_interface_to_friendly_interface_name($realif);
2379
		if (!isset($config['interfaces'][$if])) {
2380
			return;
2381
		}
2382

    
2383
		if (!isset($config['interfaces'][$if]['enable'])) {
2384
			return;
2385
		}
2386
	}
2387

    
2388
	$af = 'inet';
2389
	if (is_ipaddrv6($vip['subnet'])) {
2390
		$af = 'inet6';
2391
	}
2392
	$iface = $vip['interface'];
2393
	$vhid = '';
2394
	if (substr($vip['interface'], 0, 4) == "_vip") {
2395
		$carpvip = get_configured_vip($vip['interface']);
2396
		$iface = $carpvip['interface'];
2397
		$vhid = "vhid {$carpvip['vhid']}";
2398
	}
2399
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2400
	unset($iface, $af, $realif, $carpvip, $vhid);
2401
}
2402

    
2403
function interface_carp_configure(&$vip) {
2404
	global $config, $g;
2405
	if (isset($config['system']['developerspew'])) {
2406
		$mt = microtime();
2407
		echo "interface_carp_configure() being called $mt\n";
2408
	}
2409

    
2410
	if ($vip['mode'] != "carp") {
2411
		return;
2412
	}
2413

    
2414
	/* NOTE: Maybe its useless nowadays */
2415
	$realif = get_real_interface($vip['interface']);
2416
	if (!does_interface_exist($realif)) {
2417
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2418
		return;
2419
	}
2420

    
2421
	$vip_password = $vip['password'];
2422
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2423
	if ($vip['password'] != "") {
2424
		$password = " pass {$vip_password}";
2425
	}
2426

    
2427
	$advbase = "";
2428
	if (!empty($vip['advbase'])) {
2429
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2430
	}
2431

    
2432
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2433
	if ($carp_maintenancemode) {
2434
		$advskew = "advskew 254";
2435
	} else {
2436
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2437
	}
2438

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

    
2441
	if (is_ipaddrv4($vip['subnet'])) {
2442
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2443
	} else if (is_ipaddrv6($vip['subnet'])) {
2444
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2445
	}
2446

    
2447
	return $realif;
2448
}
2449

    
2450
function interface_wireless_clone($realif, $wlcfg) {
2451
	global $config, $g;
2452
	/*   Check to see if interface has been cloned as of yet.
2453
	 *   If it has not been cloned then go ahead and clone it.
2454
	 */
2455
	$needs_clone = false;
2456
	if (is_array($wlcfg['wireless'])) {
2457
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2458
	} else {
2459
		$wlcfg_mode = $wlcfg['mode'];
2460
	}
2461
	switch ($wlcfg_mode) {
2462
		case "hostap":
2463
			$mode = "wlanmode hostap";
2464
			break;
2465
		case "adhoc":
2466
			$mode = "wlanmode adhoc";
2467
			break;
2468
		default:
2469
			$mode = "";
2470
			break;
2471
	}
2472
	$baseif = interface_get_wireless_base($wlcfg['if']);
2473
	if (does_interface_exist($realif)) {
2474
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2475
		$ifconfig_str = implode($output);
2476
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2477
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2478
			$needs_clone = true;
2479
		}
2480
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2481
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2482
			$needs_clone = true;
2483
		}
2484
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2485
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2486
			$needs_clone = true;
2487
		}
2488
	} else {
2489
		$needs_clone = true;
2490
	}
2491

    
2492
	if ($needs_clone == true) {
2493
		/* remove previous instance if it exists */
2494
		if (does_interface_exist($realif)) {
2495
			pfSense_interface_destroy($realif);
2496
		}
2497

    
2498
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2499
		// Create the new wlan interface. FreeBSD returns the new interface name.
2500
		// example:  wlan2
2501
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2502
		if ($ret <> 0) {
2503
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2504
			return false;
2505
		}
2506
		$newif = trim($out[0]);
2507
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2508
		pfSense_interface_rename($newif, $realif);
2509
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2510
	}
2511
	return true;
2512
}
2513

    
2514
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2515
	global $config, $g;
2516

    
2517
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2518
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2519
				 'regdomain', 'regcountry', 'reglocation');
2520

    
2521
	if (!is_interface_wireless($ifcfg['if'])) {
2522
		return;
2523
	}
2524

    
2525
	$baseif = interface_get_wireless_base($ifcfg['if']);
2526

    
2527
	// Sync shared settings for assigned clones
2528
	$iflist = get_configured_interface_list(false, true);
2529
	foreach ($iflist as $if) {
2530
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2531
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2532
				foreach ($shared_settings as $setting) {
2533
					if ($sync_changes) {
2534
						if (isset($ifcfg['wireless'][$setting])) {
2535
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2536
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2537
							unset($config['interfaces'][$if]['wireless'][$setting]);
2538
						}
2539
					} else {
2540
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2541
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2542
						} else if (isset($ifcfg['wireless'][$setting])) {
2543
							unset($ifcfg['wireless'][$setting]);
2544
						}
2545
					}
2546
				}
2547
				if (!$sync_changes) {
2548
					break;
2549
				}
2550
			}
2551
		}
2552
	}
2553

    
2554
	// Read or write settings at shared area
2555
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2556
		foreach ($shared_settings as $setting) {
2557
			if ($sync_changes) {
2558
				if (isset($ifcfg['wireless'][$setting])) {
2559
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2560
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2561
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2562
				}
2563
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2564
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2565
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2566
				} else if (isset($ifcfg['wireless'][$setting])) {
2567
					unset($ifcfg['wireless'][$setting]);
2568
				}
2569
			}
2570
		}
2571
	}
2572

    
2573
	// Sync the mode on the clone creation page with the configured mode on the interface
2574
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2575
		foreach ($config['wireless']['clone'] as &$clone) {
2576
			if ($clone['cloneif'] == $ifcfg['if']) {
2577
				if ($sync_changes) {
2578
					$clone['mode'] = $ifcfg['wireless']['mode'];
2579
				} else {
2580
					$ifcfg['wireless']['mode'] = $clone['mode'];
2581
				}
2582
				break;
2583
			}
2584
		}
2585
		unset($clone);
2586
	}
2587
}
2588

    
2589
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2590
	global $config, $g;
2591

    
2592
	/*    open up a shell script that will be used to output the commands.
2593
	 *    since wireless is changing a lot, these series of commands are fragile
2594
	 *    and will sometimes need to be verified by a operator by executing the command
2595
	 *    and returning the output of the command to the developers for inspection.  please
2596
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2597
	 */
2598

    
2599
	// Remove script file
2600
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2601

    
2602
	// Clone wireless nic if needed.
2603
	interface_wireless_clone($if, $wl);
2604

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

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

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

    
2614
	/* set values for /path/program */
2615
	$hostapd = "/usr/sbin/hostapd";
2616
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2617
	$ifconfig = "/sbin/ifconfig";
2618
	$sysctl = "/sbin/sysctl";
2619
	$killall = "/usr/bin/killall";
2620

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

    
2623
	$wlcmd = array();
2624
	$wl_sysctl = array();
2625
	/* Make sure it's up */
2626
	$wlcmd[] = "up";
2627
	/* Set a/b/g standard */
2628
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2629
	/* skip mode entirely for "auto" */
2630
	if ($wlcfg['standard'] != "auto") {
2631
		$wlcmd[] = "mode " . escapeshellarg($standard);
2632
	}
2633

    
2634
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2635
	 * to prevent massive packet loss under certain conditions. */
2636
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2637
		$wlcmd[] = "-ampdu";
2638
	}
2639

    
2640
	/* Set ssid */
2641
	if ($wlcfg['ssid']) {
2642
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2643
	}
2644

    
2645
	/* Set 802.11g protection mode */
2646
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2647

    
2648
	/* set wireless channel value */
2649
	if (isset($wlcfg['channel'])) {
2650
		if ($wlcfg['channel'] == "0") {
2651
			$wlcmd[] = "channel any";
2652
		} else {
2653
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2654
		}
2655
	}
2656

    
2657
	/* Set antenna diversity value */
2658
	if (isset($wlcfg['diversity'])) {
2659
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2660
	}
2661

    
2662
	/* Set txantenna value */
2663
	if (isset($wlcfg['txantenna'])) {
2664
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2665
	}
2666

    
2667
	/* Set rxantenna value */
2668
	if (isset($wlcfg['rxantenna'])) {
2669
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2670
	}
2671

    
2672
	/* set Distance value */
2673
	if ($wlcfg['distance']) {
2674
		$distance = escapeshellarg($wlcfg['distance']);
2675
	}
2676

    
2677
	/* Set wireless hostap mode */
2678
	if ($wlcfg['mode'] == "hostap") {
2679
		$wlcmd[] = "mediaopt hostap";
2680
	} else {
2681
		$wlcmd[] = "-mediaopt hostap";
2682
	}
2683

    
2684
	/* Set wireless adhoc mode */
2685
	if ($wlcfg['mode'] == "adhoc") {
2686
		$wlcmd[] = "mediaopt adhoc";
2687
	} else {
2688
		$wlcmd[] = "-mediaopt adhoc";
2689
	}
2690

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

    
2693
	/* handle hide ssid option */
2694
	if (isset($wlcfg['hidessid']['enable'])) {
2695
		$wlcmd[] = "hidessid";
2696
	} else {
2697
		$wlcmd[] = "-hidessid";
2698
	}
2699

    
2700
	/* handle pureg (802.11g) only option */
2701
	if (isset($wlcfg['pureg']['enable'])) {
2702
		$wlcmd[] = "mode 11g pureg";
2703
	} else {
2704
		$wlcmd[] = "-pureg";
2705
	}
2706

    
2707
	/* handle puren (802.11n) only option */
2708
	if (isset($wlcfg['puren']['enable'])) {
2709
		$wlcmd[] = "puren";
2710
	} else {
2711
		$wlcmd[] = "-puren";
2712
	}
2713

    
2714
	/* enable apbridge option */
2715
	if (isset($wlcfg['apbridge']['enable'])) {
2716
		$wlcmd[] = "apbridge";
2717
	} else {
2718
		$wlcmd[] = "-apbridge";
2719
	}
2720

    
2721
	/* handle turbo option */
2722
	if (isset($wlcfg['turbo']['enable'])) {
2723
		$wlcmd[] = "mediaopt turbo";
2724
	} else {
2725
		$wlcmd[] = "-mediaopt turbo";
2726
	}
2727

    
2728
	/* handle txpower setting */
2729
	// or don't. this has issues at the moment.
2730
	/*
2731
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2732
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2733
	}*/
2734

    
2735
	/* handle wme option */
2736
	if (isset($wlcfg['wme']['enable'])) {
2737
		$wlcmd[] = "wme";
2738
	} else {
2739
		$wlcmd[] = "-wme";
2740
	}
2741

    
2742
	/* Enable wpa if it's configured. No WEP support anymore. */
2743
	if (isset($wlcfg['wpa']['enable'])) {
2744
		$wlcmd[] = "authmode wpa wepmode off ";
2745
	} else {
2746
		$wlcmd[] = "authmode open wepmode off ";
2747
	}
2748

    
2749
	kill_hostapd($if);
2750
	mwexec(kill_wpasupplicant("{$if}"));
2751

    
2752
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2753
	conf_mount_rw();
2754

    
2755
	switch ($wlcfg['mode']) {
2756
		case 'bss':
2757
			if (isset($wlcfg['wpa']['enable'])) {
2758
				$wpa .= <<<EOD
2759
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2760
ctrl_interface_group=0
2761
ap_scan=1
2762
#fast_reauth=1
2763
network={
2764
ssid="{$wlcfg['ssid']}"
2765
scan_ssid=1
2766
priority=5
2767
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2768
psk="{$wlcfg['wpa']['passphrase']}"
2769
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2770
group={$wlcfg['wpa']['wpa_pairwise']}
2771
}
2772
EOD;
2773

    
2774
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2775
				unset($wpa);
2776
			}
2777
			break;
2778
		case 'hostap':
2779
			if (!empty($wlcfg['wpa']['passphrase'])) {
2780
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2781
			} else {
2782
				$wpa_passphrase = "";
2783
			}
2784
			if (isset($wlcfg['wpa']['enable'])) {
2785
				$wpa .= <<<EOD
2786
interface={$if}
2787
driver=bsd
2788
logger_syslog=-1
2789
logger_syslog_level=0
2790
logger_stdout=-1
2791
logger_stdout_level=0
2792
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2793
ctrl_interface={$g['varrun_path']}/hostapd
2794
ctrl_interface_group=wheel
2795
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2796
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2797
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2798
ssid={$wlcfg['ssid']}
2799
debug={$wlcfg['wpa']['debug_mode']}
2800
wpa={$wlcfg['wpa']['wpa_mode']}
2801
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2802
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2803
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2804
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2805
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2806
{$wpa_passphrase}
2807

    
2808
EOD;
2809

    
2810
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2811
					$wpa .= <<<EOD
2812
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
2813
rsn_preauth=1
2814
rsn_preauth_interfaces={$if}
2815

    
2816
EOD;
2817
				}
2818
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2819
					$wpa .= "ieee8021x=1\n";
2820

    
2821
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2822
						$auth_server_port = "1812";
2823
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2824
							$auth_server_port = intval($wlcfg['auth_server_port']);
2825
						}
2826
						$wpa .= <<<EOD
2827

    
2828
auth_server_addr={$wlcfg['auth_server_addr']}
2829
auth_server_port={$auth_server_port}
2830
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2831

    
2832
EOD;
2833
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2834
							$auth_server_port2 = "1812";
2835
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2836
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2837
							}
2838

    
2839
							$wpa .= <<<EOD
2840
auth_server_addr={$wlcfg['auth_server_addr2']}
2841
auth_server_port={$auth_server_port2}
2842
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2843

    
2844
EOD;
2845
						}
2846
					}
2847
				}
2848

    
2849
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2850
				unset($wpa);
2851
			}
2852
			break;
2853
	}
2854

    
2855
	/*
2856
	 *    all variables are set, lets start up everything
2857
	 */
2858

    
2859
	$baseif = interface_get_wireless_base($if);
2860
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2861
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2862

    
2863
	/* set sysctls for the wireless interface */
2864
	if (!empty($wl_sysctl)) {
2865
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2866
		foreach ($wl_sysctl as $wl_sysctl_line) {
2867
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2868
		}
2869
	}
2870

    
2871
	/* set ack timers according to users preference (if he/she has any) */
2872
	if ($distance) {
2873
		fwrite($fd_set, "# Enable ATH distance settings\n");
2874
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2875
	}
2876

    
2877
	if (isset($wlcfg['wpa']['enable'])) {
2878
		if ($wlcfg['mode'] == "bss") {
2879
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2880
		}
2881
		if ($wlcfg['mode'] == "hostap") {
2882
			/* add line to script to restore old mac to make hostapd happy */
2883
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2884
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2885
				if (is_macaddr($if_oldmac)) {
2886
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2887
						" link " . escapeshellarg($if_oldmac) . "\n");
2888
				}
2889
			}
2890

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

    
2893
			/* add line to script to restore spoofed mac after running hostapd */
2894
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2895
				if ($wl['spoofmac']) {
2896
					$if_curmac = $wl['spoofmac'];
2897
				} else {
2898
					$if_curmac = get_interface_mac($if);
2899
				}
2900
				if (is_macaddr($if_curmac)) {
2901
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2902
						" link " . escapeshellarg($if_curmac) . "\n");
2903
				}
2904
			}
2905
		}
2906
	}
2907

    
2908
	fclose($fd_set);
2909
	conf_mount_ro();
2910

    
2911
	/* Making sure regulatory settings have actually changed
2912
	 * before applying, because changing them requires bringing
2913
	 * down all wireless networks on the interface. */
2914
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2915
	$ifconfig_str = implode($output);
2916
	unset($output);
2917
	$reg_changing = false;
2918

    
2919
	/* special case for the debug country code */
2920
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
2921
		$reg_changing = true;
2922
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
2923
		$reg_changing = true;
2924
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
2925
		$reg_changing = true;
2926
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
2927
		$reg_changing = true;
2928
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
2929
		$reg_changing = true;
2930
	}
2931

    
2932
	if ($reg_changing) {
2933
		/* set regulatory domain */
2934
		if ($wlcfg['regdomain']) {
2935
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2936
		}
2937

    
2938
		/* set country */
2939
		if ($wlcfg['regcountry']) {
2940
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2941
		}
2942

    
2943
		/* set location */
2944
		if ($wlcfg['reglocation']) {
2945
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2946
		}
2947

    
2948
		$wlregcmd_args = implode(" ", $wlregcmd);
2949

    
2950
		/* build a complete list of the wireless clones for this interface */
2951
		$clone_list = array();
2952
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2953
			$clone_list[] = interface_get_wireless_clone($baseif);
2954
		}
2955
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2956
			foreach ($config['wireless']['clone'] as $clone) {
2957
				if ($clone['if'] == $baseif) {
2958
					$clone_list[] = $clone['cloneif'];
2959
				}
2960
			}
2961
		}
2962

    
2963
		/* find which clones are up and bring them down */
2964
		$clones_up = array();
2965
		foreach ($clone_list as $clone_if) {
2966
			$clone_status = pfSense_get_interface_addresses($clone_if);
2967
			if ($clone_status['status'] == 'up') {
2968
				$clones_up[] = $clone_if;
2969
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2970
			}
2971
		}
2972

    
2973
		/* apply the regulatory settings */
2974
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2975
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2976

    
2977
		/* bring the clones back up that were previously up */
2978
		foreach ($clones_up as $clone_if) {
2979
			interfaces_bring_up($clone_if);
2980

    
2981
			/*
2982
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2983
			 * is in infrastructure mode, and WPA is enabled.
2984
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2985
			 */
2986
			if ($clone_if != $if) {
2987
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2988
				if ((!empty($friendly_if)) &&
2989
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
2990
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
2991
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2992
				}
2993
			}
2994
		}
2995
	}
2996

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

    
3000
	 * The mode must be specified in a separate command before ifconfig
3001
	 * will allow the mode and channel at the same time in the next. */
3002
	//mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3003
	//fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3004

    
3005
	/* configure wireless */
3006
	$wlcmd_args = implode(" ", $wlcmd);
3007
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3008
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3009
	fclose($wlan_setup_log);
3010

    
3011
	unset($wlcmd_args, $wlcmd);
3012

    
3013

    
3014
	sleep(1);
3015
	/* execute hostapd and wpa_supplicant if required in shell */
3016
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3017

    
3018
	return 0;
3019

    
3020
}
3021

    
3022
function kill_hostapd($interface) {
3023
	global $g;
3024

    
3025
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3026
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3027
	}
3028
}
3029

    
3030
function kill_wpasupplicant($interface) {
3031
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3032
}
3033

    
3034
function find_dhclient_process($interface) {
3035
	if ($interface) {
3036
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3037
	} else {
3038
		$pid = 0;
3039
	}
3040

    
3041
	return intval($pid);
3042
}
3043

    
3044
function kill_dhclient_process($interface) {
3045
	if (empty($interface) || !does_interface_exist($interface)) {
3046
		return;
3047
	}
3048

    
3049
	$i = 0;
3050
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3051
		/* 3rd time make it die for sure */
3052
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3053
		posix_kill($pid, $sig);
3054
		sleep(1);
3055
		$i++;
3056
	}
3057
	unset($i);
3058
}
3059

    
3060
function find_dhcp6c_process($interface) {
3061
	global $g;
3062

    
3063
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3064
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3065
	} else {
3066
		return(false);
3067
	}
3068

    
3069
	return intval($pid);
3070
}
3071

    
3072
function interface_virtual_create($interface) {
3073
	global $config;
3074

    
3075
	if (strstr($interface, "_vlan")) {
3076
		interfaces_vlan_configure($vlan);
3077
	} else if (substr($interface, 0, 3) == "gre") {
3078
		interfaces_gre_configure(0, $interface);
3079
	} else if (substr($interface, 0, 3) == "gif") {
3080
		interfaces_gif_configure(0, $interface);
3081
	} else if (substr($interface, 0, 5) == "ovpns") {
3082
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3083
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3084
				if ($interface == "ovpns{$server['vpnid']}") {
3085
					if (!function_exists('openvpn_resync')) {
3086
						require_once('openvpn.inc');
3087
					}
3088
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3089
					openvpn_resync('server', $server);
3090
				}
3091
			}
3092
			unset($server);
3093
		}
3094
	} else if (substr($interface, 0, 5) == "ovpnc") {
3095
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3096
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3097
				if ($interface == "ovpnc{$client['vpnid']}") {
3098
					if (!function_exists('openvpn_resync')) {
3099
						require_once('openvpn.inc');
3100
					}
3101
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3102
					openvpn_resync('client', $client);
3103
				}
3104
			}
3105
			unset($client);
3106
		}
3107
	} else if (substr($interface, 0, 4) == "lagg") {
3108
		interfaces_lagg_configure($interface);
3109
	} else if (substr($interface, 0, 6) == "bridge") {
3110
		interfaces_bridge_configure(0, $interface);
3111
	}
3112
}
3113

    
3114
function interface_vlan_mtu_configured($iface) {
3115
	global $config;
3116

    
3117
	$mtu = 0;
3118
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3119
		foreach ($config['vlans']['vlan'] as $vlan) {
3120

    
3121
			if ($vlan['vlanif'] != $iface)
3122
				continue;
3123

    
3124
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3125
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3126
				/* VLAN MTU */
3127
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3128
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3129
				/* Parent MTU */
3130
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3131
			}
3132
		}
3133
	}
3134

    
3135
	return $mtu;
3136
}
3137

    
3138
function interface_mtu_wanted_for_pppoe($realif) {
3139
	global $config;
3140

    
3141
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3142
		return 0;
3143

    
3144
	$mtu = 0;
3145
	foreach ($config['ppps']['ppp'] as $ppp) {
3146
		if ($ppp['type'] != "pppoe") {
3147
			continue;
3148
		}
3149

    
3150
		$mtus = array();
3151
		if (!empty($ppp['mtu'])) {
3152
			$mtus = explode(',', $ppp['mtu']);
3153
		}
3154
		$ports = explode(',', $ppp['ports']);
3155

    
3156
		foreach ($ports as $pid => $port) {
3157
			$parentifa = get_parent_interface($port);
3158
			$parentif = $parentifa[0];
3159
			if ($parentif != $realif)
3160
				continue;
3161

    
3162
			// there is an MTU configured on the port in question
3163
			if (!empty($mtus[$pid])) {
3164
				$mtu = intval($mtus[$pid]) + 8;
3165
			// or use the MTU configured on the interface ...
3166
			} elseif (is_array($config['interfaces'])) {
3167
				foreach ($config['interfaces'] as $interface) {
3168
					if ($interface['if'] == $ppp['if'] &&
3169
					    !empty($interface['mtu'])) {
3170
						$mtu = intval($interface['mtu']) + 8;
3171
						break;
3172
					}
3173
				}
3174
			}
3175
		}
3176
	}
3177

    
3178
	return $mtu;
3179
}
3180

    
3181
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3182
	global $config, $g;
3183
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3184
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3185

    
3186
	$wancfg = $config['interfaces'][$interface];
3187

    
3188
	if (!isset($wancfg['enable'])) {
3189
		return;
3190
	}
3191

    
3192
	$realif = get_real_interface($interface);
3193
	$realhwif_array = get_parent_interface($interface);
3194
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3195
	$realhwif = $realhwif_array[0];
3196

    
3197
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3198
		/* remove all IPv4 and IPv6 addresses */
3199
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3200
		if (is_array($tmpifaces)) {
3201
			foreach ($tmpifaces as $tmpiface) {
3202
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3203
					if (!is_linklocal($tmpiface)) {
3204
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3205
					}
3206
				} else {
3207
					if (is_subnetv4($tmpiface)) {
3208
						$tmpip = explode('/', $tmpiface);
3209
						$tmpip = $tmpip[0];
3210
					} else {
3211
						$tmpip = $tmpiface;
3212
					}
3213
					pfSense_interface_deladdress($realif, $tmpip);
3214
				}
3215
			}
3216
		}
3217

    
3218
		/* only bring down the interface when both v4 and v6 are set to NONE */
3219
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3220
			interface_bring_down($interface);
3221
		}
3222
	}
3223

    
3224
	$interface_to_check = $realif;
3225
	if (interface_isppp_type($interface)) {
3226
		$interface_to_check = $realhwif;
3227
	}
3228

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

    
3234
	/* Disable Accepting router advertisements unless specifically requested */
3235
	if ($g['debug']) {
3236
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3237
	}
3238
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3239

    
3240
	/* wireless configuration? */
3241
	if (is_array($wancfg['wireless'])) {
3242
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3243
	}
3244

    
3245
	$mac = get_interface_mac($realhwif);
3246
	/*
3247
	 * Don't try to reapply the spoofed MAC if it's already applied.
3248
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3249
	 * the interface config again, which attempts to spoof the MAC again,
3250
	 * which cycles the link again...
3251
	 */
3252
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
3253
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3254
			" link " . escapeshellarg($wancfg['spoofmac']));
3255
	} else {
3256

    
3257
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3258
			/*   this is not a valid mac address.  generate a
3259
			 *   temporary mac address so the machine can get online.
3260
			 */
3261
			echo gettext("Generating new MAC address.");
3262
			$random_mac = generate_random_mac_address();
3263
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3264
				" link " . escapeshellarg($random_mac));
3265
			$wancfg['spoofmac'] = $random_mac;
3266
			write_config();
3267
			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");
3268
		}
3269
	}
3270

    
3271
	/* media */
3272
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3273
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3274
		if ($wancfg['media']) {
3275
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3276
		}
3277
		if ($wancfg['mediaopt']) {
3278
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3279
		}
3280
		mwexec($cmd);
3281
	}
3282

    
3283
	/* Apply hw offloading policies as configured */
3284
	enable_hardware_offloading($interface);
3285

    
3286
	/* invalidate interface/ip/sn cache */
3287
	get_interface_arr(true);
3288
	unset($interface_ip_arr_cache[$realif]);
3289
	unset($interface_sn_arr_cache[$realif]);
3290
	unset($interface_ipv6_arr_cache[$realif]);
3291
	unset($interface_snv6_arr_cache[$realif]);
3292

    
3293
	$tunnelif = substr($realif, 0, 3);
3294

    
3295
	$mtuif = $realif;
3296
	$mtuhwif = $realhwif;
3297

    
3298
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3299
	if (interface_isppp_type($interface)) {
3300
		$mtuif = $realhwif;
3301
		$mtuhwif_array = get_parent_interface($mtuif);
3302
		$mtuhwif = $mtuhwif_array[0];
3303
	}
3304

    
3305
	$wantedmtu = 0;
3306
	if (is_array($config['interfaces'])) {
3307
		foreach ($config['interfaces'] as $tmpinterface) {
3308
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3309
				$wantedmtu = $tmpinterface['mtu'];
3310
				break;
3311
			}
3312
		}
3313
	}
3314

    
3315
	/* MTU is not specified for interface, try the pppoe settings. */
3316
	if ($wantedmtu == 0) {
3317
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3318
	}
3319
	if ($wantedmtu == 0 && stristr($mtuif, "_vlan") && interface_isppp_type($interface)) {
3320
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3321
	}
3322

    
3323
	/* Set the MTU to 1500 if no explicit MTU configured. */
3324
	if ($wantedmtu == 0) {
3325
		$wantedmtu = 1500; /* Default */
3326
	}
3327

    
3328
	if (stristr($mtuif, "_vlan")) {
3329
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3330
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3331
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3332
			if ($wancfg['mtu'] > $parentmtu) {
3333
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3334
			}
3335
		}
3336

    
3337
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3338

    
3339
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3340
			$configuredmtu = $parentmtu;
3341
		if ($configuredmtu != 0)
3342
			$mtu = $configuredmtu;
3343
		else
3344
			$mtu = $wantedmtu;
3345

    
3346
		/* Set the parent MTU. */
3347
		if (get_interface_mtu($mtuhwif) < $mtu)
3348
			set_interface_mtu($mtuhwif, $mtu);
3349
		/* Set the VLAN MTU. */
3350
		if (get_interface_mtu($mtuif) != $mtu)
3351
			set_interface_mtu($mtuif, $mtu);
3352
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3353
		/* LAGG interface must be destroyed and re-created to change MTU */
3354
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3355
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3356
				foreach ($config['laggs']['lagg'] as $lagg) {
3357
					if ($lagg['laggif'] == $mtuif) {
3358
						interface_lagg_configure($lagg);
3359
						break;
3360
					}
3361
				}
3362
			}
3363
		}
3364
	} else {
3365
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3366
			pfSense_interface_mtu($mtuif, $wantedmtu);
3367
		}
3368
	}
3369
	/* XXX: What about gre/gif/.. ? */
3370

    
3371
	if (does_interface_exist($wancfg['if'])) {
3372
		interfaces_bring_up($wancfg['if']);
3373
	}
3374

    
3375
	switch ($wancfg['ipaddr']) {
3376
		case 'dhcp':
3377
			interface_dhcp_configure($interface);
3378
			break;
3379
		case 'pppoe':
3380
		case 'l2tp':
3381
		case 'pptp':
3382
		case 'ppp':
3383
			interface_ppps_configure($interface);
3384
			break;
3385
		default:
3386
			/* XXX: Kludge for now related to #3280 */
3387
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3388
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3389
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3390
				}
3391
			}
3392
			break;
3393
	}
3394

    
3395
	switch ($wancfg['ipaddrv6']) {
3396
		case 'slaac':
3397
		case 'dhcp6':
3398
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
3399
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
3400
			// handles all non-PPP connections with 'dhcp6usev4iface' set
3401
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
3402
				interface_dhcpv6_configure($interface, $wancfg);
3403
			}
3404
			break;
3405
		case '6rd':
3406
			interface_6rd_configure($interface, $wancfg);
3407
			break;
3408
		case '6to4':
3409
			interface_6to4_configure($interface, $wancfg);
3410
			break;
3411
		case 'track6':
3412
			interface_track6_configure($interface, $wancfg, $linkupevent);
3413
			break;
3414
		default:
3415
			/* XXX: Kludge for now related to #3280 */
3416
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3417
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3418
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3419
					// FIXME: Add IPv6 Support to the pfSense module
3420
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3421
				}
3422
			}
3423
			break;
3424
	}
3425

    
3426
	interface_netgraph_needed($interface);
3427

    
3428
	if (!platform_booting()) {
3429
		link_interface_to_vips($interface, "update");
3430

    
3431
		if ($tunnelif != 'gre') {
3432
			unset($gre);
3433
			$gre = link_interface_to_gre($interface);
3434
			if (!empty($gre)) {
3435
				array_walk($gre, 'interface_gre_configure');
3436
			}
3437
		}
3438

    
3439
		if ($tunnelif != 'gif') {
3440
			unset($gif);
3441
			$gif = link_interface_to_gif ($interface);
3442
			if (!empty($gif)) {
3443
				array_walk($gif, 'interface_gif_configure');
3444
			}
3445
		}
3446

    
3447
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3448
			unset($bridgetmp);
3449
			$bridgetmp = link_interface_to_bridge($interface);
3450
			if (!empty($bridgetmp)) {
3451
				interface_bridge_add_member($bridgetmp, $realif);
3452
			}
3453
		}
3454

    
3455
		$grouptmp = link_interface_to_group($interface);
3456
		if (!empty($grouptmp)) {
3457
			array_walk($grouptmp, 'interface_group_add_member');
3458
		}
3459

    
3460
		if ($interface == "lan") {
3461
			/* make new hosts file */
3462
			system_hosts_generate();
3463
		}
3464

    
3465
		if ($reloadall == true) {
3466

    
3467
			/* reconfigure static routes (kernel may have deleted them) */
3468
			system_routing_configure($interface);
3469

    
3470
			/* reload ipsec tunnels */
3471
			send_event("service reload ipsecdns");
3472

    
3473
			/* restart dnsmasq or unbound */
3474
			if (isset($config['dnsmasq']['enable'])) {
3475
				services_dnsmasq_configure();
3476
			} elseif (isset($config['unbound']['enable'])) {
3477
				services_unbound_configure();
3478
			}
3479

    
3480
			/* update dyndns */
3481
			send_event("service reload dyndns {$interface}");
3482

    
3483
			/* reload captive portal */
3484
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3485
				require_once('captiveportal.inc');
3486
			}
3487
			captiveportal_init_rules_byinterface($interface);
3488
		}
3489
	}
3490

    
3491
	interfaces_staticarp_configure($interface);
3492
	return 0;
3493
}
3494

    
3495
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3496
	global $config, $g;
3497

    
3498
	if (!is_array($wancfg)) {
3499
		return;
3500
	}
3501

    
3502
	if (!isset($wancfg['enable'])) {
3503
		return;
3504
	}
3505

    
3506
	/* If the interface is not configured via another, exit */
3507
	if (empty($wancfg['track6-interface'])) {
3508
		return;
3509
	}
3510

    
3511
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3512
	$realif = get_real_interface($interface);
3513
	$linklocal = find_interface_ipv6_ll($realif);
3514
	if (!empty($linklocal)) {
3515
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3516
	}
3517
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3518
	/* XXX: Probably should remove? */
3519
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3520

    
3521
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3522
	if (!isset($trackcfg['enable'])) {
3523
		log_error(sprintf(gettext('Interface %1$s tracking non-existant interface %2$s'), $interface, $wancfg['track6-interface']));
3524
		return;
3525
	}
3526

    
3527
	switch ($trackcfg['ipaddrv6']) {
3528
		case "6to4":
3529
			if ($g['debug']) {
3530
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3531
			}
3532
			interface_track6_6to4_configure($interface, $wancfg);
3533
			break;
3534
		case "6rd":
3535
			if ($g['debug']) {
3536
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3537
			}
3538
			interface_track6_6rd_configure($interface, $wancfg);
3539
			break;
3540
		case "dhcp6":
3541
			if ($linkupevent == true) {
3542
				/*
3543
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
3544
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3545
				 *
3546
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
3547
				 */
3548
				$parentrealif = get_real_interface($wancfg['track6-interface']);
3549
				$pidv6 = find_dhcp6c_process($parentrealif);
3550
				if ($pidv6) {
3551
					posix_kill($pidv6, SIGHUP);
3552
				}
3553
			}
3554
			break;
3555
	}
3556

    
3557
	if ($linkupevent == false) {
3558
		if (!function_exists('services_dhcpd_configure')) {
3559
			require_once("services.inc");
3560
		}
3561

    
3562
		if (isset($config['unbound']['enable'])) {
3563
			services_unbound_configure();
3564
		}
3565

    
3566
		services_dhcpd_configure("inet6");
3567
	}
3568

    
3569
	return 0;
3570
}
3571

    
3572
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3573
	global $config, $g;
3574
	global $interface_ipv6_arr_cache;
3575
	global $interface_snv6_arr_cache;
3576

    
3577
	if (!is_array($lancfg)) {
3578
		return;
3579
	}
3580

    
3581
	/* If the interface is not configured via another, exit */
3582
	if (empty($lancfg['track6-interface'])) {
3583
		return;
3584
	}
3585

    
3586
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3587
	if (empty($wancfg)) {
3588
		log_error(sprintf(gettext('Interface %1$s tracking non-existant interface %2$s'), $interface, $lancfg['track6-interface']));
3589
		return;
3590
	}
3591

    
3592
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3593
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3594
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not valid, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
3595
		return;
3596
	}
3597
	$hexwanv4 = return_hex_ipv4($ip4address);
3598

    
3599
	/* create the long prefix notation for math, save the prefix length */
3600
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3601
	$rd6prefixlen = $rd6prefix[1];
3602
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3603

    
3604
	/* binary presentation of the prefix for all 128 bits. */
3605
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3606

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

    
3612
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3613
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3614
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3615
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3616
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3617
	/* fill the rest out with zeros */
3618
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3619

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

    
3623
	$lanif = get_real_interface($interface);
3624
	$oip = find_interface_ipv6($lanif);
3625
	if (is_ipaddrv6($oip)) {
3626
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3627
	}
3628
	unset($interface_ipv6_arr_cache[$lanif]);
3629
	unset($interface_snv6_arr_cache[$lanif]);
3630
	log_error(sprintf(gettext('rd6 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $rd6lan, $lancfg['track6-interface'], $ip4address));
3631
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3632

    
3633
	return 0;
3634
}
3635

    
3636
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3637
	global $config, $g;
3638
	global $interface_ipv6_arr_cache;
3639
	global $interface_snv6_arr_cache;
3640

    
3641
	if (!is_array($lancfg)) {
3642
		return;
3643
	}
3644

    
3645
	/* If the interface is not configured via another, exit */
3646
	if (empty($lancfg['track6-interface'])) {
3647
		return;
3648
	}
3649

    
3650
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3651
	if (empty($wancfg)) {
3652
		log_error(sprintf(gettext('Interface %1$s tracking non-existant interface %2$s'), $interface, $lancfg['track6-interface']));
3653
		return;
3654
	}
3655

    
3656
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3657
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3658
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
3659
		return;
3660
	}
3661
	$hexwanv4 = return_hex_ipv4($ip4address);
3662

    
3663
	/* create the long prefix notation for math, save the prefix length */
3664
	$sixto4prefix = "2002::";
3665
	$sixto4prefixlen = 16;
3666
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3667

    
3668
	/* binary presentation of the prefix for all 128 bits. */
3669
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3670

    
3671
	/* just save the left prefix length bits */
3672
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3673
	/* add the v4 address */
3674
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3675
	/* add the custom prefix id */
3676
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3677
	/* fill the rest out with zeros */
3678
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3679

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

    
3683
	$lanif = get_real_interface($interface);
3684
	$oip = find_interface_ipv6($lanif);
3685
	if (is_ipaddrv6($oip)) {
3686
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3687
	}
3688
	unset($interface_ipv6_arr_cache[$lanif]);
3689
	unset($interface_snv6_arr_cache[$lanif]);
3690
	log_error(sprintf(gettext('sixto4 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $sixto4lan, $lancfg['track6-interface'], $ip4address));
3691
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3692

    
3693
	return 0;
3694
}
3695

    
3696
function interface_6rd_configure($interface = "wan", $wancfg) {
3697
	global $config, $g;
3698

    
3699
	/* because this is a tunnel interface we can only function
3700
	 *	with a public IPv4 address on the interface */
3701

    
3702
	if (!is_array($wancfg)) {
3703
		return;
3704
	}
3705

    
3706
	if (!is_module_loaded('if_stf.ko')) {
3707
		mwexec('/sbin/kldload if_stf.ko');
3708
	}
3709

    
3710
	$wanif = get_real_interface($interface);
3711
	$ip4address = find_interface_ip($wanif);
3712
	if (!is_ipaddrv4($ip4address)) {
3713
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3714
		return false;
3715
	}
3716
	$hexwanv4 = return_hex_ipv4($ip4address);
3717

    
3718
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3719
		$wancfg['prefix-6rd-v4plen'] = 0;
3720
	}
3721

    
3722
	/* create the long prefix notation for math, save the prefix length */
3723
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3724
	$rd6prefixlen = $rd6prefix[1];
3725
	$brgw = explode('.', $wancfg['gateway-6rd']);
3726
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3727
	$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);
3728
	if (strlen($rd6brgw) < 128) {
3729
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3730
	}
3731
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3732
	unset($brgw);
3733
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3734

    
3735
	/* binary presentation of the prefix for all 128 bits. */
3736
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3737

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

    
3745
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3746
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3747

    
3748

    
3749
	/* XXX: need to extend to support variable prefix size for v4 */
3750
	if (!is_module_loaded("if_stf")) {
3751
		mwexec("/sbin/kldload if_stf.ko");
3752
	}
3753
	$stfiface = "{$interface}_stf";
3754
	if (does_interface_exist($stfiface)) {
3755
		pfSense_interface_destroy($stfiface);
3756
	}
3757
	$tmpstfiface = pfSense_interface_create("stf");
3758
	pfSense_interface_rename($tmpstfiface, $stfiface);
3759
	pfSense_interface_flags($stfiface, IFF_LINK2);
3760
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3761
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3762
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3763
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3764
	}
3765
	if ($g['debug']) {
3766
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3767
	}
3768

    
3769
	/* write out a default router file */
3770
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3771
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3772

    
3773
	$ip4gateway = get_interface_gateway($interface);
3774
	if (is_ipaddrv4($ip4gateway)) {
3775
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3776
	}
3777

    
3778
	/* configure dependent interfaces */
3779
	if (!platform_booting()) {
3780
		link_interface_to_track6($interface, "update");
3781
	}
3782

    
3783
	return 0;
3784
}
3785

    
3786
function interface_6to4_configure($interface = "wan", $wancfg) {
3787
	global $config, $g;
3788

    
3789
	/* because this is a tunnel interface we can only function
3790
	 *	with a public IPv4 address on the interface */
3791

    
3792
	if (!is_array($wancfg)) {
3793
		return;
3794
	}
3795

    
3796
	$wanif = get_real_interface($interface);
3797
	$ip4address = find_interface_ip($wanif);
3798
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3799
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3800
		return false;
3801
	}
3802

    
3803
	/* create the long prefix notation for math, save the prefix length */
3804
	$stfprefixlen = 16;
3805
	$stfprefix = Net_IPv6::uncompress("2002::");
3806
	$stfarr = explode(":", $stfprefix);
3807
	$v4prefixlen = "0";
3808

    
3809
	/* we need the hex form of the interface IPv4 address */
3810
	$ip4arr = explode(".", $ip4address);
3811
	$hexwanv4 = "";
3812
	foreach ($ip4arr as $octet) {
3813
		$hexwanv4 .= sprintf("%02x", $octet);
3814
	}
3815

    
3816
	/* we need the hex form of the broker IPv4 address */
3817
	$ip4arr = explode(".", "192.88.99.1");
3818
	$hexbrv4 = "";
3819
	foreach ($ip4arr as $octet) {
3820
		$hexbrv4 .= sprintf("%02x", $octet);
3821
	}
3822

    
3823
	/* binary presentation of the prefix for all 128 bits. */
3824
	$stfprefixbin = "";
3825
	foreach ($stfarr as $element) {
3826
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3827
	}
3828
	/* just save the left prefix length bits */
3829
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3830

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

    
3835
	/* for the local subnet too. */
3836
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3837
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3838

    
3839
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3840
	$stfbrarr = array();
3841
	$stfbrbinarr = array();
3842
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3843
	foreach ($stfbrbinarr as $bin) {
3844
		$stfbrarr[] = dechex(bindec($bin));
3845
	}
3846
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3847

    
3848
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3849
	$stflanarr = array();
3850
	$stflanbinarr = array();
3851
	$stflanbinarr = str_split($stflanbin, 16);
3852
	foreach ($stflanbinarr as $bin) {
3853
		$stflanarr[] = dechex(bindec($bin));
3854
	}
3855
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3856
	$stflanarr[7] = 1;
3857
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3858

    
3859
	/* setup the stf interface */
3860
	if (!is_module_loaded("if_stf")) {
3861
		mwexec("/sbin/kldload if_stf.ko");
3862
	}
3863
	$stfiface = "{$interface}_stf";
3864
	if (does_interface_exist($stfiface)) {
3865
		pfSense_interface_destroy($stfiface);
3866
	}
3867
	$tmpstfiface = pfSense_interface_create("stf");
3868
	pfSense_interface_rename($tmpstfiface, $stfiface);
3869
	pfSense_interface_flags($stfiface, IFF_LINK2);
3870
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3871

    
3872
	if ($g['debug']) {
3873
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3874
	}
3875

    
3876
	/* write out a default router file */
3877
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3878
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3879

    
3880
	$ip4gateway = get_interface_gateway($interface);
3881
	if (is_ipaddrv4($ip4gateway)) {
3882
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3883
	}
3884

    
3885
	if (!platform_booting()) {
3886
		link_interface_to_track6($interface, "update");
3887
	}
3888

    
3889
	return 0;
3890
}
3891

    
3892
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3893
	global $config, $g;
3894

    
3895
	if (!is_array($wancfg)) {
3896
		return;
3897
	}
3898

    
3899
	$wanif = get_real_interface($interface, "inet6");
3900
	$dhcp6cconf = "";
3901

    
3902
	if ($wancfg['adv_dhcp6_config_file_override']) {
3903
		// DHCP6 Config File Override
3904
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3905
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3906
		// DHCP6 Config File Advanced
3907
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3908
	} else {
3909
		// DHCP6 Config File Basic
3910
		$dhcp6cconf .= "interface {$wanif} {\n";
3911

    
3912
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3913
		if ($wancfg['ipaddrv6'] == "slaac") {
3914
			$dhcp6cconf .= "\tinformation-only;\n";
3915
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3916
			$dhcp6cconf .= "\trequest domain-name;\n";
3917
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3918
			$dhcp6cconf .= "};\n";
3919
		} else {
3920
			$trackiflist = array();
3921
			$iflist = link_interface_to_track6($interface);
3922
			foreach ($iflist as $ifname => $ifcfg) {
3923
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3924
					$trackiflist[$ifname] = $ifcfg;
3925
				}
3926
			}
3927

    
3928
			/* skip address request if this is set */
3929
			if (!isset($wancfg['dhcp6prefixonly'])) {
3930
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3931
			}
3932
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3933
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3934
			}
3935

    
3936
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3937
			$dhcp6cconf .= "\trequest domain-name;\n";
3938
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3939
			$dhcp6cconf .= "};\n";
3940

    
3941
			if (!isset($wancfg['dhcp6prefixonly'])) {
3942
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3943
			}
3944

    
3945
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3946
				/* Setup the prefix delegation */
3947
				$dhcp6cconf .= "id-assoc pd 0 {\n";
3948
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3949
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
3950
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
3951
				}
3952
				foreach ($trackiflist as $friendly => $ifcfg) {
3953
					if ($g['debug']) {
3954
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3955
					}
3956
					$realif = get_real_interface($friendly);
3957
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
3958
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
3959
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3960
					$dhcp6cconf .= "\t};\n";
3961
				}
3962
				unset($preflen, $iflist, $ifcfg, $ifname);
3963
				$dhcp6cconf .= "};\n";
3964
			}
3965
			unset($trackiflist);
3966
		}
3967
	}
3968

    
3969
	/* wide-dhcp6c works for now. */
3970
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3971
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3972
		unset($dhcp6cconf);
3973
		return 1;
3974
	}
3975
	unset($dhcp6cconf);
3976

    
3977
	$dhcp6cscript = "#!/bin/sh\n";
3978
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3979
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3980
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3981
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3982
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3983
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3984
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3985
		unset($dhcp6cscript);
3986
		return 1;
3987
	}
3988
	unset($dhcp6cscript);
3989
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3990

    
3991
	$rtsoldscript = "#!/bin/sh\n";
3992
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3993
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3994
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3995
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Recieved RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
3996
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3997
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3998
	$rtsoldscript .= "\t/bin/sleep 1\n";
3999
	$rtsoldscript .= "fi\n";
4000
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4001
	$rtsoldscript .= "/usr/local/sbin/dhcp6c {$debugOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4002
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4003
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4004
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4005
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4006
		unset($rtsoldscript);
4007
		return 1;
4008
	}
4009
	unset($rtsoldscript);
4010
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4011

    
4012
	/* accept router advertisements for this interface */
4013
	log_error("Accept router advertisements on interface {$wanif} ");
4014
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4015

    
4016
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
4017
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4018
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4019
		sleep(2);
4020
	}
4021
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
4022

    
4023
	/* NOTE: will be called from rtsold invoked script
4024
	 * link_interface_to_track6($interface, "update");
4025
	 */
4026

    
4027
	return 0;
4028
}
4029

    
4030
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4031
	global $g;
4032

    
4033
	$send_options = "";
4034
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4035
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_send_options']);
4036
		foreach ($options as $option) {
4037
			$send_options .= "\tsend " . trim($option) . ";\n";
4038
		}
4039
	}
4040

    
4041
	$request_options = "";
4042
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4043
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_request_options']);
4044
		foreach ($options as $option) {
4045
			$request_options .= "\trequest " . trim($option) . ";\n";
4046
		}
4047
	}
4048

    
4049
	$information_only = "";
4050
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4051
		$information_only = "\tinformation-only;\n";
4052
	}
4053

    
4054
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4055
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4056
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4057
	}
4058

    
4059
	$interface_statement  = "interface";
4060
	$interface_statement .= " {$wanif}";
4061
	$interface_statement .= " {\n";
4062
	$interface_statement .= "$send_options";
4063
	$interface_statement .= "$request_options";
4064
	$interface_statement .= "$information_only";
4065
	$interface_statement .= "$script";
4066
	$interface_statement .= "};\n";
4067

    
4068
	$id_assoc_statement_address = "";
4069
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4070
		$id_assoc_statement_address .= "id-assoc";
4071
		$id_assoc_statement_address .= " na";
4072
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4073
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4074
		}
4075
		$id_assoc_statement_address .= " { ";
4076

    
4077
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4078
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4079
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4080
			$id_assoc_statement_address .= "\n\taddress";
4081
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4082
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4083
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4084
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4085
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4086
			}
4087
			$id_assoc_statement_address .= ";\n";
4088
		}
4089

    
4090
		$id_assoc_statement_address .= "};\n";
4091
	}
4092

    
4093
	$id_assoc_statement_prefix = "";
4094
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4095
		$id_assoc_statement_prefix .= "id-assoc";
4096
		$id_assoc_statement_prefix .= " pd";
4097
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4098
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4099
		}
4100
		$id_assoc_statement_prefix .= " { ";
4101

    
4102
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4103
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4104
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4105
			$id_assoc_statement_prefix .= "\n\tprefix";
4106
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4107
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4108
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4109
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4110
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4111
			}
4112
			$id_assoc_statement_prefix .= ";";
4113
		}
4114

    
4115
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4116
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4117
			$id_assoc_statement_prefix .= " {$wanif}";
4118
			$id_assoc_statement_prefix .= " {\n";
4119
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4120
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4121
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4122
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4123
			}
4124
			$id_assoc_statement_prefix .= "\t};";
4125
		}
4126

    
4127
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4128
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4129
			$id_assoc_statement_prefix .= "\n";
4130
		}
4131

    
4132
		$id_assoc_statement_prefix .= "};\n";
4133
	}
4134

    
4135
	$authentication_statement = "";
4136
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4137
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4138
		$authentication_statement .= "authentication";
4139
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4140
		$authentication_statement .= " {\n";
4141
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4142
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4143
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4144
		}
4145
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4146
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4147
		}
4148
		$authentication_statement .= "};\n";
4149
	}
4150

    
4151
	$key_info_statement = "";
4152
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4153
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4154
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4155
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4156
		$key_info_statement .= "keyinfo";
4157
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4158
		$key_info_statement .= " {\n";
4159
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4160
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4161
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4162
		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'])) {
4163
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4164
		}
4165
		$key_info_statement .= "};\n";
4166
	}
4167

    
4168
	$dhcp6cconf  = $interface_statement;
4169
	$dhcp6cconf .= $id_assoc_statement_address;
4170
	$dhcp6cconf .= $id_assoc_statement_prefix;
4171
	$dhcp6cconf .= $authentication_statement;
4172
	$dhcp6cconf .= $key_info_statement;
4173

    
4174
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4175

    
4176
	return $dhcp6cconf;
4177
}
4178

    
4179

    
4180
function DHCP6_Config_File_Override($wancfg, $wanif) {
4181

    
4182
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4183

    
4184
	if ($dhcp6cconf === false) {
4185
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4186
		return '';
4187
	} else {
4188
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4189
	}
4190
}
4191

    
4192

    
4193
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4194

    
4195
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4196

    
4197
	return $dhcp6cconf;
4198
}
4199

    
4200

    
4201
function interface_dhcp_configure($interface = "wan") {
4202
	global $config, $g;
4203

    
4204
	$wancfg = $config['interfaces'][$interface];
4205
	$wanif = $wancfg['if'];
4206
	if (empty($wancfg)) {
4207
		$wancfg = array();
4208
	}
4209

    
4210
	/* generate dhclient_wan.conf */
4211
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4212
	if (!$fd) {
4213
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4214
		return 1;
4215
	}
4216

    
4217
	if ($wancfg['dhcphostname']) {
4218
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4219
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4220
	} else {
4221
		$dhclientconf_hostname = "";
4222
	}
4223

    
4224
	$wanif = get_real_interface($interface);
4225
	if (empty($wanif)) {
4226
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4227
		return 0;
4228
	}
4229
	$dhclientconf = "";
4230

    
4231
	$dhclientconf .= <<<EOD
4232
interface "{$wanif}" {
4233
timeout 60;
4234
retry 15;
4235
select-timeout 0;
4236
initial-interval 1;
4237
	{$dhclientconf_hostname}
4238
	script "/sbin/dhclient-script";
4239
EOD;
4240

    
4241
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4242
		$dhclientconf .= <<<EOD
4243

    
4244
	reject {$wancfg['dhcprejectfrom']};
4245
EOD;
4246
	}
4247
	$dhclientconf .= <<<EOD
4248

    
4249
}
4250

    
4251
EOD;
4252

    
4253
	// DHCP Config File Advanced
4254
	if ($wancfg['adv_dhcp_config_advanced']) {
4255
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4256
	}
4257

    
4258
	if (is_ipaddr($wancfg['alias-address'])) {
4259
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4260
		$dhclientconf .= <<<EOD
4261
alias {
4262
	interface "{$wanif}";
4263
	fixed-address {$wancfg['alias-address']};
4264
	option subnet-mask {$subnetmask};
4265
}
4266

    
4267
EOD;
4268
	}
4269

    
4270
	// DHCP Config File Override
4271
	if ($wancfg['adv_dhcp_config_file_override']) {
4272
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4273
	}
4274

    
4275
	fwrite($fd, $dhclientconf);
4276
	fclose($fd);
4277

    
4278
	/* bring wan interface up before starting dhclient */
4279
	if ($wanif) {
4280
		interfaces_bring_up($wanif);
4281
	} else {
4282
		log_error(sprintf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4283
	}
4284

    
4285
	/* Make sure dhclient is not running */
4286
	kill_dhclient_process($wanif);
4287

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

    
4291
	return 0;
4292
}
4293

    
4294
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4295

    
4296
	$hostname = "";
4297
	if ($wancfg['dhcphostname'] != '') {
4298
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4299
	}
4300

    
4301
	/* DHCP Protocol Timings */
4302
	$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");
4303
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4304
		$pt_variable = "{$Protocol_Timing}";
4305
		${$pt_variable} = "";
4306
		if ($wancfg[$Protocol_Timing] != "") {
4307
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4308
		}
4309
	}
4310

    
4311
	$send_options = "";
4312
	if ($wancfg['adv_dhcp_send_options'] != '') {
4313
		$options = explode(',', $wancfg['adv_dhcp_send_options']);
4314
		foreach ($options as $option) {
4315
			$send_options .= "\tsend " . trim($option) . ";\n";
4316
		}
4317
	}
4318

    
4319
	$request_options = "";
4320
	if ($wancfg['adv_dhcp_request_options'] != '') {
4321
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4322
	}
4323

    
4324
	$required_options = "";
4325
	if ($wancfg['adv_dhcp_required_options'] != '') {
4326
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4327
	}
4328

    
4329
	$option_modifiers = "";
4330
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4331
		$modifiers = explode(',', $wancfg['adv_dhcp_option_modifiers']);
4332
		foreach ($modifiers as $modifier) {
4333
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4334
		}
4335
	}
4336

    
4337
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4338
	$dhclientconf .= "\n";
4339
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4340
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4341
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4342
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4343
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4344
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4345
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4346
	$dhclientconf .= "\n";
4347
	$dhclientconf .= "# DHCP Protocol Options\n";
4348
	$dhclientconf .= "{$hostname}";
4349
	$dhclientconf .= "{$send_options}";
4350
	$dhclientconf .= "{$request_options}";
4351
	$dhclientconf .= "{$required_options}";
4352
	$dhclientconf .= "{$option_modifiers}";
4353
	$dhclientconf .= "\n";
4354
	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4355
	$dhclientconf .= "}\n";
4356

    
4357
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4358

    
4359
	return $dhclientconf;
4360
}
4361

    
4362

    
4363
function DHCP_Config_File_Override($wancfg, $wanif) {
4364

    
4365
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4366

    
4367
	if ($dhclientconf === false) {
4368
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading.\n"), $wancfg['adv_dhcp_config_file_override_path']));
4369
		return '';
4370
	} else {
4371
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4372
	}
4373
}
4374

    
4375

    
4376
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4377

    
4378
	/* Apply Interface Substitutions */
4379
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4380

    
4381
	/* Apply Hostname Substitutions */
4382
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4383

    
4384
	/* Arrays of MAC Address Types, Cases, Delimiters */
4385
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4386
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4387
	$various_mac_cases      = array("U", "L");
4388
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4389

    
4390
	/* Apply MAC Address Substitutions */
4391
	foreach ($various_mac_types as $various_mac_type) {
4392
		foreach ($various_mac_cases as $various_mac_case) {
4393
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4394

    
4395
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4396
				if ($res !== false) {
4397

    
4398
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4399
					if ("$various_mac_case" == "U") {
4400
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4401
					}
4402
					if ("$various_mac_case" == "L") {
4403
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4404
					}
4405

    
4406
					if ("$various_mac_type" == "mac_addr_hex") {
4407
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4408
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4409
						$dhcpclientconf_mac_hex = "";
4410
						$delimiter = "";
4411
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4412
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4413
							$delimiter = ":";
4414
						}
4415
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4416
					}
4417

    
4418
					/* MAC Address Delimiter Substitutions */
4419
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4420

    
4421
					/* Apply MAC Address Substitutions */
4422
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4423
				}
4424
			}
4425
		}
4426
	}
4427

    
4428
	return $dhclientconf;
4429
}
4430

    
4431
function interfaces_group_setup() {
4432
	global $config;
4433

    
4434
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4435
		return;
4436
	}
4437

    
4438
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4439
		interface_group_setup($groupar);
4440
	}
4441

    
4442
	return;
4443
}
4444

    
4445
function interface_group_setup(&$groupname /* The parameter is an array */) {
4446
	global $config;
4447

    
4448
	if (!is_array($groupname)) {
4449
		return;
4450
	}
4451
	$members = explode(" ", $groupname['members']);
4452
	foreach ($members as $ifs) {
4453
		$realif = get_real_interface($ifs);
4454
		if ($realif && does_interface_exist($realif)) {
4455
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4456
		}
4457
	}
4458

    
4459
	return;
4460
}
4461

    
4462
function is_interface_group($if) {
4463
	global $config;
4464

    
4465
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4466
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4467
			if ($groupentry['ifname'] === $if) {
4468
				return true;
4469
			}
4470
		}
4471
	}
4472

    
4473
	return false;
4474
}
4475

    
4476
function interface_group_add_member($interface, $groupname) {
4477
	$interface = get_real_interface($interface);
4478
	if (does_interface_exist($interface)) {
4479
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4480
	}
4481
}
4482

    
4483
/* COMPAT Function */
4484
function convert_friendly_interface_to_real_interface_name($interface) {
4485
	return get_real_interface($interface);
4486
}
4487

    
4488
/* COMPAT Function */
4489
function get_real_wan_interface($interface = "wan") {
4490
	return get_real_interface($interface);
4491
}
4492

    
4493
/* COMPAT Function */
4494
function get_current_wan_address($interface = "wan") {
4495
	return get_interface_ip($interface);
4496
}
4497

    
4498
/*
4499
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4500
 */
4501
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4502
	global $config;
4503

    
4504
	/* XXX: For speed reasons reference directly the interface array */
4505
	$ifdescrs = &$config['interfaces'];
4506
	//$ifdescrs = get_configured_interface_list(false, true);
4507

    
4508
	foreach ($ifdescrs as $if => $ifname) {
4509
		if ($if == $interface || $ifname['if'] == $interface) {
4510
			return $if;
4511
		}
4512

    
4513
		if (get_real_interface($if) == $interface) {
4514
			return $if;
4515
		}
4516

    
4517
		if ($checkparent == false) {
4518
			continue;
4519
		}
4520

    
4521
		$int = get_parent_interface($if, true);
4522
		if (is_array($int)) {
4523
			foreach ($int as $iface) {
4524
				if ($iface == $interface) {
4525
					return $if;
4526
				}
4527
			}
4528
		}
4529
	}
4530

    
4531
	if ($interface == "enc0") {
4532
		return 'IPsec';
4533
	}
4534
}
4535

    
4536
/* attempt to resolve interface to friendly descr */
4537
function convert_friendly_interface_to_friendly_descr($interface) {
4538
	global $config;
4539

    
4540
	switch ($interface) {
4541
		case "l2tp":
4542
			$ifdesc = "L2TP";
4543
			break;
4544
		case "pptp":
4545
			$ifdesc = "PPTP";
4546
			break;
4547
		case "pppoe":
4548
			$ifdesc = "PPPoE";
4549
			break;
4550
		case "openvpn":
4551
			$ifdesc = "OpenVPN";
4552
			break;
4553
		case "lo0":
4554
			$ifdesc = "Loopback";
4555
			break;
4556
		case "enc0":
4557
		case "ipsec":
4558
		case "IPsec":
4559
			$ifdesc = "IPsec";
4560
			break;
4561
		default:
4562
			if (isset($config['interfaces'][$interface])) {
4563
				if (empty($config['interfaces'][$interface]['descr'])) {
4564
					$ifdesc = strtoupper($interface);
4565
				} else {
4566
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4567
				}
4568
				break;
4569
			} else if (substr($interface, 0, 4) == '_vip') {
4570
				if (is_array($config['virtualip']['vip'])) {
4571
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
4572
						if ($vip['mode'] == "carp") {
4573
							if ($interface == "_vip{$vip['uniqid']}") {
4574
								return "{$vip['subnet']} - {$vip['descr']}";
4575
							}
4576
						}
4577
					}
4578
				}
4579
			} else if (substr($interface, 0, 5) == '_lloc') {
4580
				return get_interface_linklocal($interface);
4581
			} else {
4582
				/* if list */
4583
				$ifdescrs = get_configured_interface_with_descr(false, true);
4584
				foreach ($ifdescrs as $if => $ifname) {
4585
					if ($if == $interface || $ifname == $interface) {
4586
						return $ifname;
4587
					}
4588
				}
4589
			}
4590
			break;
4591
	}
4592

    
4593
	return $ifdesc;
4594
}
4595

    
4596
function convert_real_interface_to_friendly_descr($interface) {
4597

    
4598
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4599

    
4600
	if (!empty($ifdesc)) {
4601
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4602
	}
4603

    
4604
	return $interface;
4605
}
4606

    
4607
/*
4608
 *  get_parent_interface($interface):
4609
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4610
 *				or virtual interface (i.e. vlan)
4611
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4612
 *			-- returns $interface passed in if $interface parent is not found
4613
 *			-- returns empty array if an invalid interface is passed
4614
 *	(Only handles ppps and vlans now.)
4615
 */
4616
function get_parent_interface($interface, $avoidrecurse = false) {
4617
	global $config;
4618

    
4619
	$parents = array();
4620
	//Check that we got a valid interface passed
4621
	$realif = get_real_interface($interface);
4622
	if ($realif == NULL) {
4623
		return $parents;
4624
	}
4625

    
4626
	// If we got a real interface, find it's friendly assigned name
4627
	if ($interface == $realif && $avoidrecurse == false) {
4628
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4629
	}
4630

    
4631
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4632
		$ifcfg = $config['interfaces'][$interface];
4633
		switch ($ifcfg['ipaddr']) {
4634
			case "ppp":
4635
			case "pppoe":
4636
			case "pptp":
4637
			case "l2tp":
4638
				if (empty($parents)) {
4639
					if (is_array($config['ppps']['ppp'])) {
4640
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4641
							if ($ifcfg['if'] == $ppp['if']) {
4642
								$ports = explode(',', $ppp['ports']);
4643
								foreach ($ports as $pid => $parent_if) {
4644
									$parents[$pid] = get_real_interface($parent_if);
4645
								}
4646
								break;
4647
							}
4648
						}
4649
					}
4650
				}
4651
				break;
4652
			case "dhcp":
4653
			case "static":
4654
			default:
4655
				// Handle _vlans
4656
				if (strpos($realif, '_vlan') !== FALSE) {
4657
					if (is_array($config['vlans']['vlan'])) {
4658
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4659
							if ($ifcfg['if'] == $vlan['vlanif']) {
4660
								$parents[0] = $vlan['if'];
4661
								break;
4662
							}
4663
						}
4664
					}
4665
				}
4666
				break;
4667
		}
4668
	}
4669

    
4670
	if (empty($parents)) {
4671
		// Handle _vlans not assigned to an interface
4672
		if (strpos($realif, '_vlan') !== FALSE) {
4673
			if (is_array($config['vlans']['vlan'])) {
4674
				foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4675
					if ($realif == $vlan['vlanif']) {
4676
						$parents[0] = $vlan['if'];
4677
						break;
4678
					}
4679
				}
4680
			}
4681
		}
4682
	}
4683

    
4684
	if (empty($parents)) {
4685
		$parents[0] = $realif;
4686
	}
4687

    
4688
	return $parents;
4689
}
4690

    
4691
/*
4692
 *  get_parent_physical_interface($interface):
4693
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
4694
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
4695
 */
4696
function get_parent_physical_interface($interface) {
4697
	global $config;
4698

    
4699
	$realif = get_parent_interface($interface);
4700

    
4701
	if (substr($realif[0], 0, 4) == "lagg") {
4702
		foreach ($config['laggs']['lagg'] as $lagg) {
4703
			if ($realif[0] == $lagg['laggif']) {
4704
				return explode(",", $lagg['members']);
4705
			}
4706
		}
4707
	} else {
4708
		return $realif;
4709
	}
4710
}
4711

    
4712
function interface_is_wireless_clone($wlif) {
4713
	if (!stristr($wlif, "_wlan")) {
4714
		return false;
4715
	} else {
4716
		return true;
4717
	}
4718
}
4719

    
4720
function interface_get_wireless_base($wlif) {
4721
	if (!stristr($wlif, "_wlan")) {
4722
		return $wlif;
4723
	} else {
4724
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4725
	}
4726
}
4727

    
4728
function interface_get_wireless_clone($wlif) {
4729
	if (!stristr($wlif, "_wlan")) {
4730
		return $wlif . "_wlan0";
4731
	} else {
4732
		return $wlif;
4733
	}
4734
}
4735

    
4736
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4737
	global $config, $g;
4738

    
4739
	$wanif = NULL;
4740

    
4741
	switch ($interface) {
4742
		case "l2tp":
4743
			$wanif = "l2tp";
4744
			break;
4745
		case "pptp":
4746
			$wanif = "pptp";
4747
			break;
4748
		case "pppoe":
4749
			$wanif = "pppoe";
4750
			break;
4751
		case "openvpn":
4752
			$wanif = "openvpn";
4753
			break;
4754
		case "IPsec":
4755
		case "ipsec":
4756
		case "enc0":
4757
			$wanif = "enc0";
4758
			break;
4759
		case "ppp":
4760
			$wanif = "ppp";
4761
			break;
4762
		default:
4763
			if (substr($interface, 0, 4) == '_vip') {
4764
				$wanif = get_configured_vip_interface($interface);
4765
				if (!empty($wanif)) {
4766
					$wanif = get_real_interface($wanif);
4767
				}
4768
				break;
4769
			} else if (substr($interface, 0, 5) == '_lloc') {
4770
				$interface = substr($interface, 5);
4771
			} else if (strstr($interface, "_vlan") ||
4772
			    does_interface_exist($interface, $flush)) {
4773
				/*
4774
				 * If a real interface was already passed simply
4775
				 * pass the real interface back.  This encourages
4776
				 * the usage of this function in more cases so that
4777
				 * we can combine logic for more flexibility.
4778
				 */
4779
				$wanif = $interface;
4780
				break;
4781
			}
4782

    
4783
			if (empty($config['interfaces'][$interface])) {
4784
				break;
4785
			}
4786

    
4787
			$cfg = &$config['interfaces'][$interface];
4788

    
4789
			if ($family == "inet6") {
4790
				switch ($cfg['ipaddrv6']) {
4791
					case "6rd":
4792
					case "6to4":
4793
						$wanif = "{$interface}_stf";
4794
						break;
4795
					case 'pppoe':
4796
					case 'ppp':
4797
					case 'l2tp':
4798
					case 'pptp':
4799
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4800
							$wanif = interface_get_wireless_clone($cfg['if']);
4801
						} else {
4802
							$wanif = $cfg['if'];
4803
						}
4804
						break;
4805
					default:
4806
						switch ($cfg['ipaddr']) {
4807
							case 'pppoe':
4808
							case 'ppp':
4809
							case 'l2tp':
4810
							case 'pptp':
4811
								if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false) {
4812
									$wanif = $cfg['if'];
4813
								} else {
4814
									$parents = get_parent_interface($interface);
4815
									if (!empty($parents[0])) {
4816
										$wanif = $parents[0];
4817
									} else {
4818
										$wanif = $cfg['if'];
4819
									}
4820
								}
4821
								break;
4822
							default:
4823
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4824
									$wanif = interface_get_wireless_clone($cfg['if']);
4825
								} else {
4826
									$wanif = $cfg['if'];
4827
								}
4828
								break;
4829
						}
4830
						break;
4831
				}
4832
			} else {
4833
				// Wireless cloned NIC support (FreeBSD 8+)
4834
				// interface name format: $parentnic_wlanparentnic#
4835
				// example: ath0_wlan0
4836
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4837
					$wanif = interface_get_wireless_clone($cfg['if']);
4838
				} else {
4839
					$wanif = $cfg['if'];
4840
				}
4841
			}
4842
			break;
4843
	}
4844

    
4845
	return $wanif;
4846
}
4847

    
4848
/* Guess the physical interface by providing a IP address */
4849
function guess_interface_from_ip($ipaddress) {
4850

    
4851
	$family = '';
4852
	if (is_ipaddrv4($ipaddress)) {
4853
		$family = 'inet';
4854
	}
4855
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4856
		$family = 'inet6';
4857
	}
4858

    
4859
	if (empty($family)) {
4860
		return false;
4861
	}
4862

    
4863
	/* create a route table we can search */
4864
	$output = '';
4865
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4866
	$output[0] = trim($output[0], " \n");
4867
	if (!empty($output[0])) {
4868
		return $output[0];
4869
	}
4870

    
4871
	return false;
4872
}
4873

    
4874
/*
4875
 * find_ip_interface($ip): return the interface where an ip is defined
4876
 *   (or if $bits is specified, where an IP within the subnet is defined)
4877
 */
4878
function find_ip_interface($ip, $bits = null) {
4879
	if (!is_ipaddr($ip)) {
4880
		return false;
4881
	}
4882

    
4883
	$isv6ip = is_ipaddrv6($ip);
4884

    
4885
	/* if list */
4886
	$ifdescrs = get_configured_interface_list();
4887

    
4888
	foreach ($ifdescrs as $ifdescr => $ifname) {
4889
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4890
		if (is_null($ifip)) {
4891
			continue;
4892
		}
4893
		if (is_null($bits)) {
4894
			if ($ip == $ifip) {
4895
				$int = get_real_interface($ifname);
4896
				return $int;
4897
			}
4898
		} else {
4899
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4900
				$int = get_real_interface($ifname);
4901
				return $int;
4902
			}
4903
		}
4904
	}
4905

    
4906
	return false;
4907
}
4908

    
4909
/*
4910
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4911
 *   (or if $bits is specified, where an IP within the subnet is found)
4912
 */
4913
function find_virtual_ip_alias($ip, $bits = null) {
4914
	global $config;
4915

    
4916
	if (!is_array($config['virtualip']['vip'])) {
4917
		return false;
4918
	}
4919
	if (!is_ipaddr($ip)) {
4920
		return false;
4921
	}
4922

    
4923
	$isv6ip = is_ipaddrv6($ip);
4924

    
4925
	foreach ($config['virtualip']['vip'] as $vip) {
4926
		if ($vip['mode'] === "ipalias") {
4927
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
4928
				continue;
4929
			}
4930
			if (is_null($bits)) {
4931
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4932
					return $vip;
4933
				}
4934
			} else {
4935
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
4936
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4937
					return $vip;
4938
				}
4939
			}
4940
		}
4941
	}
4942
	return false;
4943
}
4944

    
4945
function link_interface_to_track6($int, $action = "") {
4946
	global $config;
4947

    
4948
	if (empty($int)) {
4949
		return;
4950
	}
4951

    
4952
	if (is_array($config['interfaces'])) {
4953
		$list = array();
4954
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4955
			if (!isset($ifcfg['enable'])) {
4956
				continue;
4957
			}
4958
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4959
				if ($action == "update") {
4960
					interface_track6_configure($ifname, $ifcfg);
4961
				} else if ($action == "") {
4962
					$list[$ifname] = $ifcfg;
4963
				}
4964
			}
4965
		}
4966
		return $list;
4967
	}
4968
}
4969

    
4970
function interface_find_child_cfgmtu($realiface) {
4971
	global $config;
4972

    
4973
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
4974
	$vlans = link_interface_to_vlans($realiface);
4975
	$qinqs = link_interface_to_qinqs($realiface);
4976
	$bridge = link_interface_to_bridge($realiface);
4977
	if (!empty($interface)) {
4978
		$gifs = link_interface_to_gif($interface);
4979
		$gres = link_interface_to_gre($interface);
4980
	} else {
4981
		$gifs = array();
4982
		$gres = array();
4983
	}
4984

    
4985
	$mtu = 0;
4986
	if (is_array($vlans)) {
4987
		foreach ($vlans as $vlan) {
4988
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4989
			if (empty($ifass)) {
4990
				continue;
4991
			}
4992
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4993
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4994
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4995
				}
4996
			}
4997
		}
4998
	}
4999
	if (is_array($qinqs)) {
5000
		foreach ($qinqs as $qinq) {
5001
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5002
			if (empty($ifass)) {
5003
				continue;
5004
			}
5005
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5006
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5007
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5008
				}
5009
			}
5010
		}
5011
	}
5012
	if (is_array($gifs)) {
5013
		foreach ($gifs as $gif) {
5014
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5015
			if (empty($ifass)) {
5016
				continue;
5017
			}
5018
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5019
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5020
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5021
				}
5022
			}
5023
		}
5024
	}
5025
	if (is_array($gres)) {
5026
		foreach ($gres as $gre) {
5027
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5028
			if (empty($ifass)) {
5029
				continue;
5030
			}
5031
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5032
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5033
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5034
				}
5035
			}
5036
		}
5037
	}
5038
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5039
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5040
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5041
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5042
		}
5043
	}
5044
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5045

    
5046
	return $mtu;
5047
}
5048

    
5049
function link_interface_to_vlans($int, $action = "") {
5050
	global $config;
5051

    
5052
	if (empty($int)) {
5053
		return;
5054
	}
5055

    
5056
	if (is_array($config['vlans']['vlan'])) {
5057
		$ifaces = array();
5058
		foreach ($config['vlans']['vlan'] as $vlan) {
5059
			if ($int == $vlan['if']) {
5060
				if ($action == "update") {
5061
					interfaces_bring_up($int);
5062
				} else {
5063
					$ifaces[$vlan['tag']] = $vlan;
5064
				}
5065
			}
5066
		}
5067
		if (!empty($ifaces)) {
5068
			return $ifaces;
5069
		}
5070
	}
5071
}
5072

    
5073
function link_interface_to_qinqs($int, $action = "") {
5074
	global $config;
5075

    
5076
	if (empty($int)) {
5077
		return;
5078
	}
5079

    
5080
	if (is_array($config['qinqs']['qinqentry'])) {
5081
		$ifaces = array();
5082
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5083
			if ($int == $qinq['if']) {
5084
				if ($action == "update") {
5085
					interfaces_bring_up($int);
5086
				} else {
5087
					$ifaces[$qinq['tag']] = $qinq;
5088
				}
5089
			}
5090
		}
5091
		if (!empty($ifaces)) {
5092
			return $ifaces;
5093
		}
5094
	}
5095
}
5096

    
5097
function link_interface_to_vips($int, $action = "", $vhid = '') {
5098
	global $config;
5099

    
5100
	if (is_array($config['virtualip']['vip'])) {
5101
		$result = array();
5102
		foreach ($config['virtualip']['vip'] as $vip) {
5103
			if (substr($vip['interface'], 0, 4) == "_vip")
5104
				$iface = get_configured_vip_interface($vip['interface']);
5105
			else
5106
				$iface = $vip['interface'];
5107
			if ($int != $iface)
5108
				continue;
5109
			if ($action == "update") {
5110
				interfaces_vips_configure($int);
5111
			} else {
5112
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5113
				    substr($vip['interface'], 0, 4) == "_vip") {
5114
					$result[] = $vip;
5115
				}
5116
			}
5117
		}
5118
		return $result;
5119
	}
5120

    
5121
	return NULL;
5122
}
5123

    
5124
/****f* interfaces/link_interface_to_bridge
5125
 * NAME
5126
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5127
 * INPUTS
5128
 *   $ip
5129
 * RESULT
5130
 *   bridge[0-99]
5131
 ******/
5132
function link_interface_to_bridge($int) {
5133
	global $config;
5134

    
5135
	if (is_array($config['bridges']['bridged'])) {
5136
		foreach ($config['bridges']['bridged'] as $bridge) {
5137
			if (in_array($int, explode(',', $bridge['members']))) {
5138
				return "{$bridge['bridgeif']}";
5139
			}
5140
		}
5141
	}
5142
}
5143

    
5144
function link_interface_to_group($int) {
5145
	global $config;
5146

    
5147
	$result = array();
5148

    
5149
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5150
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5151
			if (in_array($int, explode(" ", $group['members']))) {
5152
				$result[$group['ifname']] = $int;
5153
			}
5154
		}
5155
	}
5156

    
5157
	return $result;
5158
}
5159

    
5160
function link_interface_to_gre($interface) {
5161
	global $config;
5162

    
5163
	$result = array();
5164

    
5165
	if (is_array($config['gres']['gre'])) {
5166
		foreach ($config['gres']['gre'] as $gre) {
5167
			if ($gre['if'] == $interface) {
5168
				$result[] = $gre;
5169
			}
5170
		}
5171
	}
5172

    
5173
	return $result;
5174
}
5175

    
5176
function link_interface_to_gif($interface) {
5177
	global $config;
5178

    
5179
	$result = array();
5180

    
5181
	if (is_array($config['gifs']['gif'])) {
5182
		foreach ($config['gifs']['gif'] as $gif) {
5183
			if ($gif['if'] == $interface) {
5184
				$result[] = $gif;
5185
			}
5186
		}
5187
	}
5188

    
5189
	return $result;
5190
}
5191

    
5192
/*
5193
 * find_interface_ip($interface): return the interface ip (first found)
5194
 */
5195
function find_interface_ip($interface, $flush = false) {
5196
	global $interface_ip_arr_cache;
5197
	global $interface_sn_arr_cache;
5198

    
5199
	$interface = str_replace("\n", "", $interface);
5200

    
5201
	if (!does_interface_exist($interface)) {
5202
		return;
5203
	}
5204

    
5205
	/* Setup IP cache */
5206
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5207
		$ifinfo = pfSense_get_interface_addresses($interface);
5208
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5209
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5210
	}
5211

    
5212
	return $interface_ip_arr_cache[$interface];
5213
}
5214

    
5215
/*
5216
 * find_interface_ipv6($interface): return the interface ip (first found)
5217
 */
5218
function find_interface_ipv6($interface, $flush = false) {
5219
	global $interface_ipv6_arr_cache;
5220
	global $interface_snv6_arr_cache;
5221
	global $config;
5222

    
5223
	$interface = trim($interface);
5224
	$interface = get_real_interface($interface);
5225

    
5226
	if (!does_interface_exist($interface)) {
5227
		return;
5228
	}
5229

    
5230
	/* Setup IP cache */
5231
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5232
		$ifinfo = pfSense_get_interface_addresses($interface);
5233
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5234
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5235
	}
5236

    
5237
	return $interface_ipv6_arr_cache[$interface];
5238
}
5239

    
5240
/*
5241
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5242
 */
5243
function find_interface_ipv6_ll($interface, $flush = false) {
5244
	global $interface_llv6_arr_cache;
5245
	global $config;
5246

    
5247
	$interface = str_replace("\n", "", $interface);
5248

    
5249
	if (!does_interface_exist($interface)) {
5250
		return;
5251
	}
5252

    
5253
	/* Setup IP cache */
5254
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5255
		$ifinfo = pfSense_getall_interface_addresses($interface);
5256
		foreach ($ifinfo as $line) {
5257
			if (strstr($line, ":")) {
5258
				$parts = explode("/", $line);
5259
				if (is_linklocal($parts[0])) {
5260
					$ifinfo['linklocal'] = $parts[0];
5261
				}
5262
			}
5263
		}
5264
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5265
	}
5266
	return $interface_llv6_arr_cache[$interface];
5267
}
5268

    
5269
function find_interface_subnet($interface, $flush = false) {
5270
	global $interface_sn_arr_cache;
5271
	global $interface_ip_arr_cache;
5272

    
5273
	$interface = str_replace("\n", "", $interface);
5274
	if (does_interface_exist($interface) == false) {
5275
		return;
5276
	}
5277

    
5278
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5279
		$ifinfo = pfSense_get_interface_addresses($interface);
5280
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5281
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5282
	}
5283

    
5284
	return $interface_sn_arr_cache[$interface];
5285
}
5286

    
5287
function find_interface_subnetv6($interface, $flush = false) {
5288
	global $interface_snv6_arr_cache;
5289
	global $interface_ipv6_arr_cache;
5290

    
5291
	$interface = str_replace("\n", "", $interface);
5292
	if (does_interface_exist($interface) == false) {
5293
		return;
5294
	}
5295

    
5296
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5297
		$ifinfo = pfSense_get_interface_addresses($interface);
5298
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5299
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5300
	}
5301

    
5302
	return $interface_snv6_arr_cache[$interface];
5303
}
5304

    
5305
function ip_in_interface_alias_subnet($interface, $ipalias) {
5306
	global $config;
5307

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

    
5327
	return false;
5328
}
5329

    
5330
function get_possible_listen_ips($include_ipv6_link_local=false) {
5331

    
5332
	$interfaces = get_configured_interface_with_descr();
5333
	foreach ($interfaces as $iface => $ifacename) {
5334
		if ($include_ipv6_link_local) {
5335
			/* This is to avoid going though added ll below */
5336
			if (substr($iface, 0, 5) == '_lloc') {
5337
				continue;
5338
			}
5339
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5340
			if (!empty($llip)) {
5341
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5342
			}
5343
		}
5344
	}
5345
	$viplist = get_configured_vip_list();
5346
	foreach ($viplist as $vip => $address) {
5347
		$interfaces[$vip] = $address;
5348
		if (get_vip_descr($address)) {
5349
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5350
		}
5351
	}
5352

    
5353
	$interfaces['lo0'] = 'Localhost';
5354

    
5355
	return $interfaces;
5356
}
5357

    
5358
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5359
	global $config;
5360

    
5361
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5362
	foreach (array('server', 'client') as $mode) {
5363
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5364
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5365
				if (!isset($setting['disable'])) {
5366
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5367
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5368
				}
5369
			}
5370
		}
5371
	}
5372
	return $sourceips;
5373
}
5374

    
5375
function get_interface_ip($interface = "wan") {
5376

    
5377
	if (substr($interface, 0, 4) == '_vip') {
5378
		return get_configured_vip_ipv4($interface);
5379
	} else if (substr($interface, 0, 5) == '_lloc') {
5380
		/* No link-local address for v4. */
5381
		return null;
5382
	}
5383

    
5384
	$realif = get_failover_interface($interface, 'inet');
5385
	if (!$realif) {
5386
		return null;
5387
	}
5388

    
5389
	if (substr($realif, 0, 4) == '_vip') {
5390
		return get_configured_vip_ipv4($realif);
5391
	} else if (substr($realif, 0, 5) == '_lloc') {
5392
		/* No link-local address for v4. */
5393
		return null;
5394
	}
5395

    
5396
	if (is_array($config['interfaces'][$interface]) &&
5397
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5398
		return ($config['interfaces'][$interface]['ipaddr']);
5399
	}
5400

    
5401
	/*
5402
	 * Beaware that find_interface_ip() is our last option, it will
5403
	 * return the first IP it find on interface, not necessarily the
5404
	 * main IP address.
5405
	 */
5406
	$curip = find_interface_ip($realif);
5407
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5408
		return $curip;
5409
	} else {
5410
		return null;
5411
	}
5412
}
5413

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

    
5417
	if (substr($interface, 0, 4) == '_vip') {
5418
		return get_configured_vip_ipv6($interface);
5419
	} else if (substr($interface, 0, 5) == '_lloc') {
5420
		return get_interface_linklocal($interface);
5421
	}
5422

    
5423
	$realif = get_failover_interface($interface, 'inet6');
5424
	if (!$realif) {
5425
		return null;
5426
	}
5427

    
5428
	if (substr($realif, 0, 4) == '_vip') {
5429
		return get_configured_vip_ipv6($realif);
5430
	} else if (substr($realif, 0, 5) == '_lloc') {
5431
		return get_interface_linklocal($realif);
5432
	}
5433

    
5434
	if (is_array($config['interfaces'][$interface])) {
5435
		switch ($config['interfaces'][$interface]['ipaddr']) {
5436
			case 'pppoe':
5437
			case 'l2tp':
5438
			case 'pptp':
5439
			case 'ppp':
5440
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5441
					$realif = get_real_interface($interface, 'inet6', false);
5442
				}
5443
				break;
5444
		}
5445
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5446
			return ($config['interfaces'][$interface]['ipaddrv6']);
5447
		}
5448
	}
5449

    
5450
	/*
5451
	 * Beaware that find_interface_ip() is our last option, it will
5452
	 * return the first IP it find on interface, not necessarily the
5453
	 * main IP address.
5454
	 */
5455
	$curip = find_interface_ipv6($realif, $flush);
5456
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5457
		return $curip;
5458
	} else {
5459
		/*
5460
		 * NOTE: On the case when only the prefix is requested,
5461
		 * the communication on WAN will be done over link-local.
5462
		 */
5463
		if (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
5464
			$curip = find_interface_ipv6_ll($realif, $flush);
5465
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5466
				return $curip;
5467
			}
5468
		}
5469
	}
5470
	return null;
5471
}
5472

    
5473
function get_interface_linklocal($interface = "wan") {
5474

    
5475
	$realif = get_failover_interface($interface, 'inet6');
5476
	if (!$realif) {
5477
		return null;
5478
	}
5479

    
5480
	if (substr($interface, 0, 4) == '_vip') {
5481
		$realif = get_real_interface($interface);
5482
	} else if (substr($interface, 0, 5) == '_lloc') {
5483
		$realif = get_real_interface(substr($interface, 5));
5484
	}
5485

    
5486
	$curip = find_interface_ipv6_ll($realif);
5487
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5488
		return $curip;
5489
	} else {
5490
		return null;
5491
	}
5492
}
5493

    
5494
function get_interface_subnet($interface = "wan") {
5495

    
5496
	if (substr($interface, 0, 4) == '_vip') {
5497
		return (get_configured_vip_subnetv4($interface));
5498
	}
5499

    
5500
	$realif = get_real_interface($interface);
5501
	if (!$realif) {
5502
		return (NULL);
5503
	}
5504

    
5505
	$cursn = find_interface_subnet($realif);
5506
	if (!empty($cursn)) {
5507
		return ($cursn);
5508
	}
5509

    
5510
	return (NULL);
5511
}
5512

    
5513
function get_interface_subnetv6($interface = "wan") {
5514

    
5515
	if (substr($interface, 0, 4) == '_vip') {
5516
		return (get_configured_vip_subnetv6($interface));
5517
	} else if (substr($interface, 0, 5) == '_lloc') {
5518
		$interface = substr($interface, 5);
5519
	}
5520

    
5521
	$realif = get_real_interface($interface, 'inet6');
5522
	if (!$realif) {
5523
		return (NULL);
5524
	}
5525

    
5526
	$cursn = find_interface_subnetv6($realif);
5527
	if (!empty($cursn)) {
5528
		return ($cursn);
5529
	}
5530

    
5531
	return (NULL);
5532
}
5533

    
5534
/* return outside interfaces with a gateway */
5535
function get_interfaces_with_gateway() {
5536
	global $config;
5537

    
5538
	$ints = array();
5539

    
5540
	/* loop interfaces, check config for outbound */
5541
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5542
		switch ($ifname['ipaddr']) {
5543
			case "dhcp":
5544
			case "pppoe":
5545
			case "pptp":
5546
			case "l2tp":
5547
			case "ppp":
5548
				$ints[$ifdescr] = $ifdescr;
5549
				break;
5550
			default:
5551
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5552
				    !empty($ifname['gateway'])) {
5553
					$ints[$ifdescr] = $ifdescr;
5554
				}
5555
				break;
5556
		}
5557
	}
5558
	return $ints;
5559
}
5560

    
5561
/* return true if interface has a gateway */
5562
function interface_has_gateway($friendly) {
5563
	global $config;
5564

    
5565
	if (!empty($config['interfaces'][$friendly])) {
5566
		$ifname = &$config['interfaces'][$friendly];
5567
		switch ($ifname['ipaddr']) {
5568
			case "dhcp":
5569
			case "pppoe":
5570
			case "pptp":
5571
			case "l2tp":
5572
			case "ppp":
5573
				return true;
5574
			break;
5575
			default:
5576
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5577
					return true;
5578
				}
5579
				$tunnelif = substr($ifname['if'], 0, 3);
5580
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5581
					if (find_interface_ip($ifname['if'])) {
5582
						return true;
5583
					}
5584
				}
5585
				if (!empty($ifname['gateway'])) {
5586
					return true;
5587
				}
5588
			break;
5589
		}
5590
	}
5591

    
5592
	return false;
5593
}
5594

    
5595
/* return true if interface has a gateway */
5596
function interface_has_gatewayv6($friendly) {
5597
	global $config;
5598

    
5599
	if (!empty($config['interfaces'][$friendly])) {
5600
		$ifname = &$config['interfaces'][$friendly];
5601
		switch ($ifname['ipaddrv6']) {
5602
			case "slaac":
5603
			case "dhcp6":
5604
			case "6to4":
5605
			case "6rd":
5606
				return true;
5607
				break;
5608
			default:
5609
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5610
					return true;
5611
				}
5612
				$tunnelif = substr($ifname['if'], 0, 3);
5613
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5614
					if (find_interface_ipv6($ifname['if'])) {
5615
						return true;
5616
					}
5617
				}
5618
				if (!empty($ifname['gatewayv6'])) {
5619
					return true;
5620
				}
5621
				break;
5622
		}
5623
	}
5624

    
5625
	return false;
5626
}
5627

    
5628
/****f* interfaces/is_altq_capable
5629
 * NAME
5630
 *   is_altq_capable - Test if interface is capable of using ALTQ
5631
 * INPUTS
5632
 *   $int            - string containing interface name
5633
 * RESULT
5634
 *   boolean         - true or false
5635
 ******/
5636

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

    
5651
	$int_family = remove_ifindex($int);
5652

    
5653
	if (in_array($int_family, $capable)) {
5654
		return true;
5655
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5656
		return true;
5657
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5658
		return true;
5659
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5660
		return true;
5661
	} else {
5662
		return false;
5663
	}
5664
}
5665

    
5666
/****f* interfaces/is_interface_wireless
5667
 * NAME
5668
 *   is_interface_wireless - Returns if an interface is wireless
5669
 * RESULT
5670
 *   $tmp       - Returns if an interface is wireless
5671
 ******/
5672
function is_interface_wireless($interface) {
5673
	global $config, $g;
5674

    
5675
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5676
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5677
		if (preg_match($g['wireless_regex'], $interface)) {
5678
			if (isset($config['interfaces'][$friendly])) {
5679
				$config['interfaces'][$friendly]['wireless'] = array();
5680
			}
5681
			return true;
5682
		}
5683
		return false;
5684
	} else {
5685
		return true;
5686
	}
5687
}
5688

    
5689
function get_wireless_modes($interface) {
5690
	/* return wireless modes and channels */
5691
	$wireless_modes = array();
5692

    
5693
	$cloned_interface = get_real_interface($interface);
5694

    
5695
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5696
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5697
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5698
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5699

    
5700
		$interface_channels = "";
5701
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5702
		$interface_channel_count = count($interface_channels);
5703

    
5704
		$c = 0;
5705
		while ($c < $interface_channel_count) {
5706
			$channel_line = explode(",", $interface_channels["$c"]);
5707
			$wireless_mode = trim($channel_line[0]);
5708
			$wireless_channel = trim($channel_line[1]);
5709
			if (trim($wireless_mode) != "") {
5710
				/* if we only have 11g also set 11b channels */
5711
				if ($wireless_mode == "11g") {
5712
					if (!isset($wireless_modes["11b"])) {
5713
						$wireless_modes["11b"] = array();
5714
					}
5715
				} else if ($wireless_mode == "11g ht") {
5716
					if (!isset($wireless_modes["11b"])) {
5717
						$wireless_modes["11b"] = array();
5718
					}
5719
					if (!isset($wireless_modes["11g"])) {
5720
						$wireless_modes["11g"] = array();
5721
					}
5722
					$wireless_mode = "11ng";
5723
				} else if ($wireless_mode == "11a ht") {
5724
					if (!isset($wireless_modes["11a"])) {
5725
						$wireless_modes["11a"] = array();
5726
					}
5727
					$wireless_mode = "11na";
5728
				}
5729
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5730
			}
5731
			$c++;
5732
		}
5733
	}
5734
	return($wireless_modes);
5735
}
5736

    
5737
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5738
function get_wireless_channel_info($interface) {
5739
	$wireless_channels = array();
5740

    
5741
	$cloned_interface = get_real_interface($interface);
5742

    
5743
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5744
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5745
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5746
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5747

    
5748
		$interface_channels = "";
5749
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5750

    
5751
		foreach ($interface_channels as $channel_line) {
5752
			$channel_line = explode(",", $channel_line);
5753
			if (!isset($wireless_channels[$channel_line[0]])) {
5754
				$wireless_channels[$channel_line[0]] = $channel_line;
5755
			}
5756
		}
5757
	}
5758
	return($wireless_channels);
5759
}
5760

    
5761
function set_interface_mtu($interface, $mtu) {
5762

    
5763
	/* LAGG interface must be destroyed and re-created to change MTU */
5764
	if (substr($interface, 0, 4) == 'lagg') {
5765
		if (isset($config['laggs']['lagg']) &&
5766
		    is_array($config['laggs']['lagg'])) {
5767
			foreach ($config['laggs']['lagg'] as $lagg) {
5768
				if ($lagg['laggif'] == $interface) {
5769
					interface_lagg_configure($lagg);
5770
					break;
5771
				}
5772
			}
5773
		}
5774
	} else {
5775
		pfSense_interface_mtu($interface, $mtu);
5776
	}
5777
}
5778

    
5779
/****f* interfaces/get_interface_mtu
5780
 * NAME
5781
 *   get_interface_mtu - Return the mtu of an interface
5782
 * RESULT
5783
 *   $tmp       - Returns the mtu of an interface
5784
 ******/
5785
function get_interface_mtu($interface) {
5786
	$mtu = pfSense_interface_getmtu($interface);
5787
	return $mtu['mtu'];
5788
}
5789

    
5790
function get_interface_mac($interface) {
5791

    
5792
	$macinfo = pfSense_get_interface_addresses($interface);
5793
	return $macinfo["macaddr"];
5794
}
5795

    
5796
/****f* pfsense-utils/generate_random_mac_address
5797
 * NAME
5798
 *   generate_random_mac - generates a random mac address
5799
 * INPUTS
5800
 *   none
5801
 * RESULT
5802
 *   $mac - a random mac address
5803
 ******/
5804
function generate_random_mac_address() {
5805
	$mac = "02";
5806
	for ($x = 0; $x < 5; $x++) {
5807
		$mac .= ":" . dechex(rand(16, 255));
5808
	}
5809
	return $mac;
5810
}
5811

    
5812
/****f* interfaces/is_jumbo_capable
5813
 * NAME
5814
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5815
 * INPUTS
5816
 *   $int             - string containing interface name
5817
 * RESULT
5818
 *   boolean          - true or false
5819
 ******/
5820
function is_jumbo_capable($iface) {
5821
	$iface = trim($iface);
5822
	$capable = pfSense_get_interface_addresses($iface);
5823

    
5824
	if (isset($capable['caps']['vlanmtu'])) {
5825
		return true;
5826
	}
5827

    
5828
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5829
	if (substr($iface, 0, 4) == "lagg") {
5830
		return true;
5831
	}
5832

    
5833
	return false;
5834
}
5835

    
5836
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5837
	global $g;
5838

    
5839
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5840

    
5841
	if (!empty($iface) && !empty($pppif)) {
5842
		$cron_cmd = <<<EOD
5843
#!/bin/sh
5844
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5845
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5846

    
5847
EOD;
5848

    
5849
		@file_put_contents($cron_file, $cron_cmd);
5850
		chmod($cron_file, 0755);
5851
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5852
	} else {
5853
		unlink_if_exists($cron_file);
5854
	}
5855
}
5856

    
5857
function get_interface_default_mtu($type = "ethernet") {
5858
	switch ($type) {
5859
		case "gre":
5860
			return 1476;
5861
			break;
5862
		case "gif":
5863
			return 1280;
5864
			break;
5865
		case "tun":
5866
		case "vlan":
5867
		case "tap":
5868
		case "ethernet":
5869
		default:
5870
			return 1500;
5871
			break;
5872
	}
5873

    
5874
	/* Never reached */
5875
	return 1500;
5876
}
5877

    
5878
function get_vip_descr($ipaddress) {
5879
	global $config;
5880

    
5881
	foreach ($config['virtualip']['vip'] as $vip) {
5882
		if ($vip['subnet'] == $ipaddress) {
5883
			return ($vip['descr']);
5884
		}
5885
	}
5886
	return "";
5887
}
5888

    
5889
function interfaces_staticarp_configure($if) {
5890
	global $config, $g;
5891
	if (isset($config['system']['developerspew'])) {
5892
		$mt = microtime();
5893
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5894
	}
5895

    
5896
	$ifcfg = $config['interfaces'][$if];
5897

    
5898
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5899
		return 0;
5900
	}
5901

    
5902
	/* Enable staticarp, if enabled */
5903
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5904
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5905
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5906
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5907
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5908
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5909
			}
5910
		}
5911
	} else {
5912
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5913
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5914
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5915
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5916
				if (isset($arpent['arp_table_static_entry'])) {
5917
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5918
				}
5919
			}
5920
		}
5921
	}
5922

    
5923
	return 0;
5924
}
5925

    
5926
function get_failover_interface($interface, $family = "all") {
5927
	global $config;
5928

    
5929
	/* shortcut to get_real_interface if we find it in the config */
5930
	if (is_array($config['interfaces'][$interface])) {
5931
		return get_real_interface($interface, $family);
5932
	}
5933

    
5934
	/* compare against gateway groups */
5935
	$a_groups = return_gateway_groups_array();
5936
	if (is_array($a_groups[$interface])) {
5937
		/* we found a gateway group, fetch the interface or vip */
5938
		if (!empty($a_groups[$interface][0]['vip'])) {
5939
			return $a_groups[$interface][0]['vip'];
5940
		} else {
5941
			return $a_groups[$interface][0]['int'];
5942
		}
5943
	}
5944
	/* fall through to get_real_interface */
5945
	/* XXX: Really needed? */
5946
	return get_real_interface($interface, $family);
5947
}
5948

    
5949
function remove_ifindex($ifname) {
5950
	return preg_replace("/[0-9]+$/", "", $ifname);
5951
}
5952

    
5953
?>
(1-1/2)