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
		if (isset($config['dnsmasq']['enable'])) {
1208
			services_dnsmasq_configure();
1209
		}
1210

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

    
1216
	return 0;
1217
}
1218

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1443
	return;
1444
}
1445

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

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

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

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

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

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

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

    
1495
	return false;
1496
}
1497

    
1498
function interfaces_ptpid_next() {
1499

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

    
1505
	return $ptpid;
1506
}
1507

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

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

    
1520
	return NULL;
1521
}
1522

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

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

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

    
1533
	$itemhash = getMPDCRONSettings($pppif);
1534

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1822
EOD;
1823

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

    
1828
EOD;
1829
	}
1830

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

    
1839
EOD;
1840

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

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

    
1851
EOD;
1852
	}
1853

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

    
1859
EOD;
1860
	}
1861

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

    
1866
EOD;
1867
	}
1868

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

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

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

    
1884
EOD;
1885
		}
1886

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

    
1891
EOD;
1892
		}
1893

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

    
1898
EOD;
1899
		}
1900

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

    
1906
EOD;
1907

    
1908

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

    
1913
EOD;
1914
		}
1915

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

    
1929
EOD;
1930
		}
1931

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

    
1936
EOD;
1937
		}
1938

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

    
1943
EOD;
1944
		}
1945

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

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

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

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

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

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

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

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

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

    
2010
EOD;
2011
		}
2012

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

    
2018
EOD;
2019
		}
2020

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

    
2024

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

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

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

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

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

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

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

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

    
2134
	return 1;
2135
}
2136

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

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

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

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

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

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

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

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

    
2182
		sleep(1);
2183

    
2184
		/* XXX: Handle an issue with pfsync(4) and carp(4). In a cluster carp will come up before pfsync(4) has updated and so will cause issues
2185
		 * for existing sessions.
2186
		 */
2187
		log_error(gettext("waiting for pfsync..."));
2188
		$i = 0;
2189
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2190
			$i++;
2191
			sleep(1);
2192
		}
2193
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2194
		log_error(gettext("Configuring CARP settings finalize..."));
2195
	} else {
2196
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2197
	}
2198

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2447
	return $realif;
2448
}
2449

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2808
EOD;
2809

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

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

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

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

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

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

    
2844
EOD;
2845
						}
2846
					}
2847
				}
2848

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3011
	unset($wlcmd_args, $wlcmd);
3012

    
3013

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

    
3018
	return 0;
3019

    
3020
}
3021

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

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

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

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

    
3041
	return intval($pid);
3042
}
3043

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

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

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

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

    
3069
	return intval($pid);
3070
}
3071

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

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

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

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

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

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

    
3135
	return $mtu;
3136
}
3137

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

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

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

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

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

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

    
3178
	return $mtu;
3179
}
3180

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

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

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

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

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

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

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

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

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

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

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

    
3257
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3258
			/*   this is not a valid mac address.  generate a
3259
			 *   temporary mac address so the machine can get online.
3260
			 */
3261
			echo gettext("Generating new MAC address.");
3262
			$random_mac = generate_random_mac_address();
3263
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3264
				" link " . escapeshellarg($random_mac));
3265
			$wancfg['spoofmac'] = $random_mac;
3266
			write_config();
3267
			file_notice("MAC Address altered", sprintf(gettext('The INVALID MAC address (ff:ff:ff:ff:ff:ff) on interface %1$s has been automatically replaced with %2$s'), $realif, $random_mac), "Interfaces");
3268
		}
3269
	}
3270

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

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

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

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

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

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

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

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

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

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

    
3337
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3338

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

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

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

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

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

    
3426
	interface_netgraph_needed($interface);
3427

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

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

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

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

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

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

    
3465
		if ($reloadall == true) {
3466

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

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

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

    
3477
			if (isset($config['unbound']['enable'])) {
3478
				services_unbound_configure();
3479
			}
3480

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

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

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

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

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

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

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

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

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

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

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

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

    
3567
		if (isset($config['dnsmasq']['enable'])) {
3568
			services_dnsmasq_configure();
3569
		}
3570

    
3571
		services_dhcpd_configure("inet6");
3572
	}
