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 {$qinqif}qinq:\n");
322
		exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
323
		if (empty($result)) {
324
			fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
325
			fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
326
			fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
327
		}
328
	} else {
329
		fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
330
		fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
331
		fwrite($fd, "connect {$qinqif}: {$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
	pfSense_interface_capabilities($laggif, -$flags_off);
802
	pfSense_interface_capabilities($laggif, $flags_on);
803

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

    
806
	interfaces_bring_up($laggif);
807

    
808
	return $laggif;
809
}
810

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

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

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

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

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

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

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

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

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

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

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

    
907
	interfaces_bring_up($greif);
908

    
909
	return $greif;
910
}
911

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

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

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

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

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

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

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

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

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

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

    
1043

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

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

    
1058
	interfaces_bring_up($gifif);
1059

    
1060
	return $gifif;
1061
}
1062

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

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

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

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

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

    
1078
	interfaces_qinq_configure();
1079

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

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

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

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

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

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

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

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

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

    
1142
		interface_configure($if, $reload);
1143

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

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

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

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

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

    
1166
		interface_configure($if, $reload);
1167

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

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

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

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

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

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

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

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

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

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

    
1215
	return 0;
1216
}
1217

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1442
	return;
1443
}
1444

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

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

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

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

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

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

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

    
1494
	return false;
1495
}
1496

    
1497
function interfaces_ptpid_next() {
1498

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

    
1504
	return $ptpid;
1505
}
1506

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

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

    
1519
	return NULL;
1520
}
1521

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

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

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

    
1532
	$itemhash = getMPDCRONSettings($pppif);
1533

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1821
EOD;
1822

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

    
1827
EOD;
1828
	}
1829

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

    
1838
EOD;
1839

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

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

    
1850
EOD;
1851
	}
1852

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

    
1858
EOD;
1859
	}
1860

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

    
1865
EOD;
1866
	}
1867

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

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

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

    
1883
EOD;
1884
		}
1885

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

    
1890
EOD;
1891
		}
1892

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

    
1897
EOD;
1898
		}
1899

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

    
1905
EOD;
1906

    
1907

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

    
1912
EOD;
1913
		}
1914

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

    
1928
EOD;
1929
		}
1930

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

    
1935
EOD;
1936
		}
1937

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

    
1942
EOD;
1943
		}
1944

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

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

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

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

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

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

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

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

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

    
2009
EOD;
2010
		}
2011

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

    
2017
EOD;
2018
		}
2019

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

    
2023

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

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

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

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

    
2081
	/* fire up mpd */
2082
	mwexec("/usr/local/sbin/mpd5 -b -k -d {$g['varetc_path']} -f mpd_{$interface}.conf -p {$g['varrun_path']}/" .
2083
		escapeshellarg($ppp['type']) . "_{$interface}.pid -s ppp " . 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 you want 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, "/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
			/* restart dnsmasq or unbound */
3473
			if (isset($config['dnsmasq']['enable'])) {
3474
				services_dnsmasq_configure();
3475
			} elseif (isset($config['unbound']['enable'])) {
3476
				services_unbound_configure();
3477
			}
3478

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

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

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

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

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

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

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

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

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

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

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

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

    
3565
		services_dhcpd_configure("inet6");
3566
	}
3567

    
3568
	return 0;
3569
}
3570

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

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

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

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

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

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

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

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

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

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

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

    
3632
	return 0;
3633
}
3634

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

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

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

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

    
3655
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3656
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3657
		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']));
3658
		return;
3659
	}
3660
	$hexwanv4 = return_hex_ipv4($ip4address);
3661

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

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

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

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

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

    
3692
	return 0;
3693
}
3694

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

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

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

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

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

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

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

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

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

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

    
3747

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

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

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

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

    
3782
	return 0;
3783
}
3784

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3888
	return 0;
3889
}
3890

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4026
	return 0;
4027
}
4028

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4175
	return $dhcp6cconf;
4176
}
4177

    
4178

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

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

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

    
4191

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

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

    
4196
	return $dhcp6cconf;
4197
}
4198

    
4199

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

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

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

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

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

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

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

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

    
4248
}
4249

    
4250
EOD;
4251

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

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

    
4266
EOD;
4267
	}
4268

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

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

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

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

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

    
4290
	return 0;
4291
}
4292

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

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

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

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

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

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

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

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

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

    
4358
	return $dhclientconf;
