Project

General

Profile

Feature #6899 » interfaces.inc

Solution - Luka Pavlyuk, 11/05/2016 12:43 PM

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

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

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

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

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

    
83
	return $interface_arr_cache;
84
}
85

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

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

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

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

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

    
116

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

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

    
139
	return false;
140
}
141

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
269
	interfaces_bring_up($vlanif);
270

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

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

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

    
285
	return $vlanif;
286
}
287

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

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

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

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

    
308
	$vlanif = interface_vlan_configure($vlan);
309

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

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

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

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

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

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

    
364
	return $vlanif;
365
}
366

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

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

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

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

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

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

    
409
	return $vlanif;
410
}
411

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

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

    
419
	$iflist = get_configured_interface_list();
420

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

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

    
444
}
445

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

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

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

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

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

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

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

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

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

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

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

    
549
	$checklist = get_configured_interface_list();
550

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

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

    
572
	interface_bridge_configure_advanced($bridge);
573

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
773
	/* Check if MTU was defined for this lagg interface */
774
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
775
	if ($lagg_mtu == 0 &&
776
	    is_array($config['interfaces'])) {
777
		foreach ($config['interfaces'] as $tmpinterface) {
778
			if ($tmpinterface['if'] == $lagg['laggif'] &&
779
			    !empty($tmpinterface['mtu'])) {
780
				$lagg_mtu = $tmpinterface['mtu'];
781
				break;
782
			}
783
		}
784
	}
785

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

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

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

    
804
	interfaces_bring_up($laggif);
805

    
806
	return $laggif;
807
}
808

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

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

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

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

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

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

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

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

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

    
880
	if ($greif) {
881
		interfaces_bring_up($greif);
882
	} else {
883
		log_error(gettext("Could not bring greif up -- variable not defined."));
884
	}
885

    
886
	if (isset($gre['link1']) && $gre['link1']) {
887
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
888
	}
889
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
890
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
891
	}
892
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
893
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
894
	}
895

    
896
	interfaces_bring_up($greif);
897

    
898
	return $greif;
899
}
900

    
901
function interfaces_gif_configure($checkparent = 0, $realif = "") {
902
	global $config;
903

    
904
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
905
		foreach ($config['gifs']['gif'] as $i => $gif) {
906
			if (empty($gif['gifif'])) {
907
				$gre['gifif'] = "gif{$i}";
908
			}
909
			if (!empty($realif) && $realif != $gif['gifif']) {
910
				continue;
911
			}
912

    
913
			if ($checkparent == 1) {
914
				if (substr($gif['if'], 0, 4) == '_vip') {
915
					continue;
916
				}
917
				if (substr($gif['if'], 0, 5) == '_lloc') {
918
					continue;
919
				}
920
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
921
					continue;
922
				}
923
			}
924
			else if ($checkparent == 2) {
925
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
926
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
927
					continue;
928
				}
929
			}
930
			/* XXX: Maybe we should report any errors?! */
931
			interface_gif_configure($gif);
932
		}
933
	}
934
}
935

    
936
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
937
function interface_gif_configure(&$gif, $gifkey = "") {
938
	global $config, $g;
939

    
940
	if (!is_array($gif)) {
941
		return -1;
942
	}
943

    
944
	$realif = get_real_interface($gif['if']);
945
	$ipaddr = get_interface_ip($gif['if']);
946

    
947
	if (is_ipaddrv4($gif['remote-addr'])) {
948
		if (is_ipaddrv4($ipaddr)) {
949
			$realifip = $ipaddr;
950
		} else {
951
			$realifip = get_interface_ip($gif['if']);
952
		}
953
		$realifgw = get_interface_gateway($gif['if']);
954
	} else if (is_ipaddrv6($gif['remote-addr'])) {
955
		if (is_ipaddrv6($ipaddr)) {
956
			$realifip = $ipaddr;
957
		} else {
958
			$realifip = get_interface_ipv6($gif['if']);
959
		}
960
		$realifgw = get_interface_gateway_v6($gif['if']);
961
	}
962
	/* make sure the parent interface is up */
963
	if ($realif) {
964
		interfaces_bring_up($realif);
965
	} else {
966
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
967
	}
968

    
969
	if (platform_booting() || !(empty($gif['gifif']))) {
970
		pfSense_interface_destroy($gif['gifif']);
971
		pfSense_interface_create($gif['gifif']);
972
		$gifif = $gif['gifif'];
973
	} else {
974
		$gifif = pfSense_interface_create("gif");
975
	}
976

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

    
1016
	if (!platform_booting()) {
1017
		$iflist = get_configured_interface_list();
1018
		foreach ($iflist as $ifname) {
1019
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1020
				if (get_interface_gateway($ifname)) {
1021
					system_routing_configure($ifname);
1022
					break;
1023
				}
1024
				if (get_interface_gateway_v6($ifname)) {
1025
					system_routing_configure($ifname);
1026
					break;
1027
				}
1028
			}
1029
		}
1030
	}
1031

    
1032

    
1033
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1034
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1035
	}
1036
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1037
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1038
	}
1039

    
1040
	if (is_ipaddrv4($realifgw)) {
1041
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1042
	}
1043
	if (is_ipaddrv6($realifgw)) {
1044
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1045
	}
1046

    
1047
	interfaces_bring_up($gifif);
1048

    
1049
	return $gifif;