3573

    
3574
	return 0;
3575
}
3576

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

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

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

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

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

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

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

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

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

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

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

    
3638
	return 0;
3639
}
3640

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

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

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

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

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

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

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

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

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

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

    
3698
	return 0;
3699
}
3700

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

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

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

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

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

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

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

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

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

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

    
3753

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

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

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

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

    
3788
	return 0;
3789
}
3790

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3894
	return 0;
3895
}
3896

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4032
	return 0;
4033
}
4034

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4181
	return $dhcp6cconf;
4182
}
4183

    
4184

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

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

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

    
4197

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

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

    
4202
	return $dhcp6cconf;
4203
}
4204

    
4205

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

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

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

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

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

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

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

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

    
4254
}
4255

    
4256
EOD;
4257

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

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

    
4272
EOD;
4273
	}
4274

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

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

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

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

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

    
4296
	return 0;
4297
}
4298

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

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

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

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

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

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

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

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

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

    
4364
	return $dhclientconf;
4365
}
4366

    
4367

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

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

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

    
4380

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

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

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

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

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

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

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

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

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

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

    
4433
	return $dhclientconf;
4434
}
4435

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

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

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

    
4447
	return;
4448
}
4449

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

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

    
4464
	return;
4465
}
4466

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

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

    
4478
	return false;
4479
}
4480

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4598
	return $ifdesc;
4599
}
4600

    
4601
function convert_real_interface_to_friendly_descr($interface) {
4602

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

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

    
4609
	return $interface;
4610
}
4611

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

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

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

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

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

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

    
4693
	return $parents;
4694
}
4695

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

    
4704
	$realif = get_parent_interface($interface);
4705

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

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

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

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

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

    
4744
	$wanif = NULL;
4745

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

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

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

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

    
4850
	return $wanif;
4851
}
4852

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

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

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

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

    
4876
	return false;
4877
}
4878

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

    
4888
	$isv6ip = is_ipaddrv6($ip);
4889

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

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

    
4911
	return false;
4912
}
4913

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

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

    
4928
	$isv6ip = is_ipaddrv6($ip);
4929

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

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

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

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

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

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

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

    
5037
	return $mtu;
5038
}
5039

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

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

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

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

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

    
5088
	return NULL;
5089
}
5090

    
5091
/****f* interfaces/link_interface_to_bridge
5092
 * NAME
5093
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5094
 * INPUTS
5095
 *   $ip
5096
 * RESULT
5097
 *   bridge[0-99]
5098
 ******/
5099
function link_interface_to_bridge($int) {
5100
	global $config;
5101

    
5102
	if (is_array($config['bridges']['bridged'])) {
5103
		foreach ($config['bridges']['bridged'] as $bridge) {
5104
			if (in_array($int, explode(',', $bridge['members']))) {
5105
				return "{$bridge['bridgeif']}";
5106
			}
5107
		}
5108
	}
5109
}
5110

    
5111
function link_interface_to_group($int) {
5112
	global $config;
5113

    
5114
	$result = array();
5115

    
5116
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5117
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5118
			if (in_array($int, explode(" ", $group['members']))) {
5119
				$result[$group['ifname']] = $int;
5120
			}
5121
		}
5122
	}
5123

    
5124
	return $result;
5125
}
5126

    
5127
function link_interface_to_gre($interface) {
5128
	global $config;
5129

    
5130
	$result = array();
5131

    
5132
	if (is_array($config['gres']['gre'])) {
5133
		foreach ($config['gres']['gre'] as $gre) {
5134
			if ($gre['if'] == $interface) {
5135
				$result[] = $gre;
5136
			}
5137
		}
5138
	}
5139

    
5140
	return $result;
5141
}
5142

    
5143
function link_interface_to_gif($interface) {
5144
	global $config;
5145

    
5146
	$result = array();
5147

    
5148
	if (is_array($config['gifs']['gif'])) {
5149
		foreach ($config['gifs']['gif'] as $gif) {
5150
			if ($gif['if'] == $interface) {
5151
				$result[] = $gif;
5152
			}
5153
		}
5154
	}
5155

    
5156
	return $result;
5157
}
5158

    
5159
/*
5160
 * find_interface_ip($interface): return the interface ip (first found)
5161
 */