4359
}
4360

    
4361

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

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

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

    
4374

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

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

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

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

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

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

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

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

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

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

    
4427
	return $dhclientconf;
4428
}
4429

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

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

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

    
4441
	return;
4442
}
4443

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

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

    
4458
	return;
4459
}
4460

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

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

    
4472
	return false;
4473
}
4474

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4592
	return $ifdesc;
4593
}
4594

    
4595
function convert_real_interface_to_friendly_descr($interface) {
4596

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

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

    
4603
	return $interface;
4604
}
4605

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

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

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

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

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

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

    
4687
	return $parents;
4688
}
4689

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

    
4698
	$realif = get_parent_interface($interface);
4699

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

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

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

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

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

    
4738
	$wanif = NULL;
4739

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

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

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

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

    
4844
	return $wanif;
4845
}
4846

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

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

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

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

    
4870
	return false;
4871
}
4872

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

    
4882
	$isv6ip = is_ipaddrv6($ip);
4883

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

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

    
4905
	return false;
4906
}
4907

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

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

    
4922
	$isv6ip = is_ipaddrv6($ip);
4923

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

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

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

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

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

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

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

    
5031
	return $mtu;
5032
}
5033

    
5034
function link_interface_to_vlans($int, $action = "") {
5035
	global $config;
5036

    
5037
	if (empty($int)) {
5038
		return;
5039
	}
5040

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

    
5058
function link_interface_to_vips($int, $action = "", $vhid = '') {
5059
	global $config;
5060

    
5061
	if (is_array($config['virtualip']['vip'])) {
5062
		$result = array();
5063
		foreach ($config['virtualip']['vip'] as $vip) {
5064
			if (substr($vip['interface'], 0, 4) == "_vip")
5065
				$iface = get_configured_vip_interface($vip['interface']);
5066
			else
5067
				$iface = $vip['interface'];
5068
			if ($int != $iface)
5069
				continue;
5070
			if ($action == "update") {
5071
				interfaces_vips_configure($int);
5072
			} else {
5073
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5074
				    substr($vip['interface'], 0, 4) == "_vip") {
5075
					$result[] = $vip;
5076
				}
5077
			}
5078
		}
5079
		return $result;
5080
	}
5081

    
5082
	return NULL;
5083
}
5084

    
5085
/****f* interfaces/link_interface_to_bridge
5086
 * NAME
5087
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5088
 * INPUTS
5089
 *   $ip
5090
 * RESULT
5091
 *   bridge[0-99]
5092
 ******/
5093
function link_interface_to_bridge($int) {
5094
	global $config;
5095

    
5096
	if (is_array($config['bridges']['bridged'])) {
5097
		foreach ($config['bridges']['bridged'] as $bridge) {
5098
			if (in_array($int, explode(',', $bridge['members']))) {
5099
				return "{$bridge['bridgeif']}";
5100
			}
5101
		}
5102
	}
5103
}
5104

    
5105
function link_interface_to_group($int) {
5106
	global $config;
5107

    
5108
	$result = array();
5109

    
5110
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5111
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5112
			if (in_array($int, explode(" ", $group['members']))) {
5113
				$result[$group['ifname']] = $int;
5114
			}
5115
		}
5116
	}
5117

    
5118
	return $result;
5119
}
5120

    
5121
function link_interface_to_gre($interface) {
5122
	global $config;
5123

    
5124
	$result = array();
5125

    
5126
	if (is_array($config['gres']['gre'])) {
5127
		foreach ($config['gres']['gre'] as $gre) {
5128
			if ($gre['if'] == $interface) {
5129
				$result[] = $gre;
5130
			}
5131
		}
5132
	}
5133

    
5134
	return $result;
5135
}
5136

    
5137
function link_interface_to_gif($interface) {
5138
	global $config;
5139

    
5140
	$result = array();
5141

    
5142
	if (is_array($config['gifs']['gif'])) {
5143
		foreach ($config['gifs']['gif'] as $gif) {
5144
			if ($gif['if'] == $interface) {
5145
				$result[] = $gif;
5146
			}
5147
		}
5148
	}
5149

    
5150
	return $result;
5151
}
5152

    
5153
/*
5154
 * find_interface_ip($interface): return the interface ip (first found)
5155
 */
