Project

General

Profile

Download (171 KB) Statistics
| Branch: | Tag: | Revision:
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
	if ($lagg_mtu == 0 &&
776
	    is_array($config['interfaces'])) {
777
		foreach ($config['interfaces'] as $tmpinterface) {
778
			if ($tmpinterface['if'] == $lagg['laggif'] &&
779
			    !empty($tmpinterface['mtu'])) {
780
				$lagg_mtu = $tmpinterface['mtu'];
781
				break;
782
			}
783
		}
784
	}
785

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

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

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

    
804
	interfaces_bring_up($laggif);
805

    
806
	return $laggif;
807
}
808

    
809
function interfaces_gre_configure($checkparent = 0, $realif = "") {
810
	global $config;
811

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

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

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

    
847
	if (!is_array($gre)) {
848
		return -1;
849
	}
850

    
851
	$realif = get_real_interface($gre['if']);
852
	$realifip = get_interface_ip($gre['if']);
853
	$realifip6 = get_interface_ipv6($gre['if']);
854

    
855
	/* make sure the parent interface is up */
856
	interfaces_bring_up($realif);
857

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

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

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

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

    
905
	interfaces_bring_up($greif);
906

    
907
	return $greif;
908
}
909

    
910
function interfaces_gif_configure($checkparent = 0, $realif = "") {
911
	global $config;
912

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

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

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

    
949
	if (!is_array($gif)) {
950
		return -1;
951
	}
952

    
953
	$realif = get_real_interface($gif['if']);
954
	$ipaddr = get_interface_ip($gif['if']);
955

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

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

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

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

    
1041

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

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

    
1056
	interfaces_bring_up($gifif);
1057

    
1058
	return $gifif;
1059
}
1060

    
1061
function interfaces_configure() {
1062
	global $config, $g;
1063

    
1064
	/* Set up our loopback interface */
1065
	interfaces_loopback_configure();
1066

    
1067
	/* create the unconfigured wireless clones */
1068
	interfaces_create_wireless_clones();
1069

    
1070
	/* set up LAGG virtual interfaces */
1071
	interfaces_lagg_configure();
1072

    
1073
	/* set up VLAN virtual interfaces */
1074
	interfaces_vlan_configure();
1075

    
1076
	interfaces_qinq_configure();
1077

    
1078
	$iflist = get_configured_interface_with_descr();
1079
	$delayed_list = array();
1080
	$bridge_list = array();
1081
	$track6_list = array();
1082

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

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

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

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

    
1123
	/* set up GRE virtual interfaces */
1124
	interfaces_gre_configure(1);
1125

    
1126
	/* set up GIF virtual interfaces */
1127
	interfaces_gif_configure(1);
1128

    
1129
	/* set up BRIDGe virtual interfaces */
1130
	interfaces_bridge_configure(1);
1131

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

    
1140
		interface_configure($if, $reload);
1141

    
1142
		if (platform_booting()) {
1143
			echo gettext("done.") . "\n";
1144
		}
1145
	}
1146

    
1147
	/* bring up vip interfaces */
1148
	interfaces_vips_configure();
1149

    
1150
	/* set up GRE virtual interfaces */
1151
	interfaces_gre_configure(2);
1152

    
1153
	/* set up GIF virtual interfaces */
1154
	interfaces_gif_configure(2);
1155

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

    
1164
		interface_configure($if, $reload);
1165

    
1166
		if (platform_booting()) {
1167
			echo gettext("done.") . "\n";
1168
		}
1169
	}
1170

    
1171
	/* set up BRIDGe virtual interfaces */
1172
	interfaces_bridge_configure(2);
1173

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

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

    
1187
		if (platform_booting()) {
1188
			echo gettext("done.") . "\n";
1189
		}
1190
	}
1191

    
1192
	/* configure interface groups */
1193
	interfaces_group_setup();
1194

    
1195
	if (!platform_booting()) {
1196
		/* reconfigure static routes (kernel may have deleted them) */
1197
		system_routing_configure();
1198

    
1199
		/* reload IPsec tunnels */
1200
		vpn_ipsec_configure();
1201

    
1202
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1203
		services_dhcpd_configure();
1204

    
1205
		if (isset($config['dnsmasq']['enable'])) {
1206
			services_dnsmasq_configure();
1207
		}
1208

    
1209
		if (isset($config['unbound']['enable'])) {
1210
			services_unbound_configure();
1211
		}
1212
	}
1213

    
1214
	return 0;
1215
}
1216

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

    
1222
function interface_vip_bring_down($vip) {
1223
	global $g;
1224

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

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

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

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

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

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

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

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

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

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

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

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

    
1441
	return;
1442
}
1443

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

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

    
1462
function interface_isppp_type($interface) {
1463
	global $config;
1464

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

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

    
1482
function interfaces_ptpid_used($ptpid) {
1483
	global $config;
1484

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

    
1493
	return false;
1494
}
1495

    
1496
function interfaces_ptpid_next() {
1497

    
1498
	$ptpid = 0;
1499
	while (interfaces_ptpid_used($ptpid)) {
1500
		$ptpid++;
1501
	}
1502

    
1503
	return $ptpid;
1504
}
1505

    
1506
function getMPDCRONSettings($pppif) {
1507
	global $config;
1508

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

    
1518
	return NULL;
1519
}
1520

    
1521
function handle_pppoe_reset($post_array) {
1522
	global $config, $g;
1523

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

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

    
1531
	$itemhash = getMPDCRONSettings($pppif);
1532

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1820
EOD;
1821

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

    
1826
EOD;
1827
	}
1828

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

    
1837
EOD;
1838

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

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

    
1849
EOD;
1850
	}
1851

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

    
1857
EOD;
1858
	}
1859

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

    
1864
EOD;
1865
	}
1866

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

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

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

    
1882
EOD;
1883
		}
1884

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

    
1889
EOD;
1890
		}
1891

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

    
1896
EOD;
1897
		}
1898

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

    
1904
EOD;
1905

    
1906

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

    
1911
EOD;
1912
		}
1913

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

    
1927
EOD;
1928
		}
1929

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

    
1934
EOD;
1935
		}
1936

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

    
1941
EOD;
1942
		}
1943

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

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

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

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

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

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

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

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

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

    
2008
EOD;
2009
		}
2010

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

    
2016
EOD;
2017
		}
2018

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

    
2022

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

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

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

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

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

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

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

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

    
2133
	return 1;
2134
}
2135

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

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

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

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

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

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

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

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

    
2181
		sleep(1);
2182

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2446
	return $realif;
