Project

General

Profile

Download (176 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * interfaces.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
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
 * Validate comma-separated list of IPv4 addresses
74
 */
75
function validate_ipv4_list($value) {
76
	$value = trim($value);
77

    
78
	if (empty($value)) {
79
		return false;
80
	}
81

    
82
	$list = explode(',', $value);
83

    
84
	foreach ($list as $ip) {
85
		if (!is_ipaddrv4($ip)) {
86
			return false;
87
		}
88
	}
89

    
90
	return true;
91
}
92

    
93
/*
94
 * Return the interface array
95
 */
96
function get_interface_arr($flush = false) {
97
	global $interface_arr_cache;
98

    
99
	/* If the cache doesn't exist, build it */
100
	if (!isset($interface_arr_cache) or $flush) {
101
		$interface_arr_cache = pfSense_interface_listget();
102
	}
103

    
104
	return $interface_arr_cache;
105
}
106

    
107
/*
108
 * does_interface_exist($interface): return true or false if a interface is
109
 * detected.
110
 */
111
function does_interface_exist($interface, $flush = true) {
112
	global $config;
113

    
114
	if (!$interface) {
115
		return false;
116
	}
117

    
118
	$ints = get_interface_arr($flush);
119
	if (in_array($interface, $ints)) {
120
		return true;
121
	} else {
122
		return false;
123
	}
124
}
125

    
126
/*
127
 * does_vip_exist($vip): return true or false if a vip is
128
 * configured.
129
 */
130
function does_vip_exist($vip) {
131
	global $config;
132

    
133
	if (!$vip) {
134
		return false;
135
	}
136

    
137

    
138
	switch ($vip['mode']) {
139
		case "carp":
140
		case "ipalias":
141
			/* XXX: Make proper checks? */
142
			$realif = get_real_interface($vip['interface']);
143
			if (!does_interface_exist($realif)) {
144
				return false;
145
			}
146
			break;
147
		case "proxyarp":
148
			/* XXX: Implement this */
149
		default:
150
			return false;
151
	}
152

    
153
	$ifacedata = pfSense_getall_interface_addresses($realif);
154
	foreach ($ifacedata as $vipips) {
155
		if ($vipips == "{$vip['subnet']}/{$vip['subnet_bits']}") {
156
			return true;
157
		}
158
	}
159

    
160
	return false;
161
}
162

    
163
function interface_netgraph_needed($interface = "wan") {
164
	global $config;
165

    
166
	$found = false;
167
	if (!empty($config['l2tp']) &&
168
	    $config['l2tp']['mode'] == "server") {
169
		$found = true;
170
	}
171
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
172
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
173
			if ($pppoe['mode'] != "server") {
174
				continue;
175
			}
176
			if ($pppoe['interface'] == $interface) {
177
				$found = true;
178
				break;
179
			}
180
		}
181
	}
182
	if ($found == false) {
183
		$found = interface_isppp_type($interface);
184
	}
185

    
186
	if ($found == false) {
187
		$realif = get_real_interface($interface);
188
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
189
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
190
				$ports = explode(',', $ppp['ports']);
191
				foreach ($ports as $pid => $port) {
192
					$port = get_real_interface($port);
193
					if ($realif == $port) {
194
						$found = true;
195
						break;
196
					}
197
					/* Find the parent interfaces of the vlans in the MLPPP configs
198
					* there should be only one element in the array here
199
					* -- this could be better . . . */
200
					$parent_if = get_parent_interface($port);
201
					if ($realif == $parent_if[0]) {
202
						$found = true;
203
						break;
204
					}
205
				}
206
			}
207
		}
208
	}
209

    
210
	if ($found == false) {
211
		$realif = get_real_interface($interface);
212
		pfSense_ngctl_detach("{$realif}:", $realif);
213
	}
214
	/* NOTE: We make sure for this on interface_ppps_configure()
215
	 *	no need to do it here again.
216
	 *	else
217
	 *		pfSense_ngctl_attach(".", $realif);
218
	 */
219
}
220

    
221
function interfaces_loopback_configure() {
222
	global $g;
223

    
224
	if (platform_booting()) {
225
		echo gettext("Configuring loopback interface...");
226
	}
227
	pfSense_interface_setaddress("lo0", "127.0.0.1");
228
	interfaces_bring_up("lo0");
229
	if (platform_booting()) {
230
		echo gettext("done.") . "\n";
231
	}
232
	return 0;
233
}
234

    
235
function interfaces_vlan_configure($realif = "") {
236
	global $config, $g;
237
	if (platform_booting()) {
238
		echo gettext("Configuring VLAN interfaces...");
239
	}
240
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
241
		foreach ($config['vlans']['vlan'] as $vlan) {
242
			if (empty($vlan['vlanif'])) {
243
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
244
			}
245
			if (!empty($realif) && $realif != $vlan['vlanif']) {
246
				continue;
247
			}
248

    
249
			/* XXX: Maybe we should report any errors?! */
250
			interface_vlan_configure($vlan);
251
		}
252
	}
253
	if (platform_booting()) {
254
		echo gettext("done.") . "\n";
255
	}
256
}
257

    
258
function interface_vlan_configure(&$vlan) {
259
	global $config, $g;
260

    
261
	if (!is_array($vlan)) {
262
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
263
		return;
264
	}
265
	$if = $vlan['if'];
266
	if (empty($if)) {
267
		log_error(gettext("interface_vlan_configure called with if undefined."));
268
		return;
269
	}
270

    
271
	$vlanif = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
272
	$tag = $vlan['tag'];
273
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
274

    
275
	/* make sure the parent interface is up */
276
	interfaces_bring_up($if);
277
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
278
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
279

    
280
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
281
		pfSense_interface_destroy($vlanif);
282
	}
283

    
284
	$tmpvlanif = pfSense_interface_create("vlan");
285
	pfSense_interface_rename($tmpvlanif, $vlanif);
286
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
287

    
288
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
289

    
290
	interfaces_bring_up($vlanif);
291

    
292
	/* invalidate interface cache */
293
	get_interface_arr(true);
294

    
295
	/* configure interface if assigned */
296
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
297
	if ($assignedif) {
298
		if (isset($config['interfaces'][$assignedif]['enable'])) {
299
			interface_configure($assignedif, true);
300
		}
301
	}
302

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

    
306
	return $vlanif;
307
}
308

    
309
function interface_qinq_configure(&$vlan, $fd = NULL) {
310
	global $config, $g;
311

    
312
	if (!is_array($vlan)) {
313
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
314
		return;
315
	}
316

    
317
	$qinqif = $vlan['if'];
318
	$tag = $vlan['tag'];
319
	if (empty($qinqif)) {
320
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
321
		return;
322
	}
323

    
324
	if (!does_interface_exist($qinqif)) {
325
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
326
		return;
327
	}
328

    
329
	$vlanif = interface_vlan_configure($vlan);
330

    
331
	if ($fd == NULL) {
332
		$exec = true;
333
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
334
	} else {
335
		$exec = false;
336
	}
337
	/* make sure the parent is converted to ng_vlan(4) and is up */
338
	interfaces_bring_up($qinqif);
339

    
340
	pfSense_ngctl_attach(".", $qinqif);
341
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
342
		fwrite($fd, "shutdown {$vlanif}qinq:\n");
343
		exec("/usr/sbin/ngctl msg {$vlanif}qinq: gettable", $result);
344
		if (empty($result)) {
345
			fwrite($fd, "mkpeer {$vlanif}: vlan lower downstream\n");
346
			fwrite($fd, "name {$vlanif}:lower {$vlanif}qinq\n");
347
			fwrite($fd, "connect {$vlanif}: {$vlanif}qinq: upper nomatch\n");
348
		}
349
	} else {
350
		fwrite($fd, "mkpeer {$vlanif}: vlan lower downstream\n");
351
		fwrite($fd, "name {$vlanif}:lower {$vlanif}qinq\n");
352
		fwrite($fd, "connect {$vlanif}: {$vlanif}qinq: upper nomatch\n");
353
	}
354

    
355
	/* invalidate interface cache */
356
	get_interface_arr(true);
357

    
358
	if (!stristr($qinqif, "_vlan")) {
359
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
360
	}
361

    
362
	$macaddr = get_interface_mac($qinqif);
363
	if (!empty($vlan['members'])) {
364
		$members = explode(" ", $vlan['members']);
365
		foreach ($members as $qtag) {
366
			$qinq = array();
367
			$qinq['tag'] = $qtag;
368
			$qinq['if'] = $vlanif;
369
			interface_qinq2_configure($qinq, $fd, $macaddr);
370
		}
371
	}
372
	if ($exec == true) {
373
		fclose($fd);
374
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
375
	}
376

    
377
	interfaces_bring_up($qinqif);
378
	if (!empty($vlan['members'])) {
379
		$members = explode(" ", $vlan['members']);
380
		foreach ($members as $qif) {
381
			interfaces_bring_up("{$vlanif}_{$qif}");
382
		}
383
	}
384

    
385
	return $vlanif;
386
}
387

    
388
function interfaces_qinq_configure() {
389
	global $config, $g;
390
	if (platform_booting()) {
391
		echo gettext("Configuring QinQ interfaces...");
392
	}
393
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
394
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
395
			/* XXX: Maybe we should report any errors?! */
396
			interface_qinq_configure($qinq);
397
		}
398
	}
399
	if (platform_booting()) {
400
		echo gettext("done.") . "\n";
401
	}
402
}
403

    
404
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
405
	global $config, $g;
406

    
407
	if (!is_array($qinq)) {
408
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
409
		return;
410
	}
411

    
412
	$if = $qinq['if'];
413
	$tag = $qinq['tag'];
414
	$vlanif = "{$if}_{$tag}";
415
	if (empty($if)) {
416
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
417
		return;
418
	}
419

    
420
	fwrite($fd, "shutdown {$if}h{$tag}:\n");
421
	fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
422
	fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
423
	fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
424
	fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
425
	fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
426

    
427
	/* invalidate interface cache */
428
	get_interface_arr(true);
429

    
430
	return $vlanif;
431
}
432

    
433
function interfaces_create_wireless_clones() {
434
	global $config, $g;
435

    
436
	if (platform_booting()) {
437
		echo gettext("Creating wireless clone interfaces...");
438
	}
439

    
440
	$iflist = get_configured_interface_list();
441

    
442
	foreach ($iflist as $if) {
443
		$realif = $config['interfaces'][$if]['if'];
444
		if (is_interface_wireless($realif)) {
445
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
446
		}
447
	}
448

    
449
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
450
		foreach ($config['wireless']['clone'] as $clone) {
451
			if (empty($clone['cloneif'])) {
452
				continue;
453
			}
454
			if (does_interface_exist($clone['cloneif'])) {
455
				continue;
456
			}
457
			/* XXX: Maybe we should report any errors?! */
458
			interface_wireless_clone($clone['cloneif'], $clone);
459
		}
460
	}
461
	if (platform_booting()) {
462
		echo gettext("done.") . "\n";
463
	}
464

    
465
}
466

    
467
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
468
	global $config;
469

    
470
	$i = 0;
471
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
472
		foreach ($config['bridges']['bridged'] as $bridge) {
473
			if (empty($bridge['bridgeif'])) {
474
				$bridge['bridgeif'] = "bridge{$i}";
475
			}
476
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
477
				continue;
478
			}
479

    
480
			if ($checkmember == 1) {
481
				/* XXX: It should not be possible no? */
482
				if (strstr($bridge['if'], '_vip')) {
483
					continue;
484
				}
485
				$members = explode(',', $bridge['members']);
486
				foreach ($members as $member) {
487
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6") {
488
						continue 2;
489
					}
490
				}
491
			}
492
			else if ($checkmember == 2) {
493
				$members = explode(',', $bridge['members']);
494
				foreach ($members as $member) {
495
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6") {
496
						continue 2;
497
					}
498
				}
499
			}
500
			/* XXX: Maybe we should report any errors?! */
501
			interface_bridge_configure($bridge, $checkmember);
502
			$i++;
503
		}
504
	}
505
}
506

    
507
function interface_bridge_configure(&$bridge, $checkmember = 0) {
508
	global $config, $g;
509

    
510
	if (!is_array($bridge)) {
511
		return;
512
	}
513

    
514
	if (empty($bridge['members'])) {
515
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
516
		return;
517
	}
518

    
519
	$members = explode(',', $bridge['members']);
520
	if (!count($members)) {
521
		return;
522
	}
523

    
524
	/* Calculate smaller mtu and enforce it */
525
	$smallermtu = 0;
526
	$foundgif = false;
527
	foreach ($members as $member) {
528
		$realif = get_real_interface($member);
529
		$mtu = get_interface_mtu($realif);
530
		if (substr($realif, 0, 3) == "gif") {
531
			$foundgif = true;
532
			if ($checkmember == 1) {
533
				return;
534
			}
535
			if ($mtu <= 1500) {
536
				continue;
537
			}
538
		}
539
		if ($smallermtu == 0 && !empty($mtu)) {
540
			$smallermtu = $mtu;
541
		} else if (!empty($mtu) && $mtu < $smallermtu) {
542
			$smallermtu = $mtu;
543
		}
544
	}
545
	if ($foundgif == false && $checkmember == 2) {
546
		return;
547
	}
548

    
549
	/* Just in case anything is not working well */
550
	if ($smallermtu == 0) {
551
		$smallermtu = 1500;
552
	}
553

    
554
	if (!empty($bridge['bridgeif'])) {
555
		pfSense_interface_destroy($bridge['bridgeif']);
556
		pfSense_interface_create($bridge['bridgeif']);
557
		$bridgeif = escapeshellarg($bridge['bridgeif']);
558
	} else {
559
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
560
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
561
		$bridgeif = pfSense_interface_create("bridge");
562
		$bridge['bridgeif'] = $bridgeif;
563
	}
564

    
565
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
566
	if ($bridgemtu > $smallermtu) {
567
		$smallermtu = $bridgemtu;
568
	}
569

    
570
	$checklist = get_configured_interface_list();
571

    
572
	/* Add interfaces to bridge */
573
	foreach ($members as $member) {
574
		if (empty($checklist[$member])) {
575
			continue;
576
		}
577
		$realif = get_real_interface($member);
578
		if (!$realif) {
579
			log_error(gettext("realif not defined in interfaces bridge - up"));
580
			continue;
581
		}
582
		/* make sure the parent interface is up */
583
		pfSense_interface_mtu($realif, $smallermtu);
584
		interfaces_bring_up($realif);
585
		enable_hardware_offloading($member);
586
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
587
	}
588

    
589
	if (isset($bridge['enablestp'])) {
590
		interface_bridge_configure_stp($bridge);
591
	}
592

    
593
	interface_bridge_configure_advanced($bridge);
594

    
595
	if ($bridge['bridgeif']) {
596
		interfaces_bring_up($bridge['bridgeif']);
597
	} else {
598
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
599
	}
600
}
601

    
602
function interface_bridge_configure_stp($bridge) {
603
	if (isset($bridge['enablestp'])) {
604
		$bridgeif = $bridge['bridgeif'];
605
		/* configure spanning tree proto */
606
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
607

    
608
		if (!empty($bridge['stp'])) {
609
			$stpifs = explode(',', $bridge['stp']);
610
			foreach ($stpifs as $stpif) {
611
				$realif = get_real_interface($stpif);
612
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
613
			}
614
		}
615
		if (!empty($bridge['maxage'])) {
616
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
617
		}
618
		if (!empty($bridge['fwdelay'])) {
619
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
620
		}
621
		if (!empty($bridge['hellotime'])) {
622
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
623
		}
624
		if (!empty($bridge['priority'])) {
625
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
626
		}
627
		if (!empty($bridge['holdcnt'])) {
628
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
629
		}
630
		if (!empty($bridge['ifpriority'])) {
631
			$pconfig = explode(",", $bridge['ifpriority']);
632
			$ifpriority = array();
633
			foreach ($pconfig as $cfg) {
634
				$embcfg = explode_assoc(":", $cfg);
635
				foreach ($embcfg as $key => $value) {
636
					$ifpriority[$key] = $value;
637
				}
638
			}
639
			foreach ($ifpriority as $key => $value) {
640
				$realif = get_real_interface($key);
641
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
642
			}
643
		}
644
		if (!empty($bridge['ifpathcost'])) {
645
			$pconfig = explode(",", $bridge['ifpathcost']);
646
			$ifpathcost = array();
647
			foreach ($pconfig as $cfg) {
648
				$embcfg = explode_assoc(":", $cfg);
649
				foreach ($embcfg as $key => $value) {
650
					$ifpathcost[$key] = $value;
651
				}
652
			}
653
			foreach ($ifpathcost as $key => $value) {
654
				$realif = get_real_interface($key);
655
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
656
			}
657
		}
658
	}
659
}
660

    
661
function interface_bridge_configure_advanced($bridge) {
662
	$bridgeif = $bridge['bridgeif'];
663

    
664
	if ($bridge['maxaddr'] <> "") {
665
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
666
	}
667
	if ($bridge['timeout'] <> "") {
668
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
669
	}
670
	if (!empty($bridge['span'])) {
671
		$spanifs = explode(",", $bridge['span']);
672
		foreach ($spanifs as $spanif) {
673
			$realif = get_real_interface($spanif);
674
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
675
		}
676
	}
677
	if (!empty($bridge['edge'])) {
678
		$edgeifs = explode(',', $bridge['edge']);
679
		foreach ($edgeifs as $edgeif) {
680
			$realif = get_real_interface($edgeif);
681
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
682
		}
683
	}
684
	if (!empty($bridge['autoedge'])) {
685
		$edgeifs = explode(',', $bridge['autoedge']);
686
		foreach ($edgeifs as $edgeif) {
687
			$realif = get_real_interface($edgeif);
688
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
689
		}
690
	}
691
	if (!empty($bridge['ptp'])) {
692
		$ptpifs = explode(',', $bridge['ptp']);
693
		foreach ($ptpifs as $ptpif) {
694
			$realif = get_real_interface($ptpif);
695
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
696
		}
697
	}
698
	if (!empty($bridge['autoptp'])) {
699
		$ptpifs = explode(',', $bridge['autoptp']);
700
		foreach ($ptpifs as $ptpif) {
701
			$realif = get_real_interface($ptpif);
702
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
703
		}
704
	}
705
	if (!empty($bridge['static'])) {
706
		$stickyifs = explode(',', $bridge['static']);
707
		foreach ($stickyifs as $stickyif) {
708
			$realif = get_real_interface($stickyif);
709
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
710
		}
711
	}
712
	if (!empty($bridge['private'])) {
713
		$privateifs = explode(',', $bridge['private']);
714
		foreach ($privateifs as $privateif) {
715
			$realif = get_real_interface($privateif);
716
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
717
		}
718
	}
719
}
720

    
721
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
722
	global $config;
723

    
724
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
725
		return;
726
	}
727

    
728
	if ($flagsapplied == false) {
729
		$mtu = get_interface_mtu($bridgeif);
730
		$mtum = get_interface_mtu($interface);
731
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
732
			pfSense_interface_mtu($interface, $mtu);
733
		}
734

    
735
		hardware_offloading_applyflags($interface);
736
		interfaces_bring_up($interface);
737
	}
738

    
739
	pfSense_bridge_add_member($bridgeif, $interface);
740
	if (is_array($config['bridges']['bridged'])) {
741
		foreach ($config['bridges']['bridged'] as $bridge) {
742
			if ($bridgeif == $bridge['bridgeif']) {
743
				interface_bridge_configure_stp($bridge);
744
				interface_bridge_configure_advanced($bridge);
745
			}
746
		}
747
	}
748
}
749

    
750
function interfaces_lagg_configure($realif = "") {
751
	global $config, $g;
752
	if (platform_booting()) {
753
		echo gettext("Configuring LAGG interfaces...");
754
	}
755
	$i = 0;
756
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
757
		foreach ($config['laggs']['lagg'] as $lagg) {
758
			if (empty($lagg['laggif'])) {
759
				$lagg['laggif'] = "lagg{$i}";
760
			}
761
			if (!empty($realif) && $realif != $lagg['laggif']) {
762
				continue;
763
			}
764
			/* XXX: Maybe we should report any errors?! */
765
			interface_lagg_configure($lagg);
766
			$i++;
767
		}
768
	}