5156
function find_interface_ip($interface, $flush = false) {
5157
	global $interface_ip_arr_cache;
5158
	global $interface_sn_arr_cache;
5159

    
5160
	$interface = str_replace("\n", "", $interface);
5161

    
5162
	if (!does_interface_exist($interface)) {
5163
		return;
5164
	}
5165

    
5166
	/* Setup IP cache */
5167
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5168
		$ifinfo = pfSense_get_interface_addresses($interface);
5169
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5170
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5171
	}
5172

    
5173
	return $interface_ip_arr_cache[$interface];
5174
}
5175

    
5176
/*
5177
 * find_interface_ipv6($interface): return the interface ip (first found)
5178
 */
5179
function find_interface_ipv6($interface, $flush = false) {
5180
	global $interface_ipv6_arr_cache;
5181
	global $interface_snv6_arr_cache;
5182
	global $config;
5183

    
5184
	$interface = trim($interface);
5185
	$interface = get_real_interface($interface);
5186

    
5187
	if (!does_interface_exist($interface)) {
5188
		return;
5189
	}
5190

    
5191
	/* Setup IP cache */
5192
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5193
		$ifinfo = pfSense_get_interface_addresses($interface);
5194
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5195
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5196
	}
5197

    
5198
	return $interface_ipv6_arr_cache[$interface];
5199
}
5200

    
5201
/*
5202
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5203
 */
5204
function find_interface_ipv6_ll($interface, $flush = false) {
5205
	global $interface_llv6_arr_cache;
5206
	global $config;
5207

    
5208
	$interface = str_replace("\n", "", $interface);
5209

    
5210
	if (!does_interface_exist($interface)) {
5211
		return;
5212
	}
5213

    
5214
	/* Setup IP cache */
5215
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5216
		$ifinfo = pfSense_getall_interface_addresses($interface);
5217
		foreach ($ifinfo as $line) {
5218
			if (strstr($line, ":")) {
5219
				$parts = explode("/", $line);
5220
				if (is_linklocal($parts[0])) {
5221
					$ifinfo['linklocal'] = $parts[0];
5222
				}
5223
			}
5224
		}
5225
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5226
	}
5227
	return $interface_llv6_arr_cache[$interface];
5228
}
5229

    
5230
function find_interface_subnet($interface, $flush = false) {
5231
	global $interface_sn_arr_cache;
5232
	global $interface_ip_arr_cache;
5233

    
5234
	$interface = str_replace("\n", "", $interface);
5235
	if (does_interface_exist($interface) == false) {
5236
		return;
5237
	}
5238

    
5239
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5240
		$ifinfo = pfSense_get_interface_addresses($interface);
5241
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5242
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5243
	}
5244

    
5245
	return $interface_sn_arr_cache[$interface];
5246
}
5247

    
5248
function find_interface_subnetv6($interface, $flush = false) {
5249
	global $interface_snv6_arr_cache;
5250
	global $interface_ipv6_arr_cache;
5251

    
5252
	$interface = str_replace("\n", "", $interface);
5253
	if (does_interface_exist($interface) == false) {
5254
		return;
5255
	}
5256

    
5257
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5258
		$ifinfo = pfSense_get_interface_addresses($interface);
5259
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5260
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5261
	}
5262

    
5263
	return $interface_snv6_arr_cache[$interface];
5264
}
5265

    
5266
function ip_in_interface_alias_subnet($interface, $ipalias) {
5267
	global $config;
5268

    
5269
	if (empty($interface) || !is_ipaddr($ipalias)) {
5270
		return false;
5271
	}
5272
	if (is_array($config['virtualip']['vip'])) {
5273
		foreach ($config['virtualip']['vip'] as $vip) {
5274
			switch ($vip['mode']) {
5275
				case "ipalias":
5276
					if ($vip['interface'] <> $interface) {
5277
						break;
5278
					}
5279
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5280
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5281
						return true;
5282
					}
5283
					break;
5284
			}
5285
		}
5286
	}
5287

    
5288
	return false;