2447
}
2448

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2807
EOD;
2808

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

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

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

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

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

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

    
2843
EOD;
2844
						}
2845
					}
2846
				}
2847

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3010
	unset($wlcmd_args, $wlcmd);
3011

    
3012

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

    
3017
	return 0;
3018

    
3019
}
3020

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

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

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

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

    
3040
	return intval($pid);
3041
}
3042

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

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

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

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

    
3068
	return intval($pid);
3069
}
3070

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

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

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

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

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

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

    
3134
	return $mtu;
3135
}
3136

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

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

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

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

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

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

    
3177
	return $mtu;
3178
}
3179

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3336
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3337

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

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

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

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

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

    
3425
	interface_netgraph_needed($interface);
3426

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

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

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

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

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

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

    
3464
		if ($reloadall == true) {
3465

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

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

    
3472
			if (isset($config['dnsmasq']['enable'])) {
3473
				services_dnsmasq_configure();
3474
			}
3475

    
3476
			if (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, true);
3514
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
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-existent 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 && !platform_booting()) {
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
		if (isset($config['dnsmasq']['enable'])) {
3567
			services_dnsmasq_configure();
3568
		}
3569

    
3570
		services_dhcpd_configure("inet6");
3571
	}
3572

    
3573
	return 0;
3574
}
3575

    
3576
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3577
	global $config, $g;
3578
	global $interface_ipv6_arr_cache;
3579
	global $interface_snv6_arr_cache;
3580

    
3581
	if (!is_array($lancfg)) {
3582
		return;
3583
	}
3584

    
3585
	/* If the interface is not configured via another, exit */
3586
	if (empty($lancfg['track6-interface'])) {
3587
		return;
3588
	}
3589

    
3590
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3591
	if (empty($wancfg)) {
3592
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3593
		return;
3594
	}
3595

    
3596
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3597
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3598
		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']));
3599
		return;
3600
	}
3601
	$hexwanv4 = return_hex_ipv4($ip4address);
3602

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

    
3608
	/* binary presentation of the prefix for all 128 bits. */
3609
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3610

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

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

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

    
3627
	$lanif = get_real_interface($interface);
3628
	$oip = find_interface_ipv6($lanif);
3629
	if (is_ipaddrv6($oip)) {
3630
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3631
	}
3632
	unset($interface_ipv6_arr_cache[$lanif]);
3633
	unset($interface_snv6_arr_cache[$lanif]);
3634
	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));
3635
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3636

    
3637
	return 0;
3638
}
3639

    
3640
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3641
	global $config, $g;
3642
	global $interface_ipv6_arr_cache;
3643
	global $interface_snv6_arr_cache;
3644

    
3645
	if (!is_array($lancfg)) {
3646
		return;
3647
	}
3648

    
3649
	/* If the interface is not configured via another, exit */
3650
	if (empty($lancfg['track6-interface'])) {
3651
		return;
3652
	}
3653

    
3654
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3655
	if (empty($wancfg)) {
3656
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3657
		return;
3658
	}
3659

    
3660
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3661
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3662
		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']));
3663
		return;
3664
	}
3665
	$hexwanv4 = return_hex_ipv4($ip4address);
3666

    
3667
	/* create the long prefix notation for math, save the prefix length */
3668
	$sixto4prefix = "2002::";
3669
	$sixto4prefixlen = 16;
3670
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3671

    
3672
	/* binary presentation of the prefix for all 128 bits. */
3673
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3674

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

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

    
3687
	$lanif = get_real_interface($interface);
3688
	$oip = find_interface_ipv6($lanif);
3689
	if (is_ipaddrv6($oip)) {
3690
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3691
	}
3692
	unset($interface_ipv6_arr_cache[$lanif]);
3693
	unset($interface_snv6_arr_cache[$lanif]);
3694
	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));
3695
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3696

    
3697
	return 0;
3698
}
3699

    
3700
function interface_6rd_configure($interface = "wan", $wancfg) {
3701
	global $config, $g;
3702

    
3703
	/* because this is a tunnel interface we can only function
3704
	 *	with a public IPv4 address on the interface */
3705

    
3706
	if (!is_array($wancfg)) {
3707
		return;
3708
	}
3709

    
3710
	if (!is_module_loaded('if_stf.ko')) {
3711
		mwexec('/sbin/kldload if_stf.ko');
3712
	}
3713

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

    
3722
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3723
		$wancfg['prefix-6rd-v4plen'] = 0;
3724
	}
3725

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

    
3739
	/* binary presentation of the prefix for all 128 bits. */
3740
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3741

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

    
3749
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3750
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3751

    
3752

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

    
3773
	/* write out a default router file */
3774
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3775
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3776

    
3777
	$ip4gateway = get_interface_gateway($interface);
3778
	if (is_ipaddrv4($ip4gateway)) {
3779
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3780
	}
3781

    
3782
	/* configure dependent interfaces */
3783
	if (!platform_booting()) {
3784
		link_interface_to_track6($interface, "update");
3785
	}
3786

    
3787
	return 0;
3788
}
3789

    
3790
function interface_6to4_configure($interface = "wan", $wancfg) {
3791
	global $config, $g;
3792

    
3793
	/* because this is a tunnel interface we can only function
3794
	 *	with a public IPv4 address on the interface */
3795

    
3796
	if (!is_array($wancfg)) {
3797
		return;
3798
	}
3799

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

    
3807
	/* create the long prefix notation for math, save the prefix length */
3808
	$stfprefixlen = 16;
3809
	$stfprefix = Net_IPv6::uncompress("2002::");
3810
	$stfarr = explode(":", $stfprefix);
3811
	$v4prefixlen = "0";
3812

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

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

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

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

    
3839
	/* for the local subnet too. */
3840
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3841
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3842

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

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

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

    
3876
	if ($g['debug']) {
3877
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3878
	}
3879

    
3880
	/* write out a default router file */
3881
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3882
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3883

    
3884
	$ip4gateway = get_interface_gateway($interface);
3885
	if (is_ipaddrv4($ip4gateway)) {
3886
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3887
	}
3888

    
3889
	if (!platform_booting()) {
3890
		link_interface_to_track6($interface, "update");
3891
	}
3892

    
3893
	return 0;
3894
}
3895

    
3896
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3897
	global $config, $g;
3898

    
3899
	if (!is_array($wancfg)) {
3900
		return;
3901
	}
3902

    
3903
	$wanif = get_real_interface($interface, "inet6");
3904
	$dhcp6cconf = "";