5162
function find_interface_ip($interface, $flush = false) {
5163
	global $interface_ip_arr_cache;
5164
	global $interface_sn_arr_cache;
5165

    
5166
	$interface = str_replace("\n", "", $interface);
5167

    
5168
	if (!does_interface_exist($interface)) {
5169
		return;
5170
	}
5171

    
5172
	/* Setup IP cache */
5173
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5174
		$ifinfo = pfSense_get_interface_addresses($interface);
5175
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5176
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5177
	}
5178

    
5179
	return $interface_ip_arr_cache[$interface];
5180
}
5181

    
5182
/*
5183
 * find_interface_ipv6($interface): return the interface ip (first found)
5184
 */
5185
function find_interface_ipv6($interface, $flush = false) {
5186
	global $interface_ipv6_arr_cache;
5187
	global $interface_snv6_arr_cache;
5188
	global $config;
5189

    
5190
	$interface = trim($interface);
5191
	$interface = get_real_interface($interface);
5192

    
5193
	if (!does_interface_exist($interface)) {
5194
		return;
5195
	}
5196

    
5197
	/* Setup IP cache */
5198
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5199
		$ifinfo = pfSense_get_interface_addresses($interface);
5200
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5201
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5202
	}
5203

    
5204
	return $interface_ipv6_arr_cache[$interface];
5205
}
5206

    
5207
/*
5208
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5209
 */
5210
function find_interface_ipv6_ll($interface, $flush = false) {
5211
	global $interface_llv6_arr_cache;
5212
	global $config;
5213

    
5214
	$interface = str_replace("\n", "", $interface);
5215

    
5216
	if (!does_interface_exist($interface)) {
5217
		return;
5218
	}
5219

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

    
5236
function find_interface_subnet($interface, $flush = false) {
5237
	global $interface_sn_arr_cache;
5238
	global $interface_ip_arr_cache;
5239

    
5240
	$interface = str_replace("\n", "", $interface);
5241
	if (does_interface_exist($interface) == false) {
5242
		return;
5243
	}
5244

    
5245
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5246
		$ifinfo = pfSense_get_interface_addresses($interface);
5247
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5248
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5249
	}
5250

    
5251
	return $interface_sn_arr_cache[$interface];
5252
}
5253

    
5254
function find_interface_subnetv6($interface, $flush = false) {
5255
	global $interface_snv6_arr_cache;
5256
	global $interface_ipv6_arr_cache;
5257

    
5258
	$interface = str_replace("\n", "", $interface);
5259
	if (does_interface_exist($interface) == false) {
5260
		return;
5261
	}
5262

    
5263
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5264
		$ifinfo = pfSense_get_interface_addresses($interface);
5265
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5266
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5267
	}
5268

    
5269
	return $interface_snv6_arr_cache[$interface];
5270
}
5271

    
5272
function ip_in_interface_alias_subnet($interface, $ipalias) {
5273
	global $config;
5274

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

    
5294
	return false;
5295
}
5296

    
5297
function get_possible_listen_ips($include_ipv6_link_local=false) {
5298

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

    
5320
	$interfaces['lo0'] = 'Localhost';
5321

    
5322
	return $interfaces;
5323
}
5324

    
5325
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5326
	global $config;