1050
}
1051

    
1052
function interfaces_configure() {
1053
	global $config, $g;
1054

    
1055
	/* Set up our loopback interface */
1056
	interfaces_loopback_configure();
1057

    
1058
	/* create the unconfigured wireless clones */
1059
	interfaces_create_wireless_clones();
1060

    
1061
	/* set up LAGG virtual interfaces */
1062
	interfaces_lagg_configure();
1063

    
1064
	/* set up VLAN virtual interfaces */
1065
	interfaces_vlan_configure();
1066

    
1067
	interfaces_qinq_configure();
1068

    
1069
	$iflist = get_configured_interface_with_descr();
1070
	$delayed_list = array();
1071
	$bridge_list = array();
1072
	$track6_list = array();
1073

    
1074
	/* This is needed to speedup interfaces on bootup. */
1075
	$reload = false;
1076
	if (!platform_booting()) {
1077
		$reload = true;
1078
	}
1079

    
1080
	foreach ($iflist as $if => $ifname) {
1081
		$realif = $config['interfaces'][$if]['if'];
1082
		if (strstr($realif, "bridge")) {
1083
			$bridge_list[$if] = $ifname;
1084
		} else if (strstr($realif, "gre")) {
1085
			$delayed_list[$if] = $ifname;
1086
		} else if (strstr($realif, "gif")) {
1087
			$delayed_list[$if] = $ifname;
1088
		} else if (strstr($realif, "ovpn")) {
1089
			//echo "Delaying OpenVPN interface configuration...done.\n";
1090
			continue;
1091
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1092
			$track6_list[$if] = $ifname;
1093
		} else {
1094
			if (platform_booting()) {
1095
				printf(gettext("Configuring %s interface..."), $ifname);
1096
			}
1097

    
1098
			if ($g['debug']) {
1099
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1100
			}
1101
			interface_configure($if, $reload);
1102
			if (platform_booting()) {
1103
				echo gettext("done.") . "\n";
1104
			}
1105
		}
1106
	}
1107

    
1108
	/*
1109
	 * NOTE: The following function parameter consists of
1110
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1111
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1112
	 */
1113

    
1114
	/* set up GRE virtual interfaces */
1115
	interfaces_gre_configure(1);
1116

    
1117
	/* set up GIF virtual interfaces */
1118
	interfaces_gif_configure(1);
1119

    
1120
	/* set up BRIDGe virtual interfaces */
1121
	interfaces_bridge_configure(1);
1122

    
1123
	foreach ($track6_list as $if => $ifname) {
1124
		if (platform_booting()) {
1125
			printf(gettext("Configuring %s interface..."), $ifname);
1126
		}
1127
		if ($g['debug']) {
1128
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1129
		}
1130

    
1131
		interface_configure($if, $reload);
1132

    
1133
		if (platform_booting()) {
1134
			echo gettext("done.") . "\n";
1135
		}
1136
	}
1137

    
1138
	/* bring up vip interfaces */
1139
	interfaces_vips_configure();
1140

    
1141
	/* set up GRE virtual interfaces */
1142
	interfaces_gre_configure(2);
1143

    
1144
	/* set up GIF virtual interfaces */
1145
	interfaces_gif_configure(2);
1146

    
1147
	foreach ($delayed_list as $if => $ifname) {
1148
		if (platform_booting()) {
1149
			printf(gettext("Configuring %s interface..."), $ifname);
1150
		}
1151
		if ($g['debug']) {
1152
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1153
		}
1154

    
1155
		interface_configure($if, $reload);
1156

    
1157
		if (platform_booting()) {
1158
			echo gettext("done.") . "\n";
1159
		}
1160
	}
1161

    
1162
	/* set up BRIDGe virtual interfaces */
1163
	interfaces_bridge_configure(2);
1164

    
1165
	foreach ($bridge_list as $if => $ifname) {
1166
		if (platform_booting()) {
1167
			printf(gettext("Configuring %s interface..."), $ifname);
1168
		}
1169
		if ($g['debug']) {
1170
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1171
		}
1172

    
1173
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1174
		// redmine #3997
1175
		interface_reconfigure($if, $reload);
1176
		interfaces_vips_configure($if);
1177

    
1178
		if (platform_booting()) {
1179
			echo gettext("done.") . "\n";
1180
		}
1181
	}
1182

    
1183
	/* configure interface groups */
1184
	interfaces_group_setup();
1185

    
1186
	if (!platform_booting()) {
1187
		/* reconfigure static routes (kernel may have deleted them) */
1188
		system_routing_configure();
1189

    
1190
		/* reload IPsec tunnels */
1191
		vpn_ipsec_configure();
1192

    
1193
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1194
		services_dhcpd_configure();
1195

    
1196
		if (isset($config['dnsmasq']['enable'])) {
1197
			services_dnsmasq_configure();
1198
		}
1199

    
1200
		if (isset($config['unbound']['enable'])) {
1201
			services_unbound_configure();
1202
		}
1203
	}
1204

    
1205
	return 0;
1206
}
1207

    
1208
function interface_reconfigure($interface = "wan", $reloadall = false) {
1209
	interface_bring_down($interface);
1210
	interface_configure($interface, $reloadall);
1211
}
1212

    
1213
function interface_vip_bring_down($vip) {
1214
	global $g;
1215

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

    
1245
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1246
	global $config, $g;
1247

    
1248
	if (!isset($config['interfaces'][$interface])) {
1249
		return;
1250
	}
1251

    
1252
	if ($g['debug']) {
1253
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1254
	}
1255

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

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

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

    
1397
	if (!empty($track6) && is_array($track6)) {
1398
		if (!function_exists('services_dhcpd_configure')) {
1399
			require_once('services.inc');
1400
		}
1401
		/* Bring down radvd and dhcp6 on these interfaces */
1402
		services_dhcpd_configure('inet6', $track6);
1403
	}
1404

    
1405
	$old_router = '';
1406
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1407
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1408
	}
1409

    
1410
	/* remove interface up file if it exists */
1411
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1412
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1413
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1414
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1415
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1416
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1417
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1418

    
1419
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1420
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1421
	if (is_array($ifcfg['wireless'])) {
1422
		kill_hostapd($realif);
1423
		mwexec(kill_wpasupplicant($realif));
1424
	}
1425

    
1426
	if ($destroy == true) {
1427
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1428
			pfSense_interface_destroy($realif);
1429
		}
1430
	}
1431

    
1432
	return;
1433
}
1434

    
1435
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1436
	global $config;
1437
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1438
		unset($config["virtualip_carp_maintenancemode"]);
1439
		write_config("Leave CARP maintenance mode");
1440
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1441
		$config["virtualip_carp_maintenancemode"] = true;
1442
		write_config(gettext("Enter CARP maintenance mode"));
1443
	}
1444

    
1445
	$viparr = &$config['virtualip']['vip'];
1446
	foreach ($viparr as $vip) {
1447
		if ($vip['mode'] == "carp") {
1448
			interface_carp_configure($vip);
1449
		}
1450
	}
1451
}
1452

    
1453
function interface_isppp_type($interface) {
1454
	global $config;
1455

    
1456
	if (!is_array($config['interfaces'][$interface])) {
1457
		return false;
1458
	}
1459

    
1460
	switch ($config['interfaces'][$interface]['ipaddr']) {
1461
		case 'pptp':
1462
		case 'l2tp':
1463
		case 'pppoe':
1464
		case 'ppp':
1465
			return true;
1466
			break;
1467
		default:
1468
			return false;
1469
			break;
1470
	}
1471
}
1472

    
1473
function interfaces_ptpid_used($ptpid) {
1474
	global $config;
1475

    
1476
	if (is_array($config['ppps']['ppp'])) {
1477
		foreach ($config['ppps']['ppp'] as & $settings) {
1478
			if ($ptpid == $settings['ptpid']) {
1479
				return true;
1480
			}
1481
		}
1482
	}
1483

    
1484
	return false;
1485
}
1486

    
1487
function interfaces_ptpid_next() {
1488

    
1489
	$ptpid = 0;
1490
	while (interfaces_ptpid_used($ptpid)) {
1491
		$ptpid++;
1492
	}
1493

    
1494
	return $ptpid;
1495
}
1496

    
1497
function getMPDCRONSettings($pppif) {
1498
	global $config;
1499

    
1500
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1501
	if (is_array($config['cron']['item'])) {
1502
		foreach ($config['cron']['item'] as $i => $item) {
1503
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1504
				return array("ID" => $i, "ITEM" => $item);
1505
			}
1506
		}
1507
	}