3905

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

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

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

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

    
3945
			if (!isset($wancfg['dhcp6prefixonly'])) {
3946
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3947
			}
3948

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

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

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

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

    
4016
	/* accept router advertisements for this interface */
4017
	log_error("Accept router advertisements on interface {$wanif} ");
4018
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4019

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

    
4027
	/* NOTE: will be called from rtsold invoked script
4028
	 * link_interface_to_track6($interface, "update");
4029
	 */
4030

    
4031
	return 0;
4032
}
4033

    
4034
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4035
	global $g;
4036

    
4037
	$send_options = "";
4038
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4039
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_send_options']);
4040
		foreach ($options as $option) {
4041
			$send_options .= "\tsend " . trim($option) . ";\n";
4042
		}
4043
	}
4044

    
4045
	$request_options = "";
4046
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4047
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_request_options']);
4048
		foreach ($options as $option) {
4049
			$request_options .= "\trequest " . trim($option) . ";\n";
4050
		}
4051
	}
4052

    
4053
	$information_only = "";
4054
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4055
		$information_only = "\tinformation-only;\n";
4056
	}
4057

    
4058
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4059
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4060
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4061
	}
4062

    
4063
	$interface_statement  = "interface";
4064
	$interface_statement .= " {$wanif}";
4065
	$interface_statement .= " {\n";
4066
	$interface_statement .= "$send_options";
4067
	$interface_statement .= "$request_options";
4068
	$interface_statement .= "$information_only";
4069
	$interface_statement .= "$script";
4070
	$interface_statement .= "};\n";
4071

    
4072
	$id_assoc_statement_address = "";
4073
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4074
		$id_assoc_statement_address .= "id-assoc";
4075
		$id_assoc_statement_address .= " na";
4076
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4077
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4078
		}
4079
		$id_assoc_statement_address .= " { ";
4080

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

    
4094
		$id_assoc_statement_address .= "};\n";
4095
	}
4096

    
4097
	$id_assoc_statement_prefix = "";
4098
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4099
		$id_assoc_statement_prefix .= "id-assoc";
4100
		$id_assoc_statement_prefix .= " pd";
4101
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4102
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4103
		}
4104
		$id_assoc_statement_prefix .= " { ";
4105

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

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

    
4131
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4132
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4133
			$id_assoc_statement_prefix .= "\n";
4134
		}
4135

    
4136
		$id_assoc_statement_prefix .= "};\n";
4137
	}
4138

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

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

    
4172
	$dhcp6cconf  = $interface_statement;
4173
	$dhcp6cconf .= $id_assoc_statement_address;
4174
	$dhcp6cconf .= $id_assoc_statement_prefix;
4175
	$dhcp6cconf .= $authentication_statement;
4176
	$dhcp6cconf .= $key_info_statement;
4177

    
4178
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4179

    
4180
	return $dhcp6cconf;
4181
}
4182

    
4183

    
4184
function DHCP6_Config_File_Override($wancfg, $wanif) {
4185

    
4186
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4187

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

    
4196

    
4197
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4198

    
4199
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4200

    
4201
	return $dhcp6cconf;
4202
}
4203

    
4204

    
4205
function interface_dhcp_configure($interface = "wan") {
4206
	global $config, $g;
4207

    
4208
	$wancfg = $config['interfaces'][$interface];
4209
	$wanif = $wancfg['if'];
4210
	if (empty($wancfg)) {
4211
		$wancfg = array();
4212
	}
4213

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

    
4221
	if ($wancfg['dhcphostname']) {
4222
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4223
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4224
	} else {
4225
		$dhclientconf_hostname = "";
4226
	}
4227

    
4228
	$wanif = get_real_interface($interface);
4229
	if (empty($wanif)) {
4230
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4231
		return 0;
4232
	}
4233
	$dhclientconf = "";
4234

    
4235
	$dhclientconf .= <<<EOD
4236
interface "{$wanif}" {
4237
timeout 60;
4238
retry 15;
4239
select-timeout 0;
4240
initial-interval 1;
4241
	{$dhclientconf_hostname}
4242
	script "/usr/local/sbin/pfSense-dhclient-script";
4243
EOD;
4244

    
4245
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4246
		$dhclientconf .= <<<EOD
4247

    
4248
	reject {$wancfg['dhcprejectfrom']};
4249
EOD;
4250
	}
4251
	$dhclientconf .= <<<EOD
4252

    
4253
}
4254

    
4255
EOD;
4256

    
4257
	// DHCP Config File Advanced
4258
	if ($wancfg['adv_dhcp_config_advanced']) {
4259
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4260
	}
4261

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

    
4271
EOD;
4272
	}
4273

    
4274
	// DHCP Config File Override
4275
	if ($wancfg['adv_dhcp_config_file_override']) {
4276
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4277
	}
4278

    
4279
	fwrite($fd, $dhclientconf);
4280
	fclose($fd);
4281

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

    
4289
	/* Make sure dhclient is not running */
4290
	kill_dhclient_process($wanif);
4291

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

    
4295
	return 0;
4296
}
4297

    
4298
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4299

    
4300
	$hostname = "";
4301
	if ($wancfg['dhcphostname'] != '') {
4302
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4303
	}
4304

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

    
4315
	$send_options = "";
4316
	if ($wancfg['adv_dhcp_send_options'] != '') {
4317
		$options = explode(',', $wancfg['adv_dhcp_send_options']);
4318
		foreach ($options as $option) {
4319
			$send_options .= "\tsend " . trim($option) . ";\n";
4320
		}
4321
	}
4322

    
4323
	$request_options = "";
4324
	if ($wancfg['adv_dhcp_request_options'] != '') {
4325
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4326
	}
4327

    
4328
	$required_options = "";
4329
	if ($wancfg['adv_dhcp_required_options'] != '') {
4330
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4331
	}
4332

    
4333
	$option_modifiers = "";
4334
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4335
		$modifiers = explode(',', $wancfg['adv_dhcp_option_modifiers']);
4336
		foreach ($modifiers as $modifier) {
4337
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4338
		}
4339
	}
4340

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

    
4361
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4362

    
4363
	return $dhclientconf;
4364
}
4365

    
4366

    
4367
function DHCP_Config_File_Override($wancfg, $wanif) {
4368

    
4369
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4370

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

    
4379

    
4380
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4381

    
4382
	/* Apply Interface Substitutions */
4383
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4384

    
4385
	/* Apply Hostname Substitutions */
4386
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4387

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

    
4394
	/* Apply MAC Address Substitutions */
4395
	foreach ($various_mac_types as $various_mac_type) {
4396
		foreach ($various_mac_cases as $various_mac_case) {
4397
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4398

    
4399
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4400
				if ($res !== false) {
4401

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

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

    
4422
					/* MAC Address Delimiter Substitutions */
4423
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4424

    
4425
					/* Apply MAC Address Substitutions */
4426
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4427
				}
4428
			}
4429
		}
4430
	}