769
	if (platform_booting()) {
770
		echo gettext("done.") . "\n";
771
	}
772
}
773

    
774
function interface_lagg_configure($lagg) {
775
	global $config, $g;
776

    
777
	if (!is_array($lagg)) {
778
		return -1;
779
	}
780

    
781
	$members = explode(',', $lagg['members']);
782
	if (!count($members)) {
783
		return -1;
784
	}
785

    
786
	if (platform_booting() || !(empty($lagg['laggif']))) {
787
		pfSense_interface_destroy($lagg['laggif']);
788
		pfSense_interface_create($lagg['laggif']);
789
		$laggif = $lagg['laggif'];
790
	} else {
791
		$laggif = pfSense_interface_create("lagg");
792
	}
793

    
794
	/* Check if MTU was defined for this lagg interface */
795
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
796
	if ($lagg_mtu == 0 &&
797
	    is_array($config['interfaces'])) {
798
		foreach ($config['interfaces'] as $tmpinterface) {
799
			if ($tmpinterface['if'] == $lagg['laggif'] &&
800
			    !empty($tmpinterface['mtu'])) {
801
				$lagg_mtu = $tmpinterface['mtu'];
802
				break;
803
			}
804
		}
805
	}
806

    
807
	/* Just in case anything is not working well */
808
	if ($lagg_mtu == 0) {
809
		$lagg_mtu = 1500;
810
	}
811

    
812
	foreach ($members as $member) {
813
		if (!does_interface_exist($member)) {
814
			continue;
815
		}
816
		/* make sure the parent interface is up */
817
		pfSense_interface_mtu($member, $lagg_mtu);
818
		interfaces_bring_up($member);
819
		hardware_offloading_applyflags($member);
820
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
821
	}
822

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

    
825
	interfaces_bring_up($laggif);
826

    
827
	return $laggif;
828
}
829

    
830
function interfaces_gre_configure($checkparent = 0, $realif = "") {
831
	global $config;
832

    
833
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
834
		foreach ($config['gres']['gre'] as $i => $gre) {
835
			if (empty($gre['greif'])) {
836
				$gre['greif'] = "gre{$i}";
837
			}
838
			if (!empty($realif) && $realif != $gre['greif']) {
839
				continue;
840
			}
841

    
842
			if ($checkparent == 1) {
843
				if (substr($gre['if'], 0, 4) == '_vip') {
844
					continue;
845
				}
846
				if (substr($gre['if'], 0, 5) == '_lloc') {
847
					continue;
848
				}
849
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6") {
850
					continue;
851
				}
852
			} else if ($checkparent == 2) {
853
				if ((substr($gre['if'], 0, 4) != '_vip' && substr($gre['if'], 0, 5) != '_lloc') &&
854
				    (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")) {
855
					continue;
856
				}
857
			}
858
			/* XXX: Maybe we should report any errors?! */
859
			interface_gre_configure($gre);
860
		}
861
	}
862
}
863

    
864
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
865
function interface_gre_configure(&$gre, $grekey = "") {
866
	global $config, $g;
867

    
868
	if (!is_array($gre)) {
869
		return -1;
870
	}
871

    
872
	$realif = get_real_interface($gre['if']);
873
	$realifip = get_interface_ip($gre['if']);
874
	$realifip6 = get_interface_ipv6($gre['if']);
875

    
876
	/* make sure the parent interface is up */
877
	interfaces_bring_up($realif);
878

    
879
	if (platform_booting() || !(empty($gre['greif']))) {
880
		pfSense_interface_destroy($gre['greif']);
881
		pfSense_interface_create($gre['greif']);
882
		$greif = $gre['greif'];
883
	} else {
884
		$greif = pfSense_interface_create("gre");
885
	}
886

    
887
	/* Do not change the order here for more see gre(4) NOTES section. */
888
	if (is_ipaddrv6($gre['remote-addr'])) {
889
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
890
	} else {
891
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
892
	}
893
	if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
894
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
895
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
896
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
897
	} else {
898
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
899
	}
900

    
901
	if ($greif) {
902
		interfaces_bring_up($greif);
903
	} else {
904
		log_error(gettext("Could not bring greif up -- variable not defined."));
905
	}
906

    
907
	if (isset($gre['link1']) && $gre['link1']) {
908
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
909
	}
910
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
911
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
912
	}
913
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
914
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
915
	}
916

    
917
	interfaces_bring_up($greif);
918

    
919
	return $greif;
920
}
921

    
922
function interfaces_gif_configure($checkparent = 0, $realif = "") {
923
	global $config;
924

    
925
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
926
		foreach ($config['gifs']['gif'] as $i => $gif) {
927
			if (empty($gif['gifif'])) {
928
				$gre['gifif'] = "gif{$i}";
929
			}
930
			if (!empty($realif) && $realif != $gif['gifif']) {
931
				continue;
932
			}
933

    
934
			if ($checkparent == 1) {
935
				if (substr($gif['if'], 0, 4) == '_vip') {
936
					continue;
937
				}
938
				if (substr($gif['if'], 0, 5) == '_lloc') {
939
					continue;
940
				}
941
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
942
					continue;
943
				}
944
			}
945
			else if ($checkparent == 2) {
946
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
947
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
948
					continue;
949
				}
950
			}
951
			/* XXX: Maybe we should report any errors?! */
952
			interface_gif_configure($gif);
953
		}
954
	}
955
}
956

    
957
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
958
function interface_gif_configure(&$gif, $gifkey = "") {
959
	global $config, $g;
960

    
961
	if (!is_array($gif)) {
962
		return -1;
963
	}
964

    
965
	$realif = get_real_interface($gif['if']);
966
	$ipaddr = get_interface_ip($gif['if']);
967

    
968
	if (is_ipaddrv4($gif['remote-addr'])) {
969
		if (is_ipaddrv4($ipaddr)) {
970
			$realifip = $ipaddr;
971
		} else {
972
			$realifip = get_interface_ip($gif['if']);
973
		}
974
		$realifgw = get_interface_gateway($gif['if']);
975
	} else if (is_ipaddrv6($gif['remote-addr'])) {
976
		if (is_ipaddrv6($ipaddr)) {
977
			$realifip = $ipaddr;
978
		} else {
979
			$realifip = get_interface_ipv6($gif['if']);
980
		}
981
		$realifgw = get_interface_gateway_v6($gif['if']);
982
	}
983
	/* make sure the parent interface is up */
984
	if ($realif) {
985
		interfaces_bring_up($realif);
986
	} else {
987
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
988
	}
989

    
990
	if (platform_booting() || !(empty($gif['gifif']))) {
991
		pfSense_interface_destroy($gif['gifif']);
992
		pfSense_interface_create($gif['gifif']);
993
		$gifif = $gif['gifif'];
994
	} else {
995
		$gifif = pfSense_interface_create("gif");
996
	}
997

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

    
1037
	if (!platform_booting()) {
1038
		$iflist = get_configured_interface_list();
1039
		foreach ($iflist as $ifname) {
1040
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1041
				if (get_interface_gateway($ifname)) {
1042
					system_routing_configure($ifname);
1043
					break;
1044
				}
1045
				if (get_interface_gateway_v6($ifname)) {
1046
					system_routing_configure($ifname);
1047
					break;
1048
				}
1049
			}
1050
		}
1051
	}
1052

    
1053

    
1054
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1055
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1056
	}
1057
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1058
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1059
	}
1060

    
1061
	if (is_ipaddrv4($realifgw)) {
1062
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1063
	}
1064
	if (is_ipaddrv6($realifgw)) {
1065
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1066
	}
1067

    
1068
	interfaces_bring_up($gifif);
1069

    
1070
	return $gifif;
1071
}
1072

    
1073
function interfaces_configure() {
1074
	global $config, $g;
1075

    
1076
	/* Set up our loopback interface */
1077
	interfaces_loopback_configure();
1078

    
1079
	/* create the unconfigured wireless clones */
1080
	interfaces_create_wireless_clones();
1081

    
1082
	/* set up LAGG virtual interfaces */
1083
	interfaces_lagg_configure();
1084

    
1085
	/* set up VLAN virtual interfaces */
1086
	interfaces_vlan_configure();
1087

    
1088
	interfaces_qinq_configure();
1089

    
1090
	$iflist = get_configured_interface_with_descr();
1091
	$delayed_list = array();
1092
	$bridge_list = array();
1093
	$track6_list = array();
1094

    
1095
	/* This is needed to speedup interfaces on bootup. */
1096
	$reload = false;
1097
	if (!platform_booting()) {
1098
		$reload = true;
1099
	}
1100

    
1101
	foreach ($iflist as $if => $ifname) {
1102
		$realif = $config['interfaces'][$if]['if'];
1103
		if (strstr($realif, "bridge")) {
1104
			$bridge_list[$if] = $ifname;
1105
		} else if (strstr($realif, "gre")) {
1106
			$delayed_list[$if] = $ifname;
1107
		} else if (strstr($realif, "gif")) {
1108
			$delayed_list[$if] = $ifname;
1109
		} else if (strstr($realif, "ovpn")) {
1110
			//echo "Delaying OpenVPN interface configuration...done.\n";
1111
			continue;
1112
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1113
			$track6_list[$if] = $ifname;
1114
		} else {
1115
			if (platform_booting()) {
1116
				printf(gettext("Configuring %s interface..."), $ifname);
1117
			}
1118

    
1119
			if ($g['debug']) {
1120
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1121
			}
1122
			interface_configure($if, $reload);
1123
			if (platform_booting()) {
1124
				echo gettext("done.") . "\n";
1125
			}
1126
		}
1127
	}
1128

    
1129
	/*
1130
	 * NOTE: The following function parameter consists of
1131
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1132
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1133
	 */
1134

    
1135
	/* set up GRE virtual interfaces */
1136
	interfaces_gre_configure(1);
1137

    
1138
	/* set up GIF virtual interfaces */
1139
	interfaces_gif_configure(1);
1140

    
1141
	/* set up BRIDGe virtual interfaces */
1142
	interfaces_bridge_configure(1);
1143

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

    
1152
		interface_configure($if, $reload);
1153

    
1154
		if (platform_booting()) {
1155
			echo gettext("done.") . "\n";
1156
		}
1157
	}
1158

    
1159
	/* bring up vip interfaces */
1160
	interfaces_vips_configure();
1161

    
1162
	/* set up GRE virtual interfaces */
1163
	interfaces_gre_configure(2);
1164

    
1165
	/* set up GIF virtual interfaces */
1166
	interfaces_gif_configure(2);
1167

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

    
1176
		interface_configure($if, $reload);
1177

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

    
1183
	/* set up BRIDGe virtual interfaces */
1184
	interfaces_bridge_configure(2);
1185

    
1186
	foreach ($bridge_list as $if => $ifname) {
1187
		if (platform_booting()) {
1188
			printf(gettext("Configuring %s interface..."), $ifname);
1189
		}
1190
		if ($g['debug']) {
1191
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1192
		}
1193

    
1194
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1195
		// redmine #3997
1196
		interface_reconfigure($if, $reload);
1197
		interfaces_vips_configure($if);
1198

    
1199
		if (platform_booting()) {
1200
			echo gettext("done.") . "\n";
1201
		}
1202
	}
1203

    
1204
	/* configure interface groups */
1205
	interfaces_group_setup();
1206

    
1207
	if (!platform_booting()) {
1208
		/* reconfigure static routes (kernel may have deleted them) */
1209
		system_routing_configure();
1210

    
1211
		/* reload IPsec tunnels */
1212
		vpn_ipsec_configure();
1213

    
1214
		/* restart dns servers (defering dhcpd reload) */
1215
		if (isset($config['dnsmasq']['enable'])) {
1216
			services_dnsmasq_configure(false);
1217
		}
1218
		if (isset($config['unbound']['enable'])) {
1219
			services_unbound_configure(false);
1220
		}
1221

    
1222
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1223
		services_dhcpd_configure();
1224
	}
1225

    
1226
	return 0;
1227
}
1228

    
1229
function interface_reconfigure($interface = "wan", $reloadall = false) {
1230
	interface_bring_down($interface);
1231
	interface_configure($interface, $reloadall);
1232
}
1233

    
1234
function interface_vip_bring_down($vip) {
1235
	global $g;
1236

    
1237
	$vipif = get_real_interface($vip['interface']);
1238
	switch ($vip['mode']) {
1239
		case "proxyarp":
1240
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1241
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1242
			}
1243
			break;
1244
		case "ipalias":
1245
			if (does_interface_exist($vipif)) {
1246
				if (is_ipaddrv6($vip['subnet'])) {
1247
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1248
				} else {
1249
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1250
				}
1251
			}
1252
			break;
1253
		case "carp":
1254
			/* XXX: Is enough to delete ip address? */
1255
			if (does_interface_exist($vipif)) {
1256
				if (is_ipaddrv6($vip['subnet'])) {
1257
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1258
				} else {
1259
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1260
				}
1261
			}
1262
			break;
1263
	}
1264
}
1265

    
1266
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1267
	global $config, $g;
1268

    
1269
	if (!isset($config['interfaces'][$interface])) {
1270
		return;
1271
	}
1272

    
1273
	if ($g['debug']) {
1274
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1275
	}
1276

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

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

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

    
1414
	if (!empty($track6) && is_array($track6)) {
1415
		if (!function_exists('services_dhcpd_configure')) {
1416
			require_once('services.inc');
1417
		}
1418
		/* Bring down radvd and dhcp6 on these interfaces */
1419
		services_dhcpd_configure('inet6', $track6);
1420
	}
1421

    
1422
	$old_router = '';
1423
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1424
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1425
	}
1426

    
1427
	/* remove interface up file if it exists */
1428
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1429
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1430
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1431
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1432
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1433
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1434
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1435

    
1436
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1437
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1438
	if (is_array($ifcfg['wireless'])) {
1439
		kill_hostapd($realif);
1440
		mwexec(kill_wpasupplicant($realif));
1441
	}
1442

    
1443
	if ($destroy == true) {
1444
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1445
			pfSense_interface_destroy($realif);
1446
		}
1447
	}
1448

    
1449
	return;
1450
}
1451

    
1452
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1453
	global $config;
1454
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1455
		unset($config["virtualip_carp_maintenancemode"]);
1456
		write_config("Leave CARP maintenance mode");
1457
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1458
		$config["virtualip_carp_maintenancemode"] = true;
1459
		write_config(gettext("Enter CARP maintenance mode"));
1460
	}
1461

    
1462
	$viparr = &$config['virtualip']['vip'];
1463
	foreach ($viparr as $vip) {
1464
		if ($vip['mode'] == "carp") {
1465
			interface_carp_configure($vip);
1466
		}
1467
	}
1468
}
1469

    
1470
function interface_isppp_type($interface) {
1471
	global $config;
1472

    
1473
	if (!is_array($config['interfaces'][$interface])) {
1474
		return false;
1475
	}
1476

    
1477
	switch ($config['interfaces'][$interface]['ipaddr']) {
1478
		case 'pptp':
1479
		case 'l2tp':
1480
		case 'pppoe':
1481
		case 'ppp':
1482
			return true;
1483
			break;
1484
		default:
1485
			return false;
1486
			break;
1487
	}
1488
}
1489

    
1490
function interfaces_ptpid_used($ptpid) {
1491
	global $config;
1492

    
1493
	if (is_array($config['ppps']['ppp'])) {
1494
		foreach ($config['ppps']['ppp'] as & $settings) {
1495
			if ($ptpid == $settings['ptpid']) {
1496
				return true;
1497
			}
1498
		}
1499
	}
1500

    
1501
	return false;
1502
}
1503

    
1504
function interfaces_ptpid_next() {
1505

    
1506
	$ptpid = 0;
1507
	while (interfaces_ptpid_used($ptpid)) {
1508
		$ptpid++;
1509
	}
1510

    
1511
	return $ptpid;
1512
}
1513

    
1514
function getMPDCRONSettings($pppif) {
1515
	global $config;
1516

    
1517
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1518
	if (is_array($config['cron']['item'])) {
1519
		foreach ($config['cron']['item'] as $i => $item) {
1520
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1521
				return array("ID" => $i, "ITEM" => $item);
1522
			}
1523
		}
1524
	}
1525

    
1526
	return NULL;
1527
}
1528

    
1529
function handle_pppoe_reset($post_array) {
1530
	global $config, $g;
1531

    
1532
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1533
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1534

    
1535
	if (!is_array($config['cron']['item'])) {
1536
		$config['cron']['item'] = array();
1537
	}
1538

    
1539
	$itemhash = getMPDCRONSettings($pppif);
1540

    
1541
	// reset cron items if necessary and return
1542
	if (empty($post_array['pppoe-reset-type'])) {
1543
		if (isset($itemhash)) {
1544
			unset($config['cron']['item'][$itemhash['ID']]);
1545
		}
1546
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1547
		return;
1548
	}
1549

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

    
1612
/*
1613
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1614
 * It writes the mpd config file to /var/etc every time the link is opened.
1615
 */
1616
function interface_ppps_configure($interface) {
1617
	global $config, $g;
1618

    
1619
	/* Return for unassigned interfaces. This is a minimum requirement. */
1620
	if (empty($config['interfaces'][$interface])) {
1621
		return 0;
1622
	}
1623
	$ifcfg = $config['interfaces'][$interface];
1624
	if (!isset($ifcfg['enable'])) {
1625
		return 0;
1626
	}
1627

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

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

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

    
1666
	$ports = explode(',', $ppp['ports']);
1667
	if ($type != "modem") {
1668
		foreach ($ports as $pid => $port) {
1669
			$ports[$pid] = get_real_interface($port);
1670
			if (empty($ports[$pid])) {
1671
				return 0;
1672
			}
1673
		}
1674
	}
1675
	$localips = explode(',', $ppp['localip']);
1676
	$gateways = explode(',', $ppp['gateway']);
1677
	$subnets = explode(',', $ppp['subnet']);
1678

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

    
1702
				if (!is_ipaddr($localips[$pid])) {
1703
					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));
1704
					$localips[$pid] = "0.0.0.0";
1705
				}
1706
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
1707
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1708
				}
1709
				if (!is_ipaddr($gateways[$pid])) {
1710
					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));
1711
					return 0;
1712
				}
1713
				pfSense_ngctl_attach(".", $port);
1714
				break;
1715
			case "ppp":
1716
				if (!file_exists("{$port}")) {
1717
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1718
					return 0;
1719
				}
1720
				break;
1721
			default:
1722
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1723
				break;
1724
		}
1725
	}
1726

    
1727
	if (is_array($ports) && count($ports) > 1) {
1728
		$multilink = "enable";
1729
	} else {
1730
		$multilink = "disable";
1731
	}
1732

    
1733
	if ($type == "modem") {
1734
		if (is_ipaddr($ppp['localip'])) {
1735
			$localip = $ppp['localip'];
1736
		} else {
1737
			$localip = '0.0.0.0';
1738
		}
1739

    
1740
		if (is_ipaddr($ppp['gateway'])) {
1741
			$gateway = $ppp['gateway'];
1742
		} else {
1743
			$gateway = "10.64.64.{$pppid}";
1744
		}
1745
		$ranges = "{$localip}/0 {$gateway}/0";
1746

    
1747
		if (empty($ppp['apnum'])) {
1748
			$ppp['apnum'] = 1;
1749
		}
1750
	} else {
1751
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1752
	}
1753

    
1754
	if (isset($ppp['ondemand'])) {
1755
		$ondemand = "enable";
1756
	} else {
1757
		$ondemand = "disable";
1758
	}
1759
	if (!isset($ppp['idletimeout'])) {
1760
		$ppp['idletimeout'] = 0;
1761
	}
1762

    
1763
	if (empty($ppp['username']) && $type == "modem") {
1764
		$ppp['username'] = "user";
1765
		$ppp['password'] = "none";
1766
	}
1767
	if (empty($ppp['password']) && $type == "modem") {
1768
		$passwd = "none";
1769
	} else {
1770
		$passwd = base64_decode($ppp['password']);
1771
	}