5289
}
5290

    
5291
function get_possible_listen_ips($include_ipv6_link_local=false) {
5292

    
5293
	$interfaces = get_configured_interface_with_descr();
5294
	foreach ($interfaces as $iface => $ifacename) {
5295
		if ($include_ipv6_link_local) {
5296
			/* This is to avoid going though added ll below */
5297
			if (substr($iface, 0, 5) == '_lloc') {
5298
				continue;
5299
			}
5300
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5301
			if (!empty($llip)) {
5302
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5303
			}
5304
		}
5305
	}
5306
	$viplist = get_configured_vip_list();
5307
	foreach ($viplist as $vip => $address) {
5308
		$interfaces[$vip] = $address;
5309
		if (get_vip_descr($address)) {
5310
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5311
		}
5312
	}
5313

    
5314
	$interfaces['lo0'] = 'Localhost';
5315

    
5316
	return $interfaces;
5317
}
5318

    
5319
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5320
	global $config;
5321

    
5322
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5323
	foreach (array('server', 'client') as $mode) {
5324
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5325
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5326
				if (!isset($setting['disable'])) {
5327
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5328
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5329
				}
5330
			}
5331
		}
5332
	}
5333
	return $sourceips;
5334
}
5335

    
5336
function get_interface_ip($interface = "wan") {
5337

    
5338
	if (substr($interface, 0, 4) == '_vip') {
5339
		return get_configured_vip_ipv4($interface);
5340
	} else if (substr($interface, 0, 5) == '_lloc') {
5341
		/* No link-local address for v4. */
5342
		return null;
5343
	}
5344

    
5345
	$realif = get_failover_interface($interface, 'inet');
5346
	if (!$realif) {
5347
		return null;
5348
	}
5349

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

    
5357
	if (is_array($config['interfaces'][$interface]) &&
5358
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5359
		return ($config['interfaces'][$interface]['ipaddr']);
5360
	}
5361

    
5362
	/*
5363
	 * Beaware that find_interface_ip() is our last option, it will
5364
	 * return the first IP it find on interface, not necessarily the
5365
	 * main IP address.
5366
	 */
5367
	$curip = find_interface_ip($realif);
5368
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5369
		return $curip;
5370
	} else {
5371
		return null;
5372
	}
5373
}
5374

    
5375
function get_interface_ipv6($interface = "wan", $flush = false) {
5376
	global $config;
5377

    
5378
	if (substr($interface, 0, 4) == '_vip') {
5379
		return get_configured_vip_ipv6($interface);
5380
	} else if (substr($interface, 0, 5) == '_lloc') {
5381
		return get_interface_linklocal($interface);
5382
	}
5383

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

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

    
5395
	if (is_array($config['interfaces'][$interface])) {
5396
		switch ($config['interfaces'][$interface]['ipaddr']) {
5397
			case 'pppoe':
5398
			case 'l2tp':
5399
			case 'pptp':
5400
			case 'ppp':
5401
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5402
					$realif = get_real_interface($interface, 'inet6', false);
5403
				}
5404
				break;
5405
		}
5406
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5407
			return ($config['interfaces'][$interface]['ipaddrv6']);
5408
		}
5409
	}
5410

    
5411
	/*
5412
	 * Beaware that find_interface_ip() is our last option, it will
5413
	 * return the first IP it find on interface, not necessarily the
5414
	 * main IP address.
5415
	 */
5416
	$curip = find_interface_ipv6($realif, $flush);
5417
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5418
		return $curip;
5419
	} else {
5420
		/*
5421
		 * NOTE: On the case when only the prefix is requested,
5422
		 * the communication on WAN will be done over link-local.
5423
		 */
5424
		if (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
5425
			$curip = find_interface_ipv6_ll($realif, $flush);
5426
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5427
				return $curip;
5428
			}
5429
		}
5430
	}
5431
	return null;
5432
}
5433

    
5434
function get_interface_linklocal($interface = "wan") {
5435

    
5436
	$realif = get_failover_interface($interface, 'inet6');
5437
	if (!$realif) {
5438
		return null;
5439
	}
5440

    
5441
	if (substr($interface, 0, 4) == '_vip') {
5442
		$realif = get_real_interface($interface);
5443
	} else if (substr($interface, 0, 5) == '_lloc') {
5444
		$realif = get_real_interface(substr($interface, 5));
5445
	}
5446

    
5447
	$curip = find_interface_ipv6_ll($realif);
5448
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5449
		return $curip;
5450
	} else {
5451
		return null;
5452
	}