4431

    
4432
	return $dhclientconf;
4433
}
4434

    
4435
function interfaces_group_setup() {
4436
	global $config;
4437

    
4438
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4439
		return;
4440
	}
4441

    
4442
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4443
		interface_group_setup($groupar);
4444
	}
4445

    
4446
	return;
4447
}
4448

    
4449
function interface_group_setup(&$groupname /* The parameter is an array */) {
4450
	global $config;
4451

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

    
4463
	return;
4464
}
4465

    
4466
function is_interface_group($if) {
4467
	global $config;
4468

    
4469
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4470
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4471
			if ($groupentry['ifname'] === $if) {
4472
				return true;
4473
			}
4474
		}
4475
	}
4476

    
4477
	return false;
4478
}
4479

    
4480
function interface_group_add_member($interface, $groupname) {
4481
	$interface = get_real_interface($interface);
4482
	if (does_interface_exist($interface)) {
4483
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4484
	}
4485
}
4486

    
4487
/* COMPAT Function */
4488
function convert_friendly_interface_to_real_interface_name($interface) {
4489
	return get_real_interface($interface);
4490
}
4491

    
4492
/* COMPAT Function */
4493
function get_real_wan_interface($interface = "wan") {
4494
	return get_real_interface($interface);
4495
}
4496

    
4497
/* COMPAT Function */
4498
function get_current_wan_address($interface = "wan") {
4499
	return get_interface_ip($interface);
4500
}
4501

    
4502
/*
4503
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4504
 */
4505
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4506
	global $config;
4507

    
4508
	/* XXX: For speed reasons reference directly the interface array */
4509
	$ifdescrs = &$config['interfaces'];
4510
	//$ifdescrs = get_configured_interface_list(false, true);
4511

    
4512
	foreach ($ifdescrs as $if => $ifname) {
4513
		if ($if == $interface || $ifname['if'] == $interface) {
4514
			return $if;
4515
		}
4516

    
4517
		if (get_real_interface($if) == $interface) {
4518
			return $if;
4519
		}
4520

    
4521
		if ($checkparent == false) {
4522
			continue;
4523
		}
4524

    
4525
		$int = get_parent_interface($if, true);
4526
		if (is_array($int)) {
4527
			foreach ($int as $iface) {
4528
				if ($iface == $interface) {
4529
					return $if;
4530
				}
4531
			}
4532
		}
4533
	}
4534

    
4535
	if ($interface == "enc0") {
4536
		return 'IPsec';
4537
	}
4538
}
4539

    
4540
/* attempt to resolve interface to friendly descr */
4541
function convert_friendly_interface_to_friendly_descr($interface) {
4542
	global $config;
4543

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

    
4597
	return $ifdesc;
4598
}
4599

    
4600
function convert_real_interface_to_friendly_descr($interface) {
4601

    
4602
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4603

    
4604
	if (!empty($ifdesc)) {
4605
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4606
	}
4607

    
4608
	return $interface;
4609
}
4610

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

    
4623
	$parents = array();
4624
	//Check that we got a valid interface passed
4625
	$realif = get_real_interface($interface);
4626
	if ($realif == NULL) {
4627
		return $parents;
4628
	}
4629

    
4630
	// If we got a real interface, find it's friendly assigned name
4631
	if ($interface == $realif && $avoidrecurse == false) {
4632
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4633
	}
4634

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

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

    
4688
	if (empty($parents)) {
4689
		$parents[0] = $realif;
4690
	}
4691

    
4692
	return $parents;
4693
}
4694

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

    
4703
	$realif = get_parent_interface($interface);
4704

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

    
4716
function interface_is_wireless_clone($wlif) {
4717
	if (!stristr($wlif, "_wlan")) {
4718
		return false;
4719
	} else {
4720
		return true;
4721
	}
4722
}
4723

    
4724
function interface_get_wireless_base($wlif) {
4725
	if (!stristr($wlif, "_wlan")) {
4726
		return $wlif;
4727
	} else {
4728
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4729
	}
4730
}
4731

    
4732
function interface_get_wireless_clone($wlif) {
4733
	if (!stristr($wlif, "_wlan")) {
4734
		return $wlif . "_wlan0";
4735
	} else {
4736
		return $wlif;
4737
	}
4738
}
4739

    
4740
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4741
	global $config, $g;
4742

    
4743
	$wanif = NULL;
4744

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

    
4787
			if (empty($config['interfaces'][$interface])) {
4788
				break;
4789
			}
4790

    
4791
			$cfg = &$config['interfaces'][$interface];
4792

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

    
4849
	return $wanif;
4850
}
4851

    
4852
/* Guess the physical interface by providing a IP address */
4853
function guess_interface_from_ip($ipaddress) {
4854

    
4855
	$family = '';
4856
	if (is_ipaddrv4($ipaddress)) {
4857
		$family = 'inet';
4858
	}
4859
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4860
		$family = 'inet6';
4861
	}
4862

    
4863
	if (empty($family)) {
4864
		return false;
4865
	}
4866

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

    
4875
	return false;
4876
}
4877

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

    
4887
	$isv6ip = is_ipaddrv6($ip);
4888

    
4889
	/* if list */
4890
	$ifdescrs = get_configured_interface_list();
4891

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

    
4910
	return false;
4911
}
4912

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

    
4920
	if (!is_array($config['virtualip']['vip'])) {
4921
		return false;
4922
	}
4923
	if (!is_ipaddr($ip)) {
4924
		return false;
4925
	}
4926

    
4927
	$isv6ip = is_ipaddrv6($ip);