1772

    
1773
	$bandwidths = explode(',', $ppp['bandwidth']);
1774
	$defaultmtu = "1492";
1775
	if (!empty($ifcfg['mtu'])) {
1776
		$defaultmtu = intval($ifcfg['mtu']);
1777
	}
1778
	if (isset($ppp['mtu'])) {
1779
		$mtus = explode(',', $ppp['mtu']);
1780
	}
1781
	if (isset($ppp['mru'])) {
1782
		$mrus = explode(',', $ppp['mru']);
1783
	}
1784
	if (isset($ppp['mrru'])) {
1785
		$mrrus = explode(',', $ppp['mrru']);
1786
	}
1787

    
1788
	// Construct the mpd.conf file
1789
	$mpdconf = <<<EOD
1790
startup:
1791
	# configure the console
1792
	set console close
1793
	# configure the web server
1794
	set web close
1795

    
1796
default:
1797
{$ppp['type']}client:
1798
	create bundle static {$interface}
1799
	set bundle enable ipv6cp
1800
	set iface name {$pppif}
1801

    
1802
EOD;
1803
	$setdefaultgw = false;
1804
	$founddefaultgw = false;
1805
	if (is_array($config['gateways']['gateway_item'])) {
1806
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1807
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1808
				$setdefaultgw = true;
1809
				break;
1810
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1811
				$founddefaultgw = true;
1812
				break;
1813
			}
1814
		}
1815
	}
1816

    
1817
/* Omit this, we maintain the default route by other means, and it causes problems with
1818
 * default gateway switching. See redmine #1837 for original issue
1819
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some 
1820
 * edge case. redmine #6495 open to address. 
1821
 */
1822
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1823
		$setdefaultgw = true;
1824
		$mpdconf .= <<<EOD
1825
	set iface route default
1826

    
1827
EOD;
1828
	}
1829
	$mpdconf .= <<<EOD
1830
	set iface {$ondemand} on-demand
1831
	set iface idle {$ppp['idletimeout']}
1832

    
1833
EOD;
1834

    
1835
	if (isset($ppp['ondemand'])) {
1836
		$mpdconf .= <<<EOD
1837
	set iface addrs 10.10.1.1 10.10.1.2
1838

    
1839
EOD;
1840
	}
1841

    
1842
	if (isset($ppp['tcpmssfix'])) {
1843
		$tcpmss = "disable";
1844
	} else {
1845
		$tcpmss = "enable";
1846
	}
1847
	$mpdconf .= <<<EOD
1848
	set iface {$tcpmss} tcpmssfix
1849

    
1850
EOD;
1851

    
1852
	$mpdconf .= <<<EOD
1853
	set iface up-script /usr/local/sbin/ppp-linkup
1854
	set iface down-script /usr/local/sbin/ppp-linkdown
1855
	set ipcp ranges {$ranges}
1856

    
1857
EOD;
1858
	if (isset($ppp['vjcomp'])) {
1859
		$mpdconf .= <<<EOD
1860
	set ipcp no vjcomp
1861

    
1862
EOD;
1863
	}
1864

    
1865
	if (isset($config['system']['dnsallowoverride'])) {
1866
		$mpdconf .= <<<EOD
1867
	set ipcp enable req-pri-dns
1868
	set ipcp enable req-sec-dns
1869

    
1870
EOD;
1871
	}
1872

    
1873
	if (!isset($ppp['verbose_log'])) {
1874
		$mpdconf .= <<<EOD
1875
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1876

    
1877
EOD;
1878
	}
1879

    
1880
	foreach ($ports as $pid => $port) {
1881
		$port = get_real_interface($port);
1882
		$mpdconf .= <<<EOD
1883

    
1884
	create link static {$interface}_link{$pid} {$type}
1885
	set link action bundle {$interface}
1886
	set link {$multilink} multilink
1887
	set link keep-alive 10 60
1888
	set link max-redial 0
1889

    
1890
EOD;
1891
		if (isset($ppp['shortseq'])) {
1892
			$mpdconf .= <<<EOD
1893
	set link no shortseq
1894

    
1895
EOD;
1896
		}
1897

    
1898
		if (isset($ppp['acfcomp'])) {
1899
			$mpdconf .= <<<EOD
1900
	set link no acfcomp
1901

    
1902
EOD;
1903
		}
1904

    
1905
		if (isset($ppp['protocomp'])) {
1906
			$mpdconf .= <<<EOD
1907
	set link no protocomp
1908

    
1909
EOD;
1910
		}
1911

    
1912
		$mpdconf .= <<<EOD
1913
	set link disable chap pap
1914
	set link accept chap pap eap
1915
	set link disable incoming
1916

    
1917
EOD;
1918

    
1919

    
1920
		if (!empty($bandwidths[$pid])) {
1921
			$mpdconf .= <<<EOD
1922
	set link bandwidth {$bandwidths[$pid]}
1923

    
1924
EOD;
1925
		}
1926

    
1927
		if (empty($mtus[$pid])) {
1928
			$mtus[$pid] = $defaultmtu;
1929
		}
1930
		if ($type == "pppoe") {
1931
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
1932
				$mtus[$pid] = get_interface_mtu($port) - 8;
1933
			}
1934
		}
1935
		if (! ($type == "pppoe" && $mtus[$pid] > 1492) ) {
1936
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
1937
			$mpdconf .= <<<EOD
1938
	set link mtu {$mtus[$pid]}
1939

    
1940
EOD;
1941
		}
1942

    
1943
		if (!empty($mrus[$pid])) {
1944
			$mpdconf .= <<<EOD
1945
	set link mru {$mrus[$pid]}
1946

    
1947
EOD;
1948
		}
1949

    
1950
		if (!empty($mrrus[$pid])) {
1951
			$mpdconf .= <<<EOD
1952
	set link mrru {$mrrus[$pid]}
1953

    
1954
EOD;
1955
		}
1956

    
1957
		$mpdconf .= <<<EOD
1958
	set auth authname "{$ppp['username']}"
1959
	set auth password {$passwd}
1960

    
1961
EOD;
1962
		if ($type == "modem") {
1963
			$mpdconf .= <<<EOD
1964
	set modem device {$ppp['ports']}
1965
	set modem script DialPeer
1966
	set modem idle-script Ringback
1967
	set modem watch -cd
1968
	set modem var \$DialPrefix "DT"
1969
	set modem var \$Telephone "{$ppp['phone']}"
1970

    
1971
EOD;
1972
		}
1973
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1974
			$mpdconf .= <<<EOD
1975
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1976

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

    
1984
EOD;
1985
		}
1986
		if (isset($ppp['simpin']) && $type == "modem") {
1987
			if ($ppp['pin-wait'] == "") {
1988
				$ppp['pin-wait'] = 0;
1989
			}
1990
			$mpdconf .= <<<EOD
1991
	set modem var \$SimPin "{$ppp['simpin']}"
1992
	set modem var \$PinWait "{$ppp['pin-wait']}"
1993

    
1994
EOD;
1995
		}
1996
		if (isset($ppp['apn']) && $type == "modem") {
1997
			$mpdconf .= <<<EOD
1998
	set modem var \$APN "{$ppp['apn']}"
1999
	set modem var \$APNum "{$ppp['apnum']}"
2000

    
2001
EOD;
2002
		}
2003
		if ($type == "pppoe") {
2004
			// Send a null service name if none is set.
2005
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2006
			$mpdconf .= <<<EOD
2007
	set pppoe service "{$provider}"
2008

    
2009
EOD;
2010
		}
2011
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
2012
			$mpdconf .= <<<EOD
2013
	set pppoe max-payload {$mtus[$pid]}
2014

    
2015
EOD;
2016
		}
2017
		if ($type == "pppoe") {
2018
			$mpdconf .= <<<EOD
2019
	set pppoe iface {$port}
2020

    
2021
EOD;
2022
		}
2023

    
2024
		if ($type == "pptp" || $type == "l2tp") {
2025
			$mpdconf .= <<<EOD
2026
	set {$type} self {$localips[$pid]}
2027
	set {$type} peer {$gateways[$pid]}
2028

    
2029
EOD;
2030
		}
2031

    
2032
		$mpdconf .= "\topen\n";
2033
	} //end foreach ($port)
2034

    
2035

    
2036
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2037
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2038
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2039
	} else {
2040
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2041
		if (!$fd) {
2042
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2043
			return 0;
2044
		}
2045
		// Write out mpd_ppp.conf
2046
		fwrite($fd, $mpdconf);
2047
		fclose($fd);
2048
		unset($mpdconf);
2049
	}
2050

    
2051
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2052
	if (isset($ppp['uptime'])) {
2053
		if (!file_exists("/conf/{$pppif}.log")) {
2054
			conf_mount_rw();
2055
			file_put_contents("/conf/{$pppif}.log", '');
2056
			conf_mount_ro();
2057
		}
2058
	} else {
2059
		if (file_exists("/conf/{$pppif}.log")) {
2060
			conf_mount_rw();
2061
			@unlink("/conf/{$pppif}.log");
2062
			conf_mount_ro();
2063
		}
2064
	}
2065

    
2066
	/* clean up old lock files */
2067
	foreach ($ports as $port) {
2068
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2069
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2070
		}
2071
	}
2072

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

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

    
2098
	// Check for PPPoE periodic reset request
2099
	if ($type == "pppoe") {
2100
		if (!empty($ppp['pppoe-reset-type'])) {
2101
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2102
		} else {
2103
			interface_setup_pppoe_reset_file($ppp['if']);
2104
		}
2105
	}
2106
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
2107
	$i = 0;
2108
	while ($i < 3) {
2109
		sleep(10);
2110
		if (does_interface_exist($ppp['if'], true)) {
2111
			break;
2112
		}
2113
		$i++;
2114
	}
2115

    
2116
	/* Remove all temporary bogon IPv4 addresses */
2117
	if (is_array($tempaddr)) {
2118
		foreach ($tempaddr as $tempiface) {
2119
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2120
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2121
			}
2122
		}
2123
		unset ($tempaddr);
2124
	}
2125

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

    
2146
	return 1;
2147
}
2148

    
2149
function interfaces_sync_setup() {
2150
	global $g, $config;
2151

    
2152
	if (isset($config['system']['developerspew'])) {
2153
		$mt = microtime();
2154
		echo "interfaces_sync_setup() being called $mt\n";
2155
	}
2156

    
2157
	if (platform_booting()) {
2158
		echo gettext("Configuring CARP settings...");
2159
		mute_kernel_msgs();
2160
	}
2161

    
2162
	/* suck in configuration items */
2163
	if ($config['hasync']) {
2164
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2165
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2166
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2167
	} else {
2168
		unset($pfsyncinterface);
2169
		unset($pfsyncenabled);
2170
	}
2171

    
2172
	set_sysctl(array(
2173
		"net.inet.carp.preempt" => "1",
2174
		"net.inet.carp.log" => "1")
2175
	);
2176

    
2177
	if (!empty($pfsyncinterface)) {
2178
		$carp_sync_int = get_real_interface($pfsyncinterface);
2179
	} else {
2180
		unset($carp_sync_int);
2181
	}
2182

    
2183
	/* setup pfsync interface */
2184
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2185
		if (is_ipaddr($pfsyncpeerip)) {
2186
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2187
		} else {
2188
			$syncpeer = "-syncpeer";
2189
		}
2190

    
2191
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2192
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2193

    
2194
		sleep(1);
2195

    
2196
		/* 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
2197
		 * for existing sessions.
2198
		 */
2199
		log_error(gettext("waiting for pfsync..."));
2200
		$i = 0;
2201
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2202
			$i++;
2203
			sleep(1);
2204
		}
2205
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2206
		log_error(gettext("Configuring CARP settings finalize..."));
2207
	} else {
2208
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2209
	}
2210

    
2211
	$carplist = get_configured_vip_list('all', VIP_CARP);
2212
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2213
		set_single_sysctl("net.inet.carp.allow", "1");
2214
	} else {
2215
		set_single_sysctl("net.inet.carp.allow", "0");
2216
	}
2217

    
2218
	if (platform_booting()) {
2219
		unmute_kernel_msgs();
2220
		echo gettext("done.") . "\n";
2221
	}
2222
}
2223

    
2224
function interface_proxyarp_configure($interface = "") {
2225
	global $config, $g;
2226
	if (isset($config['system']['developerspew'])) {
2227
		$mt = microtime();
2228
		echo "interface_proxyarp_configure() being called $mt\n";
2229
	}
2230

    
2231
	/* kill any running choparp */
2232
	if (empty($interface)) {
2233
		killbyname("choparp");
2234
	} else {
2235
		$vipif = get_real_interface($interface);
2236
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2237
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2238
		}
2239
	}
2240

    
2241
	$paa = array();
2242
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2243

    
2244
		/* group by interface */
2245
		foreach ($config['virtualip']['vip'] as $vipent) {
2246
			if ($vipent['mode'] === "proxyarp") {
2247
				if ($vipent['interface']) {
2248
					$proxyif = $vipent['interface'];
2249
				} else {
2250
					$proxyif = "wan";
2251
				}
2252

    
2253
				if (!empty($interface) && $interface != $proxyif) {
2254
					continue;
2255
				}
2256

    
2257
				if (!is_array($paa[$proxyif])) {
2258
					$paa[$proxyif] = array();
2259
				}
2260

    
2261
				$paa[$proxyif][] = $vipent;
2262
			}
2263
		}
2264
	}
2265

    
2266
	if (!empty($interface)) {
2267
		if (is_array($paa[$interface])) {
2268
			$paaifip = get_interface_ip($interface);
2269
			if (!is_ipaddr($paaifip)) {
2270
				return;
2271
			}
2272
			$vipif = get_real_interface($interface);
2273
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2274
			$args .= $vipif . " auto";
2275
			foreach ($paa[$interface] as $paent) {
2276
				if (isset($paent['subnet'])) {
2277
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2278
				} else if (isset($paent['range'])) {
2279
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2280
				}
2281
			}
2282
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2283
		}
2284
	} else if (count($paa) > 0) {
2285
		foreach ($paa as $paif => $paents) {
2286
			$paaifip = get_interface_ip($paif);
2287
			if (!is_ipaddr($paaifip)) {
2288
				continue;
2289
			}
2290
			$vipif = get_real_interface($paif);
2291
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2292
			$args .= $vipif . " auto";
2293
			foreach ($paents as $paent) {
2294
				if (isset($paent['subnet'])) {
2295
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2296
				} else if (isset($paent['range'])) {
2297
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2298
				}
2299
			}
2300
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2301
		}
2302
	}
2303
}
2304

    
2305
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2306
	global $g, $config;
2307

    
2308
	if (is_array($config['virtualip']['vip'])) {
2309
		foreach ($config['virtualip']['vip'] as $vip) {
2310

    
2311
			$iface = $vip['interface'];
2312
			if (substr($iface, 0, 4) == "_vip")
2313
				$iface = get_configured_vip_interface($vip['interface']);
2314
			if ($iface != $interface)
2315
				continue;
2316
			if ($type == VIP_CARP) {
2317
				if ($vip['mode'] != "carp")
2318
					continue;
2319
			} elseif ($type == VIP_IPALIAS) {
2320
				if ($vip['mode'] != "ipalias")
2321
					continue;
2322
			} else {
2323
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2324
					continue;
2325
			}
2326

    
2327
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2328
				interface_vip_bring_down($vip);
2329
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2330
				interface_vip_bring_down($vip);
2331
			else if ($inet == "all")
2332
				interface_vip_bring_down($vip);
2333
		}
2334
	}
2335
}
2336

    
2337
function interfaces_vips_configure($interface = "") {
2338
	global $g, $config;
2339
	if (isset($config['system']['developerspew'])) {
2340
		$mt = microtime();
2341
		echo "interfaces_vips_configure() being called $mt\n";
2342
	}
2343
	$paa = array();
2344
	if (is_array($config['virtualip']['vip'])) {
2345
		$carp_setuped = false;
2346
		$anyproxyarp = false;
2347
		foreach ($config['virtualip']['vip'] as $vip) {
2348
			switch ($vip['mode']) {
2349
				case "proxyarp":
2350
					/* nothing it is handled on interface_proxyarp_configure() */
2351
					if ($interface <> "" && $vip['interface'] <> $interface) {
2352
						continue;
2353
					}
2354
					$anyproxyarp = true;
2355
					break;
2356
				case "ipalias":
2357
					$iface = $vip['interface'];
2358
					if (substr($iface, 0, 4) == "_vip")
2359
						$iface = get_configured_vip_interface($vip['interface']);
2360
					if ($interface <> "" && $iface <> $interface) {
2361
						continue;
2362
					}
2363
					interface_ipalias_configure($vip);
2364
					break;
2365
				case "carp":
2366
					if ($interface <> "" && $vip['interface'] <> $interface) {
2367
						continue;
2368
					}
2369
					if ($carp_setuped == false) {
2370
						$carp_setuped = true;
2371
					}
2372
					interface_carp_configure($vip);
2373
					break;
2374
			}
2375
		}
2376
		if ($carp_setuped == true) {
2377
			interfaces_sync_setup();
2378
		}
2379
		if ($anyproxyarp == true) {
2380
			interface_proxyarp_configure();
2381
		}
2382
	}
2383
}
2384

    
2385
function interface_ipalias_configure(&$vip) {
2386
	global $config;
2387

    
2388
	if ($vip['mode'] != 'ipalias') {
2389
		return;
2390
	}
2391

    
2392
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2393
	if ($realif != "lo0") {
2394
		$if = convert_real_interface_to_friendly_interface_name($realif);
2395
		if (!isset($config['interfaces'][$if])) {
2396
			return;
2397
		}
2398

    
2399
		if (!isset($config['interfaces'][$if]['enable'])) {
2400
			return;
2401
		}
2402
	}
2403

    
2404
	$af = 'inet';
2405
	if (is_ipaddrv6($vip['subnet'])) {
2406
		$af = 'inet6';
2407
	}
2408
	$iface = $vip['interface'];
2409
	$vhid = '';
2410
	if (substr($vip['interface'], 0, 4) == "_vip") {
2411
		$carpvip = get_configured_vip($vip['interface']);
2412
		$iface = $carpvip['interface'];
2413
		$vhid = "vhid {$carpvip['vhid']}";
2414
	}
2415
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2416
	unset($iface, $af, $realif, $carpvip, $vhid);
2417
}
2418

    
2419
function interface_carp_configure(&$vip) {
2420
	global $config, $g;
2421
	if (isset($config['system']['developerspew'])) {
2422
		$mt = microtime();
2423
		echo "interface_carp_configure() being called $mt\n";
2424
	}
2425

    
2426
	if ($vip['mode'] != "carp") {
2427
		return;
2428
	}
2429

    
2430
	/* NOTE: Maybe its useless nowadays */
2431
	$realif = get_real_interface($vip['interface']);
2432
	if (!does_interface_exist($realif)) {
2433
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2434
		return;
2435
	}
2436

    
2437
	$vip_password = $vip['password'];
2438
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2439
	if ($vip['password'] != "") {
2440
		$password = " pass {$vip_password}";
2441
	}
2442

    
2443
	$advbase = "";
2444
	if (!empty($vip['advbase'])) {
2445
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2446
	}
2447

    
2448
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2449
	if ($carp_maintenancemode) {
2450
		$advskew = "advskew 254";
2451
	} else {
2452
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2453
	}
2454

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

    
2457
	if (is_ipaddrv4($vip['subnet'])) {
2458
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2459
	} else if (is_ipaddrv6($vip['subnet'])) {
2460
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2461
	}
2462

    
2463
	return $realif;
2464
}
2465

    
2466
function interface_wireless_clone($realif, $wlcfg) {
2467
	global $config, $g;
2468
	/*   Check to see if interface has been cloned as of yet.
2469
	 *   If it has not been cloned then go ahead and clone it.
2470
	 */
2471
	$needs_clone = false;
2472
	if (is_array($wlcfg['wireless'])) {
2473
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2474
	} else {
2475
		$wlcfg_mode = $wlcfg['mode'];
2476
	}
2477
	switch ($wlcfg_mode) {
2478
		case "hostap":
2479
			$mode = "wlanmode hostap";
2480
			break;
2481
		case "adhoc":
2482
			$mode = "wlanmode adhoc";
2483
			break;
2484
		default:
2485
			$mode = "";
2486
			break;
2487
	}
2488
	$baseif = interface_get_wireless_base($wlcfg['if']);
2489
	if (does_interface_exist($realif)) {
2490
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2491
		$ifconfig_str = implode($output);
2492
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2493
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2494
			$needs_clone = true;
2495
		}
2496
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2497
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2498
			$needs_clone = true;
2499
		}