1508

    
1509
	return NULL;
1510
}
1511

    
1512
function handle_pppoe_reset($post_array) {
1513
	global $config, $g;
1514

    
1515
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1516
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1517

    
1518
	if (!is_array($config['cron']['item'])) {
1519
		$config['cron']['item'] = array();
1520
	}
1521

    
1522
	$itemhash = getMPDCRONSettings($pppif);
1523

    
1524
	// reset cron items if necessary and return
1525
	if (empty($post_array['pppoe-reset-type'])) {
1526
		if (isset($itemhash)) {
1527
			unset($config['cron']['item'][$itemhash['ID']]);
1528
		}
1529
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1530
		return;
1531
	}
1532

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

    
1595
/*
1596
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1597
 * It writes the mpd config file to /var/etc every time the link is opened.
1598
 */
1599
function interface_ppps_configure($interface) {
1600
	global $config, $g;
1601

    
1602
	/* Return for unassigned interfaces. This is a minimum requirement. */
1603
	if (empty($config['interfaces'][$interface])) {
1604
		return 0;
1605
	}
1606
	$ifcfg = $config['interfaces'][$interface];
1607
	if (!isset($ifcfg['enable'])) {
1608
		return 0;
1609
	}
1610

    
1611
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1612
	if (!is_dir("/var/spool/lock")) {
1613
		mkdir("/var/spool/lock", 0777, true);
1614
	}
1615
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1616
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1617
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1618
	}
1619

    
1620
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1621
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1622
			if ($ifcfg['if'] == $ppp['if']) {
1623
				break;
1624
			}
1625
		}
1626
	}
1627
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
1628
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1629
		return 0;
1630
	}
1631
	$pppif = $ifcfg['if'];
1632
	if ($ppp['type'] == "ppp") {
1633
		$type = "modem";
1634
	} else {
1635
		$type = $ppp['type'];
1636
	}
1637
	$upper_type = strtoupper($ppp['type']);
1638

    
1639
	/* XXX: This does not make sense and may create trouble
1640
	 * comment it for now to be removed later on.
1641
	if (platform_booting()) {
1642
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1643
		echo "starting {$pppif} link...";
1644
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1645
			return 0;
1646
	}
1647
	*/
1648

    
1649
	$ports = explode(',', $ppp['ports']);
1650
	if ($type != "modem") {
1651
		foreach ($ports as $pid => $port) {
1652
			$ports[$pid] = get_real_interface($port);
1653
			if (empty($ports[$pid])) {
1654
				return 0;
1655
			}
1656
		}
1657
	}
1658
	$localips = explode(',', $ppp['localip']);
1659
	$gateways = explode(',', $ppp['gateway']);
1660
	$subnets = explode(',', $ppp['subnet']);
1661

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

    
1685
				if (!is_ipaddr($localips[$pid])) {
1686
					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));
1687
					$localips[$pid] = "0.0.0.0";
1688
				}
1689
				if(!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])){
1690
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1691
				}
1692
				if (!is_ipaddr($gateways[$pid])) {
1693
					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));
1694
					return 0;
1695
				}
1696
				pfSense_ngctl_attach(".", $port);
1697
				break;
1698
			case "ppp":
1699
				if (!file_exists("{$port}")) {
1700
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1701
					return 0;
1702
				}
1703
				break;
1704
			default:
1705
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1706
				break;
1707
		}
1708
	}
1709

    
1710
	if (is_array($ports) && count($ports) > 1) {
1711
		$multilink = "enable";
1712
	} else {
1713
		$multilink = "disable";
1714
	}
1715

    
1716
	if ($type == "modem") {
1717
		if (is_ipaddr($ppp['localip'])) {
1718
			$localip = $ppp['localip'];
1719
		} else {
1720
			$localip = '0.0.0.0';
1721
		}
1722

    
1723
		if (is_ipaddr($ppp['gateway'])) {
1724
			$gateway = $ppp['gateway'];
1725
		} else {
1726
			$gateway = "10.64.64.{$pppid}";
1727
		}
1728
		$ranges = "{$localip}/0 {$gateway}/0";
1729

    
1730
		if (empty($ppp['apnum'])) {
1731
			$ppp['apnum'] = 1;
1732
		}
1733
	} else {
1734
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1735
	}
1736

    
1737
	if (isset($ppp['ondemand'])) {
1738
		$ondemand = "enable";
1739
	} else {
1740
		$ondemand = "disable";
1741
	}
1742
	if (!isset($ppp['idletimeout'])) {
1743
		$ppp['idletimeout'] = 0;
1744
	}
1745

    
1746
	if (empty($ppp['username']) && $type == "modem") {
1747
		$ppp['username'] = "user";
1748
		$ppp['password'] = "none";
1749
	}
1750
	if (empty($ppp['password']) && $type == "modem") {
1751
		$passwd = "none";
1752
	} else {
1753
		$passwd = base64_decode($ppp['password']);
1754
	}
1755

    
1756
	$bandwidths = explode(',', $ppp['bandwidth']);
1757
	$defaultmtu = "1492";
1758
	if (!empty($ifcfg['mtu'])) {
1759
		$defaultmtu = intval($ifcfg['mtu']);
1760
	}
1761
	if (isset($ppp['mtu'])) {
1762
		$mtus = explode(',', $ppp['mtu']);
1763
	}
1764
	if (isset($ppp['mru'])) {
1765
		$mrus = explode(',', $ppp['mru']);
1766
	}
1767
	if (isset($ppp['mrru'])) {
1768
		$mrrus = explode(',', $ppp['mrru']);
1769
	}
1770

    
1771
	// Construct the mpd.conf file
1772
	$mpdconf = <<<EOD
1773
startup:
1774
	# configure the console
1775
	set console close
1776
	# configure the web server
1777
	set web close
1778

    
1779
default:
1780
{$ppp['type']}client:
1781
	create bundle static {$interface}
1782
	set bundle enable ipv6cp
1783
	set iface name {$pppif}
1784

    
1785
EOD;
1786
	$setdefaultgw = false;
1787
	$founddefaultgw = false;
1788
	if (is_array($config['gateways']['gateway_item'])) {
1789
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1790
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1791
				$setdefaultgw = true;
1792
				break;
1793
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1794
				$founddefaultgw = true;
1795
				break;
1796
			}
1797
		}
1798
	}
1799

    
1800
/* Omit this, we maintain the default route by other means, and it causes problems with
1801
 * default gateway switching. See redmine #1837 for original issue
1802
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some 
1803
 * edge case. redmine #6495 open to address. 
1804
 */
1805
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1806
		$setdefaultgw = true;
1807
		$mpdconf .= <<<EOD
1808
	set iface route default
1809

    
1810
EOD;
1811
	}
1812
	$mpdconf .= <<<EOD