4928

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

    
4949
function link_interface_to_track6($int, $action = "") {
4950
	global $config;
4951

    
4952
	if (empty($int)) {
4953
		return;
4954
	}
4955

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

    
4974
function interface_find_child_cfgmtu($realiface) {
4975
	global $config;
4976

    
4977
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
4978
	$vlans = link_interface_to_vlans($realiface);
4979
	$bridge = link_interface_to_bridge($realiface);
4980
	if (!empty($interface)) {
4981
		$gifs = link_interface_to_gif($interface);
4982
		$gres = link_interface_to_gre($interface);
4983
	} else {
4984
		$gifs = array();
4985
		$gres = array();
4986
	}
4987

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

    
5036
	return $mtu;
5037
}
5038

    
5039
function link_interface_to_vlans($int, $action = "") {
5040
	global $config;
5041

    
5042
	if (empty($int)) {
5043
		return;
5044
	}
5045

    
5046
	if (is_array($config['vlans']['vlan'])) {
5047
		$ifaces = array();
5048
		foreach ($config['vlans']['vlan'] as $vlan) {
5049
			if ($int == $vlan['if']) {
5050
				if ($action == "update") {
5051
					interfaces_bring_up($int);
5052
				} else {
5053
					$ifaces[$vlan['tag']] = $vlan;
5054
				}
5055
			}
5056
		}
5057
		if (!empty($ifaces)) {
5058
			return $ifaces;
5059
		}
5060
	}
5061
}
5062

    
5063
function link_interface_to_vips($int, $action = "", $vhid = '') {
5064
	global $config;
5065

    
5066
	$updatevips = false;
5067
	if (is_array($config['virtualip']['vip'])) {
5068
		$result = array();
5069
		foreach ($config['virtualip']['vip'] as $vip) {
5070
			if (substr($vip['interface'], 0, 4) == "_vip") {
5071
				$iface = get_configured_vip_interface($vip['interface']);
5072
			} else {
5073
				$iface = $vip['interface'];
5074
			}
5075
			if ($int != $iface) {
5076
				continue;
5077
			}
5078
			if ($action == "update") {
5079
				$updatevips = true;
5080
			} else {
5081
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5082
				    substr($vip['interface'], 0, 4) == "_vip") {
5083
					$result[] = $vip;
5084
				}
5085
			}
5086
		}
5087
		if ($updatevips === true) {
5088
			interfaces_vips_configure($int);
5089
		}
5090
		return $result;
5091
	}
5092

    
5093
	return NULL;
5094
}
5095

    
5096
/****f* interfaces/link_interface_to_bridge
5097
 * NAME
5098
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5099
 * INPUTS
5100
 *   $ip
5101
 * RESULT
5102
 *   bridge[0-99]
5103
 ******/
5104
function link_interface_to_bridge($int) {
5105
	global $config;
5106

    
5107
	if (is_array($config['bridges']['bridged'])) {
5108
		foreach ($config['bridges']['bridged'] as $bridge) {
5109
			if (in_array($int, explode(',', $bridge['members']))) {
5110
				return "{$bridge['bridgeif']}";
5111
			}
5112
		}
5113
	}
5114
}
5115

    
5116
function link_interface_to_group($int) {
5117
	global $config;
5118

    
5119
	$result = array();
5120

    
5121
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5122
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5123
			if (in_array($int, explode(" ", $group['members']))) {
5124
				$result[$group['ifname']] = $int;
5125
			}
5126
		}
5127
	}
5128

    
5129
	return $result;
5130
}
5131

    
5132
function link_interface_to_gre($interface) {
5133
	global $config;
5134

    
5135
	$result = array();
5136

    
5137
	if (is_array($config['gres']['gre'])) {
5138
		foreach ($config['gres']['gre'] as $gre) {
5139
			if ($gre['if'] == $interface) {
5140
				$result[] = $gre;
5141
			}
5142
		}
5143
	}
5144

    
5145
	return $result;
5146
}
5147

    
5148
function link_interface_to_gif($interface) {
5149
	global $config;
5150

    
5151
	$result = array();
5152

    
5153
	if (is_array($config['gifs']['gif'])) {
5154
		foreach ($config['gifs']['gif'] as $gif) {
5155
			if ($gif['if'] == $interface) {
5156
				$result[] = $gif;
5157
			}
5158
		}
5159
	}
5160

    
5161
	return $result;
5162
}
5163

    
5164
/*
5165
 * find_interface_ip($interface): return the interface ip (first found)
5166
 */
5167
function find_interface_ip($interface, $flush = false) {
5168
	global $interface_ip_arr_cache;
5169
	global $interface_sn_arr_cache;
5170

    
5171
	$interface = str_replace("\n", "", $interface);
5172

    
5173
	if (!does_interface_exist($interface)) {
5174
		return;
5175
	}
5176

    
5177
	/* Setup IP cache */
5178
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5179
		$ifinfo = pfSense_get_interface_addresses($interface);
5180
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5181
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5182
	}
5183

    
5184
	return $interface_ip_arr_cache[$interface];
5185
}
5186

    
5187
/*
5188
 * find_interface_ipv6($interface): return the interface ip (first found)
5189
 */
5190
function find_interface_ipv6($interface, $flush = false) {
5191
	global $interface_ipv6_arr_cache;
5192
	global $interface_snv6_arr_cache;
5193
	global $config;
5194

    
5195
	$interface = trim($interface);
5196
	$interface = get_real_interface($interface);
5197

    
5198
	if (!does_interface_exist($interface)) {
5199
		return;
5200
	}
5201

    
5202
	/* Setup IP cache */
5203
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5204
		$ifinfo = pfSense_get_interface_addresses($interface);
5205
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5206
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5207
	}
5208

    
5209
	return $interface_ipv6_arr_cache[$interface];
5210
}
5211

    
5212
/*
5213
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5214
 */
5215
function find_interface_ipv6_ll($interface, $flush = false) {
5216
	global $interface_llv6_arr_cache;
5217
	global $config;
5218

    
5219
	$interface = str_replace("\n", "", $interface);
5220

    
5221
	if (!does_interface_exist($interface)) {
5222
		return;
5223
	}
5224

    
5225
	/* Setup IP cache */
5226
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5227
		$ifinfo = pfSense_getall_interface_addresses($interface);
5228
		foreach ($ifinfo as $line) {
5229
			if (strstr($line, ":")) {
5230
				$parts = explode("/", $line);
5231
				if (is_linklocal($parts[0])) {
5232
					$ifinfo['linklocal'] = $parts[0];
5233
				}
5234
			}
5235
		}
5236
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5237
	}
5238
	return $interface_llv6_arr_cache[$interface];
5239
}
5240

    
5241
function find_interface_subnet($interface, $flush = false) {
5242
	global $interface_sn_arr_cache;
5243
	global $interface_ip_arr_cache;
5244

    
5245
	$interface = str_replace("\n", "", $interface);
5246
	if (does_interface_exist($interface) == false) {
5247
		return;
5248
	}
5249

    
5250
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5251
		$ifinfo = pfSense_get_interface_addresses($interface);
5252
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5253
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5254
	}