5453
}
5454

    
5455
function get_interface_subnet($interface = "wan") {
5456

    
5457
	if (substr($interface, 0, 4) == '_vip') {
5458
		return (get_configured_vip_subnetv4($interface));
5459
	}
5460

    
5461
	$realif = get_real_interface($interface);
5462
	if (!$realif) {
5463
		return (NULL);
5464
	}
5465

    
5466
	$cursn = find_interface_subnet($realif);
5467
	if (!empty($cursn)) {
5468
		return ($cursn);
5469
	}
5470

    
5471
	return (NULL);
5472
}
5473

    
5474
function get_interface_subnetv6($interface = "wan") {
5475

    
5476
	if (substr($interface, 0, 4) == '_vip') {
5477
		return (get_configured_vip_subnetv6($interface));
5478
	} else if (substr($interface, 0, 5) == '_lloc') {
5479
		$interface = substr($interface, 5);
5480
	}
5481

    
5482
	$realif = get_real_interface($interface, 'inet6');
5483
	if (!$realif) {
5484
		return (NULL);
5485
	}
5486

    
5487
	$cursn = find_interface_subnetv6($realif);
5488
	if (!empty($cursn)) {
5489
		return ($cursn);
5490
	}
5491

    
5492
	return (NULL);
5493
}
5494

    
5495
/* return outside interfaces with a gateway */
5496
function get_interfaces_with_gateway() {
5497
	global $config;
5498

    
5499
	$ints = array();
5500

    
5501
	/* loop interfaces, check config for outbound */
5502
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5503
		switch ($ifname['ipaddr']) {
5504
			case "dhcp":
5505
			case "pppoe":
5506
			case "pptp":
5507
			case "l2tp":
5508
			case "ppp":
5509
				$ints[$ifdescr] = $ifdescr;
5510
				break;
5511
			default:
5512
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5513
				    !empty($ifname['gateway'])) {
5514
					$ints[$ifdescr] = $ifdescr;
5515
				}
5516
				break;
5517
		}
5518
	}
5519
	return $ints;
5520
}
5521

    
5522
/* return true if interface has a gateway */
5523
function interface_has_gateway($friendly) {
5524
	global $config;
5525

    
5526
	if (!empty($config['interfaces'][$friendly])) {
5527
		$ifname = &$config['interfaces'][$friendly];
5528
		switch ($ifname['ipaddr']) {
5529
			case "dhcp":
5530
			case "pppoe":
5531
			case "pptp":
5532
			case "l2tp":
5533
			case "ppp":
5534
				return true;
5535
			break;
5536
			default:
5537
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5538
					return true;
5539
				}
5540
				$tunnelif = substr($ifname['if'], 0, 3);
5541
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5542
					if (find_interface_ip($ifname['if'])) {
5543
						return true;
5544
					}
5545
				}
5546
				if (!empty($ifname['gateway'])) {
5547
					return true;
5548
				}
5549
			break;
5550
		}
5551
	}
5552

    
5553
	return false;
5554
}
5555

    
5556
/* return true if interface has a gateway */
5557
function interface_has_gatewayv6($friendly) {
5558
	global $config;
5559

    
5560
	if (!empty($config['interfaces'][$friendly])) {
5561
		$ifname = &$config['interfaces'][$friendly];
5562
		switch ($ifname['ipaddrv6']) {
5563
			case "slaac":
5564
			case "dhcp6":
5565
			case "6to4":
5566
			case "6rd":
5567
				return true;
5568
				break;
5569
			default:
5570
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5571
					return true;
5572
				}
5573
				$tunnelif = substr($ifname['if'], 0, 3);
5574
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5575
					if (find_interface_ipv6($ifname['if'])) {
5576
						return true;
5577
					}
5578
				}
5579
				if (!empty($ifname['gatewayv6'])) {
5580
					return true;
5581
				}
5582
				break;
5583
		}
5584
	}
5585

    
5586
	return false;
5587
}
5588

    
5589
/****f* interfaces/is_altq_capable
5590
 * NAME
5591
 *   is_altq_capable - Test if interface is capable of using ALTQ
5592
 * INPUTS
5593
 *   $int            - string containing interface name
5594
 * RESULT
5595
 *   boolean         - true or false
5596
 ******/
5597

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

    
5612
	$int_family = remove_ifindex($int);
5613

    
5614
	if (in_array($int_family, $capable)) {
5615
		return true;
5616
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5617
		return true;
5618
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5619
		return true;
5620
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5621
		return true;
5622
	} else {
5623
		return false;
5624
	}