1813
	set iface {$ondemand} on-demand
1814
	set iface idle {$ppp['idletimeout']}
1815

    
1816
EOD;
1817

    
1818
	if (isset($ppp['ondemand'])) {
1819
		$mpdconf .= <<<EOD
1820
	set iface addrs 10.10.1.1 10.10.1.2
1821

    
1822
EOD;
1823
	}
1824

    
1825
	if (isset($ppp['tcpmssfix'])) {
1826
		$tcpmss = "disable";
1827
	} else {
1828
		$tcpmss = "enable";
1829
	}
1830
	$mpdconf .= <<<EOD
1831
	set iface {$tcpmss} tcpmssfix
1832

    
1833
EOD;
1834

    
1835
	$mpdconf .= <<<EOD
1836
	set iface up-script /usr/local/sbin/ppp-linkup
1837
	set iface down-script /usr/local/sbin/ppp-linkdown
1838
	set ipcp ranges {$ranges}
1839

    
1840
EOD;
1841
	if (isset($ppp['vjcomp'])) {
1842
		$mpdconf .= <<<EOD
1843
	set ipcp no vjcomp
1844

    
1845
EOD;
1846
	}
1847

    
1848
	if (isset($config['system']['dnsallowoverride'])) {
1849
		$mpdconf .= <<<EOD
1850
	set ipcp enable req-pri-dns
1851
	set ipcp enable req-sec-dns
1852

    
1853
EOD;
1854
	}
1855

    
1856
	if (!isset($ppp['verbose_log'])) {
1857
		$mpdconf .= <<<EOD
1858
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1859

    
1860
EOD;
1861
	}
1862

    
1863
	foreach ($ports as $pid => $port) {
1864
		$port = get_real_interface($port);
1865
		$mpdconf .= <<<EOD
1866

    
1867
	create link static {$interface}_link{$pid} {$type}
1868
	set link action bundle {$interface}
1869
	set link {$multilink} multilink
1870
	set link keep-alive 10 60
1871
	set link max-redial 0
1872

    
1873
EOD;
1874
		if (isset($ppp['shortseq'])) {
1875
			$mpdconf .= <<<EOD
1876
	set link no shortseq
1877

    
1878
EOD;
1879
		}
1880

    
1881
		if (isset($ppp['acfcomp'])) {
1882
			$mpdconf .= <<<EOD
1883
	set link no acfcomp
1884

    
1885
EOD;
1886
		}
1887

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

    
1892
EOD;
1893
		}
1894

    
1895
		$mpdconf .= <<<EOD
1896
	set link disable chap pap
1897
	set link accept chap pap eap
1898
	set link disable incoming
1899

    
1900
EOD;
1901

    
1902

    
1903
		if (!empty($bandwidths[$pid])) {
1904
			$mpdconf .= <<<EOD
1905
	set link bandwidth {$bandwidths[$pid]}
1906

    
1907
EOD;
1908
		}
1909

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

    
1923
EOD;
1924
		}
1925

    
1926
		if (!empty($mrus[$pid])) {
1927
			$mpdconf .= <<<EOD
1928
	set link mru {$mrus[$pid]}
1929

    
1930
EOD;
1931
		}
1932

    
1933
		if (!empty($mrrus[$pid])) {
1934
			$mpdconf .= <<<EOD
1935
	set link mrru {$mrrus[$pid]}
1936

    
1937
EOD;
1938
		}
1939

    
1940
		$mpdconf .= <<<EOD
1941
	set auth authname "{$ppp['username']}"
1942
	set auth password {$passwd}
1943

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

    
1954
EOD;
1955
		}
1956
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1957
			$mpdconf .= <<<EOD
1958
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1959

    
1960
EOD;
1961
		}
1962
		if (isset($ppp['initstr']) && $type == "modem") {
1963
			$initstr = base64_decode($ppp['initstr']);
1964
			$mpdconf .= <<<EOD
1965
	set modem var \$InitString "{$initstr}"
1966

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

    
1977
EOD;
1978
		}
1979
		if (isset($ppp['apn']) && $type == "modem") {
1980
			$mpdconf .= <<<EOD
1981
	set modem var \$APN "{$ppp['apn']}"
1982
	set modem var \$APNum "{$ppp['apnum']}"
1983

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

    
1992
EOD;
1993
		}
1994
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
1995
			$mpdconf .= <<<EOD
1996
	set pppoe max-payload {$mtus[$pid]}
1997

    
1998
EOD;
1999
		}
2000
		if ($type == "pppoe") {
2001
			$mpdconf .= <<<EOD
2002
	set pppoe iface {$port}
2003

    
2004
EOD;
2005
		}
2006

    
2007
		if ($type == "pptp" || $type == "l2tp") {
2008
			$mpdconf .= <<<EOD
2009
	set {$type} self {$localips[$pid]}
2010
	set {$type} peer {$gateways[$pid]}
2011

    
2012
EOD;
2013
		}
2014

    
2015
		$mpdconf .= "\topen\n";
2016
	} //end foreach ($port)
2017

    
2018

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

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

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

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

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

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

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

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

    
2129
	return 1;
2130
}
2131

    
2132
function interfaces_sync_setup() {
2133
	global $g, $config;
2134

    
2135
	if (isset($config['system']['developerspew'])) {
2136
		$mt = microtime();
2137
		echo "interfaces_sync_setup() being called $mt\n";
2138
	}
2139

    
2140
	if (platform_booting()) {
2141
		echo gettext("Configuring CARP settings...");
2142
		mute_kernel_msgs();
2143
	}
2144

    
2145
	/* suck in configuration items */
2146
	if ($config['hasync']) {
2147
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2148
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2149
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2150
	} else {
2151
		unset($pfsyncinterface);
2152
		unset($pfsyncenabled);
2153
	}
2154

    
2155
	set_sysctl(array(
2156
		"net.inet.carp.preempt" => "1",
2157
		"net.inet.carp.log" => "1")
2158
	);
2159

    
2160
	if (!empty($pfsyncinterface)) {
2161
		$carp_sync_int = get_real_interface($pfsyncinterface);
2162
	} else {
2163
		unset($carp_sync_int);
2164
	}
2165

    
2166
	/* setup pfsync interface */
2167
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2168
		if (is_ipaddr($pfsyncpeerip)) {
2169
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2170
		} else {
2171
			$syncpeer = "-syncpeer";
2172
		}
2173

    
2174
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2175
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2176

    
2177
		sleep(1);
2178

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

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

    
2201
	if (platform_booting()) {
2202
		unmute_kernel_msgs();
2203
		echo gettext("done.") . "\n";
2204
	}
2205
}
2206

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

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

    
2224
	$paa = array();
2225
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2226

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

    
2236
				if (!empty($interface) && $interface != $proxyif) {
2237
					continue;
2238
				}