2500
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2501
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2502
			$needs_clone = true;
2503
		}
2504
	} else {
2505
		$needs_clone = true;
2506
	}
2507

    
2508
	if ($needs_clone == true) {
2509
		/* remove previous instance if it exists */
2510
		if (does_interface_exist($realif)) {
2511
			pfSense_interface_destroy($realif);
2512
		}
2513

    
2514
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2515
		// Create the new wlan interface. FreeBSD returns the new interface name.
2516
		// example:  wlan2
2517
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2518
		if ($ret <> 0) {
2519
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2520
			return false;
2521
		}
2522
		$newif = trim($out[0]);
2523
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2524
		pfSense_interface_rename($newif, $realif);
2525
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2526
	}
2527
	return true;
2528
}
2529

    
2530
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2531
	global $config, $g;
2532

    
2533
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2534
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2535
				 'regdomain', 'regcountry', 'reglocation');
2536

    
2537
	if (!is_interface_wireless($ifcfg['if'])) {
2538
		return;
2539
	}
2540

    
2541
	$baseif = interface_get_wireless_base($ifcfg['if']);
2542

    
2543
	// Sync shared settings for assigned clones
2544
	$iflist = get_configured_interface_list(false, true);
2545
	foreach ($iflist as $if) {
2546
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2547
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2548
				foreach ($shared_settings as $setting) {
2549
					if ($sync_changes) {
2550
						if (isset($ifcfg['wireless'][$setting])) {
2551
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2552
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2553
							unset($config['interfaces'][$if]['wireless'][$setting]);
2554
						}
2555
					} else {
2556
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2557
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2558
						} else if (isset($ifcfg['wireless'][$setting])) {
2559
							unset($ifcfg['wireless'][$setting]);
2560
						}
2561
					}
2562
				}
2563
				if (!$sync_changes) {
2564
					break;
2565
				}
2566
			}
2567
		}
2568
	}
2569

    
2570
	// Read or write settings at shared area
2571
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2572
		foreach ($shared_settings as $setting) {
2573
			if ($sync_changes) {
2574
				if (isset($ifcfg['wireless'][$setting])) {
2575
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2576
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2577
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2578
				}
2579
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2580
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2581
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2582
				} else if (isset($ifcfg['wireless'][$setting])) {
2583
					unset($ifcfg['wireless'][$setting]);
2584
				}
2585
			}
2586
		}
2587
	}
2588

    
2589
	// Sync the mode on the clone creation page with the configured mode on the interface
2590
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2591
		foreach ($config['wireless']['clone'] as &$clone) {
2592
			if ($clone['cloneif'] == $ifcfg['if']) {
2593
				if ($sync_changes) {
2594
					$clone['mode'] = $ifcfg['wireless']['mode'];
2595
				} else {
2596
					$ifcfg['wireless']['mode'] = $clone['mode'];
2597
				}
2598
				break;
2599
			}
2600
		}
2601
		unset($clone);
2602
	}
2603
}
2604

    
2605
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2606
	global $config, $g;
2607

    
2608
	/*    open up a shell script that will be used to output the commands.
2609
	 *    since wireless is changing a lot, these series of commands are fragile
2610
	 *    and will sometimes need to be verified by a operator by executing the command
2611
	 *    and returning the output of the command to the developers for inspection.  please
2612
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2613
	 */
2614

    
2615
	// Remove script file
2616
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2617

    
2618
	// Clone wireless nic if needed.
2619
	interface_wireless_clone($if, $wl);
2620

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

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

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

    
2630
	/* set values for /path/program */
2631
	$hostapd = "/usr/sbin/hostapd";
2632
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2633
	$ifconfig = "/sbin/ifconfig";
2634
	$sysctl = "/sbin/sysctl";
2635
	$killall = "/usr/bin/killall";
2636

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

    
2639
	$wlcmd = array();
2640
	$wl_sysctl = array();
2641
	/* Set a/b/g standard */
2642
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2643
	/* skip mode entirely for "auto" */
2644
	if ($wlcfg['standard'] != "auto") {
2645
		$wlcmd[] = "mode " . escapeshellarg($standard);
2646
	}
2647

    
2648
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2649
	 * to prevent massive packet loss under certain conditions. */
2650
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2651
		$wlcmd[] = "-ampdu";
2652
	}
2653

    
2654
	/* Set ssid */
2655
	if ($wlcfg['ssid']) {
2656
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2657
	}
2658

    
2659
	/* Set 802.11g protection mode */
2660
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2661

    
2662
	/* set wireless channel value */
2663
	if (isset($wlcfg['channel'])) {
2664
		if ($wlcfg['channel'] == "0") {
2665
			$wlcmd[] = "channel any";
2666
		} else {
2667
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2668
		}
2669
	}
2670

    
2671
	/* Set antenna diversity value */
2672
	if (isset($wlcfg['diversity'])) {
2673
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2674
	}
2675

    
2676
	/* Set txantenna value */
2677
	if (isset($wlcfg['txantenna'])) {
2678
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2679
	}
2680

    
2681
	/* Set rxantenna value */
2682
	if (isset($wlcfg['rxantenna'])) {
2683
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2684
	}
2685

    
2686
	/* set Distance value */
2687
	if ($wlcfg['distance']) {
2688
		$distance = escapeshellarg($wlcfg['distance']);
2689
	}
2690

    
2691
	/* Set wireless hostap mode */
2692
	if ($wlcfg['mode'] == "hostap") {
2693
		$wlcmd[] = "mediaopt hostap";
2694
	} else {
2695
		$wlcmd[] = "-mediaopt hostap";
2696
	}
2697

    
2698
	/* Set wireless adhoc mode */
2699
	if ($wlcfg['mode'] == "adhoc") {
2700
		$wlcmd[] = "mediaopt adhoc";
2701
	} else {
2702
		$wlcmd[] = "-mediaopt adhoc";
2703
	}
2704

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

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

    
2714
	/* handle pureg (802.11g) only option */
2715
	if (isset($wlcfg['pureg']['enable'])) {
2716
		$wlcmd[] = "mode 11g pureg";
2717
	} else {
2718
		$wlcmd[] = "-pureg";
2719
	}
2720

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

    
2728
	/* enable apbridge option */
2729
	if (isset($wlcfg['apbridge']['enable'])) {
2730
		$wlcmd[] = "apbridge";
2731
	} else {
2732
		$wlcmd[] = "-apbridge";
2733
	}
2734

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

    
2742
	/* handle txpower setting */
2743
	// or don't. this has issues at the moment.
2744
	/*
2745
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2746
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2747
	}*/
2748

    
2749
	/* handle wme option */
2750
	if (isset($wlcfg['wme']['enable'])) {
2751
		$wlcmd[] = "wme";
2752
	} else {
2753
		$wlcmd[] = "-wme";
2754
	}
2755

    
2756
	/* Enable wpa if it's configured. No WEP support anymore. */
2757
	if (isset($wlcfg['wpa']['enable'])) {
2758
		$wlcmd[] = "authmode wpa wepmode off ";
2759
	} else {
2760
		$wlcmd[] = "authmode open wepmode off ";
2761
	}
2762

    
2763
	kill_hostapd($if);
2764
	mwexec(kill_wpasupplicant("{$if}"));
2765

    
2766
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2767
	conf_mount_rw();
2768

    
2769
	switch ($wlcfg['mode']) {
2770
		case 'bss':
2771
			if (isset($wlcfg['wpa']['enable'])) {
2772
				$wpa .= <<<EOD
2773
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2774
ctrl_interface_group=0
2775
ap_scan=1
2776
#fast_reauth=1
2777
network={
2778
ssid="{$wlcfg['ssid']}"
2779
scan_ssid=1
2780
priority=5
2781
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2782
psk="{$wlcfg['wpa']['passphrase']}"
2783
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2784
group={$wlcfg['wpa']['wpa_pairwise']}
2785
}
2786
EOD;
2787

    
2788
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2789
				unset($wpa);
2790
			}
2791
			break;
2792
		case 'hostap':
2793
			if (!empty($wlcfg['wpa']['passphrase'])) {
2794
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2795
			} else {
2796
				$wpa_passphrase = "";
2797
			}
2798
			if (isset($wlcfg['wpa']['enable'])) {
2799
				$wpa .= <<<EOD
2800
interface={$if}
2801
driver=bsd
2802
logger_syslog=-1
2803
logger_syslog_level=0
2804
logger_stdout=-1
2805
logger_stdout_level=0
2806
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2807
ctrl_interface={$g['varrun_path']}/hostapd
2808
ctrl_interface_group=wheel
2809
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2810
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2811
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2812
ssid={$wlcfg['ssid']}
2813
debug={$wlcfg['wpa']['debug_mode']}
2814
wpa={$wlcfg['wpa']['wpa_mode']}
2815
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2816
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2817
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2818
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2819
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2820
{$wpa_passphrase}
2821

    
2822
EOD;
2823

    
2824
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2825
					$wpa .= <<<EOD
2826
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
2827
rsn_preauth=1
2828
rsn_preauth_interfaces={$if}
2829

    
2830
EOD;
2831
				}
2832
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2833
					$wpa .= "ieee8021x=1\n";
2834

    
2835
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2836
						$auth_server_port = "1812";
2837
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2838
							$auth_server_port = intval($wlcfg['auth_server_port']);
2839
						}
2840
						$wpa .= <<<EOD
2841

    
2842
auth_server_addr={$wlcfg['auth_server_addr']}
2843
auth_server_port={$auth_server_port}
2844
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2845

    
2846
EOD;
2847
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2848
							$auth_server_port2 = "1812";
2849
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2850
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2851
							}
2852

    
2853
							$wpa .= <<<EOD
2854
auth_server_addr={$wlcfg['auth_server_addr2']}
2855
auth_server_port={$auth_server_port2}
2856
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2857

    
2858
EOD;
2859
						}
2860
					}
2861
				}
2862

    
2863
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2864
				unset($wpa);
2865
			}
2866
			break;
2867
	}
2868

    
2869
	/*
2870
	 *    all variables are set, lets start up everything
2871
	 */
2872

    
2873
	$baseif = interface_get_wireless_base($if);
2874
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2875
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2876

    
2877
	/* set sysctls for the wireless interface */
2878
	if (!empty($wl_sysctl)) {
2879
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2880
		foreach ($wl_sysctl as $wl_sysctl_line) {
2881
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2882
		}
2883
	}
2884

    
2885
	/* set ack timers according to users preference (if he/she has any) */
2886
	if ($distance) {
2887
		fwrite($fd_set, "# Enable ATH distance settings\n");
2888
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2889
	}
2890

    
2891
	if (isset($wlcfg['wpa']['enable'])) {
2892
		if ($wlcfg['mode'] == "bss") {
2893
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2894
		}
2895
		if ($wlcfg['mode'] == "hostap") {
2896
			/* add line to script to restore old mac to make hostapd happy */
2897
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2898
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2899
				$if_curmac = get_interface_mac($if);
2900
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
2901
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2902
						" link " . escapeshellarg($if_oldmac) . "\n");
2903
				}
2904
			}
2905

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

    
2908
			/* add line to script to restore spoofed mac after running hostapd */
2909
			if ($wl['spoofmac']) {
2910
				$if_curmac = get_interface_mac($if);
2911
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
2912
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2913
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
2914
				}
2915
			}
2916
		}
2917
	}
2918

    
2919
	fclose($fd_set);
2920
	conf_mount_ro();
2921

    
2922
	/* Making sure regulatory settings have actually changed
2923
	 * before applying, because changing them requires bringing
2924
	 * down all wireless networks on the interface. */
2925
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2926
	$ifconfig_str = implode($output);
2927
	unset($output);
2928
	$reg_changing = false;
2929

    
2930
	/* special case for the debug country code */
2931
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
2932
		$reg_changing = true;
2933
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
2934
		$reg_changing = true;
2935
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
2936
		$reg_changing = true;
2937
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
2938
		$reg_changing = true;
2939
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
2940
		$reg_changing = true;
2941
	}
2942

    
2943
	if ($reg_changing) {
2944
		/* set regulatory domain */
2945
		if ($wlcfg['regdomain']) {
2946
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2947
		}
2948

    
2949
		/* set country */
2950
		if ($wlcfg['regcountry']) {
2951
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2952
		}
2953

    
2954
		/* set location */
2955
		if ($wlcfg['reglocation']) {
2956
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2957
		}
2958

    
2959
		$wlregcmd_args = implode(" ", $wlregcmd);
2960

    
2961
		/* build a complete list of the wireless clones for this interface */
2962
		$clone_list = array();
2963
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2964
			$clone_list[] = interface_get_wireless_clone($baseif);
2965
		}
2966
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2967
			foreach ($config['wireless']['clone'] as $clone) {
2968
				if ($clone['if'] == $baseif) {
2969
					$clone_list[] = $clone['cloneif'];
2970
				}
2971
			}
2972
		}
2973

    
2974
		/* find which clones are up and bring them down */
2975
		$clones_up = array();
2976
		foreach ($clone_list as $clone_if) {
2977
			$clone_status = pfSense_get_interface_addresses($clone_if);
2978
			if ($clone_status['status'] == 'up') {
2979
				$clones_up[] = $clone_if;
2980
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2981
			}
2982
		}
2983

    
2984
		/* apply the regulatory settings */
2985
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2986
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2987

    
2988
		/* bring the clones back up that were previously up */
2989
		foreach ($clones_up as $clone_if) {
2990
			interfaces_bring_up($clone_if);
2991

    
2992
			/*
2993
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2994
			 * is in infrastructure mode, and WPA is enabled.
2995
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2996
			 */
2997
			if ($clone_if != $if) {
2998
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2999
				if ((!empty($friendly_if)) &&
3000
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3001
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3002
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3003
				}
3004
			}
3005
		}
3006
	}
3007

    
3008
	/* The mode must be specified in a separate command before ifconfig
3009
	 * will allow the mode and channel at the same time in the next.
3010
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3011
	 */
3012
	if ($wlcfg['mode'] == "hostap") {
3013
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3014
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3015
	}
3016

    
3017
	/* configure wireless */
3018
	$wlcmd_args = implode(" ", $wlcmd);
3019
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3020
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3021
	/* Bring the interface up only after setting up all the other parameters. */
3022
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3023
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3024
	fclose($wlan_setup_log);
3025

    
3026
	unset($wlcmd_args, $wlcmd);
3027

    
3028

    
3029
	sleep(1);
3030
	/* execute hostapd and wpa_supplicant if required in shell */
3031
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3032

    
3033
	return 0;
3034

    
3035
}
3036

    
3037
function kill_hostapd($interface) {
3038
	global $g;
3039

    
3040
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3041
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3042
	}
3043
}
3044

    
3045
function kill_wpasupplicant($interface) {
3046
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3047
}
3048

    
3049
function find_dhclient_process($interface) {
3050
	if ($interface) {
3051
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3052
	} else {
3053
		$pid = 0;
3054
	}
3055

    
3056
	return intval($pid);
3057
}
3058

    
3059
function kill_dhclient_process($interface) {
3060
	if (empty($interface) || !does_interface_exist($interface)) {
3061
		return;
3062
	}
3063

    
3064
	$i = 0;
3065
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3066
		/* 3rd time make it die for sure */
3067
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3068
		posix_kill($pid, $sig);
3069
		sleep(1);
3070
		$i++;
3071
	}
3072
	unset($i);
3073
}
3074

    
3075
function find_dhcp6c_process($interface) {
3076
	global $g;
3077

    
3078
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3079
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3080
	} else {
3081
		return(false);
3082
	}
3083

    
3084
	return intval($pid);
3085
}
3086

    
3087
function kill_dhcp6client_process($interface) {
3088
	if (empty($interface) || !does_interface_exist($interface)) {
3089
		return;
3090
	}
3091

    
3092
	if (($pid = find_dhcp6c_process($interface)) != 0) {
3093
		mwexec("kill -9 {$pid}");
3094
		sleep(1);
3095
	}
3096
}
3097

    
3098
function interface_virtual_create($interface) {
3099
	global $config;
3100

    
3101
	if (strstr($interface, "_vlan")) {
3102
		interfaces_vlan_configure($vlan);
3103
	} else if (substr($interface, 0, 3) == "gre") {
3104
		interfaces_gre_configure(0, $interface);
3105
	} else if (substr($interface, 0, 3) == "gif") {
3106
		interfaces_gif_configure(0, $interface);
3107
	} else if (substr($interface, 0, 5) == "ovpns") {
3108
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3109
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3110
				if ($interface == "ovpns{$server['vpnid']}") {
3111
					if (!function_exists('openvpn_resync')) {
3112
						require_once('openvpn.inc');
3113
					}
3114
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3115
					openvpn_resync('server', $server);
3116
				}
3117
			}
3118
			unset($server);
3119
		}
3120
	} else if (substr($interface, 0, 5) == "ovpnc") {
3121
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3122
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3123
				if ($interface == "ovpnc{$client['vpnid']}") {
3124
					if (!function_exists('openvpn_resync')) {
3125
						require_once('openvpn.inc');
3126
					}
3127
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3128
					openvpn_resync('client', $client);
3129
				}
3130
			}
3131
			unset($client);
3132
		}
3133
	} else if (substr($interface, 0, 4) == "lagg") {
3134
		interfaces_lagg_configure($interface);
3135
	} else if (substr($interface, 0, 6) == "bridge") {
3136
		interfaces_bridge_configure(0, $interface);
3137
	}
3138
}
3139

    
3140
function interface_vlan_mtu_configured($iface) {
3141
	global $config;
3142

    
3143
	$mtu = 0;
3144
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3145
		foreach ($config['vlans']['vlan'] as $vlan) {
3146

    
3147
			if ($vlan['vlanif'] != $iface)
3148
				continue;
3149

    
3150
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3151
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3152
				/* VLAN MTU */
3153
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3154
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3155
				/* Parent MTU */
3156
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3157
			}
3158
		}
3159
	}
3160

    
3161
	return $mtu;
3162
}
3163

    
3164
function interface_mtu_wanted_for_pppoe($realif) {
3165
	global $config;
3166

    
3167
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3168
		return 0;
3169

    
3170
	$mtu = 0;
3171
	foreach ($config['ppps']['ppp'] as $ppp) {
3172
		if ($ppp['type'] != "pppoe") {
3173
			continue;
3174
		}
3175

    
3176
		$mtus = array();
3177
		if (!empty($ppp['mtu'])) {
3178
			$mtus = explode(',', $ppp['mtu']);
3179
		}
3180
		$ports = explode(',', $ppp['ports']);
3181

    
3182
		foreach ($ports as $pid => $port) {
3183
			$parentifa = get_parent_interface($port);
3184
			$parentif = $parentifa[0];
3185
			if ($parentif != $realif)
3186
				continue;
3187

    
3188
			// there is an MTU configured on the port in question
3189
			if (!empty($mtus[$pid])) {
3190
				$mtu = intval($mtus[$pid]) + 8;
3191
			// or use the MTU configured on the interface ...
3192
			} elseif (is_array($config['interfaces'])) {
3193
				foreach ($config['interfaces'] as $interface) {
3194
					if ($interface['if'] == $ppp['if'] &&
3195
					    !empty($interface['mtu'])) {
3196
						$mtu = intval($interface['mtu']) + 8;
3197
						break;
3198
					}
3199
				}
3200
			}
3201
		}
3202
	}
3203

    
3204
	return $mtu;
3205
}
3206

    
3207
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3208
	global $config, $g;
3209
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3210
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3211

    
3212
	$wancfg = $config['interfaces'][$interface];
3213

    
3214
	if (!isset($wancfg['enable'])) {
3215
		return;
3216
	}