5625
}
5626

    
5627
/****f* interfaces/is_interface_wireless
5628
 * NAME
5629
 *   is_interface_wireless - Returns if an interface is wireless
5630
 * RESULT
5631
 *   $tmp       - Returns if an interface is wireless
5632
 ******/
5633
function is_interface_wireless($interface) {
5634
	global $config, $g;
5635

    
5636
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5637
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5638
		if (preg_match($g['wireless_regex'], $interface)) {
5639
			if (isset($config['interfaces'][$friendly])) {
5640
				$config['interfaces'][$friendly]['wireless'] = array();
5641
			}
5642
			return true;
5643
		}
5644
		return false;
5645
	} else {
5646
		return true;
5647
	}
5648
}
5649

    
5650
function get_wireless_modes($interface) {
5651
	/* return wireless modes and channels */
5652
	$wireless_modes = array();
5653

    
5654
	$cloned_interface = get_real_interface($interface);
5655

    
5656
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5657
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5658
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5659
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5660

    
5661
		$interface_channels = "";
5662
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5663
		$interface_channel_count = count($interface_channels);
5664

    
5665
		$c = 0;
5666
		while ($c < $interface_channel_count) {
5667
			$channel_line = explode(",", $interface_channels["$c"]);
5668
			$wireless_mode = trim($channel_line[0]);
5669
			$wireless_channel = trim($channel_line[1]);
5670
			if (trim($wireless_mode) != "") {
5671
				/* if we only have 11g also set 11b channels */
5672
				if ($wireless_mode == "11g") {
5673
					if (!isset($wireless_modes["11b"])) {
5674
						$wireless_modes["11b"] = array();
5675
					}
5676
				} else if ($wireless_mode == "11g ht") {
5677
					if (!isset($wireless_modes["11b"])) {
5678
						$wireless_modes["11b"] = array();
5679
					}
5680
					if (!isset($wireless_modes["11g"])) {
5681
						$wireless_modes["11g"] = array();
5682
					}
5683
					$wireless_mode = "11ng";
5684
				} else if ($wireless_mode == "11a ht") {
5685
					if (!isset($wireless_modes["11a"])) {
5686
						$wireless_modes["11a"] = array();
5687
					}
5688
					$wireless_mode = "11na";
5689
				}
5690
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5691
			}
5692
			$c++;
5693
		}
5694
	}
5695
	return($wireless_modes);
5696
}
5697

    
5698
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5699
function get_wireless_channel_info($interface) {
5700
	$wireless_channels = array();
5701

    
5702
	$cloned_interface = get_real_interface($interface);
5703

    
5704
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5705
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5706
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5707
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5708

    
5709
		$interface_channels = "";
5710
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5711

    
5712
		foreach ($interface_channels as $channel_line) {
5713
			$channel_line = explode(",", $channel_line);
5714
			if (!isset($wireless_channels[$channel_line[0]])) {
5715
				$wireless_channels[$channel_line[0]] = $channel_line;
5716
			}
5717
		}
5718
	}
5719
	return($wireless_channels);
5720
}
5721

    
5722
function set_interface_mtu($interface, $mtu) {
5723

    
5724
	/* LAGG interface must be destroyed and re-created to change MTU */
5725
	if (substr($interface, 0, 4) == 'lagg') {
5726
		if (isset($config['laggs']['lagg']) &&
5727
		    is_array($config['laggs']['lagg'])) {
5728
			foreach ($config['laggs']['lagg'] as $lagg) {
5729
				if ($lagg['laggif'] == $interface) {
5730
					interface_lagg_configure($lagg);
5731
					break;
5732
				}
5733
			}
5734
		}
5735
	} else {
5736
		pfSense_interface_mtu($interface, $mtu);
5737
	}
5738
}
5739

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

    
5751
function get_interface_mac($interface) {
5752

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

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

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

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

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

    
5794
	return false;
5795
}
5796

    
5797
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5798
	global $g;
5799

    
5800
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5801

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

    
5808
EOD;
5809

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

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

    
5835
	/* Never reached */
5836
	return 1500;
5837
}
5838

    
5839
function get_vip_descr($ipaddress) {
5840
	global $config;
5841

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

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

    
5857
	$ifcfg = $config['interfaces'][$if];
5858

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

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

    
5884
	return 0;
5885
}
5886

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

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

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

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

    
5914
?>
(25-25/65)