2239

    
2240
				if (!is_array($paa[$proxyif])) {
2241
					$paa[$proxyif] = array();
2242
				}
2243

    
2244
				$paa[$proxyif][] = $vipent;
2245
			}
2246
		}
2247
	}
2248

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

    
2284
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2285
	global $g, $config;
2286

    
2287
	if (is_array($config['virtualip']['vip'])) {
2288
		foreach ($config['virtualip']['vip'] as $vip) {
2289

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

    
2306
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2307
				interface_vip_bring_down($vip);
2308
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2309
				interface_vip_bring_down($vip);
2310
			else if ($inet == "all")
2311
				interface_vip_bring_down($vip);
2312
		}
2313
	}
2314
}
2315

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

    
2364
function interface_ipalias_configure(&$vip) {
2365
	global $config;
2366

    
2367
	if ($vip['mode'] != 'ipalias') {
2368
		return;
2369
	}
2370

    
2371
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2372
	if ($realif != "lo0") {
2373
		$if = convert_real_interface_to_friendly_interface_name($realif);
2374
		if (!isset($config['interfaces'][$if])) {
2375
			return;
2376
		}
2377

    
2378
		if (!isset($config['interfaces'][$if]['enable'])) {
2379
			return;
2380
		}
2381
	}
2382

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

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

    
2405
	if ($vip['mode'] != "carp") {
2406
		return;
2407
	}
2408

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

    
2416
	$vip_password = $vip['password'];
2417
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2418
	if ($vip['password'] != "") {
2419
		$password = " pass {$vip_password}";
2420
	}
2421

    
2422
	$advbase = "";
2423
	if (!empty($vip['advbase'])) {
2424
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2425
	}
2426

    
2427
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2428
	if ($carp_maintenancemode) {
2429
		$advskew = "advskew 254";
2430
	} else {
2431
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2432
	}
2433

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

    
2436
	if (is_ipaddrv4($vip['subnet'])) {
2437
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2438
	} else if (is_ipaddrv6($vip['subnet'])) {
2439
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2440
	}
2441

    
2442
	return $realif;
2443
}
2444

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

    
2487
	if ($needs_clone == true) {
2488
		/* remove previous instance if it exists */
2489
		if (does_interface_exist($realif)) {
2490
			pfSense_interface_destroy($realif);
2491
		}
2492

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

    
2509
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2510
	global $config, $g;
2511

    
2512
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2513
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2514
				 'regdomain', 'regcountry', 'reglocation');
2515

    
2516
	if (!is_interface_wireless($ifcfg['if'])) {
2517
		return;
2518
	}
2519

    
2520
	$baseif = interface_get_wireless_base($ifcfg['if']);
2521

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

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

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

    
2584
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2585
	global $config, $g;
2586

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

    
2594
	// Remove script file
2595
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2596

    
2597
	// Clone wireless nic if needed.
2598
	interface_wireless_clone($if, $wl);
2599

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

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

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

    
2609
	/* set values for /path/program */
2610
	$hostapd = "/usr/sbin/hostapd";
2611
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2612
	$ifconfig = "/sbin/ifconfig";
2613
	$sysctl = "/sbin/sysctl";
2614
	$killall = "/usr/bin/killall";
2615

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

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

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

    
2635
	/* Set ssid */
2636
	if ($wlcfg['ssid']) {
2637
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2638
	}
2639

    
2640
	/* Set 802.11g protection mode */
2641
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2642

    
2643
	/* set wireless channel value */
2644
	if (isset($wlcfg['channel'])) {
2645
		if ($wlcfg['channel'] == "0") {
2646
			$wlcmd[] = "channel any";
2647
		} else {
2648
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2649
		}
2650
	}
2651

    
2652
	/* Set antenna diversity value */
2653
	if (isset($wlcfg['diversity'])) {
2654
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2655
	}
2656

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

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

    
2667
	/* set Distance value */
2668
	if ($wlcfg['distance']) {
2669
		$distance = escapeshellarg($wlcfg['distance']);
2670
	}
2671

    
2672
	/* Set wireless hostap mode */
2673
	if ($wlcfg['mode'] == "hostap") {
2674
		$wlcmd[] = "mediaopt hostap";
2675
	} else {
2676
		$wlcmd[] = "-mediaopt hostap";
2677
	}
2678

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

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

    
2688
	/* handle hide ssid option */
2689
	if (isset($wlcfg['hidessid']['enable'])) {
2690
		$wlcmd[] = "hidessid";
2691
	} else {
2692
		$wlcmd[] = "-hidessid";
2693
	}
2694

    
2695
	/* handle pureg (802.11g) only option */
2696
	if (isset($wlcfg['pureg']['enable'])) {
2697
		$wlcmd[] = "mode 11g pureg";
2698
	} else {
2699
		$wlcmd[] = "-pureg";
2700
	}
2701

    
2702
	/* handle puren (802.11n) only option */
2703
	if (isset($wlcfg['puren']['enable'])) {
2704
		$wlcmd[] = "puren";
2705
	} else {
2706
		$wlcmd[] = "-puren";
2707
	}
2708

    
2709
	/* enable apbridge option */
2710
	if (isset($wlcfg['apbridge']['enable'])) {
2711
		$wlcmd[] = "apbridge";
2712
	} else {
2713
		$wlcmd[] = "-apbridge";
2714
	}
2715

    
2716
	/* handle turbo option */
2717
	if (isset($wlcfg['turbo']['enable'])) {
2718
		$wlcmd[] = "mediaopt turbo";
2719
	} else {
2720
		$wlcmd[] = "-mediaopt turbo";
2721
	}
2722

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

    
2730
	/* handle wme option */
2731
	if (isset($wlcfg['wme']['enable'])) {
2732
		$wlcmd[] = "wme";
2733
	} else {
2734
		$wlcmd[] = "-wme";
2735
	}
2736

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

    
2744
	kill_hostapd($if);
2745
	mwexec(kill_wpasupplicant("{$if}"));
2746

    
2747
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2748
	conf_mount_rw();
2749

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

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

    
2803
EOD;
2804

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

    
2811
EOD;
2812
				}
2813
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2814
					$wpa .= "ieee8021x=1\n";
2815

    
2816
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2817
						$auth_server_port = "1812";
2818
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2819
							$auth_server_port = intval($wlcfg['auth_server_port']);
2820
						}
2821
						$wpa .= <<<EOD
2822

    
2823
auth_server_addr={$wlcfg['auth_server_addr']}
2824
auth_server_port={$auth_server_port}
2825
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2826

    
2827
EOD;
2828
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2829
							$auth_server_port2 = "1812";
2830
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2831
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2832
							}
2833

    
2834
							$wpa .= <<<EOD
2835
auth_server_addr={$wlcfg['auth_server_addr2']}
2836
auth_server_port={$auth_server_port2}
2837
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2838

    
2839
EOD;
2840
						}
2841
					}
2842
				}
2843

    
2844
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2845
				unset($wpa);