3217

    
3218
	$realif = get_real_interface($interface);
3219
	$realhwif_array = get_parent_interface($interface);
3220
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3221
	$realhwif = $realhwif_array[0];
3222

    
3223
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3224
		/* remove all IPv4 and IPv6 addresses */
3225
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3226
		if (is_array($tmpifaces)) {
3227
			foreach ($tmpifaces as $tmpiface) {
3228
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3229
					if (!is_linklocal($tmpiface)) {
3230
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3231
					}
3232
				} else {
3233
					if (is_subnetv4($tmpiface)) {
3234
						$tmpip = explode('/', $tmpiface);
3235
						$tmpip = $tmpip[0];
3236
					} else {
3237
						$tmpip = $tmpiface;
3238
					}
3239
					pfSense_interface_deladdress($realif, $tmpip);
3240
				}
3241
			}
3242
		}
3243

    
3244
		/* only bring down the interface when both v4 and v6 are set to NONE */
3245
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3246
			interface_bring_down($interface);
3247
		}
3248
	}
3249

    
3250
	$interface_to_check = $realif;
3251
	if (interface_isppp_type($interface)) {
3252
		$interface_to_check = $realhwif;
3253
	}
3254

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

    
3260
	/* Disable Accepting router advertisements unless specifically requested */
3261
	if ($g['debug']) {
3262
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3263
	}
3264
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3265

    
3266
	/* wireless configuration? */
3267
	if (is_array($wancfg['wireless'])) {
3268
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3269
	}
3270

    
3271
	/* Get the vendor MAC.  Use source dependent upon whether or not booting. */
3272
	$current_mac = get_interface_mac($realhwif);
3273
	if (platform_booting()) {
3274
		$vendor_mac = $current_mac;
3275
	} else {
3276
		$vendor_mac = get_interface_vendor_mac($realhwif);
3277
	}
3278
	$mac_addr = $wancfg['spoofmac'] ?: $vendor_mac;
3279
	/*
3280
	 * Don't try to reapply the MAC if it's already applied.
3281
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3282
	 * the interface config again, which attempts to apply the MAC again,
3283
	 * which cycles the link again...
3284
	 */
3285
	if (!empty($mac_addr) && ($mac_addr != $current_mac)) {
3286
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3287
			" link " . escapeshellarg($mac_addr));
3288
	} elseif ($current_mac == "ff:ff:ff:ff:ff:ff") {
3289
		/*   this is not a valid mac address.  generate a
3290
		 *   temporary mac address so the machine can get online.
3291
		 */
3292
		echo gettext("Generating new MAC address.");
3293
		$random_mac = generate_random_mac_address();
3294
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3295
			" link " . escapeshellarg($random_mac));
3296
		$wancfg['spoofmac'] = $random_mac;
3297
		write_config();
3298
		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");
3299
	}
3300

    
3301
	/* media */
3302
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3303
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3304
		if ($wancfg['media']) {
3305
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3306
		}
3307
		if ($wancfg['mediaopt']) {
3308
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3309
		}
3310
		mwexec($cmd);
3311
	}
3312

    
3313
	/* Apply hw offloading policies as configured */
3314
	enable_hardware_offloading($interface);
3315

    
3316
	/* invalidate interface/ip/sn cache */
3317
	get_interface_arr(true);
3318
	unset($interface_ip_arr_cache[$realif]);
3319
	unset($interface_sn_arr_cache[$realif]);
3320
	unset($interface_ipv6_arr_cache[$realif]);
3321
	unset($interface_snv6_arr_cache[$realif]);
3322

    
3323
	$tunnelif = substr($realif, 0, 3);
3324

    
3325
	$mtuif = $realif;
3326
	$mtuhwif = $realhwif;
3327

    
3328
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3329
	if (interface_isppp_type($interface)) {
3330
		$mtuif = $realhwif;
3331
		$mtuhwif_array = get_parent_interface($mtuif);
3332
		$mtuhwif = $mtuhwif_array[0];
3333
	}
3334

    
3335
	$wantedmtu = 0;
3336
	if (is_array($config['interfaces'])) {
3337
		foreach ($config['interfaces'] as $tmpinterface) {
3338
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3339
				$wantedmtu = $tmpinterface['mtu'];
3340
				break;
3341
			}
3342
		}
3343
	}
3344

    
3345
	/* MTU is not specified for interface, try the pppoe settings. */
3346
	if ($wantedmtu == 0) {
3347
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3348
	}
3349
	if ($wantedmtu == 0 && stristr($mtuif, "_vlan") && interface_isppp_type($interface)) {
3350
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3351
	}
3352

    
3353
	/* Set the MTU to 1500 if no explicit MTU configured. */
3354
	if ($wantedmtu == 0) {
3355
		$wantedmtu = 1500; /* Default */
3356
	}
3357

    
3358
	if (stristr($mtuif, "_vlan")) {
3359
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3360
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3361
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3362
			if ($wancfg['mtu'] > $parentmtu) {
3363
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3364
			}
3365
		}
3366

    
3367
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3368

    
3369
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3370
			$configuredmtu = $parentmtu;
3371
		if ($configuredmtu != 0)
3372
			$mtu = $configuredmtu;
3373
		else
3374
			$mtu = $wantedmtu;
3375

    
3376
		/* Set the parent MTU. */
3377
		if (get_interface_mtu($mtuhwif) < $mtu)
3378
			set_interface_mtu($mtuhwif, $mtu);
3379
		/* Set the VLAN MTU. */
3380
		if (get_interface_mtu($mtuif) != $mtu)
3381
			set_interface_mtu($mtuif, $mtu);
3382
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3383
		/* LAGG interface must be destroyed and re-created to change MTU */
3384
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3385
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3386
				foreach ($config['laggs']['lagg'] as $lagg) {
3387
					if ($lagg['laggif'] == $mtuif) {
3388
						interface_lagg_configure($lagg);
3389
						break;
3390
					}
3391
				}
3392
			}
3393
		}
3394
	} else {
3395
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3396
			pfSense_interface_mtu($mtuif, $wantedmtu);
3397
		}
3398
	}
3399
	/* XXX: What about gre/gif/.. ? */
3400

    
3401
	if (does_interface_exist($wancfg['if'])) {
3402
		interfaces_bring_up($wancfg['if']);
3403
	}
3404

    
3405
	switch ($wancfg['ipaddr']) {
3406
		case 'dhcp':
3407
			interface_dhcp_configure($interface);
3408
			break;
3409
		case 'pppoe':
3410
		case 'l2tp':
3411
		case 'pptp':
3412
		case 'ppp':
3413
			interface_ppps_configure($interface);
3414
			break;
3415
		default:
3416
			/* XXX: Kludge for now related to #3280 */
3417
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3418
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3419
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3420
				}
3421
			}
3422
			break;
3423
	}
3424

    
3425
	switch ($wancfg['ipaddrv6']) {
3426
		case 'slaac':
3427
		case 'dhcp6':
3428
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
3429
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
3430
			// handles all non-PPP connections with 'dhcp6usev4iface' set
3431
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
3432
				interface_dhcpv6_configure($interface, $wancfg);
3433
			}
3434
			break;
3435
		case '6rd':
3436
			interface_6rd_configure($interface, $wancfg);
3437
			break;
3438
		case '6to4':
3439
			interface_6to4_configure($interface, $wancfg);
3440
			break;
3441
		case 'track6':
3442
			interface_track6_configure($interface, $wancfg, $linkupevent);
3443
			break;
3444
		default:
3445
			/* XXX: Kludge for now related to #3280 */
3446
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3447
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3448
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3449
					// FIXME: Add IPv6 Support to the pfSense module
3450
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3451
				}
3452
			}
3453
			break;
3454
	}
3455

    
3456
	interface_netgraph_needed($interface);
3457

    
3458
	if (!platform_booting()) {
3459
		link_interface_to_vips($interface, "update");
3460

    
3461
		if ($tunnelif != 'gre') {
3462
			unset($gre);
3463
			$gre = link_interface_to_gre($interface);
3464
			if (!empty($gre)) {
3465
				array_walk($gre, 'interface_gre_configure');
3466
			}
3467
		}
3468

    
3469
		if ($tunnelif != 'gif') {
3470
			unset($gif);
3471
			$gif = link_interface_to_gif ($interface);
3472
			if (!empty($gif)) {
3473
				array_walk($gif, 'interface_gif_configure');
3474
			}
3475
		}
3476

    
3477
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3478
			unset($bridgetmp);
3479
			$bridgetmp = link_interface_to_bridge($interface);
3480
			if (!empty($bridgetmp)) {
3481
				interface_bridge_add_member($bridgetmp, $realif);
3482
			}
3483
		}
3484

    
3485
		$grouptmp = link_interface_to_group($interface);
3486
		if (!empty($grouptmp)) {
3487
			array_walk($grouptmp, 'interface_group_add_member');
3488
		}
3489

    
3490
		if ($interface == "lan") {
3491
			/* make new hosts file */
3492
			system_hosts_generate();
3493
		}
3494

    
3495
		if ($reloadall == true) {
3496

    
3497
			/* reconfigure static routes (kernel may have deleted them) */
3498
			system_routing_configure($interface);
3499

    
3500
			/* reload ipsec tunnels */
3501
			send_event("service reload ipsecdns");
3502

    
3503
			if (isset($config['dnsmasq']['enable'])) {
3504
				services_dnsmasq_configure();
3505
			}
3506

    
3507
			if (isset($config['unbound']['enable'])) {
3508
				services_unbound_configure();
3509
			}
3510

    
3511
			/* update dyndns */
3512
			send_event("service reload dyndns {$interface}");
3513

    
3514
			/* reload captive portal */
3515
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3516
				require_once('captiveportal.inc');
3517
			}
3518
			captiveportal_init_rules_byinterface($interface);
3519
		}
3520
	}
3521

    
3522
	interfaces_staticarp_configure($interface);
3523
	return 0;
3524
}
3525

    
3526
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3527
	global $config, $g;
3528

    
3529
	if (!is_array($wancfg)) {
3530
		return;
3531
	}
3532

    
3533
	if (!isset($wancfg['enable'])) {
3534
		return;
3535
	}
3536

    
3537
	/* If the interface is not configured via another, exit */
3538
	if (empty($wancfg['track6-interface'])) {
3539
		return;
3540
	}
3541

    
3542
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3543
	$realif = get_real_interface($interface);
3544
	$linklocal = find_interface_ipv6_ll($realif, true);
3545
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
3546
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3547
	}
3548
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3549
	/* XXX: Probably should remove? */
3550
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3551

    
3552
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3553
	if (!isset($trackcfg['enable'])) {
3554
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
3555
		return;
3556
	}
3557

    
3558
	switch ($trackcfg['ipaddrv6']) {
3559
		case "6to4":
3560
			if ($g['debug']) {
3561
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3562
			}
3563
			interface_track6_6to4_configure($interface, $wancfg);
3564
			break;
3565
		case "6rd":
3566
			if ($g['debug']) {
3567
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3568
			}
3569
			interface_track6_6rd_configure($interface, $wancfg);
3570
			break;
3571
		case "dhcp6":
3572
			if ($linkupevent == true) {
3573
				/*
3574
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
3575
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3576
				 *
3577
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
3578
				 */
3579
				$parentrealif = get_real_interface($wancfg['track6-interface']);
3580
				$pidv6 = find_dhcp6c_process($parentrealif);
3581
				if ($pidv6) {
3582
					posix_kill($pidv6, SIGHUP);
3583
				}
3584
			}
3585
			break;
3586
	}
3587

    
3588
	if ($linkupevent == false && !platform_booting()) {
3589
		if (!function_exists('services_dhcpd_configure')) {
3590
			require_once("services.inc");
3591
		}
3592

    
3593
		/* restart dns servers (defering dhcpd reload) */
3594
		if (isset($config['unbound']['enable'])) {
3595
			services_unbound_configure(false);
3596
		}
3597
		if (isset($config['dnsmasq']['enable'])) {
3598
			services_dnsmasq_configure(false);
3599
		}
3600

    
3601
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
3602
		services_dhcpd_configure("inet6");
3603
	}
3604

    
3605
	return 0;
3606
}
3607

    
3608
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3609
	global $config, $g;
3610
	global $interface_ipv6_arr_cache;
3611
	global $interface_snv6_arr_cache;
3612

    
3613
	if (!is_array($lancfg)) {
3614
		return;
3615
	}
3616

    
3617
	/* If the interface is not configured via another, exit */
3618
	if (empty($lancfg['track6-interface'])) {
3619
		return;
3620
	}
3621

    
3622
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3623
	if (empty($wancfg)) {
3624
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3625
		return;
3626
	}
3627

    
3628
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3629
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3630
		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']));
3631
		return;
3632
	}
3633
	$hexwanv4 = return_hex_ipv4($ip4address);
3634

    
3635
	/* create the long prefix notation for math, save the prefix length */
3636
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3637
	$rd6prefixlen = $rd6prefix[1];
3638
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3639

    
3640
	/* binary presentation of the prefix for all 128 bits. */
3641
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3642

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

    
3648
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3649
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3650
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3651
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3652
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3653
	/* fill the rest out with zeros */
3654
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3655

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

    
3659
	$lanif = get_real_interface($interface);
3660
	$oip = find_interface_ipv6($lanif);
3661
	if (is_ipaddrv6($oip)) {
3662
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3663
	}
3664
	unset($interface_ipv6_arr_cache[$lanif]);
3665
	unset($interface_snv6_arr_cache[$lanif]);
3666
	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));
3667
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3668

    
3669
	return 0;
3670
}
3671

    
3672
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3673
	global $config, $g;
3674
	global $interface_ipv6_arr_cache;
3675
	global $interface_snv6_arr_cache;
3676

    
3677
	if (!is_array($lancfg)) {
3678
		return;
3679
	}
3680

    
3681
	/* If the interface is not configured via another, exit */
3682
	if (empty($lancfg['track6-interface'])) {
3683
		return;
3684
	}
3685

    
3686
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3687
	if (empty($wancfg)) {
3688
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3689
		return;
3690
	}
3691

    
3692
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3693
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3694
		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']));
3695
		return;
3696
	}
3697
	$hexwanv4 = return_hex_ipv4($ip4address);
3698

    
3699
	/* create the long prefix notation for math, save the prefix length */
3700
	$sixto4prefix = "2002::";
3701
	$sixto4prefixlen = 16;
3702
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3703

    
3704
	/* binary presentation of the prefix for all 128 bits. */
3705
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3706

    
3707
	/* just save the left prefix length bits */
3708
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3709
	/* add the v4 address */
3710
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3711
	/* add the custom prefix id */
3712
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3713
	/* fill the rest out with zeros */
3714
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3715

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

    
3719
	$lanif = get_real_interface($interface);
3720
	$oip = find_interface_ipv6($lanif);
3721
	if (is_ipaddrv6($oip)) {
3722
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3723
	}
3724
	unset($interface_ipv6_arr_cache[$lanif]);
3725
	unset($interface_snv6_arr_cache[$lanif]);
3726
	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));
3727
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3728

    
3729
	return 0;
3730
}
3731

    
3732
function interface_6rd_configure($interface = "wan", $wancfg) {
3733
	global $config, $g;
3734

    
3735
	/* because this is a tunnel interface we can only function
3736
	 *	with a public IPv4 address on the interface */
3737

    
3738
	if (!is_array($wancfg)) {
3739
		return;
3740
	}
3741

    
3742
	if (!is_module_loaded('if_stf.ko')) {
3743
		mwexec('/sbin/kldload if_stf.ko');
3744
	}
3745

    
3746
	$wanif = get_real_interface($interface);
3747
	$ip4address = find_interface_ip($wanif);
3748
	if (!is_ipaddrv4($ip4address)) {
3749
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3750
		return false;
3751
	}
3752
	$hexwanv4 = return_hex_ipv4($ip4address);
3753

    
3754
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3755
		$wancfg['prefix-6rd-v4plen'] = 0;
3756
	}
3757

    
3758
	/* create the long prefix notation for math, save the prefix length */
3759
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3760
	$rd6prefixlen = $rd6prefix[1];
3761
	$brgw = explode('.', $wancfg['gateway-6rd']);
3762
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3763
	$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);
3764
	if (strlen($rd6brgw) < 128) {
3765
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3766
	}
3767
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3768
	unset($brgw);
3769
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3770

    
3771
	/* binary presentation of the prefix for all 128 bits. */
3772
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3773

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

    
3781
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3782
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3783

    
3784

    
3785
	/* XXX: need to extend to support variable prefix size for v4 */
3786
	if (!is_module_loaded("if_stf")) {
3787
		mwexec("/sbin/kldload if_stf.ko");
3788
	}
3789
	$stfiface = "{$interface}_stf";
3790
	if (does_interface_exist($stfiface)) {
3791
		pfSense_interface_destroy($stfiface);
3792
	}
3793
	$tmpstfiface = pfSense_interface_create("stf");
3794
	pfSense_interface_rename($tmpstfiface, $stfiface);
3795
	pfSense_interface_flags($stfiface, IFF_LINK2);
3796
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3797
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3798
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3799
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3800
	}
3801
	if ($g['debug']) {
3802
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3803
	}
3804

    
3805
	/* write out a default router file */
3806
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3807
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3808

    
3809
	$ip4gateway = get_interface_gateway($interface);
3810
	if (is_ipaddrv4($ip4gateway)) {
3811
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3812
	}
3813

    
3814
	/* configure dependent interfaces */
3815
	if (!platform_booting()) {
3816
		link_interface_to_track6($interface, "update");
3817
	}
3818

    
3819
	return 0;
3820
}
3821

    
3822
function interface_6to4_configure($interface = "wan", $wancfg) {
3823
	global $config, $g;
3824

    
3825
	/* because this is a tunnel interface we can only function
3826
	 *	with a public IPv4 address on the interface */
3827

    
3828
	if (!is_array($wancfg)) {
3829
		return;
3830
	}
3831

    
3832
	$wanif = get_real_interface($interface);
3833
	$ip4address = find_interface_ip($wanif);
3834
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3835
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3836
		return false;
3837
	}
3838

    
3839
	/* create the long prefix notation for math, save the prefix length */
3840
	$stfprefixlen = 16;
3841
	$stfprefix = Net_IPv6::uncompress("2002::");
3842
	$stfarr = explode(":", $stfprefix);
3843
	$v4prefixlen = "0";
3844

    
3845
	/* we need the hex form of the interface IPv4 address */
3846
	$ip4arr = explode(".", $ip4address);
3847
	$hexwanv4 = "";
3848
	foreach ($ip4arr as $octet) {
3849
		$hexwanv4 .= sprintf("%02x", $octet);
3850
	}
3851

    
3852
	/* we need the hex form of the broker IPv4 address */
3853
	$ip4arr = explode(".", "192.88.99.1");
3854
	$hexbrv4 = "";
3855
	foreach ($ip4arr as $octet) {
3856
		$hexbrv4 .= sprintf("%02x", $octet);
3857
	}
3858

    
3859
	/* binary presentation of the prefix for all 128 bits. */
3860
	$stfprefixbin = "";
3861
	foreach ($stfarr as $element) {
3862
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3863
	}
3864
	/* just save the left prefix length bits */
3865
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3866

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

    
3871
	/* for the local subnet too. */
3872
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3873
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3874

    
3875
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3876
	$stfbrarr = array();
3877
	$stfbrbinarr = array();
3878
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3879
	foreach ($stfbrbinarr as $bin) {
3880
		$stfbrarr[] = dechex(bindec($bin));
3881
	}
3882
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
3883

    
3884
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3885
	$stflanarr = array();
3886
	$stflanbinarr = array();
3887
	$stflanbinarr = str_split($stflanbin, 16);
3888
	foreach ($stflanbinarr as $bin) {
3889
		$stflanarr[] = dechex(bindec($bin));
3890
	}
3891
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
3892
	$stflanarr[7] = 1;
3893
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
3894

    
3895
	/* setup the stf interface */
3896
	if (!is_module_loaded("if_stf")) {
3897
		mwexec("/sbin/kldload if_stf.ko");
3898
	}