5255

    
5256
	return $interface_sn_arr_cache[$interface];
5257
}
5258

    
5259
function find_interface_subnetv6($interface, $flush = false) {
5260
	global $interface_snv6_arr_cache;
5261
	global $interface_ipv6_arr_cache;
5262

    
5263
	$interface = str_replace("\n", "", $interface);
5264
	if (does_interface_exist($interface) == false) {
5265
		return;
5266
	}
5267

    
5268
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5269
		$ifinfo = pfSense_get_interface_addresses($interface);
5270
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5271
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5272
	}
5273

    
5274
	return $interface_snv6_arr_cache[$interface];
5275
}
5276

    
5277
function ip_in_interface_alias_subnet($interface, $ipalias) {
5278
	global $config;
5279

    
5280
	if (empty($interface) || !is_ipaddr($ipalias)) {
5281
		return false;
5282
	}
5283
	if (is_array($config['virtualip']['vip'])) {
5284
		foreach ($config['virtualip']['vip'] as $vip) {
5285
			switch ($vip['mode']) {
5286
				case "ipalias":
5287
					if ($vip['interface'] <> $interface) {
5288
						break;
5289
					}
5290
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5291
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5292
						return true;
5293
					}
5294
					break;
5295
			}
5296
		}
5297
	}
5298

    
5299
	return false;
5300
}
5301

    
5302
function get_possible_listen_ips($include_ipv6_link_local=false) {
5303

    
5304
	$interfaces = get_configured_interface_with_descr();
5305
	foreach ($interfaces as $iface => $ifacename) {
5306
		if ($include_ipv6_link_local) {
5307
			/* This is to avoid going though added ll below */
5308
			if (substr($iface, 0, 5) == '_lloc') {
5309
				continue;
5310
			}
5311
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5312
			if (!empty($llip)) {
5313
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5314
			}
5315
		}
5316
	}
5317
	$viplist = get_configured_vip_list();
5318
	foreach ($viplist as $vip => $address) {
5319
		$interfaces[$vip] = $address;
5320
		if (get_vip_descr($address)) {
5321
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5322
		}
5323
	}
5324

    
5325
	$interfaces['lo0'] = 'Localhost';
5326

    
5327
	return $interfaces;
5328
}
5329

    
5330
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5331
	global $config;
5332

    
5333
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5334
	foreach (array('server', 'client') as $mode) {
5335
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5336
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5337
				if (!isset($setting['disable'])) {
5338
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5339
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5340
				}
5341
			}
5342
		}
5343
	}
5344
	return $sourceips;
5345
}
5346

    
5347
function get_interface_ip($interface = "wan") {
5348

    
5349
	if (substr($interface, 0, 4) == '_vip') {
5350
		return get_configured_vip_ipv4($interface);
5351
	} else if (substr($interface, 0, 5) == '_lloc') {
5352
		/* No link-local address for v4. */
5353
		return null;
5354
	}
5355

    
5356
	$realif = get_failover_interface($interface, 'inet');
5357
	if (!$realif) {
5358
		return null;
5359
	}
5360

    
5361
	if (substr($realif, 0, 4) == '_vip') {
5362
		return get_configured_vip_ipv4($realif);
5363
	} else if (substr($realif, 0, 5) == '_lloc') {
5364
		/* No link-local address for v4. */
5365
		return null;
5366
	}
5367

    
5368
	if (is_array($config['interfaces'][$interface]) &&
5369
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5370
		return ($config['interfaces'][$interface]['ipaddr']);
5371
	}
5372

    
5373
	/*
5374
	 * Beaware that find_interface_ip() is our last option, it will
5375
	 * return the first IP it find on interface, not necessarily the
5376
	 * main IP address.
5377
	 */
5378
	$curip = find_interface_ip($realif);
5379
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5380
		return $curip;
5381
	} else {
5382
		return null;
5383
	}
5384
}
5385

    
5386
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5387
	global $config;
5388

    
5389
	if (substr($interface, 0, 4) == '_vip') {
5390
		return get_configured_vip_ipv6($interface);
5391
	} else if (substr($interface, 0, 5) == '_lloc') {
5392
		return get_interface_linklocal($interface);
5393
	}
5394

    
5395
	$realif = get_failover_interface($interface, 'inet6');
5396
	if (!$realif) {
5397
		return null;
5398
	}
5399

    
5400
	if (substr($realif, 0, 4) == '_vip') {
5401
		return get_configured_vip_ipv6($realif);
5402
	} else if (substr($realif, 0, 5) == '_lloc') {
5403
		return get_interface_linklocal($realif);
5404
	}
5405

    
5406
	if (is_array($config['interfaces'][$interface])) {
5407
		switch ($config['interfaces'][$interface]['ipaddr']) {
5408
			case 'pppoe':
5409
			case 'l2tp':
5410
			case 'pptp':
5411
			case 'ppp':
5412
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5413
					$realif = get_real_interface($interface, 'inet6', false);
5414
				}
5415
				break;
5416
		}
5417
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5418
			return ($config['interfaces'][$interface]['ipaddrv6']);
5419
		}
5420
	}
5421

    
5422
	/*
5423
	 * Beaware that find_interface_ip() is our last option, it will
5424
	 * return the first IP it find on interface, not necessarily the
5425
	 * main IP address.
5426
	 */
5427
	$curip = find_interface_ipv6($realif, $flush);
5428
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5429
		return $curip;
5430
	} else {
5431
		/*
5432
		 * NOTE: On the case when only the prefix is requested,
5433
		 * the communication on WAN will be done over link-local.
5434
		 */
5435
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
5436
			$curip = find_interface_ipv6_ll($realif, $flush);
5437
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5438
				return $curip;
5439
			}
5440
		}
5441
	}
5442
	return null;
5443
}
5444

    
5445
function get_interface_linklocal($interface = "wan") {
5446

    
5447
	$realif = get_failover_interface($interface, 'inet6');
5448
	if (!$realif) {
5449
		return null;
5450
	}
5451

    
5452
	if (substr($interface, 0, 4) == '_vip') {
5453
		$realif = get_real_interface($interface);
5454
	} else if (substr($interface, 0, 5) == '_lloc') {
5455
		$realif = get_real_interface(substr($interface, 5));
5456
	}
5457

    
5458
	$curip = find_interface_ipv6_ll($realif);
5459
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5460
		return $curip;
5461
	} else {
5462
		return null;
5463
	}