2846
			}
2847
			break;
2848
	}
2849

    
2850
	/*
2851
	 *    all variables are set, lets start up everything
2852
	 */
2853

    
2854
	$baseif = interface_get_wireless_base($if);
2855
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2856
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2857

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

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

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

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

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

    
2903
	fclose($fd_set);
2904
	conf_mount_ro();
2905

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

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

    
2927
	if ($reg_changing) {
2928
		/* set regulatory domain */
2929
		if ($wlcfg['regdomain']) {
2930
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2931
		}
2932

    
2933
		/* set country */
2934
		if ($wlcfg['regcountry']) {
2935
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2936
		}
2937

    
2938
		/* set location */
2939
		if ($wlcfg['reglocation']) {
2940
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2941
		}
2942

    
2943
		$wlregcmd_args = implode(" ", $wlregcmd);
2944

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

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

    
2968
		/* apply the regulatory settings */
2969
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2970
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2971

    
2972
		/* bring the clones back up that were previously up */
2973
		foreach ($clones_up as $clone_if) {
2974
			interfaces_bring_up($clone_if);
2975

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

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

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

    
3000
	/* configure wireless */
3001
	$wlcmd_args = implode(" ", $wlcmd);
3002
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3003
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3004
	fclose($wlan_setup_log);
3005

    
3006
	unset($wlcmd_args, $wlcmd);
3007

    
3008

    
3009
	sleep(1);
3010
	/* execute hostapd and wpa_supplicant if required in shell */
3011
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3012

    
3013
	return 0;
3014

    
3015
}
3016

    
3017
function kill_hostapd($interface) {
3018
	global $g;
3019

    
3020
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3021
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3022
	}
3023
}
3024

    
3025
function kill_wpasupplicant($interface) {
3026
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3027
}
3028

    
3029
function find_dhclient_process($interface) {
3030
	if ($interface) {
3031
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3032
	} else {
3033
		$pid = 0;
3034
	}
3035

    
3036
	return intval($pid);
3037
}
3038

    
3039
function kill_dhclient_process($interface) {
3040
	if (empty($interface) || !does_interface_exist($interface)) {
3041
		return;
3042
	}
3043

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

    
3055
function find_dhcp6c_process($interface) {
3056
	global $g;
3057

    
3058
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3059
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3060
	} else {
3061
		return(false);
3062
	}
3063

    
3064
	return intval($pid);
3065
}
3066

    
3067
function interface_virtual_create($interface) {
3068
	global $config;
3069

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

    
3109
function interface_vlan_mtu_configured($iface) {
3110
	global $config;
3111

    
3112
	$mtu = 0;
3113
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3114
		foreach ($config['vlans']['vlan'] as $vlan) {
3115

    
3116
			if ($vlan['vlanif'] != $iface)
3117
				continue;
3118

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

    
3130
	return $mtu;
3131
}
3132

    
3133
function interface_mtu_wanted_for_pppoe($realif) {
3134
	global $config;
3135

    
3136
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3137
		return 0;
3138

    
3139
	$mtu = 0;
3140
	foreach ($config['ppps']['ppp'] as $ppp) {
3141
		if ($ppp['type'] != "pppoe") {
3142
			continue;
3143
		}
3144

    
3145
		$mtus = array();
3146
		if (!empty($ppp['mtu'])) {
3147
			$mtus = explode(',', $ppp['mtu']);
3148
		}
3149
		$ports = explode(',', $ppp['ports']);
3150

    
3151
		foreach ($ports as $pid => $port) {
3152
			$parentifa = get_parent_interface($port);
3153
			$parentif = $parentifa[0];
3154
			if ($parentif != $realif)
3155
				continue;
3156

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

    
3173
	return $mtu;
3174
}
3175

    
3176
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3177
	global $config, $g;
3178
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3179
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3180

    
3181
	$wancfg = $config['interfaces'][$interface];
3182

    
3183
	if (!isset($wancfg['enable'])) {
3184
		return;
3185
	}
3186

    
3187
	$realif = get_real_interface($interface);
3188
	$realhwif_array = get_parent_interface($interface);
3189
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3190
	$realhwif = $realhwif_array[0];
3191

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

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

    
3219
	$interface_to_check = $realif;
3220
	if (interface_isppp_type($interface)) {
3221
		$interface_to_check = $realhwif;
3222
	}
3223

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

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

    
3235
	/* wireless configuration? */
3236
	if (is_array($wancfg['wireless'])) {
3237
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3238
	}
3239

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

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

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

    
3278
	/* Apply hw offloading policies as configured */
3279
	enable_hardware_offloading($interface);
3280

    
3281
	/* invalidate interface/ip/sn cache */
3282
	get_interface_arr(true);
3283
	unset($interface_ip_arr_cache[$realif]);
3284
	unset($interface_sn_arr_cache[$realif]);
3285
	unset($interface_ipv6_arr_cache[$realif]);
3286
	unset($interface_snv6_arr_cache[$realif]);
3287

    
3288
	$tunnelif = substr($realif, 0, 3);
3289

    
3290
	$mtuif = $realif;
3291
	$mtuhwif = $realhwif;
3292

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

    
3300
	$wantedmtu = 0;
3301
	if (is_array($config['interfaces'])) {
3302
		foreach ($config['interfaces'] as $tmpinterface) {
3303
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3304
				$wantedmtu = $tmpinterface['mtu'];
3305
				break;
3306
			}
3307
		}
3308
	}
3309

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

    
3318
	/* Set the MTU to 1500 if no explicit MTU configured. */
3319
	if ($wantedmtu == 0) {
3320
		$wantedmtu = 1500; /* Default */
3321
	}
3322

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

    
3332
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3333

    
3334
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3335
			$configuredmtu = $parentmtu;
3336
		if ($configuredmtu != 0)
3337
			$mtu = $configuredmtu;
3338
		else
3339
			$mtu = $wantedmtu;
3340

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

    
3366
	if (does_interface_exist($wancfg['if'])) {
3367
		interfaces_bring_up($wancfg['if']);
3368
	}
3369

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

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

    
3421
	interface_netgraph_needed($interface);
3422

    
3423
	if (!platform_booting()) {
3424
		link_interface_to_vips($interface, "update");
3425

    
3426
		if ($tunnelif != 'gre') {
3427
			unset($gre);
3428
			$gre = link_interface_to_gre($interface);
3429
			if (!empty($gre)) {
3430
				array_walk($gre, 'interface_gre_configure');
3431
			}
3432
		}
3433

    
3434
		if ($tunnelif != 'gif') {
3435
			unset($gif);
3436
			$gif = link_interface_to_gif ($interface);
3437
			if (!empty($gif)) {
3438
				array_walk($gif, 'interface_gif_configure');
3439
			}
3440
		}
3441

    
3442
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3443
			unset($bridgetmp);
3444
			$bridgetmp = link_interface_to_bridge($interface);
3445
			if (!empty($bridgetmp)) {
3446
				interface_bridge_add_member($bridgetmp, $realif);
3447
			}
3448
		}
3449

    
3450
		$grouptmp = link_interface_to_group($interface);
3451
		if (!empty($grouptmp)) {
3452
			array_walk($grouptmp, 'interface_group_add_member');
3453
		}
3454

    
3455
		if ($interface == "lan") {
3456
			/* make new hosts file */
3457
			system_hosts_generate();
3458
		}
3459

    
3460
		if ($reloadall == true) {
3461

    
3462
			/* reconfigure static routes (kernel may have deleted them) */
3463
			system_routing_configure($interface);
3464

    
3465
			/* reload ipsec tunnels */
3466
			send_event("service reload ipsecdns");
3467

    
3468
			if (isset($config['dnsmasq']['enable'])) {
3469
				services_dnsmasq_configure();
3470
			}
3471

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

    
3476
			/* update dyndns */
3477
			send_event("service reload dyndns {$interface}");
3478

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

    
3487
	interfaces_staticarp_configure($interface);
3488
	return 0;
3489
}
3490

    
3491
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3492
	global $config, $g;
3493

    
3494
	if (!is_array($wancfg)) {
3495
		return;
3496
	}
3497

    
3498
	if (!isset($wancfg['enable'])) {
3499
		return;
3500
	}
3501

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

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

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

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

    
3553
	if ($linkupevent == false && !platform_booting()) {
3554
		if (!function_exists('services_dhcpd_configure')) {
3555
			require_once("services.inc");
3556
		}
3557

    
3558
		if (isset($config['unbound']['enable'])) {
3559
			services_unbound_configure();
3560
		}
3561

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

    
3566
		services_dhcpd_configure("inet6");
3567
	}
3568

    
3569
	return 0;
3570
}
3571

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

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

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

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

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

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

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

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

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

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

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

    
3633
	return 0;
3634
}
3635

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

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

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

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

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

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

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

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

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

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

    
3693
	return 0;
3694
}
3695

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

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

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

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

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

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

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

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

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

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

    
3748

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

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

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

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

    
3783
	return 0;