3899
	$stfiface = "{$interface}_stf";
3900
	if (does_interface_exist($stfiface)) {
3901
		pfSense_interface_destroy($stfiface);
3902
	}
3903
	$tmpstfiface = pfSense_interface_create("stf");
3904
	pfSense_interface_rename($tmpstfiface, $stfiface);
3905
	pfSense_interface_flags($stfiface, IFF_LINK2);
3906
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3907

    
3908
	if ($g['debug']) {
3909
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3910
	}
3911

    
3912
	/* write out a default router file */
3913
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3914
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3915

    
3916
	$ip4gateway = get_interface_gateway($interface);
3917
	if (is_ipaddrv4($ip4gateway)) {
3918
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3919
	}
3920

    
3921
	if (!platform_booting()) {
3922
		link_interface_to_track6($interface, "update");
3923
	}
3924

    
3925
	return 0;
3926
}
3927

    
3928
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3929
	global $config, $g;
3930

    
3931
	if (!is_array($wancfg)) {
3932
		return;
3933
	}
3934

    
3935
	$wanif = get_real_interface($interface, "inet6");
3936
	$dhcp6cconf = "";
3937

    
3938
	if ($wancfg['adv_dhcp6_config_file_override']) {
3939
		// DHCP6 Config File Override
3940
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3941
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3942
		// DHCP6 Config File Advanced
3943
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3944
	} else {
3945
		// DHCP6 Config File Basic
3946
		$dhcp6cconf .= "interface {$wanif} {\n";
3947

    
3948
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3949
		if ($wancfg['ipaddrv6'] == "slaac") {
3950
			$dhcp6cconf .= "\tinformation-only;\n";
3951
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3952
			$dhcp6cconf .= "\trequest domain-name;\n";
3953
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3954
			$dhcp6cconf .= "};\n";
3955
		} else {
3956
			$trackiflist = array();
3957
			$iflist = link_interface_to_track6($interface);
3958
			foreach ($iflist as $ifname => $ifcfg) {
3959
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3960
					$trackiflist[$ifname] = $ifcfg;
3961
				}
3962
			}
3963

    
3964
			/* skip address request if this is set */
3965
			if (!isset($wancfg['dhcp6prefixonly'])) {
3966
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3967
			}
3968
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3969
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3970
			}
3971

    
3972
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3973
			$dhcp6cconf .= "\trequest domain-name;\n";
3974
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3975
			$dhcp6cconf .= "};\n";
3976

    
3977
			if (!isset($wancfg['dhcp6prefixonly'])) {
3978
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3979
			}
3980

    
3981
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3982
				/* Setup the prefix delegation */
3983
				$dhcp6cconf .= "id-assoc pd 0 {\n";
3984
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3985
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
3986
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
3987
				}
3988
				foreach ($trackiflist as $friendly => $ifcfg) {
3989
					if ($g['debug']) {
3990
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3991
					}
3992
					$realif = get_real_interface($friendly);
3993
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
3994
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
3995
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3996
					$dhcp6cconf .= "\t};\n";
3997
				}
3998
				unset($preflen, $iflist, $ifcfg, $ifname);
3999
				$dhcp6cconf .= "};\n";
4000
			}
4001
			unset($trackiflist);
4002
		}
4003
	}
4004

    
4005
	/* wide-dhcp6c works for now. */
4006
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4007
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4008
		unset($dhcp6cconf);
4009
		return 1;
4010
	}
4011
	unset($dhcp6cconf);
4012

    
4013
	$dhcp6cscript = "#!/bin/sh\n";
4014
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4015
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4016
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4017
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4018
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4019
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4020
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4021
		unset($dhcp6cscript);
4022
		return 1;
4023
	}
4024
	unset($dhcp6cscript);
4025
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4026

    
4027
	$rtsoldscript = "#!/bin/sh\n";
4028
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
4029
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
4030
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
4031
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Received RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
4032

    
4033
	/* non ipoe Process */
4034
	if (!isset($wancfg['dhcp6withoutra'])) {
4035
		$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
4036
		$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4037
		$rtsoldscript .= "\t/bin/sleep 1\n";
4038
		$rtsoldscript .= "fi\n";
4039
	} else {
4040
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
4041
		$rtsoldscript .= "/bin/sleep 1\n";
4042
	}
4043
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4044
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4045

    
4046

    
4047
	/* add the start of dhcp6c to the rtsold script if we are going to wait for ra */
4048
	if (!isset($wancfg['dhcp6withoutra'])) {
4049
		$rtsoldscript .= "/usr/local/sbin/dhcp6c {$debugOption} {$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4050
		$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4051
	}
4052
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4053
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4054
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4055
		unset($rtsoldscript);
4056
		return 1;
4057
	}
4058
	unset($rtsoldscript);
4059
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4060

    
4061
	/* accept router advertisements for this interface */
4062
	log_error("Accept router advertisements on interface {$wanif} ");
4063
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4064

    
4065
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
4066
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4067
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4068
		sleep(2);
4069
	}
4070

    
4071
	/* start dhcp6c here if we don't want to wait for ra */
4072
	if (isset($wancfg['dhcp6withoutra'])) {
4073
		kill_dhcp6client_process($wanif);
4074

    
4075
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} {$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_wan.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}");
4076
		mwexec("/usr/bin/logger -t info 'Starting dhcp6 client for interface wan({$wanif} in DHCP6 without RA mode)'");
4077
	}
4078
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
4079

    
4080
	/* NOTE: will be called from rtsold invoked script
4081
	 * link_interface_to_track6($interface, "update");
4082
	 */
4083

    
4084
	return 0;
4085
}
4086

    
4087
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4088
	global $g;
4089

    
4090
	$send_options = "";
4091
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4092
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4093
		foreach ($options as $option) {
4094
			$send_options .= "\tsend " . trim($option) . ";\n";
4095
		}
4096
	}
4097

    
4098
	$request_options = "";
4099
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4100
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4101
		foreach ($options as $option) {
4102
			$request_options .= "\trequest " . trim($option) . ";\n";
4103
		}
4104
	}
4105

    
4106
	$information_only = "";
4107
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4108
		$information_only = "\tinformation-only;\n";
4109
	}
4110

    
4111
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4112
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4113
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4114
	}
4115

    
4116
	$interface_statement  = "interface";
4117
	$interface_statement .= " {$wanif}";
4118
	$interface_statement .= " {\n";
4119
	$interface_statement .= "$send_options";
4120
	$interface_statement .= "$request_options";
4121
	$interface_statement .= "$information_only";
4122
	$interface_statement .= "$script";
4123
	$interface_statement .= "};\n";
4124

    
4125
	$id_assoc_statement_address = "";
4126
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4127
		$id_assoc_statement_address .= "id-assoc";
4128
		$id_assoc_statement_address .= " na";
4129
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4130
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4131
		}
4132
		$id_assoc_statement_address .= " { ";
4133

    
4134
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4135
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4136
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4137
			$id_assoc_statement_address .= "\n\taddress";
4138
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4139
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4140
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4141
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4142
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4143
			}
4144
			$id_assoc_statement_address .= ";\n";
4145
		}
4146

    
4147
		$id_assoc_statement_address .= "};\n";
4148
	}
4149

    
4150
	$id_assoc_statement_prefix = "";
4151
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4152
		$id_assoc_statement_prefix .= "id-assoc";
4153
		$id_assoc_statement_prefix .= " pd";
4154
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4155
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4156
		}
4157
		$id_assoc_statement_prefix .= " { ";
4158

    
4159
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4160
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4161
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4162
			$id_assoc_statement_prefix .= "\n\tprefix";
4163
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4164
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4165
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4166
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4167
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4168
			}
4169
			$id_assoc_statement_prefix .= ";";
4170
		}
4171
		
4172
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
4173
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4174
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4175
			$id_assoc_statement_prefix .= " {$realif}";
4176
			$id_assoc_statement_prefix .= " {\n";
4177
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4178
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4179
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4180
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4181
			}
4182
			$id_assoc_statement_prefix .= "\t};";
4183
		}
4184

    
4185
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4186
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4187
			$id_assoc_statement_prefix .= "\n";
4188
		}
4189

    
4190
		$id_assoc_statement_prefix .= "};\n";
4191
	}
4192

    
4193
	$authentication_statement = "";
4194
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4195
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4196
		$authentication_statement .= "authentication";
4197
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4198
		$authentication_statement .= " {\n";
4199
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4200
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4201
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4202
		}
4203
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4204
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4205
		}
4206
		$authentication_statement .= "};\n";
4207
	}
4208

    
4209
	$key_info_statement = "";
4210
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4211
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4212
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4213
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4214
		$key_info_statement .= "keyinfo";
4215
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4216
		$key_info_statement .= " {\n";
4217
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4218
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4219
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4220
		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'])) {
4221
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4222
		}
4223
		$key_info_statement .= "};\n";
4224
	}
4225

    
4226
	$dhcp6cconf  = $interface_statement;
4227
	$dhcp6cconf .= $id_assoc_statement_address;
4228
	$dhcp6cconf .= $id_assoc_statement_prefix;
4229
	$dhcp6cconf .= $authentication_statement;
4230
	$dhcp6cconf .= $key_info_statement;
4231

    
4232
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4233

    
4234
	return $dhcp6cconf;
4235
}
4236

    
4237

    
4238
function DHCP6_Config_File_Override($wancfg, $wanif) {
4239

    
4240
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4241

    
4242
	if ($dhcp6cconf === false) {
4243
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4244
		return '';
4245
	} else {
4246
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4247
	}
4248
}
4249

    
4250

    
4251
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4252

    
4253
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4254

    
4255
	return $dhcp6cconf;
4256
}
4257

    
4258

    
4259
function interface_dhcp_configure($interface = "wan") {
4260
	global $config, $g;
4261

    
4262
	$wancfg = $config['interfaces'][$interface];
4263
	$wanif = $wancfg['if'];
4264
	if (empty($wancfg)) {
4265
		$wancfg = array();
4266
	}
4267

    
4268
	/* generate dhclient_wan.conf */
4269
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4270
	if (!$fd) {
4271
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4272
		return 1;
4273
	}
4274

    
4275
	if ($wancfg['dhcphostname']) {
4276
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4277
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4278
	} else {
4279
		$dhclientconf_hostname = "";
4280
	}
4281

    
4282
	$wanif = get_real_interface($interface);
4283
	if (empty($wanif)) {
4284
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4285
		return 0;
4286
	}
4287
	$dhclientconf = "";
4288

    
4289
	$dhclientconf .= <<<EOD
4290
interface "{$wanif}" {
4291
timeout 60;
4292
retry 15;
4293
select-timeout 0;
4294
initial-interval 1;
4295
	{$dhclientconf_hostname}
4296
	script "/sbin/dhclient-script";
4297
EOD;
4298

    
4299
	if (validate_ipv4_list($wancfg['dhcprejectfrom'])) {
4300
		$dhclientconf .= <<<EOD
4301

    
4302
	reject {$wancfg['dhcprejectfrom']};
4303
EOD;
4304
	}
4305
	$dhclientconf .= <<<EOD
4306

    
4307
}
4308

    
4309
EOD;
4310

    
4311
	// DHCP Config File Advanced
4312
	if ($wancfg['adv_dhcp_config_advanced']) {
4313
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4314
	}
4315

    
4316
	if (is_ipaddr($wancfg['alias-address'])) {
4317
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4318
		$dhclientconf .= <<<EOD
4319
alias {
4320
	interface "{$wanif}";
4321
	fixed-address {$wancfg['alias-address']};
4322
	option subnet-mask {$subnetmask};
4323
}
4324

    
4325
EOD;
4326
	}
4327

    
4328
	// DHCP Config File Override
4329
	if ($wancfg['adv_dhcp_config_file_override']) {
4330
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4331
	}
4332

    
4333
	fwrite($fd, $dhclientconf);
4334
	fclose($fd);
4335

    
4336
	/* bring wan interface up before starting dhclient */
4337
	if ($wanif) {
4338
		interfaces_bring_up($wanif);
4339
	} else {
4340
		log_error(sprintf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4341
	}
4342

    
4343
	/* Make sure dhclient is not running */
4344
	kill_dhclient_process($wanif);
4345

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

    
4349
	return 0;
4350
}
4351

    
4352
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4353

    
4354
	$hostname = "";
4355
	if ($wancfg['dhcphostname'] != '') {
4356
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4357
	}
4358

    
4359
	/* DHCP Protocol Timings */
4360
	$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");
4361
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4362
		$pt_variable = "{$Protocol_Timing}";
4363
		${$pt_variable} = "";
4364
		if ($wancfg[$Protocol_Timing] != "") {
4365
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4366
		}
4367
	}
4368

    
4369
	$send_options = "";
4370
	if ($wancfg['adv_dhcp_send_options'] != '') {
4371
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp_send_options']);
4372
		foreach ($options as $option) {
4373
			$send_options .= "\tsend " . trim($option) . ";\n";
4374
		}
4375
	}
4376

    
4377
	$request_options = "";
4378
	if ($wancfg['adv_dhcp_request_options'] != '') {
4379
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4380
	}
4381

    
4382
	$required_options = "";
4383
	if ($wancfg['adv_dhcp_required_options'] != '') {
4384
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4385
	}
4386

    
4387
	$option_modifiers = "";
4388
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4389
		$modifiers = DHCP_Config_Option_Split($wancfg['adv_dhcp_option_modifiers']);
4390
		foreach ($modifiers as $modifier) {
4391
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4392
		}
4393
	}
4394

    
4395
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4396
	$dhclientconf .= "\n";
4397
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4398
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4399
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4400
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4401
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4402
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4403
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4404
	$dhclientconf .= "\n";
4405
	$dhclientconf .= "# DHCP Protocol Options\n";
4406
	$dhclientconf .= "{$hostname}";
4407
	$dhclientconf .= "{$send_options}";
4408
	$dhclientconf .= "{$request_options}";
4409
	$dhclientconf .= "{$required_options}";
4410
	$dhclientconf .= "{$option_modifiers}";
4411
	$dhclientconf .= "\n";
4412
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4413
		$dhclientconf .= "reject {$wancfg['dhcprejectfrom']};\n";
4414
	}
4415
	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4416
	$dhclientconf .= "}\n";
4417

    
4418
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4419

    
4420
	return $dhclientconf;
4421
}
4422

    
4423
function DHCP_Config_Option_Split($option_string) {
4424
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4425
	return $matches ? $matches[0] : [];
4426
}
4427

    
4428
function DHCP_Config_File_Override($wancfg, $wanif) {
4429

    
4430
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4431

    
4432
	if ($dhclientconf === false) {
4433
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading.\n"), $wancfg['adv_dhcp_config_file_override_path']));
4434
		return '';
4435
	} else {
4436
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4437
	}
4438
}
4439

    
4440

    
4441
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4442

    
4443
	/* Apply Interface Substitutions */
4444
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4445

    
4446
	/* Apply Hostname Substitutions */
4447
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4448

    
4449
	/* Arrays of MAC Address Types, Cases, Delimiters */
4450
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4451
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4452
	$various_mac_cases      = array("U", "L");
4453
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4454

    
4455
	/* Apply MAC Address Substitutions */
4456
	foreach ($various_mac_types as $various_mac_type) {
4457
		foreach ($various_mac_cases as $various_mac_case) {
4458
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4459

    
4460
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4461
				if ($res !== false) {
4462

    
4463
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4464
					if ("$various_mac_case" == "U") {
4465
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4466
					}
4467
					if ("$various_mac_case" == "L") {
4468
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4469
					}
4470

    
4471
					if ("$various_mac_type" == "mac_addr_hex") {
4472
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4473
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4474
						$dhcpclientconf_mac_hex = "";
4475
						$delimiter = "";
4476
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4477
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4478
							$delimiter = ":";
4479
						}
4480
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4481
					}
4482

    
4483
					/* MAC Address Delimiter Substitutions */
4484
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4485

    
4486
					/* Apply MAC Address Substitutions */
4487
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4488
				}
4489
			}
4490
		}
4491
	}
4492

    
4493
	return $dhclientconf;
4494
}
4495

    
4496
function interfaces_group_setup() {
4497
	global $config;
4498

    
4499
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4500
		return;
4501
	}
4502

    
4503
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4504
		interface_group_setup($groupar);
4505
	}
4506

    
4507
	return;
4508
}
4509

    
4510
function interface_group_setup(&$groupname /* The parameter is an array */) {
4511
	global $config;
4512

    
4513
	if (!is_array($groupname)) {
4514
		return;
4515
	}
4516
	$members = explode(" ", $groupname['members']);
4517
	foreach ($members as $ifs) {
4518
		$realif = get_real_interface($ifs);
4519
		if ($realif && does_interface_exist($realif)) {
4520
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4521
		}
4522
	}
4523

    
4524
	return;
4525
}
4526

    
4527
function is_interface_group($if) {
4528
	global $config;
4529

    
4530
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4531
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4532
			if ($groupentry['ifname'] === $if) {
4533
				return true;
4534
			}
4535
		}
4536
	}
4537

    
4538
	return false;
4539
}
4540

    
4541
function interface_group_add_member($interface, $groupname) {
4542
	$interface = get_real_interface($interface);
4543
	if (does_interface_exist($interface)) {
4544
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4545
	}
4546
}
4547

    
4548
/* COMPAT Function */
4549
function convert_friendly_interface_to_real_interface_name($interface) {
4550
	return get_real_interface($interface);
4551
}
4552

    
4553
/* COMPAT Function */
4554
function get_real_wan_interface($interface = "wan") {
4555
	return get_real_interface($interface);
4556
}
4557

    
4558
/* COMPAT Function */
4559
function get_current_wan_address($interface = "wan") {
4560
	return get_interface_ip($interface);
4561
}
4562

    
4563
/*
4564
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4565
 */
4566
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4567
	global $config;
4568

    
4569
	/* XXX: For speed reasons reference directly the interface array */
4570
	$ifdescrs = &$config['interfaces'];
4571
	//$ifdescrs = get_configured_interface_list(false, true);
4572

    
4573
	foreach ($ifdescrs as $if => $ifname) {
4574
		if ($if == $interface || $ifname['if'] == $interface) {
4575
			return $if;
4576
		}
4577

    
4578
		if (get_real_interface($if) == $interface) {
4579
			return $if;
4580
		}
4581

    
4582
		if ($checkparent == false) {
4583
			continue;
4584
		}
4585

    
4586
		$int = get_parent_interface($if, true);
4587
		if (is_array($int)) {
4588
			foreach ($int as $iface) {
4589
				if ($iface == $interface) {
4590
					return $if;
4591
				}
4592
			}
4593
		}
4594
	}
4595

    
4596
	if ($interface == "enc0") {
4597
		return 'IPsec';
4598
	}
4599
}
4600

    
4601
/* attempt to resolve interface to friendly descr */
4602
function convert_friendly_interface_to_friendly_descr($interface) {
4603
	global $config;
4604

    
4605
	switch ($interface) {
4606
		case "l2tp":
4607
			$ifdesc = "L2TP";
4608
			break;
4609
		case "pptp":
4610
			$ifdesc = "PPTP";
4611
			break;
4612
		case "pppoe":
4613
			$ifdesc = "PPPoE";
4614
			break;
4615
		case "openvpn":
4616
			$ifdesc = "OpenVPN";
4617
			break;
4618
		case "lo0":
4619
			$ifdesc = "Loopback";
4620
			break;
4621
		case "enc0":
4622
		case "ipsec":
4623
		case "IPsec":
4624
			$ifdesc = "IPsec";
4625
			break;
4626
		default:
4627
			if (isset($config['interfaces'][$interface])) {
4628
				if (empty($config['interfaces'][$interface]['descr'])) {
4629
					$ifdesc = strtoupper($interface);
4630
				} else {
4631
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4632
				}
4633
				break;
4634
			} else if (substr($interface, 0, 4) == '_vip') {
4635
				if (is_array($config['virtualip']['vip'])) {
4636
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
4637
						if ($vip['mode'] == "carp") {
4638
							if ($interface == "_vip{$vip['uniqid']}") {
4639
								return "{$vip['subnet']} - {$vip['descr']}";
4640
							}
4641
						}
4642
					}
4643
				}
4644
			} else if (substr($interface, 0, 5) == '_lloc') {
4645
				return get_interface_linklocal($interface);
4646
			} else {
4647
				/* if list */
4648
				$ifdescrs = get_configured_interface_with_descr(false, true);
4649
				foreach ($ifdescrs as $if => $ifname) {
4650
					if ($if == $interface || $ifname == $interface) {
4651
						return $ifname;
4652
					}
4653
				}
4654
			}
4655
			break;
4656
	}