5464
}
5465

    
5466
function get_interface_subnet($interface = "wan") {
5467

    
5468
	if (substr($interface, 0, 4) == '_vip') {
5469
		return (get_configured_vip_subnetv4($interface));
5470
	}
5471

    
5472
	$realif = get_real_interface($interface);
5473
	if (!$realif) {
5474
		return (NULL);
5475
	}
5476

    
5477
	$cursn = find_interface_subnet($realif);
5478
	if (!empty($cursn)) {
5479
		return ($cursn);
5480
	}
5481

    
5482
	return (NULL);
5483
}
5484

    
5485
function get_interface_subnetv6($interface = "wan") {
5486

    
5487
	if (substr($interface, 0, 4) == '_vip') {
5488
		return (get_configured_vip_subnetv6($interface));
5489
	} else if (substr($interface, 0, 5) == '_lloc') {
5490
		$interface = substr($interface, 5);
5491
	}
5492

    
5493
	$realif = get_real_interface($interface, 'inet6');
5494
	if (!$realif) {
5495
		return (NULL);
5496
	}
5497

    
5498
	$cursn = find_interface_subnetv6($realif);
5499
	if (!empty($cursn)) {
5500
		return ($cursn);
5501
	}
5502

    
5503
	return (NULL);
5504
}
5505

    
5506
/* return outside interfaces with a gateway */
5507
function get_interfaces_with_gateway() {
5508
	global $config;
5509

    
5510
	$ints = array();
5511

    
5512
	/* loop interfaces, check config for outbound */
5513
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5514
		switch ($ifname['ipaddr']) {
5515
			case "dhcp":
5516
			case "pppoe":
5517
			case "pptp":
5518
			case "l2tp":
5519
			case "ppp":
5520
				$ints[$ifdescr] = $ifdescr;
5521
				break;
5522
			default:
5523
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5524
				    !empty($ifname['gateway'])) {
5525
					$ints[$ifdescr] = $ifdescr;
5526
				}
5527
				break;
5528
		}
5529
	}
5530
	return $ints;
5531
}
5532

    
5533
/* return true if interface has a gateway */
5534
function interface_has_gateway($friendly) {
5535
	global $config;
5536

    
5537
	if (!empty($config['interfaces'][$friendly])) {
5538
		$ifname = &$config['interfaces'][$friendly];
5539
		switch ($ifname['ipaddr']) {
5540
			case "dhcp":
5541
			case "pppoe":
5542
			case "pptp":
5543
			case "l2tp":
5544
			case "ppp":
5545
				return true;
5546
			break;
5547
			default:
5548
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5549
					return true;
5550
				}
5551
				$tunnelif = substr($ifname['if'], 0, 3);
5552
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5553
					if (find_interface_ip($ifname['if'])) {
5554
						return true;
5555
					}
5556
				}
5557
				if (!empty($ifname['gateway'])) {
5558
					return true;
5559
				}
5560
			break;
5561
		}
5562
	}
5563

    
5564
	return false;
5565
}
5566

    
5567
/* return true if interface has a gateway */
5568
function interface_has_gatewayv6($friendly) {
5569
	global $config;
5570

    
5571
	if (!empty($config['interfaces'][$friendly])) {
5572
		$ifname = &$config['interfaces'][$friendly];
5573
		switch ($ifname['ipaddrv6']) {
5574
			case "slaac":
5575
			case "dhcp6":
5576
			case "6to4":
5577
			case "6rd":
5578
				return true;
5579
				break;
5580
			default:
5581
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5582
					return true;
5583
				}
5584
				$tunnelif = substr($ifname['if'], 0, 3);
5585
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5586
					if (find_interface_ipv6($ifname['if'])) {
5587
						return true;
5588
					}
5589
				}
5590
				if (!empty($ifname['gatewayv6'])) {
5591
					return true;
5592
				}
5593
				break;
5594
		}
5595
	}
5596

    
5597
	return false;
5598
}
5599

    
5600
/****f* interfaces/is_altq_capable
5601
 * NAME
5602
 *   is_altq_capable - Test if interface is capable of using ALTQ
5603
 * INPUTS
5604
 *   $int            - string containing interface name
5605
 * RESULT
5606
 *   boolean         - true or false
5607
 ******/
5608

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

    
5623
	$int_family = remove_ifindex($int);
5624

    
5625
	if (in_array($int_family, $capable)) {
5626
		return true;
5627
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5628
		return true;
5629
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5630
		return true;
5631
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5632
		return true;
5633
	} else {
5634
		return false;
5635
	}
5636
}
5637

    
5638
/****f* interfaces/is_interface_wireless
5639
 * NAME
5640
 *   is_interface_wireless - Returns if an interface is wireless
5641
 * RESULT
5642
 *   $tmp       - Returns if an interface is wireless
5643
 ******/
5644
function is_interface_wireless($interface) {
5645
	global $config, $g;
5646

    
5647
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5648
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5649
		if (preg_match($g['wireless_regex'], $interface)) {
5650
			if (isset($config['interfaces'][$friendly])) {
5651
				$config['interfaces'][$friendly]['wireless'] = array();
5652
			}
5653
			return true;
5654
		}
5655
		return false;
5656
	} else {
5657
		return true;
5658
	}
5659
}
5660

    
5661
function get_wireless_modes($interface) {
5662
	/* return wireless modes and channels */
5663
	$wireless_modes = array();
5664

    
5665
	$cloned_interface = get_real_interface($interface);
5666

    
5667
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5668
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5669
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5670
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5671

    
5672
		$interface_channels = "";
5673
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5674
		$interface_channel_count = count($interface_channels);
5675

    
5676
		$c = 0;
5677
		while ($c < $interface_channel_count) {
5678
			$channel_line = explode(",", $interface_channels["$c"]);
5679
			$wireless_mode = trim($channel_line[0]);
5680
			$wireless_channel = trim($channel_line[1]);
5681
			if (trim($wireless_mode) != "") {
5682
				/* if we only have 11g also set 11b channels */
5683
				if ($wireless_mode == "11g") {
5684
					if (!isset($wireless_modes["11b"])) {
5685
						$wireless_modes["11b"] = array();
5686
					}
5687
				} else if ($wireless_mode == "11g ht") {
5688
					if (!isset($wireless_modes["11b"])) {
5689
						$wireless_modes["11b"] = array();
5690
					}
5691
					if (!isset($wireless_modes["11g"])) {
5692
						$wireless_modes["11g"] = array();
5693
					}
5694
					$wireless_mode = "11ng";
5695
				} else if ($wireless_mode == "11a ht") {
5696
					if (!isset($wireless_modes["11a"])) {
5697
						$wireless_modes["11a"] = array();
5698
					}
5699
					$wireless_mode = "11na";
5700
				}
5701
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5702
			}
5703
			$c++;
5704
		}
5705
	}