3784
}
3785

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3889
	return 0;
3890
}
3891

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4027
	return 0;
4028
}
4029

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4151
	$key_info_statement = "";
4152
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4153
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4154
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4155
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4156
		$key_info_statement .= "keyinfo";
4157
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4158
		$key_info_statement .= " {\n";
4159
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4160
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4161
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4162
		if (preg_match("/((([0-9]{4}-)?[0-9]{2}[0-9]{2} )?[0-9]{2}:[0-9]{2})||(foreever)/", $wancfg['adv_dhcp6_key_info_statement_expire'])) {
4163
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4164
		}
4165
		$key_info_statement .= "};\n";
4166
	}
4167

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

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

    
4176
	return $dhcp6cconf;
4177
}
4178

    
4179

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

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

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

    
4192

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

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

    
4197
	return $dhcp6cconf;
4198
}
4199

    
4200

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

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

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

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

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

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

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

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

    
4249
}
4250

    
4251
EOD;
4252

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

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

    
4267
EOD;
4268
	}
4269

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

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

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

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

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

    
4291
	return 0;
4292
}
4293

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

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

    
4301
	/* DHCP Protocol Timings */
4302
	$protocol_timings = array ('adv_dhcp_pt_timeout' => "timeout", 'adv_dhcp_pt_retry' => "retry", 'adv_dhcp_pt_select_timeout' => "select-timeout", 'adv_dhcp_pt_reboot' => "reboot", 'adv_dhcp_pt_backoff_cutoff' => "backoff-cutoff", 'adv_dhcp_pt_initial_interval' => "initial-interval");
4303
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4304
		$pt_variable = "{$Protocol_Timing}";
4305
		${$pt_variable} = "";
4306
		if ($wancfg[$Protocol_Timing] != "") {
4307
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4308
		}
4309
	}
4310

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

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

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

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

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

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

    
4362
	return $dhclientconf;
4363
}
4364

    
4365
function DHCP_Config_Option_Split($option_string) {
4366
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4367
	return $matches ? $matches[0] : [];
4368
}
4369

    
4370
function DHCP_Config_File_Override($wancfg, $wanif) {
4371

    
4372
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4373

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

    
4382

    
4383
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4384

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

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

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

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

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

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

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

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

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

    
4435
	return $dhclientconf;
4436
}
4437

    
4438
function interfaces_group_setup() {
4439
	global $config;
4440

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

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

    
4449
	return;
4450
}
4451

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

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

    
4466
	return;
4467
}
4468

    
4469
function is_interface_group($if) {
4470
	global $config;
4471

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

    
4480
	return false;
4481
}
4482

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

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

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

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

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

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

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

    
4520
		if (get_real_interface($if) == $interface) {
4521
			return $if;
4522
		}
4523

    
4524
		if ($checkparent == false) {
4525
			continue;
4526
		}
4527

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

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

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

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

    
4600
	return $ifdesc;
4601
}
4602

    
4603
function convert_real_interface_to_friendly_descr($interface) {
4604

    
4605
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4606

    
4607
	if (!empty($ifdesc)) {
4608
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4609
	}
4610

    
4611
	return $interface;
4612
}
4613

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

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

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

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

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

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

    
4695
	return $parents;
4696
}
4697

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

    
4706
	$realif = get_parent_interface($interface);
4707

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

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

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

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

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

    
4746
	$wanif = NULL;
4747

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

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

    
4794
			$cfg = &$config['interfaces'][$interface];
4795

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

    
4852
	return $wanif;
4853
}
4854

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

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

    
4866
	if (empty($family)) {
4867
		return false;
4868
	}
4869

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

    
4878
	return false;
4879
}
4880

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

    
4890
	$isv6ip = is_ipaddrv6($ip);
4891

    
4892
	/* if list */
4893
	$ifdescrs = get_configured_interface_list();
4894

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

    
4913
	return false;
4914
}
4915

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

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

    
4930
	$isv6ip = is_ipaddrv6($ip);
4931

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

    
4952
function link_interface_to_track6($int, $action = "") {
4953
	global $config;
4954

    
4955
	if (empty($int)) {
4956
		return;
4957
	}
4958

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

    
4977
function interface_find_child_cfgmtu($realiface) {
4978
	global $config;
4979

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

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

    
5039
	return $mtu;
5040
}
5041

    
5042
function link_interface_to_vlans($int, $action = "") {
5043
	global $config;
5044

    
5045
	if (empty($int)) {
5046
		return;
5047
	}
5048

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

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

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

    
5096
	return NULL;
5097
}
5098

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

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

    
5119
function link_interface_to_group($int) {
5120
	global $config;
5121

    
5122
	$result = array();
5123

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

    
5132
	return $result;
5133
}
5134

    
5135
function link_interface_to_gre($interface) {
5136
	global $config;
5137

    
5138
	$result = array();
5139

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

    
5148
	return $result;
5149
}
5150

    
5151
function link_interface_to_gif($interface) {
5152
	global $config;
5153

    
5154
	$result = array();
5155

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

    
5164
	return $result;
5165
}
5166

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

    
5174
	$interface = str_replace("\n", "", $interface);
5175

    
5176
	if (!does_interface_exist($interface)) {
5177
		return;
5178
	}
5179

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

    
5187
	return $interface_ip_arr_cache[$interface];
5188
}
5189

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

    
5198
	$interface = trim($interface);