4657

    
4658
	return $ifdesc;
4659
}
4660

    
4661
function convert_real_interface_to_friendly_descr($interface) {
4662

    
4663
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4664

    
4665
	if (!empty($ifdesc)) {
4666
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4667
	}
4668

    
4669
	return $interface;
4670
}
4671

    
4672
/*
4673
 *  get_parent_interface($interface):
4674
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4675
 *				or virtual interface (i.e. vlan)
4676
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4677
 *			-- returns $interface passed in if $interface parent is not found
4678
 *			-- returns empty array if an invalid interface is passed
4679
 *	(Only handles ppps and vlans now.)
4680
 */
4681
function get_parent_interface($interface, $avoidrecurse = false) {
4682
	global $config;
4683

    
4684
	$parents = array();
4685
	//Check that we got a valid interface passed
4686
	$realif = get_real_interface($interface);
4687
	if ($realif == NULL) {
4688
		return $parents;
4689
	}
4690

    
4691
	// If we got a real interface, find it's friendly assigned name
4692
	if ($interface == $realif && $avoidrecurse == false) {
4693
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4694
	}
4695

    
4696
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4697
		$ifcfg = $config['interfaces'][$interface];
4698
		switch ($ifcfg['ipaddr']) {
4699
			case "ppp":
4700
			case "pppoe":
4701
			case "pptp":
4702
			case "l2tp":
4703
				if (empty($parents)) {
4704
					if (is_array($config['ppps']['ppp'])) {
4705
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4706
							if ($ifcfg['if'] == $ppp['if']) {
4707
								$ports = explode(',', $ppp['ports']);
4708
								foreach ($ports as $pid => $parent_if) {
4709
									$parents[$pid] = get_real_interface($parent_if);
4710
								}
4711
								break;
4712
							}
4713
						}
4714
					}
4715
				}
4716
				break;
4717
			case "dhcp":
4718
			case "static":
4719
			default:
4720
				// Handle _vlans
4721
				if (strpos($realif, '_vlan') !== FALSE) {
4722
					if (is_array($config['vlans']['vlan'])) {
4723
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4724
							if ($ifcfg['if'] == $vlan['vlanif']) {
4725
								$parents[0] = $vlan['if'];
4726
								break;
4727
							}
4728
						}
4729
					}
4730
				}
4731
				break;
4732
		}
4733
	}
4734

    
4735
	if (empty($parents)) {
4736
		// Handle _vlans not assigned to an interface
4737
		if (strpos($realif, '_vlan') !== FALSE) {
4738
			if (is_array($config['vlans']['vlan'])) {
4739
				foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4740
					if ($realif == $vlan['vlanif']) {
4741
						$parents[0] = $vlan['if'];
4742
						break;
4743
					}
4744
				}
4745
			}
4746
		}
4747
	}
4748

    
4749
	if (empty($parents)) {
4750
		$parents[0] = $realif;
4751
	}
4752

    
4753
	return $parents;
4754
}
4755

    
4756
/*
4757
 *  get_parent_physical_interface($interface):
4758
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
4759
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
4760
 */
4761
function get_parent_physical_interface($interface) {
4762
	global $config;
4763

    
4764
	$realif = get_parent_interface($interface);
4765

    
4766
	if (substr($realif[0], 0, 4) == "lagg") {
4767
		foreach ($config['laggs']['lagg'] as $lagg) {
4768
			if ($realif[0] == $lagg['laggif']) {
4769
				return explode(",", $lagg['members']);
4770
			}
4771
		}
4772
	} else {
4773
		return $realif;
4774
	}
4775
}
4776

    
4777
function interface_is_wireless_clone($wlif) {
4778
	if (!stristr($wlif, "_wlan")) {
4779
		return false;
4780
	} else {
4781
		return true;
4782
	}
4783
}
4784

    
4785
function interface_get_wireless_base($wlif) {
4786
	if (!stristr($wlif, "_wlan")) {
4787
		return $wlif;
4788
	} else {
4789
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4790
	}
4791
}
4792

    
4793
function interface_get_wireless_clone($wlif) {
4794
	if (!stristr($wlif, "_wlan")) {
4795
		return $wlif . "_wlan0";
4796
	} else {
4797
		return $wlif;
4798
	}
4799
}
4800

    
4801
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4802
	global $config, $g;
4803

    
4804
	$wanif = NULL;
4805

    
4806
	switch ($interface) {
4807
		case "l2tp":
4808
			$wanif = "l2tp";
4809
			break;
4810
		case "pptp":
4811
			$wanif = "pptp";
4812
			break;
4813
		case "pppoe":
4814
			$wanif = "pppoe";
4815
			break;
4816
		case "openvpn":
4817
			$wanif = "openvpn";
4818
			break;
4819
		case "IPsec":
4820
		case "ipsec":
4821
		case "enc0":
4822
			$wanif = "enc0";
4823
			break;
4824
		case "ppp":
4825
			$wanif = "ppp";
4826
			break;
4827
		default:
4828
			if (substr($interface, 0, 4) == '_vip') {
4829
				$wanif = get_configured_vip_interface($interface);
4830
				if (!empty($wanif)) {
4831
					$wanif = get_real_interface($wanif);
4832
				}
4833
				break;
4834
			} else if (substr($interface, 0, 5) == '_lloc') {
4835
				$interface = substr($interface, 5);
4836
			} else if (strstr($interface, "_vlan") ||
4837
			    does_interface_exist($interface, $flush)) {
4838
				/*
4839
				 * If a real interface was already passed simply
4840
				 * pass the real interface back.  This encourages
4841
				 * the usage of this function in more cases so that
4842
				 * we can combine logic for more flexibility.
4843
				 */
4844
				$wanif = $interface;
4845
				break;
4846
			}
4847

    
4848
			if (empty($config['interfaces'][$interface])) {
4849
				break;
4850
			}
4851

    
4852
			$cfg = &$config['interfaces'][$interface];
4853

    
4854
			if ($family == "inet6") {
4855
				switch ($cfg['ipaddrv6']) {
4856
					case "6rd":
4857
					case "6to4":
4858
						$wanif = "{$interface}_stf";
4859
						break;
4860
					case 'pppoe':
4861
					case 'ppp':
4862
					case 'l2tp':
4863
					case 'pptp':
4864
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4865
							$wanif = interface_get_wireless_clone($cfg['if']);
4866
						} else {
4867
							$wanif = $cfg['if'];
4868
						}
4869
						break;
4870
					default:
4871
						switch ($cfg['ipaddr']) {
4872
							case 'pppoe':
4873
							case 'ppp':
4874
							case 'l2tp':
4875
							case 'pptp':
4876
								if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false) {
4877
									$wanif = $cfg['if'];
4878
								} else {
4879
									$parents = get_parent_interface($interface);
4880
									if (!empty($parents[0])) {
4881
										$wanif = $parents[0];
4882
									} else {
4883
										$wanif = $cfg['if'];
4884
									}
4885
								}
4886
								break;
4887
							default:
4888
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4889
									$wanif = interface_get_wireless_clone($cfg['if']);
4890
								} else {
4891
									$wanif = $cfg['if'];
4892
								}
4893
								break;
4894
						}
4895
						break;
4896
				}
4897
			} else {
4898
				// Wireless cloned NIC support (FreeBSD 8+)
4899
				// interface name format: $parentnic_wlanparentnic#
4900
				// example: ath0_wlan0
4901
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4902
					$wanif = interface_get_wireless_clone($cfg['if']);
4903
				} else {
4904
					$wanif = $cfg['if'];
4905
				}
4906
			}
4907
			break;
4908
	}
4909

    
4910
	return $wanif;
4911
}
4912

    
4913
/* Guess the physical interface by providing a IP address */
4914
function guess_interface_from_ip($ipaddress) {
4915

    
4916
	$family = '';
4917
	if (is_ipaddrv4($ipaddress)) {
4918
		$family = 'inet';
4919
	}
4920
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4921
		$family = 'inet6';
4922
	}
4923

    
4924
	if (empty($family)) {
4925
		return false;
4926
	}
4927

    
4928
	/* create a route table we can search */
4929
	$output = '';
4930
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4931
	$output[0] = trim($output[0], " \n");
4932
	if (!empty($output[0])) {
4933
		return $output[0];
4934
	}
4935

    
4936
	return false;
4937
}
4938

    
4939
/*
4940
 * find_ip_interface($ip): return the interface where an ip is defined
4941
 *   (or if $bits is specified, where an IP within the subnet is defined)
4942
 */
4943
function find_ip_interface($ip, $bits = null) {
4944
	if (!is_ipaddr($ip)) {
4945
		return false;
4946
	}
4947

    
4948
	$isv6ip = is_ipaddrv6($ip);
4949

    
4950
	/* if list */
4951
	$ifdescrs = get_configured_interface_list();
4952

    
4953
	foreach ($ifdescrs as $ifdescr => $ifname) {
4954
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4955
		if (is_null($ifip)) {
4956
			continue;
4957
		}
4958
		if (is_null($bits)) {
4959
			if ($ip == $ifip) {
4960
				$int = get_real_interface($ifname);
4961
				return $int;
4962
			}
4963
		} else {
4964
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4965
				$int = get_real_interface($ifname);
4966
				return $int;
4967
			}
4968
		}
4969
	}
4970

    
4971
	return false;
4972
}
4973

    
4974
/*
4975
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4976
 *   (or if $bits is specified, where an IP within the subnet is found)
4977
 */
4978
function find_virtual_ip_alias($ip, $bits = null) {
4979
	global $config;
4980

    
4981
	if (!is_array($config['virtualip']['vip'])) {
4982
		return false;
4983
	}
4984
	if (!is_ipaddr($ip)) {
4985
		return false;
4986
	}
4987

    
4988
	$isv6ip = is_ipaddrv6($ip);
4989

    
4990
	foreach ($config['virtualip']['vip'] as $vip) {
4991
		if ($vip['mode'] === "ipalias") {
4992
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
4993
				continue;
4994
			}
4995
			if (is_null($bits)) {
4996
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4997
					return $vip;
4998
				}
4999
			} else {
5000
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5001
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5002
					return $vip;
5003
				}
5004
			}
5005
		}
5006
	}
5007
	return false;
5008
}
5009

    
5010
function link_interface_to_track6($int, $action = "") {
5011
	global $config;
5012

    
5013
	if (empty($int)) {
5014
		return;
5015
	}
5016

    
5017
	if (is_array($config['interfaces'])) {
5018
		$list = array();
5019
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5020
			if (!isset($ifcfg['enable'])) {
5021
				continue;
5022
			}
5023
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5024
				if ($action == "update") {
5025
					interface_track6_configure($ifname, $ifcfg);
5026
				} else if ($action == "") {
5027
					$list[$ifname] = $ifcfg;
5028
				}
5029
			}
5030
		}
5031
		return $list;
5032
	}
5033
}
5034

    
5035
function interface_find_child_cfgmtu($realiface) {
5036
	global $config;
5037

    
5038
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5039
	$vlans = link_interface_to_vlans($realiface);
5040
	$qinqs = link_interface_to_qinqs($realiface);
5041
	$bridge = link_interface_to_bridge($realiface);
5042
	if (!empty($interface)) {
5043
		$gifs = link_interface_to_gif($interface);
5044
		$gres = link_interface_to_gre($interface);
5045
	} else {
5046
		$gifs = array();
5047
		$gres = array();
5048
	}
5049

    
5050
	$mtu = 0;
5051
	if (is_array($vlans)) {
5052
		foreach ($vlans as $vlan) {
5053
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5054
			if (empty($ifass)) {
5055
				continue;
5056
			}
5057
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5058
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5059
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5060
				}
5061
			}
5062
		}
5063
	}
5064
	if (is_array($qinqs)) {
5065
		foreach ($qinqs as $qinq) {
5066
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5067
			if (empty($ifass)) {
5068
				continue;
5069
			}
5070
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5071
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5072
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5073
				}
5074
			}
5075
		}
5076
	}
5077
	if (is_array($gifs)) {
5078
		foreach ($gifs as $gif) {
5079
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5080
			if (empty($ifass)) {
5081
				continue;
5082
			}
5083
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5084
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5085
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5086
				}
5087
			}
5088
		}
5089
	}
5090
	if (is_array($gres)) {
5091
		foreach ($gres as $gre) {
5092
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5093
			if (empty($ifass)) {
5094
				continue;
5095
			}
5096
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5097
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5098
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5099
				}
5100
			}
5101
		}
5102
	}
5103
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5104
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5105
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5106
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5107
		}
5108
	}
5109
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5110

    
5111
	return $mtu;
5112
}
5113

    
5114
function link_interface_to_vlans($int, $action = "") {
5115
	global $config;
5116

    
5117
	if (empty($int)) {
5118
		return;
5119
	}
5120

    
5121
	if (is_array($config['vlans']['vlan'])) {
5122
		$ifaces = array();
5123
		foreach ($config['vlans']['vlan'] as $vlan) {
5124
			if ($int == $vlan['if']) {
5125
				if ($action == "update") {
5126
					interfaces_bring_up($int);
5127
				} else {
5128
					$ifaces[$vlan['tag']] = $vlan;
5129
				}
5130
			}
5131
		}
5132
		if (!empty($ifaces)) {
5133
			return $ifaces;
5134
		}
5135
	}
5136
}
5137

    
5138
function link_interface_to_qinqs($int, $action = "") {
5139
	global $config;
5140

    
5141
	if (empty($int)) {
5142
		return;
5143
	}
5144

    
5145
	if (is_array($config['qinqs']['qinqentry'])) {
5146
		$ifaces = array();
5147
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5148
			if ($int == $qinq['if']) {
5149
				if ($action == "update") {
5150
					interfaces_bring_up($int);
5151
				} else {
5152
					$ifaces[$qinq['tag']] = $qinq;
5153
				}
5154
			}
5155
		}
5156
		if (!empty($ifaces)) {
5157
			return $ifaces;
5158
		}
5159
	}
5160
}
5161

    
5162
function link_interface_to_vips($int, $action = "", $vhid = '') {
5163
	global $config;
5164

    
5165
	$updatevips = false;
5166
	if (is_array($config['virtualip']['vip'])) {
5167
		$result = array();
5168
		foreach ($config['virtualip']['vip'] as $vip) {
5169
			if (substr($vip['interface'], 0, 4) == "_vip") {
5170
				$iface = get_configured_vip_interface($vip['interface']);
5171
			} else {
5172
				$iface = $vip['interface'];
5173
			}
5174
			if ($int != $iface) {
5175
				continue;
5176
			}
5177
			if ($action == "update") {
5178
				$updatevips = true;
5179
			} else {
5180
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5181
				    substr($vip['interface'], 0, 4) == "_vip") {
5182
					$result[] = $vip;
5183
				}
5184
			}
5185
		}
5186
		if ($updatevips === true) {
5187
			interfaces_vips_configure($int);
5188
		}
5189
		return $result;
5190
	}
5191

    
5192
	return NULL;
5193
}
5194

    
5195
/****f* interfaces/link_interface_to_bridge
5196
 * NAME
5197
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5198
 * INPUTS
5199
 *   $ip
5200
 * RESULT
5201
 *   bridge[0-99]
5202
 ******/
5203
function link_interface_to_bridge($int) {
5204
	global $config;
5205

    
5206
	if (is_array($config['bridges']['bridged'])) {
5207
		foreach ($config['bridges']['bridged'] as $bridge) {
5208
			if (in_array($int, explode(',', $bridge['members']))) {
5209
				return "{$bridge['bridgeif']}";
5210
			}
5211
		}
5212
	}
5213
}
5214

    
5215
function link_interface_to_group($int) {
5216
	global $config;
5217

    
5218
	$result = array();
5219

    
5220
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5221
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5222
			if (in_array($int, explode(" ", $group['members']))) {
5223
				$result[$group['ifname']] = $int;
5224
			}
5225
		}
5226
	}
5227

    
5228
	return $result;
5229
}
5230

    
5231
function link_interface_to_gre($interface) {
5232
	global $config;
5233

    
5234
	$result = array();
5235

    
5236
	if (is_array($config['gres']['gre'])) {
5237
		foreach ($config['gres']['gre'] as $gre) {
5238
			if ($gre['if'] == $interface) {
5239
				$result[] = $gre;
5240
			}
5241
		}
5242
	}
5243

    
5244
	return $result;
5245
}
5246

    
5247
function link_interface_to_gif($interface) {
5248
	global $config;
5249

    
5250
	$result = array();
5251

    
5252
	if (is_array($config['gifs']['gif'])) {
5253
		foreach ($config['gifs']['gif'] as $gif) {
5254
			if ($gif['if'] == $interface) {
5255
				$result[] = $gif;
5256
			}
5257
		}
5258
	}
5259

    
5260
	return $result;
5261
}
5262

    
5263
/*
5264
 * find_interface_ip($interface): return the interface ip (first found)
5265
 */
5266
function find_interface_ip($interface, $flush = false) {
5267
	global $interface_ip_arr_cache;
5268
	global $interface_sn_arr_cache;
5269

    
5270
	$interface = str_replace("\n", "", $interface);
5271

    
5272
	if (!does_interface_exist($interface)) {
5273
		return;
5274
	}
5275

    
5276
	/* Setup IP cache */
5277
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5278
		$ifinfo = pfSense_get_interface_addresses($interface);
5279
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5280
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5281
	}
5282

    
5283
	return $interface_ip_arr_cache[$interface];
5284
}
5285

    
5286
/*
5287
 * find_interface_ipv6($interface): return the interface ip (first found)
5288
 */
5289
function find_interface_ipv6($interface, $flush = false) {
5290
	global $interface_ipv6_arr_cache;
5291
	global $interface_snv6_arr_cache;
5292
	global $config;
5293

    
5294
	$interface = trim($interface);
5295
	$interface = get_real_interface($interface);
5296

    
5297
	if (!does_interface_exist($interface)) {
5298
		return;
5299
	}
5300

    
5301
	/* Setup IP cache */
5302
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5303
		$ifinfo = pfSense_get_interface_addresses($interface);
5304
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5305
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5306
	}
5307

    
5308
	return $interface_ipv6_arr_cache[$interface];
5309
}
5310

    
5311
/*
5312
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5313
 */
5314
function find_interface_ipv6_ll($interface, $flush = false) {
5315
	global $interface_llv6_arr_cache;
5316
	global $config;
5317

    
5318
	$interface = str_replace("\n", "", $interface);
5319

    
5320
	if (!does_interface_exist($interface)) {
5321
		return;
5322
	}
5323

    
5324
	/* Setup IP cache */
5325
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5326
		$ifinfo = pfSense_getall_interface_addresses($interface);
5327
		foreach ($ifinfo as $line) {
5328
			if (strstr($line, ":")) {
5329
				$parts = explode("/", $line);
5330
				if (is_linklocal($parts[0])) {
5331
					$ifinfo['linklocal'] = $parts[0];
5332
				}
5333
			}
5334
		}
5335
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5336
	}
5337
	return $interface_llv6_arr_cache[$interface];
5338
}
5339

    
5340
function find_interface_subnet($interface, $flush = false) {
5341
	global $interface_sn_arr_cache;
5342
	global $interface_ip_arr_cache;
5343

    
5344
	$interface = str_replace("\n", "", $interface);
5345
	if (does_interface_exist($interface) == false) {
5346
		return;
5347
	}
5348

    
5349
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5350
		$ifinfo = pfSense_get_interface_addresses($interface);
5351
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5352
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5353
	}
5354

    
5355
	return $interface_sn_arr_cache[$interface];