5706
	return($wireless_modes);
5707
}
5708

    
5709
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5710
function get_wireless_channel_info($interface) {
5711
	$wireless_channels = array();
5712

    
5713
	$cloned_interface = get_real_interface($interface);
5714

    
5715
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5716
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5717
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5718
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5719

    
5720
		$interface_channels = "";
5721
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5722

    
5723
		foreach ($interface_channels as $channel_line) {
5724
			$channel_line = explode(",", $channel_line);
5725
			if (!isset($wireless_channels[$channel_line[0]])) {
5726
				$wireless_channels[$channel_line[0]] = $channel_line;
5727
			}
5728
		}
5729
	}
5730
	return($wireless_channels);
5731
}
5732

    
5733
function set_interface_mtu($interface, $mtu) {
5734

    
5735
	/* LAGG interface must be destroyed and re-created to change MTU */
5736
	if (substr($interface, 0, 4) == 'lagg') {
5737
		if (isset($config['laggs']['lagg']) &&
5738
		    is_array($config['laggs']['lagg'])) {
5739
			foreach ($config['laggs']['lagg'] as $lagg) {
5740
				if ($lagg['laggif'] == $interface) {
5741
					interface_lagg_configure($lagg);
5742
					break;
5743
				}
5744
			}
5745
		}
5746
	} else {
5747
		pfSense_interface_mtu($interface, $mtu);
5748
	}
5749
}
5750

    
5751
/****f* interfaces/get_interface_mtu
5752
 * NAME
5753
 *   get_interface_mtu - Return the mtu of an interface
5754
 * RESULT
5755
 *   $tmp       - Returns the mtu of an interface
5756
 ******/
5757
function get_interface_mtu($interface) {
5758
	$mtu = pfSense_interface_getmtu($interface);
5759
	return $mtu['mtu'];
5760
}
5761

    
5762
function get_interface_mac($interface) {
5763

    
5764
	$macinfo = pfSense_get_interface_addresses($interface);
5765
	return $macinfo["macaddr"];
5766
}
5767

    
5768
/****f* pfsense-utils/generate_random_mac_address
5769
 * NAME
5770
 *   generate_random_mac - generates a random mac address
5771
 * INPUTS
5772
 *   none
5773
 * RESULT
5774
 *   $mac - a random mac address
5775
 ******/
5776
function generate_random_mac_address() {
5777
	$mac = "02";
5778
	for ($x = 0; $x < 5; $x++) {
5779
		$mac .= ":" . dechex(rand(16, 255));
5780
	}
5781
	return $mac;
5782
}
5783

    
5784
/****f* interfaces/is_jumbo_capable
5785
 * NAME
5786
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5787
 * INPUTS
5788
 *   $int             - string containing interface name
5789
 * RESULT
5790
 *   boolean          - true or false
5791
 ******/
5792
function is_jumbo_capable($iface) {
5793
	$iface = trim($iface);
5794
	$capable = pfSense_get_interface_addresses($iface);
5795

    
5796
	if (isset($capable['caps']['vlanmtu'])) {
5797
		return true;
5798
	}
5799

    
5800
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5801
	if (substr($iface, 0, 4) == "lagg") {
5802
		return true;
5803
	}
5804

    
5805
	return false;
5806
}
5807

    
5808
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5809
	global $g;
5810

    
5811
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5812

    
5813
	if (!empty($iface) && !empty($pppif)) {
5814
		$cron_cmd = <<<EOD
5815
#!/bin/sh
5816
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5817
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5818

    
5819
EOD;
5820

    
5821
		@file_put_contents($cron_file, $cron_cmd);
5822
		chmod($cron_file, 0755);
5823
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5824
	} else {
5825
		unlink_if_exists($cron_file);
5826
	}
5827
}
5828

    
5829
function get_interface_default_mtu($type = "ethernet") {
5830
	switch ($type) {
5831
		case "gre":
5832
			return 1476;
5833
			break;
5834
		case "gif":
5835
			return 1280;
5836
			break;
5837
		case "tun":
5838
		case "vlan":
5839
		case "tap":
5840
		case "ethernet":
5841
		default:
5842
			return 1500;
5843
			break;
5844
	}
5845

    
5846
	/* Never reached */
5847
	return 1500;
5848
}
5849

    
5850
function get_vip_descr($ipaddress) {
5851
	global $config;
5852

    
5853
	foreach ($config['virtualip']['vip'] as $vip) {
5854
		if ($vip['subnet'] == $ipaddress) {
5855
			return ($vip['descr']);
5856
		}
5857
	}
5858
	return "";
5859
}
5860

    
5861
function interfaces_staticarp_configure($if) {
5862
	global $config, $g;
5863
	if (isset($config['system']['developerspew'])) {
5864
		$mt = microtime();
5865
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5866
	}
5867

    
5868
	$ifcfg = $config['interfaces'][$if];
5869

    
5870
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5871
		return 0;
5872
	}
5873

    
5874
	/* Enable staticarp, if enabled */
5875
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5876
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5877
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5878
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5879
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5880
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5881
			}
5882
		}
5883
	} else {
5884
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5885
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5886
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5887
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5888
				if (isset($arpent['arp_table_static_entry'])) {
5889
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5890
				}
5891
			}
5892
		}
5893
	}
5894

    
5895
	return 0;
5896
}
5897

    
5898
function get_failover_interface($interface, $family = "all") {
5899
	global $config;
5900

    
5901
	/* shortcut to get_real_interface if we find it in the config */
5902
	if (is_array($config['interfaces'][$interface])) {
5903
		return get_real_interface($interface, $family);
5904
	}
5905

    
5906
	/* compare against gateway groups */
5907
	$a_groups = return_gateway_groups_array();
5908
	if (is_array($a_groups[$interface])) {
5909
		/* we found a gateway group, fetch the interface or vip */
5910
		if (!empty($a_groups[$interface][0]['vip'])) {
5911
			return $a_groups[$interface][0]['vip'];
5912
		} else {
5913
			return $a_groups[$interface][0]['int'];
5914
		}
5915
	}
5916
	/* fall through to get_real_interface */
5917
	/* XXX: Really needed? */
5918
	return get_real_interface($interface, $family);
5919
}
5920

    
5921
function remove_ifindex($ifname) {
5922
	return preg_replace("/[0-9]+$/", "", $ifname);
5923
}
5924

    
5925
?>
(25-25/65)