5199
	$interface = get_real_interface($interface);
5200

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

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

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

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

    
5222
	$interface = str_replace("\n", "", $interface);
5223

    
5224
	if (!does_interface_exist($interface)) {
5225
		return;
5226
	}
5227

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

    
5244
function find_interface_subnet($interface, $flush = false) {
5245
	global $interface_sn_arr_cache;
5246
	global $interface_ip_arr_cache;
5247

    
5248
	$interface = str_replace("\n", "", $interface);
5249
	if (does_interface_exist($interface) == false) {
5250
		return;
5251
	}
5252

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

    
5259
	return $interface_sn_arr_cache[$interface];
5260
}
5261

    
5262
function find_interface_subnetv6($interface, $flush = false) {
5263
	global $interface_snv6_arr_cache;
5264
	global $interface_ipv6_arr_cache;
5265

    
5266
	$interface = str_replace("\n", "", $interface);
5267
	if (does_interface_exist($interface) == false) {
5268
		return;
5269
	}
5270

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

    
5277
	return $interface_snv6_arr_cache[$interface];
5278
}
5279

    
5280
function ip_in_interface_alias_subnet($interface, $ipalias) {
5281
	global $config;
5282

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

    
5302
	return false;
5303
}
5304

    
5305
function get_possible_listen_ips($include_ipv6_link_local=false) {
5306

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

    
5328
	$interfaces['lo0'] = 'Localhost';
5329

    
5330
	return $interfaces;
5331
}
5332

    
5333
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5334
	global $config;
5335

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

    
5350
function get_interface_ip($interface = "wan") {
5351

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

    
5359
	$realif = get_failover_interface($interface, 'inet');
5360
	if (!$realif) {
5361
		return null;
5362
	}
5363

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

    
5371
	if (is_array($config['interfaces'][$interface]) &&
5372
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5373
		return ($config['interfaces'][$interface]['ipaddr']);
5374
	}
5375

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

    
5389
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5390
	global $config;
5391

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

    
5398
	$realif = get_failover_interface($interface, 'inet6');
5399
	if (!$realif) {
5400
		return null;
5401
	}
5402

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

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

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

    
5448
function get_interface_linklocal($interface = "wan") {
5449

    
5450
	$realif = get_failover_interface($interface, 'inet6');
5451
	if (!$realif) {
5452
		return null;
5453
	}
5454

    
5455
	if (substr($interface, 0, 4) == '_vip') {
5456
		$realif = get_real_interface($interface);
5457
	} else if (substr($interface, 0, 5) == '_lloc') {
5458
		$realif = get_real_interface(substr($interface, 5));
5459
	}
5460

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

    
5469
function get_interface_subnet($interface = "wan") {
5470

    
5471
	if (substr($interface, 0, 4) == '_vip') {
5472
		return (get_configured_vip_subnetv4($interface));
5473
	}
5474

    
5475
	$realif = get_real_interface($interface);
5476
	if (!$realif) {
5477
		return (NULL);
5478
	}
5479

    
5480
	$cursn = find_interface_subnet($realif);
5481
	if (!empty($cursn)) {
5482
		return ($cursn);
5483
	}
5484

    
5485
	return (NULL);
5486
}
5487

    
5488
function get_interface_subnetv6($interface = "wan") {
5489

    
5490
	if (substr($interface, 0, 4) == '_vip') {
5491
		return (get_configured_vip_subnetv6($interface));
5492
	} else if (substr($interface, 0, 5) == '_lloc') {
5493
		$interface = substr($interface, 5);
5494
	}
5495

    
5496
	$realif = get_real_interface($interface, 'inet6');
5497
	if (!$realif) {
5498
		return (NULL);
5499
	}
5500

    
5501
	$cursn = find_interface_subnetv6($realif);
5502
	if (!empty($cursn)) {
5503
		return ($cursn);
5504
	}
5505

    
5506
	return (NULL);
5507
}
5508

    
5509
/* return outside interfaces with a gateway */
5510
function get_interfaces_with_gateway() {
5511
	global $config;
5512

    
5513
	$ints = array();
5514

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

    
5536
/* return true if interface has a gateway */
5537
function interface_has_gateway($friendly) {
5538
	global $config;
5539

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

    
5567
	return false;
5568
}
5569

    
5570
/* return true if interface has a gateway */
5571
function interface_has_gatewayv6($friendly) {
5572
	global $config;
5573

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

    
5600
	return false;
5601
}
5602

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

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

    
5626
	$int_family = remove_ifindex($int);
5627

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

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

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

    
5664
function get_wireless_modes($interface) {
5665
	/* return wireless modes and channels */
5666
	$wireless_modes = array();
5667

    
5668
	$cloned_interface = get_real_interface($interface);
5669

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

    
5675
		$interface_channels = "";
5676
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5677
		$interface_channel_count = count($interface_channels);
5678

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

    
5712
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5713
function get_wireless_channel_info($interface) {
5714
	$wireless_channels = array();
5715

    
5716
	$cloned_interface = get_real_interface($interface);
5717

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

    
5723
		$interface_channels = "";
5724
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5725

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

    
5736
function set_interface_mtu($interface, $mtu) {
5737

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

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

    
5765
function get_interface_mac($interface) {
5766

    
5767
	$macinfo = pfSense_get_interface_addresses($interface);
5768
	return $macinfo["macaddr"];
5769
}
5770

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

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

    
5799
	if (isset($capable['caps']['vlanmtu'])) {
5800
		return true;
5801
	}
5802

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

    
5808
	return false;
5809
}
5810

    
5811
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5812
	global $g;
5813

    
5814
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5815

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

    
5822
EOD;
5823

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

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

    
5849
	/* Never reached */
5850
	return 1500;
5851
}
5852

    
5853
function get_vip_descr($ipaddress) {
5854
	global $config;
5855

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

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

    
5871
	$ifcfg = $config['interfaces'][$if];
5872

    
5873
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5874
		return 0;
5875
	}
5876

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

    
5898
	return 0;
5899
}
5900

    
5901
function get_failover_interface($interface, $family = "all") {
5902
	global $config;
5903

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

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

    
5924
function remove_ifindex($ifname) {
5925
	return preg_replace("/[0-9]+$/", "", $ifname);
5926
}
5927

    
5928
?>
    (1-1/1)