5356
}
5357

    
5358
function find_interface_subnetv6($interface, $flush = false) {
5359
	global $interface_snv6_arr_cache;
5360
	global $interface_ipv6_arr_cache;
5361

    
5362
	$interface = str_replace("\n", "", $interface);
5363
	if (does_interface_exist($interface) == false) {
5364
		return;
5365
	}
5366

    
5367
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5368
		$ifinfo = pfSense_get_interface_addresses($interface);
5369
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5370
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5371
	}
5372

    
5373
	return $interface_snv6_arr_cache[$interface];
5374
}
5375

    
5376
function ip_in_interface_alias_subnet($interface, $ipalias) {
5377
	global $config;
5378

    
5379
	if (empty($interface) || !is_ipaddr($ipalias)) {
5380
		return false;
5381
	}
5382
	if (is_array($config['virtualip']['vip'])) {
5383
		foreach ($config['virtualip']['vip'] as $vip) {
5384
			switch ($vip['mode']) {
5385
				case "ipalias":
5386
					if ($vip['interface'] <> $interface) {
5387
						break;
5388
					}
5389
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5390
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5391
						return true;
5392
					}
5393
					break;
5394
			}
5395
		}
5396
	}
5397

    
5398
	return false;
5399
}
5400

    
5401
function get_possible_listen_ips($include_ipv6_link_local=false) {
5402

    
5403
	$interfaces = get_configured_interface_with_descr();
5404
	foreach ($interfaces as $iface => $ifacename) {
5405
		if ($include_ipv6_link_local) {
5406
			/* This is to avoid going though added ll below */
5407
			if (substr($iface, 0, 5) == '_lloc') {
5408
				continue;
5409
			}
5410
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5411
			if (!empty($llip)) {
5412
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5413
			}
5414
		}
5415
	}
5416
	$viplist = get_configured_vip_list();
5417
	foreach ($viplist as $vip => $address) {
5418
		$interfaces[$vip] = $address;
5419
		if (get_vip_descr($address)) {
5420
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5421
		}
5422
	}
5423

    
5424
	$interfaces['lo0'] = 'Localhost';
5425

    
5426
	return $interfaces;
5427
}
5428

    
5429
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5430
	global $config;
5431

    
5432
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5433
	foreach (array('server', 'client') as $mode) {
5434
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5435
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5436
				if (!isset($setting['disable'])) {
5437
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5438
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5439
				}
5440
			}
5441
		}
5442
	}
5443
	return $sourceips;
5444
}
5445

    
5446
function get_interface_ip($interface = "wan") {
5447

    
5448
	if (substr($interface, 0, 4) == '_vip') {
5449
		return get_configured_vip_ipv4($interface);
5450
	} else if (substr($interface, 0, 5) == '_lloc') {
5451
		/* No link-local address for v4. */
5452
		return null;
5453
	}
5454

    
5455
	$realif = get_failover_interface($interface, 'inet');
5456
	if (!$realif) {
5457
		return null;
5458
	}
5459

    
5460
	if (substr($realif, 0, 4) == '_vip') {
5461
		return get_configured_vip_ipv4($realif);
5462
	} else if (substr($realif, 0, 5) == '_lloc') {
5463
		/* No link-local address for v4. */
5464
		return null;
5465
	}
5466

    
5467
	if (is_array($config['interfaces'][$interface]) &&
5468
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5469
		return ($config['interfaces'][$interface]['ipaddr']);
5470
	}
5471

    
5472
	/*
5473
	 * Beaware that find_interface_ip() is our last option, it will
5474
	 * return the first IP it find on interface, not necessarily the
5475
	 * main IP address.
5476
	 */
5477
	$curip = find_interface_ip($realif);
5478
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5479
		return $curip;
5480
	} else {
5481
		return null;
5482
	}
5483
}
5484

    
5485
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5486
	global $config;
5487

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

    
5494
	$realif = get_failover_interface($interface, 'inet6');
5495
	if (!$realif) {
5496
		return null;
5497
	}
5498

    
5499
	if (substr($realif, 0, 4) == '_vip') {
5500
		return get_configured_vip_ipv6($realif);
5501
	} else if (substr($realif, 0, 5) == '_lloc') {
5502
		return get_interface_linklocal($realif);
5503
	}
5504

    
5505
	if (is_array($config['interfaces'][$interface])) {
5506
		switch ($config['interfaces'][$interface]['ipaddr']) {
5507
			case 'pppoe':
5508
			case 'l2tp':
5509
			case 'pptp':
5510
			case 'ppp':
5511
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5512
					$realif = get_real_interface($interface, 'inet6', false);
5513
				}
5514
				break;
5515
		}
5516
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5517
			return ($config['interfaces'][$interface]['ipaddrv6']);
5518
		}
5519
	}
5520

    
5521
	/*
5522
	 * Beaware that find_interface_ip() is our last option, it will
5523
	 * return the first IP it find on interface, not necessarily the
5524
	 * main IP address.
5525
	 */
5526
	$curip = find_interface_ipv6($realif, $flush);
5527
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5528
		return $curip;
5529
	} else {
5530
		/*
5531
		 * NOTE: On the case when only the prefix is requested,
5532
		 * the communication on WAN will be done over link-local.
5533
		 */
5534
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
5535
			$curip = find_interface_ipv6_ll($realif, $flush);
5536
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5537
				return $curip;
5538
			}
5539
		}
5540
	}
5541
	return null;
5542
}
5543

    
5544
function get_interface_linklocal($interface = "wan") {
5545

    
5546
	$realif = get_failover_interface($interface, 'inet6');
5547
	if (!$realif) {
5548
		return null;
5549
	}
5550

    
5551
	if (substr($interface, 0, 4) == '_vip') {
5552
		$realif = get_real_interface($interface);
5553
	} else if (substr($interface, 0, 5) == '_lloc') {
5554
		$realif = get_real_interface(substr($interface, 5));
5555
	}
5556

    
5557
	$curip = find_interface_ipv6_ll($realif);
5558
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5559
		return $curip;
5560
	} else {
5561
		return null;
5562
	}
5563
}
5564

    
5565
function get_interface_subnet($interface = "wan") {
5566

    
5567
	if (substr($interface, 0, 4) == '_vip') {
5568
		return (get_configured_vip_subnetv4($interface));
5569
	}
5570

    
5571
	$realif = get_real_interface($interface);
5572
	if (!$realif) {
5573
		return (NULL);
5574
	}
5575

    
5576
	$cursn = find_interface_subnet($realif);
5577
	if (!empty($cursn)) {
5578
		return ($cursn);
5579
	}
5580

    
5581
	return (NULL);
5582
}
5583

    
5584
function get_interface_subnetv6($interface = "wan") {
5585

    
5586
	if (substr($interface, 0, 4) == '_vip') {
5587
		return (get_configured_vip_subnetv6($interface));
5588
	} else if (substr($interface, 0, 5) == '_lloc') {
5589
		$interface = substr($interface, 5);
5590
	}
5591

    
5592
	$realif = get_real_interface($interface, 'inet6');
5593
	if (!$realif) {
5594
		return (NULL);
5595
	}
5596

    
5597
	$cursn = find_interface_subnetv6($realif);
5598
	if (!empty($cursn)) {
5599
		return ($cursn);
5600
	}
5601

    
5602
	return (NULL);
5603
}
5604

    
5605
/* return outside interfaces with a gateway */
5606
function get_interfaces_with_gateway() {
5607
	global $config;
5608

    
5609
	$ints = array();
5610

    
5611
	/* loop interfaces, check config for outbound */
5612
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5613
		switch ($ifname['ipaddr']) {
5614
			case "dhcp":
5615
			case "pppoe":
5616
			case "pptp":
5617
			case "l2tp":
5618
			case "ppp":
5619
				$ints[$ifdescr] = $ifdescr;
5620
				break;
5621
			default:
5622
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5623
				    !empty($ifname['gateway'])) {
5624
					$ints[$ifdescr] = $ifdescr;
5625
				}
5626
				break;
5627
		}
5628
	}
5629
	return $ints;
5630
}
5631

    
5632
/* return true if interface has a gateway */
5633
function interface_has_gateway($friendly) {
5634
	global $config;
5635

    
5636
	if (!empty($config['interfaces'][$friendly])) {
5637
		$ifname = &$config['interfaces'][$friendly];
5638
		switch ($ifname['ipaddr']) {
5639
			case "dhcp":
5640
			case "pppoe":
5641
			case "pptp":
5642
			case "l2tp":
5643
			case "ppp":
5644
				return true;
5645
			break;
5646
			default:
5647
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5648
					return true;
5649
				}
5650
				$tunnelif = substr($ifname['if'], 0, 3);
5651
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5652
					if (find_interface_ip($ifname['if'])) {
5653
						return true;
5654
					}
5655
				}
5656
				if (!empty($ifname['gateway'])) {
5657
					return true;
5658
				}
5659
			break;
5660
		}
5661
	}
5662

    
5663
	return false;
5664
}
5665

    
5666
/* return true if interface has a gateway */
5667
function interface_has_gatewayv6($friendly) {
5668
	global $config;
5669

    
5670
	if (!empty($config['interfaces'][$friendly])) {
5671
		$ifname = &$config['interfaces'][$friendly];
5672
		switch ($ifname['ipaddrv6']) {
5673
			case "slaac":
5674
			case "dhcp6":
5675
			case "6to4":
5676
			case "6rd":
5677
				return true;
5678
				break;
5679
			default:
5680
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5681
					return true;
5682
				}
5683
				$tunnelif = substr($ifname['if'], 0, 3);
5684
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5685
					if (find_interface_ipv6($ifname['if'])) {
5686
						return true;
5687
					}
5688
				}
5689
				if (!empty($ifname['gatewayv6'])) {
5690
					return true;
5691
				}
5692
				break;
5693
		}
5694
	}
5695

    
5696
	return false;
5697
}
5698

    
5699
/****f* interfaces/is_altq_capable
5700
 * NAME
5701
 *   is_altq_capable - Test if interface is capable of using ALTQ
5702
 * INPUTS
5703
 *   $int            - string containing interface name
5704
 * RESULT
5705
 *   boolean         - true or false
5706
 ******/
5707

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

    
5722
	$int_family = remove_ifindex($int);
5723

    
5724
	if (in_array($int_family, $capable)) {
5725
		return true;
5726
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5727
		return true;
5728
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5729
		return true;
5730
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5731
		return true;
5732
	} else {
5733
		return false;
5734
	}
5735
}
5736

    
5737
/****f* interfaces/is_interface_wireless
5738
 * NAME
5739
 *   is_interface_wireless - Returns if an interface is wireless
5740
 * RESULT
5741
 *   $tmp       - Returns if an interface is wireless
5742
 ******/
5743
function is_interface_wireless($interface) {
5744
	global $config, $g;
5745

    
5746
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5747
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5748
		if (preg_match($g['wireless_regex'], $interface)) {
5749
			if (isset($config['interfaces'][$friendly])) {
5750
				$config['interfaces'][$friendly]['wireless'] = array();
5751
			}
5752
			return true;
5753
		}
5754
		return false;
5755
	} else {
5756
		return true;
5757
	}
5758
}
5759

    
5760
function get_wireless_modes($interface) {
5761
	/* return wireless modes and channels */
5762
	$wireless_modes = array();
5763

    
5764
	$cloned_interface = get_real_interface($interface);
5765

    
5766
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5767
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5768
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5769
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5770

    
5771
		$interface_channels = "";
5772
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5773
		$interface_channel_count = count($interface_channels);
5774

    
5775
		$c = 0;
5776
		while ($c < $interface_channel_count) {
5777
			$channel_line = explode(",", $interface_channels["$c"]);
5778
			$wireless_mode = trim($channel_line[0]);
5779
			$wireless_channel = trim($channel_line[1]);
5780
			if (trim($wireless_mode) != "") {
5781
				/* if we only have 11g also set 11b channels */
5782
				if ($wireless_mode == "11g") {
5783
					if (!isset($wireless_modes["11b"])) {
5784
						$wireless_modes["11b"] = array();
5785
					}
5786
				} else if ($wireless_mode == "11g ht") {
5787
					if (!isset($wireless_modes["11b"])) {
5788
						$wireless_modes["11b"] = array();
5789
					}
5790
					if (!isset($wireless_modes["11g"])) {
5791
						$wireless_modes["11g"] = array();
5792
					}
5793
					$wireless_mode = "11ng";
5794
				} else if ($wireless_mode == "11a ht") {
5795
					if (!isset($wireless_modes["11a"])) {
5796
						$wireless_modes["11a"] = array();
5797
					}
5798
					$wireless_mode = "11na";
5799
				}
5800
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5801
			}
5802
			$c++;
5803
		}
5804
	}
5805
	return($wireless_modes);
5806
}
5807

    
5808
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5809
function get_wireless_channel_info($interface) {
5810
	$wireless_channels = array();
5811

    
5812
	$cloned_interface = get_real_interface($interface);
5813

    
5814
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5815
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5816
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5817
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5818

    
5819
		$interface_channels = "";
5820
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5821

    
5822
		foreach ($interface_channels as $channel_line) {
5823
			$channel_line = explode(",", $channel_line);
5824
			if (!isset($wireless_channels[$channel_line[0]])) {
5825
				$wireless_channels[$channel_line[0]] = $channel_line;
5826
			}
5827
		}
5828
	}
5829
	return($wireless_channels);
5830
}
5831

    
5832
function set_interface_mtu($interface, $mtu) {
5833

    
5834
	/* LAGG interface must be destroyed and re-created to change MTU */
5835
	if (substr($interface, 0, 4) == 'lagg') {
5836
		if (isset($config['laggs']['lagg']) &&
5837
		    is_array($config['laggs']['lagg'])) {
5838
			foreach ($config['laggs']['lagg'] as $lagg) {
5839
				if ($lagg['laggif'] == $interface) {
5840
					interface_lagg_configure($lagg);
5841
					break;
5842
				}
5843
			}
5844
		}
5845
	} else {
5846
		pfSense_interface_mtu($interface, $mtu);
5847
	}
5848
}
5849

    
5850
/****f* interfaces/get_interface_mtu
5851
 * NAME
5852
 *   get_interface_mtu - Return the mtu of an interface
5853
 * RESULT
5854
 *   $tmp       - Returns the mtu of an interface
5855
 ******/
5856
function get_interface_mtu($interface) {
5857
	$mtu = pfSense_interface_getmtu($interface);
5858
	return $mtu['mtu'];
5859
}
5860

    
5861
function get_interface_mac($interface) {
5862
	$macinfo = pfSense_get_interface_addresses($interface);
5863
	return $macinfo["macaddr"];
5864
}
5865

    
5866
function get_interface_vendor_mac($interface) {
5867
	$macinfo = pfSense_get_interface_addresses($interface);
5868
	return $macinfo["hwaddr"] ?: '';
5869
}
5870

    
5871
/****f* pfsense-utils/generate_random_mac_address
5872
 * NAME
5873
 *   generate_random_mac - generates a random mac address
5874
 * INPUTS
5875
 *   none
5876
 * RESULT
5877
 *   $mac - a random mac address
5878
 ******/
5879
function generate_random_mac_address() {
5880
	$mac = "02";
5881
	for ($x = 0; $x < 5; $x++) {
5882
		$mac .= ":" . dechex(rand(16, 255));
5883
	}
5884
	return $mac;
5885
}
5886

    
5887
/****f* interfaces/is_jumbo_capable
5888
 * NAME
5889
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5890
 * INPUTS
5891
 *   $int             - string containing interface name
5892
 * RESULT
5893
 *   boolean          - true or false
5894
 ******/
5895
function is_jumbo_capable($iface) {
5896
	$iface = trim($iface);
5897
	$capable = pfSense_get_interface_addresses($iface);
5898

    
5899
	if (isset($capable['caps']['vlanmtu'])) {
5900
		return true;
5901
	}
5902

    
5903
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5904
	if (substr($iface, 0, 4) == "lagg") {
5905
		return true;
5906
	}
5907

    
5908
	return false;
5909
}
5910

    
5911
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5912
	global $g;
5913

    
5914
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5915

    
5916
	if (!empty($iface) && !empty($pppif)) {
5917
		$cron_cmd = <<<EOD
5918
#!/bin/sh
5919
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5920
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5921

    
5922
EOD;
5923

    
5924
		@file_put_contents($cron_file, $cron_cmd);
5925
		chmod($cron_file, 0755);
5926
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5927
	} else {
5928
		unlink_if_exists($cron_file);
5929
	}
5930
}
5931

    
5932
function get_interface_default_mtu($type = "ethernet") {
5933
	switch ($type) {
5934
		case "gre":
5935
			return 1476;
5936
			break;
5937
		case "gif":
5938
			return 1280;
5939
			break;
5940
		case "tun":
5941
		case "vlan":
5942
		case "tap":
5943
		case "ethernet":
5944
		default:
5945
			return 1500;
5946
			break;
5947
	}
5948

    
5949
	/* Never reached */
5950
	return 1500;
5951
}
5952

    
5953
function get_vip_descr($ipaddress) {
5954
	global $config;
5955

    
5956
	foreach ($config['virtualip']['vip'] as $vip) {
5957
		if ($vip['subnet'] == $ipaddress) {
5958
			return ($vip['descr']);
5959
		}
5960
	}
5961
	return "";
5962
}
5963

    
5964
function interfaces_staticarp_configure($if) {
5965
	global $config, $g;
5966
	if (isset($config['system']['developerspew'])) {
5967
		$mt = microtime();
5968
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5969
	}
5970

    
5971
	$ifcfg = $config['interfaces'][$if];
5972

    
5973
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5974
		return 0;
5975
	}
5976

    
5977
	/* Enable staticarp, if enabled */
5978
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5979
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5980
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5981
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5982
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5983
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5984
			}
5985
		}
5986
	} else {
5987
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5988
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5989
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5990
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5991
				if (isset($arpent['arp_table_static_entry'])) {
5992
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5993
				}
5994
			}
5995
		}
5996
	}
5997

    
5998
	return 0;
5999
}
6000

    
6001
function get_failover_interface($interface, $family = "all") {
6002
	global $config;
6003

    
6004
	/* shortcut to get_real_interface if we find it in the config */
6005
	if (is_array($config['interfaces'][$interface])) {
6006
		return get_real_interface($interface, $family);
6007
	}
6008

    
6009
	/* compare against gateway groups */
6010
	$a_groups = return_gateway_groups_array();
6011
	if (is_array($a_groups[$interface])) {
6012
		/* we found a gateway group, fetch the interface or vip */
6013
		if (!empty($a_groups[$interface][0]['vip'])) {
6014
			return $a_groups[$interface][0]['vip'];
6015
		} else {
6016
			return $a_groups[$interface][0]['int'];
6017
		}
6018
	}
6019
	/* fall through to get_real_interface */
6020
	/* XXX: Really needed? */
6021
	return get_real_interface($interface, $family);
6022
}
6023

    
6024
/****f* interfaces/interface_has_dhcp
6025
 * NAME
6026
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6027
 * INPUTS
6028
 *   interface or gateway group name
6029
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6030
 * RESULT
6031
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6032
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6033
 ******/
6034
function interface_has_dhcp($interface, $family = 4) {
6035
	global $config;
6036

    
6037
	if ($config['interfaces'][$interface]) {
6038
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6039
			return true;
6040
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6041
			return true;
6042
		} else {
6043
			return false;
6044
		}
6045
	}
6046

    
6047
	if (!is_array($config['gateways']['gateway_group'])) {
6048
		return false;
6049
	}
6050

    
6051
	if ($family == 6) {
6052
		$dhcp_string = "_DHCP6";
6053
	} else {
6054
		$dhcp_string = "_DHCP";
6055
	}
6056

    
6057
	foreach ($config['gateways']['gateway_group'] as $group) {
6058
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6059
			continue;
6060
		}
6061
		foreach ($group['item'] as $item) {
6062
			$item_data = explode("|", $item);
6063
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6064
				return true;
6065
			}
6066
		}
6067
	}
6068

    
6069
	return false;
6070
}
6071

    
6072
function remove_ifindex($ifname) {
6073
	return preg_replace("/[0-9]+$/", "", $ifname);
6074
}
6075

    
6076
?>
(27-27/67)