5327

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

    
5342
function get_interface_ip($interface = "wan") {
5343

    
5344
	if (substr($interface, 0, 4) == '_vip') {
5345
		return get_configured_vip_ipv4($interface);
5346
	} else if (substr($interface, 0, 5) == '_lloc') {
5347
		/* No link-local address for v4. */
5348
		return null;
5349
	}
5350

    
5351
	$realif = get_failover_interface($interface, 'inet');
5352
	if (!$realif) {
5353
		return null;
5354
	}
5355

    
5356
	if (substr($realif, 0, 4) == '_vip') {
5357
		return get_configured_vip_ipv4($realif);
5358
	} else if (substr($realif, 0, 5) == '_lloc') {
5359
		/* No link-local address for v4. */
5360
		return null;
5361
	}
5362

    
5363
	if (is_array($config['interfaces'][$interface]) &&
5364
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5365
		return ($config['interfaces'][$interface]['ipaddr']);
5366
	}
5367

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

    
5381
function get_interface_ipv6($interface = "wan", $flush = false) {
5382
	global $config;
5383

    
5384
	if (substr($interface, 0, 4) == '_vip') {
5385
		return get_configured_vip_ipv6($interface);
5386
	} else if (substr($interface, 0, 5) == '_lloc') {
5387
		return get_interface_linklocal($interface);
5388
	}
5389

    
5390
	$realif = get_failover_interface($interface, 'inet6');
5391
	if (!$realif) {
5392
		return null;
5393
	}
5394

    
5395
	if (substr($realif, 0, 4) == '_vip') {
5396
		return get_configured_vip_ipv6($realif);
5397
	} else if (substr($realif, 0, 5) == '_lloc') {
5398
		return get_interface_linklocal($realif);
5399
	}
5400

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

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

    
5440
function get_interface_linklocal($interface = "wan") {
5441

    
5442
	$realif = get_failover_interface($interface, 'inet6');
5443
	if (!$realif) {
5444
		return null;
5445
	}
5446

    
5447
	if (substr($interface, 0, 4) == '_vip') {
5448
		$realif = get_real_interface($interface);
5449
	} else if (substr($interface, 0, 5) == '_lloc') {
5450
		$realif = get_real_interface(substr($interface, 5));
5451
	}
5452

    
5453
	$curip = find_interface_ipv6_ll($realif);
5454
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5455
		return $curip;
5456
	} else {
5457
		return null;
5458
	}
5459
}
5460

    
5461
function get_interface_subnet($interface = "wan") {
5462

    
5463
	if (substr($interface, 0, 4) == '_vip') {
5464
		return (get_configured_vip_subnetv4($interface));
5465
	}
5466

    
5467
	$realif = get_real_interface($interface);
5468
	if (!$realif) {
5469
		return (NULL);
5470
	}
5471

    
5472
	$cursn = find_interface_subnet($realif);
5473
	if (!empty($cursn)) {
5474
		return ($cursn);
5475
	}
5476

    
5477
	return (NULL);
5478
}
5479

    
5480
function get_interface_subnetv6($interface = "wan") {
5481

    
5482
	if (substr($interface, 0, 4) == '_vip') {
5483
		return (get_configured_vip_subnetv6($interface));
5484
	} else if (substr($interface, 0, 5) == '_lloc') {
5485
		$interface = substr($interface, 5);
5486
	}
5487

    
5488
	$realif = get_real_interface($interface, 'inet6');
5489
	if (!$realif) {
5490
		return (NULL);
5491
	}
5492

    
5493
	$cursn = find_interface_subnetv6($realif);
5494
	if (!empty($cursn)) {
5495
		return ($cursn);
5496
	}
5497

    
5498
	return (NULL);
5499
}
5500

    
5501
/* return outside interfaces with a gateway */
5502
function get_interfaces_with_gateway() {
5503
	global $config;
5504

    
5505
	$ints = array();
5506

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

    
5528
/* return true if interface has a gateway */
5529
function interface_has_gateway($friendly) {
5530
	global $config;
5531

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

    
5559
	return false;
5560
}
5561

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

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

    
5592
	return false;
5593
}
5594

    
5595
/****f* interfaces/is_altq_capable
5596
 * NAME
5597
 *   is_altq_capable - Test if interface is capable of using ALTQ
5598
 * INPUTS
5599
 *   $int            - string containing interface name
5600
 * RESULT
5601
 *   boolean         - true or false
5602
 ******/
5603

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

    
5618
	$int_family = remove_ifindex($int);
5619

    
5620
	if (in_array($int_family, $capable)) {
5621
		return true;
5622
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5623
		return true;
5624
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5625
		return true;
5626
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5627
		return true;
5628
	} else {
5629
		return false;
5630
	}
5631
}
5632

    
5633
/****f* interfaces/is_interface_wireless
5634
 * NAME
5635
 *   is_interface_wireless - Returns if an interface is wireless
5636
 * RESULT
5637
 *   $tmp       - Returns if an interface is wireless
5638
 ******/
5639
function is_interface_wireless($interface) {
5640
	global $config, $g;
5641

    
5642
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5643
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5644
		if (preg_match($g['wireless_regex'], $interface)) {
5645
			if (isset($config['interfaces'][$friendly])) {
5646
				$config['interfaces'][$friendly]['wireless'] = array();
5647
			}
5648
			return true;
5649
		}
5650
		return false;
5651
	} else {
5652
		return true;
5653
	}
5654
}
5655

    
5656
function get_wireless_modes($interface) {
5657
	/* return wireless modes and channels */
5658
	$wireless_modes = array();
5659

    
5660
	$cloned_interface = get_real_interface($interface);
5661

    
5662
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5663
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5664
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5665
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5666

    
5667
		$interface_channels = "";
5668
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5669
		$interface_channel_count = count($interface_channels);
5670

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

    
5704
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5705
function get_wireless_channel_info($interface) {
5706
	$wireless_channels = array();
5707

    
5708
	$cloned_interface = get_real_interface($interface);
5709

    
5710
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5711
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5712
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5713
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5714

    
5715
		$interface_channels = "";
5716
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5717

    
5718
		foreach ($interface_channels as $channel_line) {
5719
			$channel_line = explode(",", $channel_line);
5720
			if (!isset($wireless_channels[$channel_line[0]])) {
5721
				$wireless_channels[$channel_line[0]] = $channel_line;
5722
			}
5723
		}
5724
	}
5725
	return($wireless_channels);
5726
}
5727

    
5728
function set_interface_mtu($interface, $mtu) {
5729

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

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

    
5757
function get_interface_mac($interface) {
5758

    
5759
	$macinfo = pfSense_get_interface_addresses($interface);
5760
	return $macinfo["macaddr"];
5761
}
5762

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

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

    
5791
	if (isset($capable['caps']['vlanmtu'])) {
5792
		return true;
5793
	}
5794

    
5795
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5796
	if (substr($iface, 0, 4) == "lagg") {
5797
		return true;
5798
	}
5799

    
5800
	return false;
5801
}
5802

    
5803
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5804
	global $g;
5805

    
5806
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5807

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

    
5814
EOD;
5815

    
5816
		@file_put_contents($cron_file, $cron_cmd);
5817
		chmod($cron_file, 0755);
5818
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5819
	} else {
5820
		unlink_if_exists($cron_file);
5821
	}
5822
}
5823

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

    
5841
	/* Never reached */
5842
	return 1500;
5843
}
5844

    
5845
function get_vip_descr($ipaddress) {
5846
	global $config;
5847

    
5848
	foreach ($config['virtualip']['vip'] as $vip) {
5849
		if ($vip['subnet'] == $ipaddress) {
5850
			return ($vip['descr']);
5851
		}
5852
	}
5853
	return "";
5854
}
5855

    
5856
function interfaces_staticarp_configure($if) {
5857
	global $config, $g;
5858
	if (isset($config['system']['developerspew'])) {
5859
		$mt = microtime();
5860
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5861
	}
5862

    
5863
	$ifcfg = $config['interfaces'][$if];
5864

    
5865
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5866
		return 0;
5867
	}
5868

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

    
5890
	return 0;
5891
}
5892

    
5893
function get_failover_interface($interface, $family = "all") {
5894
	global $config;
5895

    
5896
	/* shortcut to get_real_interface if we find it in the config */
5897
	if (is_array($config['interfaces'][$interface])) {
5898
		return get_real_interface($interface, $family);
5899
	}
5900

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

    
5916
function remove_ifindex($ifname) {
5917
	return preg_replace("/[0-9]+$/", "", $ifname);
5918
}
5919

    
5920
?>
(25-25/65)