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
	interface_bridge_configure_ip6linklocal($bridge);
596

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

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

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

    
663
function interface_bridge_configure_advanced($bridge) {
664
	$bridgeif = $bridge['bridgeif'];
665

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

    
723
function interface_bridge_configure_ip6linklocal($bridge) {
724
	$bridgeif = $bridge['bridgeif'];
725

    
726
	$members = explode(',', $bridge['members']);
727
	if (!count($members)) {
728
		return;
729
	}
730

    
731
	$auto_linklocal = isset($bridge['ip6linklocal']);
732
	$bridgeop = $auto_linklocal ? '' : '-';
733
	$memberop = $auto_linklocal ? '-' : '';
734

    
735
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
736
	foreach ($members as $member) {
737
		$realif = get_real_interface($member);
738
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
739
	}
740
}
741

    
742
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
743
	global $config;
744

    
745
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
746
		return;
747
	}
748

    
749
	if ($flagsapplied == false) {
750
		$mtu = get_interface_mtu($bridgeif);
751
		$mtum = get_interface_mtu($interface);
752
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
753
			pfSense_interface_mtu($interface, $mtu);
754
		}
755

    
756
		hardware_offloading_applyflags($interface);
757
		interfaces_bring_up($interface);
758
	}
759

    
760
	pfSense_bridge_add_member($bridgeif, $interface);
761
	if (is_array($config['bridges']['bridged'])) {
762
		foreach ($config['bridges']['bridged'] as $bridge) {
763
			if ($bridgeif == $bridge['bridgeif']) {
764
				interface_bridge_configure_stp($bridge);
765
				interface_bridge_configure_advanced($bridge);
766
			}
767
		}
768
	}
769
}
770

    
771
function interfaces_lagg_configure($realif = "") {
772
	global $config, $g;
773
	if (platform_booting()) {
774
		echo gettext("Configuring LAGG interfaces...");
775
	}
776
	$i = 0;
777
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
778
		foreach ($config['laggs']['lagg'] as $lagg) {
779
			if (empty($lagg['laggif'])) {
780
				$lagg['laggif'] = "lagg{$i}";
781
			}
782
			if (!empty($realif) && $realif != $lagg['laggif']) {
783
				continue;
784
			}
785
			/* XXX: Maybe we should report any errors?! */
786
			interface_lagg_configure($lagg);
787
			$i++;
788
		}
789
	}
790
	if (platform_booting()) {
791
		echo gettext("done.") . "\n";
792
	}
793
}
794

    
795
function interface_lagg_configure($lagg) {
796
	global $config, $g;
797

    
798
	if (!is_array($lagg)) {
799
		return -1;
800
	}
801

    
802
	$members = explode(',', $lagg['members']);
803
	if (!count($members)) {
804
		return -1;
805
	}
806

    
807
	if (platform_booting() || !(empty($lagg['laggif']))) {
808
		pfSense_interface_destroy($lagg['laggif']);
809
		pfSense_interface_create($lagg['laggif']);
810
		$laggif = $lagg['laggif'];
811
	} else {
812
		$laggif = pfSense_interface_create("lagg");
813
	}
814

    
815
	/* Check if MTU was defined for this lagg interface */
816
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
817
	if ($lagg_mtu == 0 &&
818
	    is_array($config['interfaces'])) {
819
		foreach ($config['interfaces'] as $tmpinterface) {
820
			if ($tmpinterface['if'] == $lagg['laggif'] &&
821
			    !empty($tmpinterface['mtu'])) {
822
				$lagg_mtu = $tmpinterface['mtu'];
823
				break;
824
			}
825
		}
826
	}
827

    
828
	/* Just in case anything is not working well */
829
	if ($lagg_mtu == 0) {
830
		$lagg_mtu = 1500;
831
	}
832

    
833
	foreach ($members as $member) {
834
		if (!does_interface_exist($member)) {
835
			continue;
836
		}
837
		/* make sure the parent interface is up */
838
		pfSense_interface_mtu($member, $lagg_mtu);
839
		interfaces_bring_up($member);
840
		hardware_offloading_applyflags($member);
841
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
842
	}
843

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

    
846
	interfaces_bring_up($laggif);
847

    
848
	return $laggif;
849
}
850

    
851
function interfaces_gre_configure($checkparent = 0, $realif = "") {
852
	global $config;
853

    
854
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
855
		foreach ($config['gres']['gre'] as $i => $gre) {
856
			if (empty($gre['greif'])) {
857
				$gre['greif'] = "gre{$i}";
858
			}
859
			if (!empty($realif) && $realif != $gre['greif']) {
860
				continue;
861
			}
862

    
863
			if ($checkparent == 1) {
864
				if (substr($gre['if'], 0, 4) == '_vip') {
865
					continue;
866
				}
867
				if (substr($gre['if'], 0, 5) == '_lloc') {
868
					continue;
869
				}
870
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6") {
871
					continue;
872
				}
873
			} else if ($checkparent == 2) {
874
				if ((substr($gre['if'], 0, 4) != '_vip' && substr($gre['if'], 0, 5) != '_lloc') &&
875
				    (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")) {
876
					continue;
877
				}
878
			}
879
			/* XXX: Maybe we should report any errors?! */
880
			interface_gre_configure($gre);
881
		}
882
	}
883
}
884

    
885
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
886
function interface_gre_configure(&$gre, $grekey = "") {
887
	global $config, $g;
888

    
889
	if (!is_array($gre)) {
890
		return -1;
891
	}
892

    
893
	$realif = get_real_interface($gre['if']);
894
	$realifip = get_interface_ip($gre['if']);
895
	$realifip6 = get_interface_ipv6($gre['if']);
896

    
897
	/* make sure the parent interface is up */
898
	interfaces_bring_up($realif);
899

    
900
	if (platform_booting() || !(empty($gre['greif']))) {
901
		pfSense_interface_destroy($gre['greif']);
902
		pfSense_interface_create($gre['greif']);
903
		$greif = $gre['greif'];
904
	} else {
905
		$greif = pfSense_interface_create("gre");
906
	}
907

    
908
	/* Do not change the order here for more see gre(4) NOTES section. */
909
	if (is_ipaddrv6($gre['remote-addr'])) {
910
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
911
	} else {
912
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
913
	}
914
	if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
915
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
916
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
917
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
918
	} else {
919
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
920
	}
921

    
922
	if ($greif) {
923
		interfaces_bring_up($greif);
924
	} else {
925
		log_error(gettext("Could not bring greif up -- variable not defined."));
926
	}
927

    
928
	if (isset($gre['link1']) && $gre['link1']) {
929
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
930
	}
931
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
932
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
933
	}
934
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
935
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
936
	}
937

    
938
	interfaces_bring_up($greif);
939

    
940
	return $greif;
941
}
942

    
943
function interfaces_gif_configure($checkparent = 0, $realif = "") {
944
	global $config;
945

    
946
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
947
		foreach ($config['gifs']['gif'] as $i => $gif) {
948
			if (empty($gif['gifif'])) {
949
				$gre['gifif'] = "gif{$i}";
950
			}
951
			if (!empty($realif) && $realif != $gif['gifif']) {
952
				continue;
953
			}
954

    
955
			if ($checkparent == 1) {
956
				if (substr($gif['if'], 0, 4) == '_vip') {
957
					continue;
958
				}
959
				if (substr($gif['if'], 0, 5) == '_lloc') {
960
					continue;
961
				}
962
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
963
					continue;
964
				}
965
			}
966
			else if ($checkparent == 2) {
967
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
968
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
969
					continue;
970
				}
971
			}
972
			/* XXX: Maybe we should report any errors?! */
973
			interface_gif_configure($gif);
974
		}
975
	}
976
}
977

    
978
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
979
function interface_gif_configure(&$gif, $gifkey = "") {
980
	global $config, $g;
981

    
982
	if (!is_array($gif)) {
983
		return -1;
984
	}
985

    
986
	$realif = get_real_interface($gif['if']);
987
	$ipaddr = get_interface_ip($gif['if']);
988

    
989
	if (is_ipaddrv4($gif['remote-addr'])) {
990
		if (is_ipaddrv4($ipaddr)) {
991
			$realifip = $ipaddr;
992
		} else {
993
			$realifip = get_interface_ip($gif['if']);
994
		}
995
		$realifgw = get_interface_gateway($gif['if']);
996
	} else if (is_ipaddrv6($gif['remote-addr'])) {
997
		if (is_ipaddrv6($ipaddr)) {
998
			$realifip = $ipaddr;
999
		} else {
1000
			$realifip = get_interface_ipv6($gif['if']);
1001
		}
1002
		$realifgw = get_interface_gateway_v6($gif['if']);
1003
	}
1004
	/* make sure the parent interface is up */
1005
	if ($realif) {
1006
		interfaces_bring_up($realif);
1007
	} else {
1008
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
1009
	}
1010

    
1011
	if (platform_booting() || !(empty($gif['gifif']))) {
1012
		pfSense_interface_destroy($gif['gifif']);
1013
		pfSense_interface_create($gif['gifif']);
1014
		$gifif = $gif['gifif'];
1015
	} else {
1016
		$gifif = pfSense_interface_create("gif");
1017
	}
1018

    
1019
	/* Do not change the order here for more see gif(4) NOTES section. */
1020
	if (is_ipaddrv6($gif['remote-addr'])) {
1021
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1022
	} else {
1023
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1024
	}
1025
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1026
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1027
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1028
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1029
	} else {
1030
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1031
	}
1032
	if (isset($gif['link1'])) {
1033
		pfSense_interface_flags($gifif, IFF_LINK1);
1034
	}
1035
	if (isset($gif['link2'])) {
1036
		pfSense_interface_flags($gifif, IFF_LINK2);
1037
	}
1038
	if ($gifif) {
1039
		interfaces_bring_up($gifif);
1040
		$gifmtu = "";
1041
		$currentgifmtu = get_interface_mtu($gifif);
1042
		foreach ($config['interfaces'] as $tmpinterface) {
1043
			if ($tmpinterface['if'] == $gifif) {
1044
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1045
					$gifmtu = $tmpinterface['mtu'];
1046
				}
1047
			}
1048
		}
1049
		if (is_numericint($gifmtu)) {
1050
			if ($gifmtu != $currentgifmtu) {
1051
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1052
			}
1053
		}
1054
	} else {
1055
		log_error(gettext("could not bring gifif up -- variable not defined"));
1056
	}
1057

    
1058
	if (!platform_booting()) {
1059
		$iflist = get_configured_interface_list();
1060
		foreach ($iflist as $ifname) {
1061
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1062
				if (get_interface_gateway($ifname)) {
1063
					system_routing_configure($ifname);
1064
					break;
1065
				}
1066
				if (get_interface_gateway_v6($ifname)) {
1067
					system_routing_configure($ifname);
1068
					break;
1069
				}
1070
			}
1071
		}
1072
	}
1073

    
1074

    
1075
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1076
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1077
	}
1078
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1079
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1080
	}
1081

    
1082
	if (is_ipaddrv4($realifgw)) {
1083
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1084
	}
1085
	if (is_ipaddrv6($realifgw)) {
1086
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1087
	}
1088

    
1089
	interfaces_bring_up($gifif);
1090

    
1091
	return $gifif;
1092
}
1093

    
1094
function interfaces_configure() {
1095
	global $config, $g;
1096

    
1097
	/* Set up our loopback interface */
1098
	interfaces_loopback_configure();
1099

    
1100
	/* create the unconfigured wireless clones */
1101
	interfaces_create_wireless_clones();
1102

    
1103
	/* set up LAGG virtual interfaces */
1104
	interfaces_lagg_configure();
1105

    
1106
	/* set up VLAN virtual interfaces */
1107
	interfaces_vlan_configure();
1108

    
1109
	interfaces_qinq_configure();
1110

    
1111
	$iflist = get_configured_interface_with_descr();
1112
	$delayed_list = array();
1113
	$bridge_list = array();
1114
	$track6_list = array();
1115

    
1116
	/* This is needed to speedup interfaces on bootup. */
1117
	$reload = false;
1118
	if (!platform_booting()) {
1119
		$reload = true;
1120
	}
1121

    
1122
	foreach ($iflist as $if => $ifname) {
1123
		$realif = $config['interfaces'][$if]['if'];
1124
		if (strstr($realif, "bridge")) {
1125
			$bridge_list[$if] = $ifname;
1126
		} else if (strstr($realif, "gre")) {
1127
			$delayed_list[$if] = $ifname;
1128
		} else if (strstr($realif, "gif")) {
1129
			$delayed_list[$if] = $ifname;
1130
		} else if (strstr($realif, "ovpn")) {
1131
			//echo "Delaying OpenVPN interface configuration...done.\n";
1132
			continue;
1133
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1134
			$track6_list[$if] = $ifname;
1135
		} else {
1136
			if (platform_booting()) {
1137
				printf(gettext("Configuring %s interface..."), $ifname);
1138
			}
1139

    
1140
			if ($g['debug']) {
1141
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1142
			}
1143
			interface_configure($if, $reload);
1144
			if (platform_booting()) {
1145
				echo gettext("done.") . "\n";
1146
			}
1147
		}
1148
	}
1149

    
1150
	/*
1151
	 * NOTE: The following function parameter consists of
1152
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1153
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1154
	 */
1155

    
1156
	/* set up GRE virtual interfaces */
1157
	interfaces_gre_configure(1);
1158

    
1159
	/* set up GIF virtual interfaces */
1160
	interfaces_gif_configure(1);
1161

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

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

    
1173
		interface_configure($if, $reload);
1174

    
1175
		if (platform_booting()) {
1176
			echo gettext("done.") . "\n";
1177
		}
1178
	}
1179

    
1180
	/* bring up vip interfaces */
1181
	interfaces_vips_configure();
1182

    
1183
	/* set up GRE virtual interfaces */
1184
	interfaces_gre_configure(2);
1185

    
1186
	/* set up GIF virtual interfaces */
1187
	interfaces_gif_configure(2);
1188

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

    
1197
		interface_configure($if, $reload);
1198

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

    
1204
	/* set up BRIDGe virtual interfaces */
1205
	interfaces_bridge_configure(2);
1206

    
1207
	foreach ($bridge_list as $if => $ifname) {
1208
		if (platform_booting()) {
1209
			printf(gettext("Configuring %s interface..."), $ifname);
1210
		}
1211
		if ($g['debug']) {
1212
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1213
		}
1214

    
1215
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1216
		// redmine #3997
1217
		interface_reconfigure($if, $reload);
1218
		interfaces_vips_configure($if);
1219

    
1220
		if (platform_booting()) {
1221
			echo gettext("done.") . "\n";
1222
		}
1223
	}
1224

    
1225
	/* configure interface groups */
1226
	interfaces_group_setup();
1227

    
1228
	if (!platform_booting()) {
1229
		/* reconfigure static routes (kernel may have deleted them) */
1230
		system_routing_configure();
1231

    
1232
		/* reload IPsec tunnels */
1233
		vpn_ipsec_configure();
1234

    
1235
		/* restart dns servers (defering dhcpd reload) */
1236
		if (isset($config['dnsmasq']['enable'])) {
1237
			services_dnsmasq_configure(false);
1238
		}
1239
		if (isset($config['unbound']['enable'])) {
1240
			services_unbound_configure(false);
1241
		}
1242

    
1243
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1244
		services_dhcpd_configure();
1245
	}
1246

    
1247
	return 0;
1248
}
1249

    
1250
function interface_reconfigure($interface = "wan", $reloadall = false) {
1251
	interface_bring_down($interface);
1252
	interface_configure($interface, $reloadall);
1253
}
1254

    
1255
function interface_vip_bring_down($vip) {
1256
	global $g;
1257

    
1258
	$vipif = get_real_interface($vip['interface']);
1259
	switch ($vip['mode']) {
1260
		case "proxyarp":
1261
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1262
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1263
			}
1264
			break;
1265
		case "ipalias":
1266
			if (does_interface_exist($vipif)) {
1267
				if (is_ipaddrv6($vip['subnet'])) {
1268
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1269
				} else {
1270
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1271
				}
1272
			}
1273
			break;
1274
		case "carp":
1275
			/* XXX: Is enough to delete ip address? */
1276
			if (does_interface_exist($vipif)) {
1277
				if (is_ipaddrv6($vip['subnet'])) {
1278
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1279
				} else {
1280
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1281
				}
1282
			}
1283
			break;
1284
	}
1285
}
1286

    
1287
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1288
	global $config, $g;
1289

    
1290
	if (!isset($config['interfaces'][$interface])) {
1291
		return;
1292
	}
1293

    
1294
	if ($g['debug']) {
1295
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1296
	}
1297

    
1298
	/*
1299
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1300
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1301
	 * Keep this in mind while doing changes here!
1302
	 */
1303
	if ($ifacecfg === false) {
1304
		$ifcfg = $config['interfaces'][$interface];
1305
		$ppps = $config['ppps']['ppp'];
1306
		$realif = get_real_interface($interface);
1307
		$realifv6 = get_real_interface($interface, "inet6", true);
1308
	} elseif (!is_array($ifacecfg)) {
1309
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1310
		$ifcfg = $config['interfaces'][$interface];
1311
		$ppps = $config['ppps']['ppp'];
1312
		$realif = get_real_interface($interface);
1313
		$realifv6 = get_real_interface($interface, "inet6", true);
1314
	} else {
1315
		$ifcfg = $ifacecfg['ifcfg'];
1316
		$ppps = $ifacecfg['ppps'];
1317
		if (isset($ifacecfg['ifcfg']['realif'])) {
1318
			$realif = $ifacecfg['ifcfg']['realif'];
1319
			/* XXX: Any better way? */
1320
			$realifv6 = $realif;
1321
		} else {
1322
			$realif = get_real_interface($interface);
1323
			$realifv6 = get_real_interface($interface, "inet6", true);
1324
		}
1325
	}
1326

    
1327
	switch ($ifcfg['ipaddr']) {
1328
		case "ppp":
1329
		case "pppoe":
1330
		case "pptp":
1331
		case "l2tp":
1332
			if (is_array($ppps) && count($ppps)) {
1333
				foreach ($ppps as $pppid => $ppp) {
1334
					if ($realif == $ppp['if']) {
1335
						if (isset($ppp['ondemand']) && !$destroy) {
1336
							send_event("interface reconfigure {$interface}");
1337
							break;
1338
						}
1339
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1340
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1341
							sleep(2);
1342
						}
1343
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1344
						break;
1345
					}
1346
				}
1347
			}
1348
			break;
1349
		case "dhcp":
1350
			kill_dhclient_process($realif);
1351
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1352
			if (does_interface_exist("$realif")) {
1353
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1354
				interface_vip_cleanup($interface, "inet4");
1355
				if ($destroy == true) {
1356
					pfSense_interface_flags($realif, -IFF_UP);
1357
				}
1358
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1359
			}
1360
			break;
1361
		default:
1362
			if (does_interface_exist("$realif")) {
1363
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1364
				interface_vip_cleanup($interface, "inet4");
1365
				if ($destroy == true) {
1366
					pfSense_interface_flags($realif, -IFF_UP);
1367
				}
1368
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1369
			}
1370
			break;
1371
	}
1372

    
1373
	$track6 = array();
1374
	switch ($ifcfg['ipaddrv6']) {
1375
		case "slaac":
1376
		case "dhcp6":
1377
			kill_dhcp6client_process($realif);
1378
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1379
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1380
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1381
			if (does_interface_exist($realifv6)) {
1382
				$ip6 = find_interface_ipv6($realifv6);
1383
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1384
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1385
				}
1386
				interface_vip_cleanup($interface, "inet6");
1387
				if ($destroy == true) {
1388
					pfSense_interface_flags($realif, -IFF_UP);
1389
				}
1390
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1391
			}
1392
			$track6 = link_interface_to_track6($interface);
1393
			break;
1394
		case "6rd":
1395
		case "6to4":
1396
			$realif = "{$interface}_stf";
1397
			if (does_interface_exist("$realif")) {
1398
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1399
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1400
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1401
					$destroy = true;
1402
				} else {
1403
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1404
					$ip6 = get_interface_ipv6($interface);
1405
					if (is_ipaddrv6($ip6)) {
1406
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1407
					}
1408
				}
1409
				interface_vip_cleanup($interface, "inet6");
1410
				if ($destroy == true) {
1411
					pfSense_interface_flags($realif, -IFF_UP);
1412
				}
1413
			}
1414
			$track6 = link_interface_to_track6($interface);
1415
			break;
1416
		default:
1417
			if (does_interface_exist("$realif")) {
1418
				$ip6 = get_interface_ipv6($interface);
1419
				if (is_ipaddrv6($ip6)) {
1420
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1421
				}
1422
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1423
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1424
				}
1425
				interface_vip_cleanup($interface, "inet6");
1426
				if ($destroy == true) {
1427
					pfSense_interface_flags($realif, -IFF_UP);
1428
				}
1429
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1430
			}
1431
			$track6 = link_interface_to_track6($interface);
1432
			break;
1433
	}
1434

    
1435
	if (!empty($track6) && is_array($track6)) {
1436
		if (!function_exists('services_dhcpd_configure')) {
1437
			require_once('services.inc');
1438
		}
1439
		/* Bring down radvd and dhcp6 on these interfaces */
1440
		services_dhcpd_configure('inet6', $track6);
1441
	}
1442

    
1443
	$old_router = '';
1444
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1445
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1446
	}
1447

    
1448
	/* remove interface up file if it exists */
1449
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1450
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1451
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1452
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1453
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1454
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1455
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1456

    
1457
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1458
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1459
	if (is_array($ifcfg['wireless'])) {
1460
		kill_hostapd($realif);
1461
		mwexec(kill_wpasupplicant($realif));
1462
	}
1463

    
1464
	if ($destroy == true) {
1465
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1466
			pfSense_interface_destroy($realif);
1467
		}
1468
	}
1469

    
1470
	return;
1471
}
1472

    
1473
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1474
	global $config;
1475
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1476
		unset($config["virtualip_carp_maintenancemode"]);
1477
		write_config("Leave CARP maintenance mode");
1478
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1479
		$config["virtualip_carp_maintenancemode"] = true;
1480
		write_config(gettext("Enter CARP maintenance mode"));
1481
	}
1482

    
1483
	$viparr = &$config['virtualip']['vip'];
1484
	foreach ($viparr as $vip) {
1485
		if ($vip['mode'] == "carp") {
1486
			interface_carp_configure($vip);
1487
		}
1488
	}
1489
}
1490

    
1491
function interface_isppp_type($interface) {
1492
	global $config;
1493

    
1494
	if (!is_array($config['interfaces'][$interface])) {
1495
		return false;
1496
	}
1497

    
1498
	switch ($config['interfaces'][$interface]['ipaddr']) {
1499
		case 'pptp':
1500
		case 'l2tp':
1501
		case 'pppoe':
1502
		case 'ppp':
1503
			return true;
1504
			break;
1505
		default:
1506
			return false;
1507
			break;
1508
	}
1509
}
1510

    
1511
function interfaces_ptpid_used($ptpid) {
1512
	global $config;
1513

    
1514
	if (is_array($config['ppps']['ppp'])) {
1515
		foreach ($config['ppps']['ppp'] as & $settings) {
1516
			if ($ptpid == $settings['ptpid']) {
1517
				return true;
1518
			}
1519
		}
1520
	}
1521

    
1522
	return false;
1523
}
1524

    
1525
function interfaces_ptpid_next() {
1526

    
1527
	$ptpid = 0;
1528
	while (interfaces_ptpid_used($ptpid)) {
1529
		$ptpid++;
1530
	}
1531

    
1532
	return $ptpid;
1533
}
1534

    
1535
function getMPDCRONSettings($pppif) {
1536
	global $config;
1537

    
1538
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1539
	if (is_array($config['cron']['item'])) {
1540
		foreach ($config['cron']['item'] as $i => $item) {
1541
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1542
				return array("ID" => $i, "ITEM" => $item);
1543
			}
1544
		}
1545
	}
1546

    
1547
	return NULL;
1548
}
1549

    
1550
function handle_pppoe_reset($post_array) {
1551
	global $config, $g;
1552

    
1553
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1554
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1555

    
1556
	if (!is_array($config['cron']['item'])) {
1557
		$config['cron']['item'] = array();
1558
	}
1559

    
1560
	$itemhash = getMPDCRONSettings($pppif);
1561

    
1562
	// reset cron items if necessary and return
1563
	if (empty($post_array['pppoe-reset-type'])) {
1564
		if (isset($itemhash)) {
1565
			unset($config['cron']['item'][$itemhash['ID']]);
1566
		}
1567
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1568
		return;
1569
	}
1570

    
1571
	if (empty($itemhash)) {
1572
		$itemhash = array();
1573
	}
1574
	$item = array();
1575
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1576
		$item['minute'] = $post_array['pppoe_resetminute'];
1577
		$item['hour'] = $post_array['pppoe_resethour'];
1578
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1579
			$date = explode("/", $post_array['pppoe_resetdate']);
1580
			$item['mday'] = $date[1];
1581
			$item['month'] = $date[0];
1582
		} else {
1583
			$item['mday'] = "*";
1584
			$item['month'] = "*";
1585
		}
1586
		$item['wday'] = "*";
1587
		$item['who'] = "root";
1588
		$item['command'] = $cron_cmd_file;
1589
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1590
		switch ($post_array['pppoe_pr_preset_val']) {
1591
			case "monthly":
1592
				$item['minute'] = "0";
1593
				$item['hour'] = "0";
1594
				$item['mday'] = "1";
1595
				$item['month'] = "*";
1596
				$item['wday'] = "*";
1597
				break;
1598
			case "weekly":
1599
				$item['minute'] = "0";
1600
				$item['hour'] = "0";
1601
				$item['mday'] = "*";
1602
				$item['month'] = "*";
1603
				$item['wday'] = "0";
1604
				break;
1605
			case "daily":
1606
				$item['minute'] = "0";
1607
				$item['hour'] = "0";
1608
				$item['mday'] = "*";
1609
				$item['month'] = "*";
1610
				$item['wday'] = "*";
1611
				break;
1612
			case "hourly":
1613
				$item['minute'] = "0";
1614
				$item['hour'] = "*";
1615
				$item['mday'] = "*";
1616
				$item['month'] = "*";
1617
				$item['wday'] = "*";
1618
				break;
1619
		} // end switch
1620
		$item['who'] = "root";
1621
		$item['command'] = $cron_cmd_file;
1622
	}
1623
	if (empty($item)) {
1624
		return;
1625
	}
1626
	if (isset($itemhash['ID'])) {
1627
		$config['cron']['item'][$itemhash['ID']] = $item;
1628
	} else {
1629
		$config['cron']['item'][] = $item;
1630
	}
1631
}
1632

    
1633
/*
1634
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1635
 * It writes the mpd config file to /var/etc every time the link is opened.
1636
 */
1637
function interface_ppps_configure($interface) {
1638
	global $config, $g;
1639

    
1640
	/* Return for unassigned interfaces. This is a minimum requirement. */
1641
	if (empty($config['interfaces'][$interface])) {
1642
		return 0;
1643
	}
1644
	$ifcfg = $config['interfaces'][$interface];
1645
	if (!isset($ifcfg['enable'])) {
1646
		return 0;
1647
	}
1648

    
1649
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1650
	if (!is_dir("/var/spool/lock")) {
1651
		mkdir("/var/spool/lock", 0777, true);
1652
	}
1653
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1654
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1655
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1656
	}
1657

    
1658
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1659
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1660
			if ($ifcfg['if'] == $ppp['if']) {
1661
				break;
1662
			}
1663
		}
1664
	}
1665
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
1666
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1667
		return 0;
1668
	}
1669
	$pppif = $ifcfg['if'];
1670
	if ($ppp['type'] == "ppp") {
1671
		$type = "modem";
1672
	} else {
1673
		$type = $ppp['type'];
1674
	}
1675
	$upper_type = strtoupper($ppp['type']);
1676

    
1677
	/* XXX: This does not make sense and may create trouble
1678
	 * comment it for now to be removed later on.
1679
	if (platform_booting()) {
1680
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1681
		echo "starting {$pppif} link...";
1682
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1683
			return 0;
1684
	}
1685
	*/
1686

    
1687
	$ports = explode(',', $ppp['ports']);
1688
	if ($type != "modem") {
1689
		foreach ($ports as $pid => $port) {
1690
			$ports[$pid] = get_real_interface($port);
1691
			if (empty($ports[$pid])) {
1692
				return 0;
1693
			}
1694
		}
1695
	}
1696
	$localips = explode(',', $ppp['localip']);
1697
	$gateways = explode(',', $ppp['gateway']);
1698
	$subnets = explode(',', $ppp['subnet']);
1699

    
1700
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1701
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1702
	 */
1703
	foreach ($ports as $pid => $port) {
1704
		switch ($ppp['type']) {
1705
			case "pppoe":
1706
				/* Bring the parent interface up */
1707
				interfaces_bring_up($port);
1708
				pfSense_ngctl_attach(".", $port);
1709
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1710
				mwexec("/usr/sbin/ngctl msg {$port}: setautosrc 1");
1711
				break;
1712
			case "pptp":
1713
			case "l2tp":
1714
				/* configure interface */
1715
				if (is_ipaddr($localips[$pid])) {
1716
					// Manually configure interface IP/subnet
1717
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1718
					interfaces_bring_up($port);
1719
				} else if (empty($localips[$pid])) {
1720
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1721
				}
1722

    
1723
				if (!is_ipaddr($localips[$pid])) {
1724
					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));
1725
					$localips[$pid] = "0.0.0.0";
1726
				}
1727
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
1728
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1729
				}
1730
				if (!is_ipaddr($gateways[$pid])) {
1731
					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));
1732
					return 0;
1733
				}
1734
				pfSense_ngctl_attach(".", $port);
1735
				break;
1736
			case "ppp":
1737
				if (!file_exists("{$port}")) {
1738
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1739
					return 0;
1740
				}
1741
				break;
1742
			default:
1743
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1744
				break;
1745
		}
1746
	}
1747

    
1748
	if (is_array($ports) && count($ports) > 1) {
1749
		$multilink = "enable";
1750
	} else {
1751
		$multilink = "disable";
1752
	}
1753

    
1754
	if ($type == "modem") {
1755
		if (is_ipaddr($ppp['localip'])) {
1756
			$localip = $ppp['localip'];
1757
		} else {
1758
			$localip = '0.0.0.0';
1759
		}
1760

    
1761
		if (is_ipaddr($ppp['gateway'])) {
1762
			$gateway = $ppp['gateway'];
1763
		} else {
1764
			$gateway = "10.64.64.{$pppid}";
1765
		}
1766
		$ranges = "{$localip}/0 {$gateway}/0";
1767

    
1768
		if (empty($ppp['apnum'])) {
1769
			$ppp['apnum'] = 1;
1770
		}
1771
	} else {
1772
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1773
	}
1774

    
1775
	if (isset($ppp['ondemand'])) {
1776
		$ondemand = "enable";
1777
	} else {
1778
		$ondemand = "disable";
1779
	}
1780
	if (!isset($ppp['idletimeout'])) {
1781
		$ppp['idletimeout'] = 0;
1782
	}
1783

    
1784
	if (empty($ppp['username']) && $type == "modem") {
1785
		$ppp['username'] = "user";
1786
		$ppp['password'] = "none";
1787
	}
1788
	if (empty($ppp['password']) && $type == "modem") {
1789
		$passwd = "none";
1790
	} else {
1791
		$passwd = base64_decode($ppp['password']);
1792
	}
1793

    
1794
	$bandwidths = explode(',', $ppp['bandwidth']);
1795
	$defaultmtu = "1492";
1796
	if (!empty($ifcfg['mtu'])) {
1797
		$defaultmtu = intval($ifcfg['mtu']);
1798
	}
1799
	if (isset($ppp['mtu'])) {
1800
		$mtus = explode(',', $ppp['mtu']);
1801
	}
1802
	if (isset($ppp['mru'])) {
1803
		$mrus = explode(',', $ppp['mru']);
1804
	}
1805
	if (isset($ppp['mrru'])) {
1806
		$mrrus = explode(',', $ppp['mrru']);
1807
	}
1808

    
1809
	// Construct the mpd.conf file
1810
	$mpdconf = <<<EOD
1811
startup:
1812
	# configure the console
1813
	set console close
1814
	# configure the web server
1815
	set web close
1816

    
1817
default:
1818
{$ppp['type']}client:
1819
	create bundle static {$interface}
1820
	set bundle enable ipv6cp
1821
	set iface name {$pppif}
1822

    
1823
EOD;
1824
	$setdefaultgw = false;
1825
	$founddefaultgw = false;
1826
	if (is_array($config['gateways']['gateway_item'])) {
1827
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1828
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1829
				$setdefaultgw = true;
1830
				break;
1831
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1832
				$founddefaultgw = true;
1833
				break;
1834
			}
1835
		}
1836
	}
1837

    
1838
/* Omit this, we maintain the default route by other means, and it causes problems with
1839
 * default gateway switching. See redmine #1837 for original issue
1840
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some 
1841
 * edge case. redmine #6495 open to address. 
1842
 */
1843
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1844
		$setdefaultgw = true;
1845
		$mpdconf .= <<<EOD
1846
	set iface route default
1847

    
1848
EOD;
1849
	}
1850
	$mpdconf .= <<<EOD
1851
	set iface {$ondemand} on-demand
1852
	set iface idle {$ppp['idletimeout']}
1853

    
1854
EOD;
1855

    
1856
	if (isset($ppp['ondemand'])) {
1857
		$mpdconf .= <<<EOD
1858
	set iface addrs 10.10.1.1 10.10.1.2
1859

    
1860
EOD;
1861
	}
1862

    
1863
	if (isset($ppp['tcpmssfix'])) {
1864
		$tcpmss = "disable";
1865
	} else {
1866
		$tcpmss = "enable";
1867
	}
1868
	$mpdconf .= <<<EOD
1869
	set iface {$tcpmss} tcpmssfix
1870

    
1871
EOD;
1872

    
1873
	$mpdconf .= <<<EOD
1874
	set iface up-script /usr/local/sbin/ppp-linkup
1875
	set iface down-script /usr/local/sbin/ppp-linkdown
1876
	set ipcp ranges {$ranges}
1877

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

    
1883
EOD;
1884
	}
1885

    
1886
	if (isset($config['system']['dnsallowoverride'])) {
1887
		$mpdconf .= <<<EOD
1888
	set ipcp enable req-pri-dns
1889
	set ipcp enable req-sec-dns
1890

    
1891
EOD;
1892
	}
1893

    
1894
	if (!isset($ppp['verbose_log'])) {
1895
		$mpdconf .= <<<EOD
1896
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1897

    
1898
EOD;
1899
	}
1900

    
1901
	foreach ($ports as $pid => $port) {
1902
		$port = get_real_interface($port);
1903
		$mpdconf .= <<<EOD
1904

    
1905
	create link static {$interface}_link{$pid} {$type}
1906
	set link action bundle {$interface}
1907
	set link {$multilink} multilink
1908
	set link keep-alive 10 60
1909
	set link max-redial 0
1910

    
1911
EOD;
1912
		if (isset($ppp['shortseq'])) {
1913
			$mpdconf .= <<<EOD
1914
	set link no shortseq
1915

    
1916
EOD;
1917
		}
1918

    
1919
		if (isset($ppp['acfcomp'])) {
1920
			$mpdconf .= <<<EOD
1921
	set link no acfcomp
1922

    
1923
EOD;
1924
		}
1925

    
1926
		if (isset($ppp['protocomp'])) {
1927
			$mpdconf .= <<<EOD
1928
	set link no protocomp
1929

    
1930
EOD;
1931
		}
1932

    
1933
		$mpdconf .= <<<EOD
1934
	set link disable chap pap
1935
	set link accept chap pap eap
1936
	set link disable incoming
1937

    
1938
EOD;
1939

    
1940

    
1941
		if (!empty($bandwidths[$pid])) {
1942
			$mpdconf .= <<<EOD
1943
	set link bandwidth {$bandwidths[$pid]}
1944

    
1945
EOD;
1946
		}
1947

    
1948
		if (empty($mtus[$pid])) {
1949
			$mtus[$pid] = $defaultmtu;
1950
		}
1951
		if ($type == "pppoe") {
1952
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
1953
				$mtus[$pid] = get_interface_mtu($port) - 8;
1954
			}
1955
		}
1956
		if (! ($type == "pppoe" && $mtus[$pid] > 1492) ) {
1957
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
1958
			$mpdconf .= <<<EOD
1959
	set link mtu {$mtus[$pid]}
1960

    
1961
EOD;
1962
		}
1963

    
1964
		if (!empty($mrus[$pid])) {
1965
			$mpdconf .= <<<EOD
1966
	set link mru {$mrus[$pid]}
1967

    
1968
EOD;
1969
		}
1970

    
1971
		if (!empty($mrrus[$pid])) {
1972
			$mpdconf .= <<<EOD
1973
	set link mrru {$mrrus[$pid]}
1974

    
1975
EOD;
1976
		}
1977

    
1978
		$mpdconf .= <<<EOD
1979
	set auth authname "{$ppp['username']}"
1980
	set auth password {$passwd}
1981

    
1982
EOD;
1983
		if ($type == "modem") {
1984
			$mpdconf .= <<<EOD
1985
	set modem device {$ppp['ports']}
1986
	set modem script DialPeer
1987
	set modem idle-script Ringback
1988
	set modem watch -cd
1989
	set modem var \$DialPrefix "DT"
1990
	set modem var \$Telephone "{$ppp['phone']}"
1991

    
1992
EOD;
1993
		}
1994
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1995
			$mpdconf .= <<<EOD
1996
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1997

    
1998
EOD;
1999
		}
2000
		if (isset($ppp['initstr']) && $type == "modem") {
2001
			$initstr = base64_decode($ppp['initstr']);
2002
			$mpdconf .= <<<EOD
2003
	set modem var \$InitString "{$initstr}"
2004

    
2005
EOD;
2006
		}
2007
		if (isset($ppp['simpin']) && $type == "modem") {
2008
			if ($ppp['pin-wait'] == "") {
2009
				$ppp['pin-wait'] = 0;
2010
			}
2011
			$mpdconf .= <<<EOD
2012
	set modem var \$SimPin "{$ppp['simpin']}"
2013
	set modem var \$PinWait "{$ppp['pin-wait']}"
2014

    
2015
EOD;
2016
		}
2017
		if (isset($ppp['apn']) && $type == "modem") {
2018
			$mpdconf .= <<<EOD
2019
	set modem var \$APN "{$ppp['apn']}"
2020
	set modem var \$APNum "{$ppp['apnum']}"
2021

    
2022
EOD;
2023
		}
2024
		if ($type == "pppoe") {
2025
			// Send a null service name if none is set.
2026
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2027
			$mpdconf .= <<<EOD
2028
	set pppoe service "{$provider}"
2029

    
2030
EOD;
2031
		}
2032
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
2033
			$mpdconf .= <<<EOD
2034
	set pppoe max-payload {$mtus[$pid]}
2035

    
2036
EOD;
2037
		}
2038
		if ($type == "pppoe") {
2039
			$mpdconf .= <<<EOD
2040
	set pppoe iface {$port}
2041

    
2042
EOD;
2043
		}
2044

    
2045
		if ($type == "pptp" || $type == "l2tp") {
2046
			$mpdconf .= <<<EOD
2047
	set {$type} self {$localips[$pid]}
2048
	set {$type} peer {$gateways[$pid]}
2049

    
2050
EOD;
2051
		}
2052

    
2053
		$mpdconf .= "\topen\n";
2054
	} //end foreach ($port)
2055

    
2056

    
2057
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2058
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2059
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2060
	} else {
2061
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2062
		if (!$fd) {
2063
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2064
			return 0;
2065
		}
2066
		// Write out mpd_ppp.conf
2067
		fwrite($fd, $mpdconf);
2068
		fclose($fd);
2069
		unset($mpdconf);
2070
	}
2071

    
2072
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2073
	if (isset($ppp['uptime'])) {
2074
		if (!file_exists("/conf/{$pppif}.log")) {
2075
			conf_mount_rw();
2076
			file_put_contents("/conf/{$pppif}.log", '');
2077
			conf_mount_ro();
2078
		}
2079
	} else {
2080
		if (file_exists("/conf/{$pppif}.log")) {
2081
			conf_mount_rw();
2082
			@unlink("/conf/{$pppif}.log");
2083
			conf_mount_ro();
2084
		}
2085
	}
2086

    
2087
	/* clean up old lock files */
2088
	foreach ($ports as $port) {
2089
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2090
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2091
		}
2092
	}
2093

    
2094
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2095
	/* random IPv6 interface identifier during boot. More details at */
2096
	/* https://forum.pfsense.org/index.php?topic=101967.msg570519#msg570519 */
2097
	if (platform_booting() && is_array($config['interfaces'])) {
2098
		$count = 0;
2099
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2100
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2101
				$tempaddr[$count]['if'] = $tempiface['if'];
2102
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2103
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2104
				$count++;
2105
			}
2106
			// Maximum /31 is is x.y.z.254/31
2107
			if ($count > 122) {
2108
				break;
2109
			}
2110
		}
2111
		unset($count);
2112
	}
2113

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

    
2119
	// Check for PPPoE periodic reset request
2120
	if ($type == "pppoe") {
2121
		if (!empty($ppp['pppoe-reset-type'])) {
2122
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2123
		} else {
2124
			interface_setup_pppoe_reset_file($ppp['if']);
2125
		}
2126
	}
2127
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
2128
	$i = 0;
2129
	while ($i < 3) {
2130
		sleep(10);
2131
		if (does_interface_exist($ppp['if'], true)) {
2132
			break;
2133
		}
2134
		$i++;
2135
	}
2136

    
2137
	/* Remove all temporary bogon IPv4 addresses */
2138
	if (is_array($tempaddr)) {
2139
		foreach ($tempaddr as $tempiface) {
2140
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2141
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2142
			}
2143
		}
2144
		unset ($tempaddr);
2145
	}
2146

    
2147
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2148
	/* We should be able to launch the right version for each modem */
2149
	/* We can also guess the mondev from the manufacturer */
2150
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2151
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2152
	foreach ($ports as $port) {
2153
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2154
			$mondev = substr(basename($port), 0, -1);
2155
			$devlist = glob("/dev/{$mondev}?");
2156
			$mondev = basename(end($devlist));
2157
		}
2158
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2159
			$mondev = substr(basename($port), 0, -1) . "1";
2160
		}
2161
		if ($mondev != '') {
2162
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2163
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2164
		}
2165
	}
2166

    
2167
	return 1;
2168
}
2169

    
2170
function interfaces_sync_setup() {
2171
	global $g, $config;
2172

    
2173
	if (isset($config['system']['developerspew'])) {
2174
		$mt = microtime();
2175
		echo "interfaces_sync_setup() being called $mt\n";
2176
	}
2177

    
2178
	if (platform_booting()) {
2179
		echo gettext("Configuring CARP settings...");
2180
		mute_kernel_msgs();
2181
	}
2182

    
2183
	/* suck in configuration items */
2184
	if ($config['hasync']) {
2185
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2186
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2187
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2188
	} else {
2189
		unset($pfsyncinterface);
2190
		unset($pfsyncenabled);
2191
	}
2192

    
2193
	set_sysctl(array(
2194
		"net.inet.carp.preempt" => "1",
2195
		"net.inet.carp.log" => "1")
2196
	);
2197

    
2198
	if (!empty($pfsyncinterface)) {
2199
		$carp_sync_int = get_real_interface($pfsyncinterface);
2200
	} else {
2201
		unset($carp_sync_int);
2202
	}
2203

    
2204
	/* setup pfsync interface */
2205
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2206
		if (is_ipaddr($pfsyncpeerip)) {
2207
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2208
		} else {
2209
			$syncpeer = "-syncpeer";
2210
		}
2211

    
2212
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2213
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2214

    
2215
		sleep(1);
2216

    
2217
		/* 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
2218
		 * for existing sessions.
2219
		 */
2220
		log_error(gettext("waiting for pfsync..."));
2221
		$i = 0;
2222
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2223
			$i++;
2224
			sleep(1);
2225
		}
2226
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2227
		log_error(gettext("Configuring CARP settings finalize..."));
2228
	} else {
2229
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2230
	}
2231

    
2232
	$carplist = get_configured_vip_list('all', VIP_CARP);
2233
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2234
		set_single_sysctl("net.inet.carp.allow", "1");
2235
	} else {
2236
		set_single_sysctl("net.inet.carp.allow", "0");
2237
	}
2238

    
2239
	if (platform_booting()) {
2240
		unmute_kernel_msgs();
2241
		echo gettext("done.") . "\n";
2242
	}
2243
}
2244

    
2245
function interface_proxyarp_configure($interface = "") {
2246
	global $config, $g;
2247
	if (isset($config['system']['developerspew'])) {
2248
		$mt = microtime();
2249
		echo "interface_proxyarp_configure() being called $mt\n";
2250
	}
2251

    
2252
	/* kill any running choparp */
2253
	if (empty($interface)) {
2254
		killbyname("choparp");
2255
	} else {
2256
		$vipif = get_real_interface($interface);
2257
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2258
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2259
		}
2260
	}
2261

    
2262
	$paa = array();
2263
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2264

    
2265
		/* group by interface */
2266
		foreach ($config['virtualip']['vip'] as $vipent) {
2267
			if ($vipent['mode'] === "proxyarp") {
2268
				if ($vipent['interface']) {
2269
					$proxyif = $vipent['interface'];
2270
				} else {
2271
					$proxyif = "wan";
2272
				}
2273

    
2274
				if (!empty($interface) && $interface != $proxyif) {
2275
					continue;
2276
				}
2277

    
2278
				if (!is_array($paa[$proxyif])) {
2279
					$paa[$proxyif] = array();
2280
				}
2281

    
2282
				$paa[$proxyif][] = $vipent;
2283
			}
2284
		}
2285
	}
2286

    
2287
	if (!empty($interface)) {
2288
		if (is_array($paa[$interface])) {
2289
			$paaifip = get_interface_ip($interface);
2290
			if (!is_ipaddr($paaifip)) {
2291
				return;
2292
			}
2293
			$vipif = get_real_interface($interface);
2294
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2295
			$args .= $vipif . " auto";
2296
			foreach ($paa[$interface] as $paent) {
2297
				if (isset($paent['subnet'])) {
2298
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2299
				} else if (isset($paent['range'])) {
2300
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2301
				}
2302
			}
2303
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2304
		}
2305
	} else if (count($paa) > 0) {
2306
		foreach ($paa as $paif => $paents) {
2307
			$paaifip = get_interface_ip($paif);
2308
			if (!is_ipaddr($paaifip)) {
2309
				continue;
2310
			}
2311
			$vipif = get_real_interface($paif);
2312
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2313
			$args .= $vipif . " auto";
2314
			foreach ($paents as $paent) {
2315
				if (isset($paent['subnet'])) {
2316
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2317
				} else if (isset($paent['range'])) {
2318
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2319
				}
2320
			}
2321
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2322
		}
2323
	}
2324
}
2325

    
2326
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2327
	global $g, $config;
2328

    
2329
	if (is_array($config['virtualip']['vip'])) {
2330
		foreach ($config['virtualip']['vip'] as $vip) {
2331

    
2332
			$iface = $vip['interface'];
2333
			if (substr($iface, 0, 4) == "_vip")
2334
				$iface = get_configured_vip_interface($vip['interface']);
2335
			if ($iface != $interface)
2336
				continue;
2337
			if ($type == VIP_CARP) {
2338
				if ($vip['mode'] != "carp")
2339
					continue;
2340
			} elseif ($type == VIP_IPALIAS) {
2341
				if ($vip['mode'] != "ipalias")
2342
					continue;
2343
			} else {
2344
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2345
					continue;
2346
			}
2347

    
2348
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2349
				interface_vip_bring_down($vip);
2350
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2351
				interface_vip_bring_down($vip);
2352
			else if ($inet == "all")
2353
				interface_vip_bring_down($vip);
2354
		}
2355
	}
2356
}
2357

    
2358
function interfaces_vips_configure($interface = "") {
2359
	global $g, $config;
2360
	if (isset($config['system']['developerspew'])) {
2361
		$mt = microtime();
2362
		echo "interfaces_vips_configure() being called $mt\n";
2363
	}
2364
	$paa = array();
2365
	if (is_array($config['virtualip']['vip'])) {
2366
		$carp_setuped = false;
2367
		$anyproxyarp = false;
2368
		foreach ($config['virtualip']['vip'] as $vip) {
2369
			switch ($vip['mode']) {
2370
				case "proxyarp":
2371
					/* nothing it is handled on interface_proxyarp_configure() */
2372
					if ($interface <> "" && $vip['interface'] <> $interface) {
2373
						continue;
2374
					}
2375
					$anyproxyarp = true;
2376
					break;
2377
				case "ipalias":
2378
					$iface = $vip['interface'];
2379
					if (substr($iface, 0, 4) == "_vip")
2380
						$iface = get_configured_vip_interface($vip['interface']);
2381
					if ($interface <> "" && $iface <> $interface) {
2382
						continue;
2383
					}
2384
					interface_ipalias_configure($vip);
2385
					break;
2386
				case "carp":
2387
					if ($interface <> "" && $vip['interface'] <> $interface) {
2388
						continue;
2389
					}
2390
					if ($carp_setuped == false) {
2391
						$carp_setuped = true;
2392
					}
2393
					interface_carp_configure($vip);
2394
					break;
2395
			}
2396
		}
2397
		if ($carp_setuped == true) {
2398
			interfaces_sync_setup();
2399
		}
2400
		if ($anyproxyarp == true) {
2401
			interface_proxyarp_configure();
2402
		}
2403
	}
2404
}
2405

    
2406
function interface_ipalias_configure(&$vip) {
2407
	global $config;
2408

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

    
2413
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2414
	if ($realif != "lo0") {
2415
		$if = convert_real_interface_to_friendly_interface_name($realif);
2416
		if (!isset($config['interfaces'][$if])) {
2417
			return;
2418
		}
2419

    
2420
		if (!isset($config['interfaces'][$if]['enable'])) {
2421
			return;
2422
		}
2423
	}
2424

    
2425
	$af = 'inet';
2426
	if (is_ipaddrv6($vip['subnet'])) {
2427
		$af = 'inet6';
2428
	}
2429
	$iface = $vip['interface'];
2430
	$vhid = '';
2431
	if (substr($vip['interface'], 0, 4) == "_vip") {
2432
		$carpvip = get_configured_vip($vip['interface']);
2433
		$iface = $carpvip['interface'];
2434
		$vhid = "vhid {$carpvip['vhid']}";
2435
	}
2436
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2437
	unset($iface, $af, $realif, $carpvip, $vhid);
2438
}
2439

    
2440
function interface_carp_configure(&$vip) {
2441
	global $config, $g;
2442
	if (isset($config['system']['developerspew'])) {
2443
		$mt = microtime();
2444
		echo "interface_carp_configure() being called $mt\n";
2445
	}
2446

    
2447
	if ($vip['mode'] != "carp") {
2448
		return;
2449
	}
2450

    
2451
	/* NOTE: Maybe its useless nowadays */
2452
	$realif = get_real_interface($vip['interface']);
2453
	if (!does_interface_exist($realif)) {
2454
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2455
		return;
2456
	}
2457

    
2458
	$vip_password = $vip['password'];
2459
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2460
	if ($vip['password'] != "") {
2461
		$password = " pass {$vip_password}";
2462
	}
2463

    
2464
	$advbase = "";
2465
	if (!empty($vip['advbase'])) {
2466
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2467
	}
2468

    
2469
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2470
	if ($carp_maintenancemode) {
2471
		$advskew = "advskew 254";
2472
	} else {
2473
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2474
	}
2475

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

    
2478
	if (is_ipaddrv4($vip['subnet'])) {
2479
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2480
	} else if (is_ipaddrv6($vip['subnet'])) {
2481
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2482
	}
2483

    
2484
	return $realif;
2485
}
2486

    
2487
function interface_wireless_clone($realif, $wlcfg) {
2488
	global $config, $g;
2489
	/*   Check to see if interface has been cloned as of yet.
2490
	 *   If it has not been cloned then go ahead and clone it.
2491
	 */
2492
	$needs_clone = false;
2493
	if (is_array($wlcfg['wireless'])) {
2494
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2495
	} else {
2496
		$wlcfg_mode = $wlcfg['mode'];
2497
	}
2498
	switch ($wlcfg_mode) {
2499
		case "hostap":
2500
			$mode = "wlanmode hostap";
2501
			break;
2502
		case "adhoc":
2503
			$mode = "wlanmode adhoc";
2504
			break;
2505
		default:
2506
			$mode = "";
2507
			break;
2508
	}
2509
	$baseif = interface_get_wireless_base($wlcfg['if']);
2510
	if (does_interface_exist($realif)) {
2511
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2512
		$ifconfig_str = implode($output);
2513
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2514
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2515
			$needs_clone = true;
2516
		}
2517
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2518
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2519
			$needs_clone = true;
2520
		}
2521
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2522
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2523
			$needs_clone = true;
2524
		}
2525
	} else {
2526
		$needs_clone = true;
2527
	}
2528

    
2529
	if ($needs_clone == true) {
2530
		/* remove previous instance if it exists */
2531
		if (does_interface_exist($realif)) {
2532
			pfSense_interface_destroy($realif);
2533
		}
2534

    
2535
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2536
		// Create the new wlan interface. FreeBSD returns the new interface name.
2537
		// example:  wlan2
2538
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2539
		if ($ret <> 0) {
2540
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2541
			return false;
2542
		}
2543
		$newif = trim($out[0]);
2544
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2545
		pfSense_interface_rename($newif, $realif);
2546
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2547
	}
2548
	return true;
2549
}
2550

    
2551
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2552
	global $config, $g;
2553

    
2554
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2555
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2556
				 'regdomain', 'regcountry', 'reglocation');
2557

    
2558
	if (!is_interface_wireless($ifcfg['if'])) {
2559
		return;
2560
	}
2561

    
2562
	$baseif = interface_get_wireless_base($ifcfg['if']);
2563

    
2564
	// Sync shared settings for assigned clones
2565
	$iflist = get_configured_interface_list(false, true);
2566
	foreach ($iflist as $if) {
2567
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2568
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2569
				foreach ($shared_settings as $setting) {
2570
					if ($sync_changes) {
2571
						if (isset($ifcfg['wireless'][$setting])) {
2572
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2573
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2574
							unset($config['interfaces'][$if]['wireless'][$setting]);
2575
						}
2576
					} else {
2577
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2578
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2579
						} else if (isset($ifcfg['wireless'][$setting])) {
2580
							unset($ifcfg['wireless'][$setting]);
2581
						}
2582
					}
2583
				}
2584
				if (!$sync_changes) {
2585
					break;
2586
				}
2587
			}
2588
		}
2589
	}
2590

    
2591
	// Read or write settings at shared area
2592
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2593
		foreach ($shared_settings as $setting) {
2594
			if ($sync_changes) {
2595
				if (isset($ifcfg['wireless'][$setting])) {
2596
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2597
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2598
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2599
				}
2600
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2601
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2602
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2603
				} else if (isset($ifcfg['wireless'][$setting])) {
2604
					unset($ifcfg['wireless'][$setting]);
2605
				}
2606
			}
2607
		}
2608
	}
2609

    
2610
	// Sync the mode on the clone creation page with the configured mode on the interface
2611
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2612
		foreach ($config['wireless']['clone'] as &$clone) {
2613
			if ($clone['cloneif'] == $ifcfg['if']) {
2614
				if ($sync_changes) {
2615
					$clone['mode'] = $ifcfg['wireless']['mode'];
2616
				} else {
2617
					$ifcfg['wireless']['mode'] = $clone['mode'];
2618
				}
2619
				break;
2620
			}
2621
		}
2622
		unset($clone);
2623
	}
2624
}
2625

    
2626
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2627
	global $config, $g;
2628

    
2629
	/*    open up a shell script that will be used to output the commands.
2630
	 *    since wireless is changing a lot, these series of commands are fragile
2631
	 *    and will sometimes need to be verified by a operator by executing the command
2632
	 *    and returning the output of the command to the developers for inspection.  please
2633
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2634
	 */
2635

    
2636
	// Remove script file
2637
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2638

    
2639
	// Clone wireless nic if needed.
2640
	interface_wireless_clone($if, $wl);
2641

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

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

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

    
2651
	/* set values for /path/program */
2652
	$hostapd = "/usr/sbin/hostapd";
2653
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2654
	$ifconfig = "/sbin/ifconfig";
2655
	$sysctl = "/sbin/sysctl";
2656
	$killall = "/usr/bin/killall";
2657

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

    
2660
	$wlcmd = array();
2661
	$wl_sysctl = array();
2662
	/* Set a/b/g standard */
2663
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2664
	/* skip mode entirely for "auto" */
2665
	if ($wlcfg['standard'] != "auto") {
2666
		$wlcmd[] = "mode " . escapeshellarg($standard);
2667
	}
2668

    
2669
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2670
	 * to prevent massive packet loss under certain conditions. */
2671
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2672
		$wlcmd[] = "-ampdu";
2673
	}
2674

    
2675
	/* Set ssid */
2676
	if ($wlcfg['ssid']) {
2677
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2678
	}
2679

    
2680
	/* Set 802.11g protection mode */
2681
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2682

    
2683
	/* set wireless channel value */
2684
	if (isset($wlcfg['channel'])) {
2685
		if ($wlcfg['channel'] == "0") {
2686
			$wlcmd[] = "channel any";
2687
		} else {
2688
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2689
		}
2690
	}
2691

    
2692
	/* Set antenna diversity value */
2693
	if (isset($wlcfg['diversity'])) {
2694
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2695
	}
2696

    
2697
	/* Set txantenna value */
2698
	if (isset($wlcfg['txantenna'])) {
2699
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2700
	}
2701

    
2702
	/* Set rxantenna value */
2703
	if (isset($wlcfg['rxantenna'])) {
2704
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2705
	}
2706

    
2707
	/* set Distance value */
2708
	if ($wlcfg['distance']) {
2709
		$distance = escapeshellarg($wlcfg['distance']);
2710
	}
2711

    
2712
	/* Set wireless hostap mode */
2713
	if ($wlcfg['mode'] == "hostap") {
2714
		$wlcmd[] = "mediaopt hostap";
2715
	} else {
2716
		$wlcmd[] = "-mediaopt hostap";
2717
	}
2718

    
2719
	/* Set wireless adhoc mode */
2720
	if ($wlcfg['mode'] == "adhoc") {
2721
		$wlcmd[] = "mediaopt adhoc";
2722
	} else {
2723
		$wlcmd[] = "-mediaopt adhoc";
2724
	}
2725

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

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

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

    
2742
	/* handle puren (802.11n) only option */
2743
	if (isset($wlcfg['puren']['enable'])) {
2744
		$wlcmd[] = "puren";
2745
	} else {
2746
		$wlcmd[] = "-puren";
2747
	}
2748

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

    
2756
	/* handle turbo option */
2757
	if (isset($wlcfg['turbo']['enable'])) {
2758
		$wlcmd[] = "mediaopt turbo";
2759
	} else {
2760
		$wlcmd[] = "-mediaopt turbo";
2761
	}
2762

    
2763
	/* handle txpower setting */
2764
	// or don't. this has issues at the moment.
2765
	/*
2766
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2767
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2768
	}*/
2769

    
2770
	/* handle wme option */
2771
	if (isset($wlcfg['wme']['enable'])) {
2772
		$wlcmd[] = "wme";
2773
	} else {
2774
		$wlcmd[] = "-wme";
2775
	}
2776

    
2777
	/* Enable wpa if it's configured. No WEP support anymore. */
2778
	if (isset($wlcfg['wpa']['enable'])) {
2779
		$wlcmd[] = "authmode wpa wepmode off ";
2780
	} else {
2781
		$wlcmd[] = "authmode open wepmode off ";
2782
	}
2783

    
2784
	kill_hostapd($if);
2785
	mwexec(kill_wpasupplicant("{$if}"));
2786

    
2787
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2788
	conf_mount_rw();
2789

    
2790
	switch ($wlcfg['mode']) {
2791
		case 'bss':
2792
			if (isset($wlcfg['wpa']['enable'])) {
2793
				$wpa .= <<<EOD
2794
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2795
ctrl_interface_group=0
2796
ap_scan=1
2797
#fast_reauth=1
2798
network={
2799
ssid="{$wlcfg['ssid']}"
2800
scan_ssid=1
2801
priority=5
2802
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2803
psk="{$wlcfg['wpa']['passphrase']}"
2804
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2805
group={$wlcfg['wpa']['wpa_pairwise']}
2806
}
2807
EOD;
2808

    
2809
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2810
				unset($wpa);
2811
			}
2812
			break;
2813
		case 'hostap':
2814
			if (!empty($wlcfg['wpa']['passphrase'])) {
2815
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2816
			} else {
2817
				$wpa_passphrase = "";
2818
			}
2819
			if (isset($wlcfg['wpa']['enable'])) {
2820
				$wpa .= <<<EOD
2821
interface={$if}
2822
driver=bsd
2823
logger_syslog=-1
2824
logger_syslog_level=0
2825
logger_stdout=-1
2826
logger_stdout_level=0
2827
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2828
ctrl_interface={$g['varrun_path']}/hostapd
2829
ctrl_interface_group=wheel
2830
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2831
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2832
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2833
ssid={$wlcfg['ssid']}
2834
debug={$wlcfg['wpa']['debug_mode']}
2835
wpa={$wlcfg['wpa']['wpa_mode']}
2836
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2837
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2838
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2839
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2840
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2841
{$wpa_passphrase}
2842

    
2843
EOD;
2844

    
2845
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2846
					$wpa .= <<<EOD
2847
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
2848
rsn_preauth=1
2849
rsn_preauth_interfaces={$if}
2850

    
2851
EOD;
2852
				}
2853
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2854
					$wpa .= "ieee8021x=1\n";
2855

    
2856
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2857
						$auth_server_port = "1812";
2858
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2859
							$auth_server_port = intval($wlcfg['auth_server_port']);
2860
						}
2861
						$wpa .= <<<EOD
2862

    
2863
auth_server_addr={$wlcfg['auth_server_addr']}
2864
auth_server_port={$auth_server_port}
2865
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2866

    
2867
EOD;
2868
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2869
							$auth_server_port2 = "1812";
2870
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2871
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2872
							}
2873

    
2874
							$wpa .= <<<EOD
2875
auth_server_addr={$wlcfg['auth_server_addr2']}
2876
auth_server_port={$auth_server_port2}
2877
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2878

    
2879
EOD;
2880
						}
2881
					}
2882
				}
2883

    
2884
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2885
				unset($wpa);
2886
			}
2887
			break;
2888
	}
2889

    
2890
	/*
2891
	 *    all variables are set, lets start up everything
2892
	 */
2893

    
2894
	$baseif = interface_get_wireless_base($if);
2895
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2896
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2897

    
2898
	/* set sysctls for the wireless interface */
2899
	if (!empty($wl_sysctl)) {
2900
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2901
		foreach ($wl_sysctl as $wl_sysctl_line) {
2902
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2903
		}
2904
	}
2905

    
2906
	/* set ack timers according to users preference (if he/she has any) */
2907
	if ($distance) {
2908
		fwrite($fd_set, "# Enable ATH distance settings\n");
2909
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2910
	}
2911

    
2912
	if (isset($wlcfg['wpa']['enable'])) {
2913
		if ($wlcfg['mode'] == "bss") {
2914
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2915
		}
2916
		if ($wlcfg['mode'] == "hostap") {
2917
			/* add line to script to restore old mac to make hostapd happy */
2918
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2919
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2920
				$if_curmac = get_interface_mac($if);
2921
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
2922
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2923
						" link " . escapeshellarg($if_oldmac) . "\n");
2924
				}
2925
			}
2926

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

    
2929
			/* add line to script to restore spoofed mac after running hostapd */
2930
			if ($wl['spoofmac']) {
2931
				$if_curmac = get_interface_mac($if);
2932
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
2933
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2934
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
2935
				}
2936
			}
2937
		}
2938
	}
2939

    
2940
	fclose($fd_set);
2941
	conf_mount_ro();
2942

    
2943
	/* Making sure regulatory settings have actually changed
2944
	 * before applying, because changing them requires bringing
2945
	 * down all wireless networks on the interface. */
2946
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2947
	$ifconfig_str = implode($output);
2948
	unset($output);
2949
	$reg_changing = false;
2950

    
2951
	/* special case for the debug country code */
2952
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
2953
		$reg_changing = true;
2954
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
2955
		$reg_changing = true;
2956
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
2957
		$reg_changing = true;
2958
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
2959
		$reg_changing = true;
2960
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
2961
		$reg_changing = true;
2962
	}
2963

    
2964
	if ($reg_changing) {
2965
		/* set regulatory domain */
2966
		if ($wlcfg['regdomain']) {
2967
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2968
		}
2969

    
2970
		/* set country */
2971
		if ($wlcfg['regcountry']) {
2972
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2973
		}
2974

    
2975
		/* set location */
2976
		if ($wlcfg['reglocation']) {
2977
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2978
		}
2979

    
2980
		$wlregcmd_args = implode(" ", $wlregcmd);
2981

    
2982
		/* build a complete list of the wireless clones for this interface */
2983
		$clone_list = array();
2984
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2985
			$clone_list[] = interface_get_wireless_clone($baseif);
2986
		}
2987
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2988
			foreach ($config['wireless']['clone'] as $clone) {
2989
				if ($clone['if'] == $baseif) {
2990
					$clone_list[] = $clone['cloneif'];
2991
				}
2992
			}
2993
		}
2994

    
2995
		/* find which clones are up and bring them down */
2996
		$clones_up = array();
2997
		foreach ($clone_list as $clone_if) {
2998
			$clone_status = pfSense_get_interface_addresses($clone_if);
2999
			if ($clone_status['status'] == 'up') {
3000
				$clones_up[] = $clone_if;
3001
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3002
			}
3003
		}
3004

    
3005
		/* apply the regulatory settings */
3006
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3007
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3008

    
3009
		/* bring the clones back up that were previously up */
3010
		foreach ($clones_up as $clone_if) {
3011
			interfaces_bring_up($clone_if);
3012

    
3013
			/*
3014
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3015
			 * is in infrastructure mode, and WPA is enabled.
3016
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3017
			 */
3018
			if ($clone_if != $if) {
3019
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3020
				if ((!empty($friendly_if)) &&
3021
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3022
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3023
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3024
				}
3025
			}
3026
		}
3027
	}
3028

    
3029
	/* The mode must be specified in a separate command before ifconfig
3030
	 * will allow the mode and channel at the same time in the next.
3031
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3032
	 */
3033
	if ($wlcfg['mode'] == "hostap") {
3034
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3035
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3036
	}
3037

    
3038
	/* configure wireless */
3039
	$wlcmd_args = implode(" ", $wlcmd);
3040
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3041
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3042
	/* Bring the interface up only after setting up all the other parameters. */
3043
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3044
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3045
	fclose($wlan_setup_log);
3046

    
3047
	unset($wlcmd_args, $wlcmd);
3048

    
3049

    
3050
	sleep(1);
3051
	/* execute hostapd and wpa_supplicant if required in shell */
3052
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3053

    
3054
	return 0;
3055

    
3056
}
3057

    
3058
function kill_hostapd($interface) {
3059
	global $g;
3060

    
3061
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3062
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3063
	}
3064
}
3065

    
3066
function kill_wpasupplicant($interface) {
3067
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3068
}
3069

    
3070
function find_dhclient_process($interface) {
3071
	if ($interface) {
3072
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3073
	} else {
3074
		$pid = 0;
3075
	}
3076

    
3077
	return intval($pid);
3078
}
3079

    
3080
function kill_dhclient_process($interface) {
3081
	if (empty($interface) || !does_interface_exist($interface)) {
3082
		return;
3083
	}
3084

    
3085
	$i = 0;
3086
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3087
		/* 3rd time make it die for sure */
3088
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3089
		posix_kill($pid, $sig);
3090
		sleep(1);
3091
		$i++;
3092
	}
3093
	unset($i);
3094
}
3095

    
3096
function find_dhcp6c_process($interface) {
3097
	global $g;
3098

    
3099
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3100
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3101
	} else {
3102
		return(false);
3103
	}
3104

    
3105
	return intval($pid);
3106
}
3107

    
3108
function kill_dhcp6client_process($interface) {
3109
	if (empty($interface) || !does_interface_exist($interface)) {
3110
		return;
3111
	}
3112

    
3113
	if (($pid = find_dhcp6c_process($interface)) != 0) {
3114
		mwexec("kill -9 {$pid}");
3115
		sleep(1);
3116
	}
3117
}
3118

    
3119
function interface_virtual_create($interface) {
3120
	global $config;
3121

    
3122
	if (strstr($interface, "_vlan")) {
3123
		interfaces_vlan_configure($vlan);
3124
	} else if (substr($interface, 0, 3) == "gre") {
3125
		interfaces_gre_configure(0, $interface);
3126
	} else if (substr($interface, 0, 3) == "gif") {
3127
		interfaces_gif_configure(0, $interface);
3128
	} else if (substr($interface, 0, 5) == "ovpns") {
3129
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3130
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3131
				if ($interface == "ovpns{$server['vpnid']}") {
3132
					if (!function_exists('openvpn_resync')) {
3133
						require_once('openvpn.inc');
3134
					}
3135
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3136
					openvpn_resync('server', $server);
3137
				}
3138
			}
3139
			unset($server);
3140
		}
3141
	} else if (substr($interface, 0, 5) == "ovpnc") {
3142
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3143
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3144
				if ($interface == "ovpnc{$client['vpnid']}") {
3145
					if (!function_exists('openvpn_resync')) {
3146
						require_once('openvpn.inc');
3147
					}
3148
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3149
					openvpn_resync('client', $client);
3150
				}
3151
			}
3152
			unset($client);
3153
		}
3154
	} else if (substr($interface, 0, 4) == "lagg") {
3155
		interfaces_lagg_configure($interface);
3156
	} else if (substr($interface, 0, 6) == "bridge") {
3157
		interfaces_bridge_configure(0, $interface);
3158
	}
3159
}
3160

    
3161
function interface_vlan_mtu_configured($iface) {
3162
	global $config;
3163

    
3164
	$mtu = 0;
3165
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3166
		foreach ($config['vlans']['vlan'] as $vlan) {
3167

    
3168
			if ($vlan['vlanif'] != $iface)
3169
				continue;
3170

    
3171
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3172
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3173
				/* VLAN MTU */
3174
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3175
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3176
				/* Parent MTU */
3177
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3178
			}
3179
		}
3180
	}
3181

    
3182
	return $mtu;
3183
}
3184

    
3185
function interface_mtu_wanted_for_pppoe($realif) {
3186
	global $config;
3187

    
3188
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3189
		return 0;
3190

    
3191
	$mtu = 0;
3192
	foreach ($config['ppps']['ppp'] as $ppp) {
3193
		if ($ppp['type'] != "pppoe") {
3194
			continue;
3195
		}
3196

    
3197
		$mtus = array();
3198
		if (!empty($ppp['mtu'])) {
3199
			$mtus = explode(',', $ppp['mtu']);
3200
		}
3201
		$ports = explode(',', $ppp['ports']);
3202

    
3203
		foreach ($ports as $pid => $port) {
3204
			$parentifa = get_parent_interface($port);
3205
			$parentif = $parentifa[0];
3206
			if ($parentif != $realif)
3207
				continue;
3208

    
3209
			// there is an MTU configured on the port in question
3210
			if (!empty($mtus[$pid])) {
3211
				$mtu = intval($mtus[$pid]) + 8;
3212
			// or use the MTU configured on the interface ...
3213
			} elseif (is_array($config['interfaces'])) {
3214
				foreach ($config['interfaces'] as $interface) {
3215
					if ($interface['if'] == $ppp['if'] &&
3216
					    !empty($interface['mtu'])) {
3217
						$mtu = intval($interface['mtu']) + 8;
3218
						break;
3219
					}
3220
				}
3221
			}
3222
		}
3223
	}
3224

    
3225
	return $mtu;
3226
}
3227

    
3228
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3229
	global $config, $g;
3230
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3231
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3232

    
3233
	$wancfg = $config['interfaces'][$interface];
3234

    
3235
	if (!isset($wancfg['enable'])) {
3236
		return;
3237
	}
3238

    
3239
	$realif = get_real_interface($interface);
3240
	$realhwif_array = get_parent_interface($interface);
3241
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3242
	$realhwif = $realhwif_array[0];
3243

    
3244
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3245
		/* remove all IPv4 and IPv6 addresses */
3246
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3247
		if (is_array($tmpifaces)) {
3248
			foreach ($tmpifaces as $tmpiface) {
3249
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3250
					if (!is_linklocal($tmpiface)) {
3251
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3252
					}
3253
				} else {
3254
					if (is_subnetv4($tmpiface)) {
3255
						$tmpip = explode('/', $tmpiface);
3256
						$tmpip = $tmpip[0];
3257
					} else {
3258
						$tmpip = $tmpiface;
3259
					}
3260
					pfSense_interface_deladdress($realif, $tmpip);
3261
				}
3262
			}
3263
		}
3264

    
3265
		/* only bring down the interface when both v4 and v6 are set to NONE */
3266
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3267
			interface_bring_down($interface);
3268
		}
3269
	}
3270

    
3271
	$interface_to_check = $realif;
3272
	if (interface_isppp_type($interface)) {
3273
		$interface_to_check = $realhwif;
3274
	}
3275

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

    
3281
	/* Disable Accepting router advertisements unless specifically requested */
3282
	if ($g['debug']) {
3283
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3284
	}
3285
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3286

    
3287
	/* wireless configuration? */
3288
	if (is_array($wancfg['wireless'])) {
3289
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3290
	}
3291

    
3292
	/* Get the vendor MAC.  Use source dependent upon whether or not booting. */
3293
	$current_mac = get_interface_mac($realhwif);
3294
	if (platform_booting()) {
3295
		$vendor_mac = $current_mac;
3296
	} else {
3297
		$vendor_mac = get_interface_vendor_mac($realhwif);
3298
	}
3299
	$mac_addr = $wancfg['spoofmac'] ?: $vendor_mac;
3300
	/*
3301
	 * Don't try to reapply the MAC if it's already applied.
3302
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3303
	 * the interface config again, which attempts to apply the MAC again,
3304
	 * which cycles the link again...
3305
	 */
3306
	if (!empty($mac_addr) && ($mac_addr != $current_mac)) {
3307
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3308
			" link " . escapeshellarg($mac_addr));
3309
	} elseif ($current_mac == "ff:ff:ff:ff:ff:ff") {
3310
		/*   this is not a valid mac address.  generate a
3311
		 *   temporary mac address so the machine can get online.
3312
		 */
3313
		echo gettext("Generating new MAC address.");
3314
		$random_mac = generate_random_mac_address();
3315
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3316
			" link " . escapeshellarg($random_mac));
3317
		$wancfg['spoofmac'] = $random_mac;
3318
		write_config();
3319
		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");
3320
	}
3321

    
3322
	/* media */
3323
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3324
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3325
		if ($wancfg['media']) {
3326
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3327
		}
3328
		if ($wancfg['mediaopt']) {
3329
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3330
		}
3331
		mwexec($cmd);
3332
	}
3333

    
3334
	/* Apply hw offloading policies as configured */
3335
	enable_hardware_offloading($interface);
3336

    
3337
	/* invalidate interface/ip/sn cache */
3338
	get_interface_arr(true);
3339
	unset($interface_ip_arr_cache[$realif]);
3340
	unset($interface_sn_arr_cache[$realif]);
3341
	unset($interface_ipv6_arr_cache[$realif]);
3342
	unset($interface_snv6_arr_cache[$realif]);
3343

    
3344
	$tunnelif = substr($realif, 0, 3);
3345

    
3346
	$mtuif = $realif;
3347
	$mtuhwif = $realhwif;
3348

    
3349
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3350
	if (interface_isppp_type($interface)) {
3351
		$mtuif = $realhwif;
3352
		$mtuhwif_array = get_parent_interface($mtuif);
3353
		$mtuhwif = $mtuhwif_array[0];
3354
	}
3355

    
3356
	$wantedmtu = 0;
3357
	if (is_array($config['interfaces'])) {
3358
		foreach ($config['interfaces'] as $tmpinterface) {
3359
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3360
				$wantedmtu = $tmpinterface['mtu'];
3361
				break;
3362
			}
3363
		}
3364
	}
3365

    
3366
	/* MTU is not specified for interface, try the pppoe settings. */
3367
	if ($wantedmtu == 0) {
3368
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3369
	}
3370
	if ($wantedmtu == 0 && stristr($mtuif, "_vlan") && interface_isppp_type($interface)) {
3371
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3372
	}
3373

    
3374
	/* Set the MTU to 1500 if no explicit MTU configured. */
3375
	if ($wantedmtu == 0) {
3376
		$wantedmtu = 1500; /* Default */
3377
	}
3378

    
3379
	if (stristr($mtuif, "_vlan")) {
3380
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3381
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3382
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3383
			if ($wancfg['mtu'] > $parentmtu) {
3384
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3385
			}
3386
		}
3387

    
3388
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3389

    
3390
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3391
			$configuredmtu = $parentmtu;
3392
		if ($configuredmtu != 0)
3393
			$mtu = $configuredmtu;
3394
		else
3395
			$mtu = $wantedmtu;
3396

    
3397
		/* Set the parent MTU. */
3398
		if (get_interface_mtu($mtuhwif) < $mtu)
3399
			set_interface_mtu($mtuhwif, $mtu);
3400
		/* Set the VLAN MTU. */
3401
		if (get_interface_mtu($mtuif) != $mtu)
3402
			set_interface_mtu($mtuif, $mtu);
3403
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3404
		/* LAGG interface must be destroyed and re-created to change MTU */
3405
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3406
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3407
				foreach ($config['laggs']['lagg'] as $lagg) {
3408
					if ($lagg['laggif'] == $mtuif) {
3409
						interface_lagg_configure($lagg);
3410
						break;
3411
					}
3412
				}
3413
			}
3414
		}
3415
	} else {
3416
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3417
			pfSense_interface_mtu($mtuif, $wantedmtu);
3418
		}
3419
	}
3420
	/* XXX: What about gre/gif/.. ? */
3421

    
3422
	if (does_interface_exist($wancfg['if'])) {
3423
		interfaces_bring_up($wancfg['if']);
3424
	}
3425

    
3426
	switch ($wancfg['ipaddr']) {
3427
		case 'dhcp':
3428
			interface_dhcp_configure($interface);
3429
			break;
3430
		case 'pppoe':
3431
		case 'l2tp':
3432
		case 'pptp':
3433
		case 'ppp':
3434
			interface_ppps_configure($interface);
3435
			break;
3436
		default:
3437
			/* XXX: Kludge for now related to #3280 */
3438
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3439
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3440
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3441
				}
3442
			}
3443
			break;
3444
	}
3445

    
3446
	switch ($wancfg['ipaddrv6']) {
3447
		case 'slaac':
3448
		case 'dhcp6':
3449
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
3450
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
3451
			// handles all non-PPP connections with 'dhcp6usev4iface' set
3452
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
3453
				interface_dhcpv6_configure($interface, $wancfg);
3454
			}
3455
			break;
3456
		case '6rd':
3457
			interface_6rd_configure($interface, $wancfg);
3458
			break;
3459
		case '6to4':
3460
			interface_6to4_configure($interface, $wancfg);
3461
			break;
3462
		case 'track6':
3463
			interface_track6_configure($interface, $wancfg, $linkupevent);
3464
			break;
3465
		default:
3466
			/* XXX: Kludge for now related to #3280 */
3467
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3468
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3469
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3470
					// FIXME: Add IPv6 Support to the pfSense module
3471
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3472
				}
3473
			}
3474
			break;
3475
	}
3476

    
3477
	interface_netgraph_needed($interface);
3478

    
3479
	if (!platform_booting()) {
3480
		link_interface_to_vips($interface, "update");
3481

    
3482
		if ($tunnelif != 'gre') {
3483
			unset($gre);
3484
			$gre = link_interface_to_gre($interface);
3485
			if (!empty($gre)) {
3486
				array_walk($gre, 'interface_gre_configure');
3487
			}
3488
		}
3489

    
3490
		if ($tunnelif != 'gif') {
3491
			unset($gif);
3492
			$gif = link_interface_to_gif ($interface);
3493
			if (!empty($gif)) {
3494
				array_walk($gif, 'interface_gif_configure');
3495
			}
3496
		}
3497

    
3498
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3499
			unset($bridgetmp);
3500
			$bridgetmp = link_interface_to_bridge($interface);
3501
			if (!empty($bridgetmp)) {
3502
				interface_bridge_add_member($bridgetmp, $realif);
3503
			}
3504
		}
3505

    
3506
		$grouptmp = link_interface_to_group($interface);
3507
		if (!empty($grouptmp)) {
3508
			array_walk($grouptmp, 'interface_group_add_member');
3509
		}
3510

    
3511
		if ($interface == "lan") {
3512
			/* make new hosts file */
3513
			system_hosts_generate();
3514
		}
3515

    
3516
		if ($reloadall == true) {
3517

    
3518
			/* reconfigure static routes (kernel may have deleted them) */
3519
			system_routing_configure($interface);
3520

    
3521
			/* reload ipsec tunnels */
3522
			send_event("service reload ipsecdns");
3523

    
3524
			if (isset($config['dnsmasq']['enable'])) {
3525
				services_dnsmasq_configure();
3526
			}
3527

    
3528
			if (isset($config['unbound']['enable'])) {
3529
				services_unbound_configure();
3530
			}
3531

    
3532
			/* update dyndns */
3533
			send_event("service reload dyndns {$interface}");
3534

    
3535
			/* reload captive portal */
3536
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3537
				require_once('captiveportal.inc');
3538
			}
3539
			captiveportal_init_rules_byinterface($interface);
3540
		}
3541
	}
3542

    
3543
	interfaces_staticarp_configure($interface);
3544
	return 0;
3545
}
3546

    
3547
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3548
	global $config, $g;
3549

    
3550
	if (!is_array($wancfg)) {
3551
		return;
3552
	}
3553

    
3554
	if (!isset($wancfg['enable'])) {
3555
		return;
3556
	}
3557

    
3558
	/* If the interface is not configured via another, exit */
3559
	if (empty($wancfg['track6-interface'])) {
3560
		return;
3561
	}
3562

    
3563
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3564
	$realif = get_real_interface($interface);
3565
	$linklocal = find_interface_ipv6_ll($realif, true);
3566
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
3567
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3568
	}
3569
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3570
	/* XXX: Probably should remove? */
3571
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3572

    
3573
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3574
	if (!isset($trackcfg['enable'])) {
3575
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
3576
		return;
3577
	}
3578

    
3579
	switch ($trackcfg['ipaddrv6']) {
3580
		case "6to4":
3581
			if ($g['debug']) {
3582
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3583
			}
3584
			interface_track6_6to4_configure($interface, $wancfg);
3585
			break;
3586
		case "6rd":
3587
			if ($g['debug']) {
3588
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3589
			}
3590
			interface_track6_6rd_configure($interface, $wancfg);
3591
			break;
3592
		case "dhcp6":
3593
			if ($linkupevent == true) {
3594
				/*
3595
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
3596
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3597
				 *
3598
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
3599
				 */
3600
				$parentrealif = get_real_interface($wancfg['track6-interface']);
3601
				$pidv6 = find_dhcp6c_process($parentrealif);
3602
				if ($pidv6) {
3603
					posix_kill($pidv6, SIGHUP);
3604
				}
3605
			}
3606
			break;
3607
	}
3608

    
3609
	if ($linkupevent == false && !platform_booting()) {
3610
		if (!function_exists('services_dhcpd_configure')) {
3611
			require_once("services.inc");
3612
		}
3613

    
3614
		/* restart dns servers (defering dhcpd reload) */
3615
		if (isset($config['unbound']['enable'])) {
3616
			services_unbound_configure(false);
3617
		}
3618
		if (isset($config['dnsmasq']['enable'])) {
3619
			services_dnsmasq_configure(false);
3620
		}
3621

    
3622
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
3623
		services_dhcpd_configure("inet6");
3624
	}
3625

    
3626
	return 0;
3627
}
3628

    
3629
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3630
	global $config, $g;
3631
	global $interface_ipv6_arr_cache;
3632
	global $interface_snv6_arr_cache;
3633

    
3634
	if (!is_array($lancfg)) {
3635
		return;
3636
	}
3637

    
3638
	/* If the interface is not configured via another, exit */
3639
	if (empty($lancfg['track6-interface'])) {
3640
		return;
3641
	}
3642

    
3643
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3644
	if (empty($wancfg)) {
3645
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3646
		return;
3647
	}
3648

    
3649
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3650
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3651
		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']));
3652
		return;
3653
	}
3654
	$hexwanv4 = return_hex_ipv4($ip4address);
3655

    
3656
	/* create the long prefix notation for math, save the prefix length */
3657
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3658
	$rd6prefixlen = $rd6prefix[1];
3659
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3660

    
3661
	/* binary presentation of the prefix for all 128 bits. */
3662
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3663

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

    
3669
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3670
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3671
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3672
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3673
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3674
	/* fill the rest out with zeros */
3675
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3676

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

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

    
3690
	return 0;
3691
}
3692

    
3693
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3694
	global $config, $g;
3695
	global $interface_ipv6_arr_cache;
3696
	global $interface_snv6_arr_cache;
3697

    
3698
	if (!is_array($lancfg)) {
3699
		return;
3700
	}
3701

    
3702
	/* If the interface is not configured via another, exit */
3703
	if (empty($lancfg['track6-interface'])) {
3704
		return;
3705
	}
3706

    
3707
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3708
	if (empty($wancfg)) {
3709
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3710
		return;
3711
	}
3712

    
3713
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3714
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3715
		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']));
3716
		return;
3717
	}
3718
	$hexwanv4 = return_hex_ipv4($ip4address);
3719

    
3720
	/* create the long prefix notation for math, save the prefix length */
3721
	$sixto4prefix = "2002::";
3722
	$sixto4prefixlen = 16;
3723
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3724

    
3725
	/* binary presentation of the prefix for all 128 bits. */
3726
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3727

    
3728
	/* just save the left prefix length bits */
3729
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3730
	/* add the v4 address */
3731
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3732
	/* add the custom prefix id */
3733
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3734
	/* fill the rest out with zeros */
3735
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3736

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

    
3740
	$lanif = get_real_interface($interface);
3741
	$oip = find_interface_ipv6($lanif);
3742
	if (is_ipaddrv6($oip)) {
3743
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3744
	}
3745
	unset($interface_ipv6_arr_cache[$lanif]);
3746
	unset($interface_snv6_arr_cache[$lanif]);
3747
	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));
3748
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3749

    
3750
	return 0;
3751
}
3752

    
3753
function interface_6rd_configure($interface = "wan", $wancfg) {
3754
	global $config, $g;
3755

    
3756
	/* because this is a tunnel interface we can only function
3757
	 *	with a public IPv4 address on the interface */
3758

    
3759
	if (!is_array($wancfg)) {
3760
		return;
3761
	}
3762

    
3763
	if (!is_module_loaded('if_stf.ko')) {
3764
		mwexec('/sbin/kldload if_stf.ko');
3765
	}
3766

    
3767
	$wanif = get_real_interface($interface);
3768
	$ip4address = find_interface_ip($wanif);
3769
	if (!is_ipaddrv4($ip4address)) {
3770
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3771
		return false;
3772
	}
3773
	$hexwanv4 = return_hex_ipv4($ip4address);
3774

    
3775
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3776
		$wancfg['prefix-6rd-v4plen'] = 0;
3777
	}
3778

    
3779
	/* create the long prefix notation for math, save the prefix length */
3780
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3781
	$rd6prefixlen = $rd6prefix[1];
3782
	$brgw = explode('.', $wancfg['gateway-6rd']);
3783
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3784
	$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);
3785
	if (strlen($rd6brgw) < 128) {
3786
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3787
	}
3788
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3789
	unset($brgw);
3790
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3791

    
3792
	/* binary presentation of the prefix for all 128 bits. */
3793
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3794

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

    
3802
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3803
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3804

    
3805

    
3806
	/* XXX: need to extend to support variable prefix size for v4 */
3807
	if (!is_module_loaded("if_stf")) {
3808
		mwexec("/sbin/kldload if_stf.ko");
3809
	}
3810
	$stfiface = "{$interface}_stf";
3811
	if (does_interface_exist($stfiface)) {
3812
		pfSense_interface_destroy($stfiface);
3813
	}
3814
	$tmpstfiface = pfSense_interface_create("stf");
3815
	pfSense_interface_rename($tmpstfiface, $stfiface);
3816
	pfSense_interface_flags($stfiface, IFF_LINK2);
3817
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3818
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3819
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3820
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3821
	}
3822
	if ($g['debug']) {
3823
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3824
	}
3825

    
3826
	/* write out a default router file */
3827
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3828
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3829

    
3830
	$ip4gateway = get_interface_gateway($interface);
3831
	if (is_ipaddrv4($ip4gateway)) {
3832
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3833
	}
3834

    
3835
	/* configure dependent interfaces */
3836
	if (!platform_booting()) {
3837
		link_interface_to_track6($interface, "update");
3838
	}
3839

    
3840
	return 0;
3841
}
3842

    
3843
function interface_6to4_configure($interface = "wan", $wancfg) {
3844
	global $config, $g;
3845

    
3846
	/* because this is a tunnel interface we can only function
3847
	 *	with a public IPv4 address on the interface */
3848

    
3849
	if (!is_array($wancfg)) {
3850
		return;
3851
	}
3852

    
3853
	$wanif = get_real_interface($interface);
3854
	$ip4address = find_interface_ip($wanif);
3855
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3856
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3857
		return false;
3858
	}
3859

    
3860
	/* create the long prefix notation for math, save the prefix length */
3861
	$stfprefixlen = 16;
3862
	$stfprefix = Net_IPv6::uncompress("2002::");
3863
	$stfarr = explode(":", $stfprefix);
3864
	$v4prefixlen = "0";
3865

    
3866
	/* we need the hex form of the interface IPv4 address */
3867
	$ip4arr = explode(".", $ip4address);
3868
	$hexwanv4 = "";
3869
	foreach ($ip4arr as $octet) {
3870
		$hexwanv4 .= sprintf("%02x", $octet);
3871
	}
3872

    
3873
	/* we need the hex form of the broker IPv4 address */
3874
	$ip4arr = explode(".", "192.88.99.1");
3875
	$hexbrv4 = "";
3876
	foreach ($ip4arr as $octet) {
3877
		$hexbrv4 .= sprintf("%02x", $octet);
3878
	}
3879

    
3880
	/* binary presentation of the prefix for all 128 bits. */
3881
	$stfprefixbin = "";
3882
	foreach ($stfarr as $element) {
3883
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3884
	}
3885
	/* just save the left prefix length bits */
3886
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3887

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

    
3892
	/* for the local subnet too. */
3893
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3894
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3895

    
3896
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3897
	$stfbrarr = array();
3898
	$stfbrbinarr = array();
3899
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3900
	foreach ($stfbrbinarr as $bin) {
3901
		$stfbrarr[] = dechex(bindec($bin));
3902
	}
3903
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
3904

    
3905
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3906
	$stflanarr = array();
3907
	$stflanbinarr = array();
3908
	$stflanbinarr = str_split($stflanbin, 16);
3909
	foreach ($stflanbinarr as $bin) {
3910
		$stflanarr[] = dechex(bindec($bin));
3911
	}
3912
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
3913
	$stflanarr[7] = 1;
3914
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
3915

    
3916
	/* setup the stf interface */
3917
	if (!is_module_loaded("if_stf")) {
3918
		mwexec("/sbin/kldload if_stf.ko");
3919
	}
3920
	$stfiface = "{$interface}_stf";
3921
	if (does_interface_exist($stfiface)) {
3922
		pfSense_interface_destroy($stfiface);
3923
	}
3924
	$tmpstfiface = pfSense_interface_create("stf");
3925
	pfSense_interface_rename($tmpstfiface, $stfiface);
3926
	pfSense_interface_flags($stfiface, IFF_LINK2);
3927
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3928

    
3929
	if ($g['debug']) {
3930
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3931
	}
3932

    
3933
	/* write out a default router file */
3934
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3935
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3936

    
3937
	$ip4gateway = get_interface_gateway($interface);
3938
	if (is_ipaddrv4($ip4gateway)) {
3939
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3940
	}
3941

    
3942
	if (!platform_booting()) {
3943
		link_interface_to_track6($interface, "update");
3944
	}
3945

    
3946
	return 0;
3947
}
3948

    
3949
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3950
	global $config, $g;
3951

    
3952
	if (!is_array($wancfg)) {
3953
		return;
3954
	}
3955

    
3956
	$wanif = get_real_interface($interface, "inet6");
3957
	$dhcp6cconf = "";
3958

    
3959
	if ($wancfg['adv_dhcp6_config_file_override']) {
3960
		// DHCP6 Config File Override
3961
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3962
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3963
		// DHCP6 Config File Advanced
3964
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3965
	} else {
3966
		// DHCP6 Config File Basic
3967
		$dhcp6cconf .= "interface {$wanif} {\n";
3968

    
3969
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3970
		if ($wancfg['ipaddrv6'] == "slaac") {
3971
			$dhcp6cconf .= "\tinformation-only;\n";
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
		} else {
3977
			$trackiflist = array();
3978
			$iflist = link_interface_to_track6($interface);
3979
			foreach ($iflist as $ifname => $ifcfg) {
3980
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3981
					$trackiflist[$ifname] = $ifcfg;
3982
				}
3983
			}
3984

    
3985
			/* skip address request if this is set */
3986
			if (!isset($wancfg['dhcp6prefixonly'])) {
3987
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3988
			}
3989
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3990
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3991
			}
3992

    
3993
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3994
			$dhcp6cconf .= "\trequest domain-name;\n";
3995
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3996
			$dhcp6cconf .= "};\n";
3997

    
3998
			if (!isset($wancfg['dhcp6prefixonly'])) {
3999
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4000
			}
4001

    
4002
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4003
				/* Setup the prefix delegation */
4004
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4005
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4006
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4007
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4008
				}
4009
				foreach ($trackiflist as $friendly => $ifcfg) {
4010
					if ($g['debug']) {
4011
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4012
					}
4013
					$realif = get_real_interface($friendly);
4014
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4015
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4016
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4017
					$dhcp6cconf .= "\t};\n";
4018
				}
4019
				unset($preflen, $iflist, $ifcfg, $ifname);
4020
				$dhcp6cconf .= "};\n";
4021
			}
4022
			unset($trackiflist);
4023
		}
4024
	}
4025

    
4026
	/* wide-dhcp6c works for now. */
4027
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4028
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4029
		unset($dhcp6cconf);
4030
		return 1;
4031
	}
4032
	unset($dhcp6cconf);
4033

    
4034
	$dhcp6cscript = "#!/bin/sh\n";
4035
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4036
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4037
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4038
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4039
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4040
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4041
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4042
		unset($dhcp6cscript);
4043
		return 1;
4044
	}
4045
	unset($dhcp6cscript);
4046
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4047

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

    
4054
	/* non ipoe Process */
4055
	if (!isset($wancfg['dhcp6withoutra'])) {
4056
		$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
4057
		$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4058
		$rtsoldscript .= "\t/bin/sleep 1\n";
4059
		$rtsoldscript .= "fi\n";
4060
	} else {
4061
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
4062
		$rtsoldscript .= "/bin/sleep 1\n";
4063
	}
4064
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4065
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4066

    
4067

    
4068
	/* add the start of dhcp6c to the rtsold script if we are going to wait for ra */
4069
	if (!isset($wancfg['dhcp6withoutra'])) {
4070
		$rtsoldscript .= "/usr/local/sbin/dhcp6c {$debugOption} {$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4071
		$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4072
	}
4073
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4074
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4075
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4076
		unset($rtsoldscript);
4077
		return 1;
4078
	}
4079
	unset($rtsoldscript);
4080
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4081

    
4082
	/* accept router advertisements for this interface */
4083
	log_error("Accept router advertisements on interface {$wanif} ");
4084
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4085

    
4086
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
4087
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4088
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4089
		sleep(2);
4090
	}
4091

    
4092
	/* start dhcp6c here if we don't want to wait for ra */
4093
	if (isset($wancfg['dhcp6withoutra'])) {
4094
		kill_dhcp6client_process($wanif);
4095

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

    
4101
	/* NOTE: will be called from rtsold invoked script
4102
	 * link_interface_to_track6($interface, "update");
4103
	 */
4104

    
4105
	return 0;
4106
}
4107

    
4108
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4109
	global $g;
4110

    
4111
	$send_options = "";
4112
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4113
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4114
		foreach ($options as $option) {
4115
			$send_options .= "\tsend " . trim($option) . ";\n";
4116
		}
4117
	}
4118

    
4119
	$request_options = "";
4120
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4121
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4122
		foreach ($options as $option) {
4123
			$request_options .= "\trequest " . trim($option) . ";\n";
4124
		}
4125
	}
4126

    
4127
	$information_only = "";
4128
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4129
		$information_only = "\tinformation-only;\n";
4130
	}
4131

    
4132
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4133
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4134
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4135
	}
4136

    
4137
	$interface_statement  = "interface";
4138
	$interface_statement .= " {$wanif}";
4139
	$interface_statement .= " {\n";
4140
	$interface_statement .= "$send_options";
4141
	$interface_statement .= "$request_options";
4142
	$interface_statement .= "$information_only";
4143
	$interface_statement .= "$script";
4144
	$interface_statement .= "};\n";
4145

    
4146
	$id_assoc_statement_address = "";
4147
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4148
		$id_assoc_statement_address .= "id-assoc";
4149
		$id_assoc_statement_address .= " na";
4150
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4151
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4152
		}
4153
		$id_assoc_statement_address .= " { ";
4154

    
4155
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4156
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4157
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4158
			$id_assoc_statement_address .= "\n\taddress";
4159
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4160
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4161
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4162
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4163
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4164
			}
4165
			$id_assoc_statement_address .= ";\n";
4166
		}
4167

    
4168
		$id_assoc_statement_address .= "};\n";
4169
	}
4170

    
4171
	$id_assoc_statement_prefix = "";
4172
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4173
		$id_assoc_statement_prefix .= "id-assoc";
4174
		$id_assoc_statement_prefix .= " pd";
4175
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4176
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4177
		}
4178
		$id_assoc_statement_prefix .= " { ";
4179

    
4180
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4181
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4182
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4183
			$id_assoc_statement_prefix .= "\n\tprefix";
4184
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4185
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4186
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4187
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4188
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4189
			}
4190
			$id_assoc_statement_prefix .= ";";
4191
		}
4192
		
4193
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
4194
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4195
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4196
			$id_assoc_statement_prefix .= " {$realif}";
4197
			$id_assoc_statement_prefix .= " {\n";
4198
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4199
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4200
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4201
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4202
			}
4203
			$id_assoc_statement_prefix .= "\t};";
4204
		}
4205

    
4206
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4207
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4208
			$id_assoc_statement_prefix .= "\n";
4209
		}
4210

    
4211
		$id_assoc_statement_prefix .= "};\n";
4212
	}
4213

    
4214
	$authentication_statement = "";
4215
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4216
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4217
		$authentication_statement .= "authentication";
4218
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4219
		$authentication_statement .= " {\n";
4220
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4221
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4222
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4223
		}
4224
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4225
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4226
		}
4227
		$authentication_statement .= "};\n";
4228
	}
4229

    
4230
	$key_info_statement = "";
4231
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4232
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4233
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4234
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4235
		$key_info_statement .= "keyinfo";
4236
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4237
		$key_info_statement .= " {\n";
4238
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4239
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4240
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4241
		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'])) {
4242
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4243
		}
4244
		$key_info_statement .= "};\n";
4245
	}
4246

    
4247
	$dhcp6cconf  = $interface_statement;
4248
	$dhcp6cconf .= $id_assoc_statement_address;
4249
	$dhcp6cconf .= $id_assoc_statement_prefix;
4250
	$dhcp6cconf .= $authentication_statement;
4251
	$dhcp6cconf .= $key_info_statement;
4252

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

    
4255
	return $dhcp6cconf;
4256
}
4257

    
4258

    
4259
function DHCP6_Config_File_Override($wancfg, $wanif) {
4260

    
4261
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4262

    
4263
	if ($dhcp6cconf === false) {
4264
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4265
		return '';
4266
	} else {
4267
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4268
	}
4269
}
4270

    
4271

    
4272
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4273

    
4274
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4275

    
4276
	return $dhcp6cconf;
4277
}
4278

    
4279

    
4280
function interface_dhcp_configure($interface = "wan") {
4281
	global $config, $g;
4282

    
4283
	$wancfg = $config['interfaces'][$interface];
4284
	$wanif = $wancfg['if'];
4285
	if (empty($wancfg)) {
4286
		$wancfg = array();
4287
	}
4288

    
4289
	/* generate dhclient_wan.conf */
4290
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4291
	if (!$fd) {
4292
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4293
		return 1;
4294
	}
4295

    
4296
	if ($wancfg['dhcphostname']) {
4297
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4298
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4299
	} else {
4300
		$dhclientconf_hostname = "";
4301
	}
4302

    
4303
	$wanif = get_real_interface($interface);
4304
	if (empty($wanif)) {
4305
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4306
		return 0;
4307
	}
4308
	$dhclientconf = "";
4309

    
4310
	$dhclientconf .= <<<EOD
4311
interface "{$wanif}" {
4312
timeout 60;
4313
retry 15;
4314
select-timeout 0;
4315
initial-interval 1;
4316
	{$dhclientconf_hostname}
4317
	script "/sbin/dhclient-script";
4318
EOD;
4319

    
4320
	if (validate_ipv4_list($wancfg['dhcprejectfrom'])) {
4321
		$dhclientconf .= <<<EOD
4322

    
4323
	reject {$wancfg['dhcprejectfrom']};
4324
EOD;
4325
	}
4326
	$dhclientconf .= <<<EOD
4327

    
4328
}
4329

    
4330
EOD;
4331

    
4332
	// DHCP Config File Advanced
4333
	if ($wancfg['adv_dhcp_config_advanced']) {
4334
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4335
	}
4336

    
4337
	if (is_ipaddr($wancfg['alias-address'])) {
4338
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4339
		$dhclientconf .= <<<EOD
4340
alias {
4341
	interface "{$wanif}";
4342
	fixed-address {$wancfg['alias-address']};
4343
	option subnet-mask {$subnetmask};
4344
}
4345

    
4346
EOD;
4347
	}
4348

    
4349
	// DHCP Config File Override
4350
	if ($wancfg['adv_dhcp_config_file_override']) {
4351
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4352
	}
4353

    
4354
	fwrite($fd, $dhclientconf);
4355
	fclose($fd);
4356

    
4357
	/* bring wan interface up before starting dhclient */
4358
	if ($wanif) {
4359
		interfaces_bring_up($wanif);
4360
	} else {
4361
		log_error(sprintf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4362
	}
4363

    
4364
	/* Make sure dhclient is not running */
4365
	kill_dhclient_process($wanif);
4366

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

    
4370
	return 0;
4371
}
4372

    
4373
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4374

    
4375
	$hostname = "";
4376
	if ($wancfg['dhcphostname'] != '') {
4377
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4378
	}
4379

    
4380
	/* DHCP Protocol Timings */
4381
	$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");
4382
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4383
		$pt_variable = "{$Protocol_Timing}";
4384
		${$pt_variable} = "";
4385
		if ($wancfg[$Protocol_Timing] != "") {
4386
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4387
		}
4388
	}
4389

    
4390
	$send_options = "";
4391
	if ($wancfg['adv_dhcp_send_options'] != '') {
4392
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp_send_options']);
4393
		foreach ($options as $option) {
4394
			$send_options .= "\tsend " . trim($option) . ";\n";
4395
		}
4396
	}
4397

    
4398
	$request_options = "";
4399
	if ($wancfg['adv_dhcp_request_options'] != '') {
4400
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4401
	}
4402

    
4403
	$required_options = "";
4404
	if ($wancfg['adv_dhcp_required_options'] != '') {
4405
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4406
	}
4407

    
4408
	$option_modifiers = "";
4409
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4410
		$modifiers = DHCP_Config_Option_Split($wancfg['adv_dhcp_option_modifiers']);
4411
		foreach ($modifiers as $modifier) {
4412
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4413
		}
4414
	}
4415

    
4416
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4417
	$dhclientconf .= "\n";
4418
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4419
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4420
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4421
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4422
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4423
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4424
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4425
	$dhclientconf .= "\n";
4426
	$dhclientconf .= "# DHCP Protocol Options\n";
4427
	$dhclientconf .= "{$hostname}";
4428
	$dhclientconf .= "{$send_options}";
4429
	$dhclientconf .= "{$request_options}";
4430
	$dhclientconf .= "{$required_options}";
4431
	$dhclientconf .= "{$option_modifiers}";
4432
	$dhclientconf .= "\n";
4433
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4434
		$dhclientconf .= "reject {$wancfg['dhcprejectfrom']};\n";
4435
	}
4436
	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4437
	$dhclientconf .= "}\n";
4438

    
4439
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4440

    
4441
	return $dhclientconf;
4442
}
4443

    
4444
function DHCP_Config_Option_Split($option_string) {
4445
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4446
	return $matches ? $matches[0] : [];
4447
}
4448

    
4449
function DHCP_Config_File_Override($wancfg, $wanif) {
4450

    
4451
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4452

    
4453
	if ($dhclientconf === false) {
4454
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading.\n"), $wancfg['adv_dhcp_config_file_override_path']));
4455
		return '';
4456
	} else {
4457
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4458
	}
4459
}
4460

    
4461

    
4462
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4463

    
4464
	/* Apply Interface Substitutions */
4465
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4466

    
4467
	/* Apply Hostname Substitutions */
4468
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4469

    
4470
	/* Arrays of MAC Address Types, Cases, Delimiters */
4471
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4472
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4473
	$various_mac_cases      = array("U", "L");
4474
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4475

    
4476
	/* Apply MAC Address Substitutions */
4477
	foreach ($various_mac_types as $various_mac_type) {
4478
		foreach ($various_mac_cases as $various_mac_case) {
4479
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4480

    
4481
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4482
				if ($res !== false) {
4483

    
4484
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4485
					if ("$various_mac_case" == "U") {
4486
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4487
					}
4488
					if ("$various_mac_case" == "L") {
4489
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4490
					}
4491

    
4492
					if ("$various_mac_type" == "mac_addr_hex") {
4493
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4494
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4495
						$dhcpclientconf_mac_hex = "";
4496
						$delimiter = "";
4497
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4498
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4499
							$delimiter = ":";
4500
						}
4501
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4502
					}
4503

    
4504
					/* MAC Address Delimiter Substitutions */
4505
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4506

    
4507
					/* Apply MAC Address Substitutions */
4508
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4509
				}
4510
			}
4511
		}
4512
	}
4513

    
4514
	return $dhclientconf;
4515
}
4516

    
4517
function interfaces_group_setup() {
4518
	global $config;
4519

    
4520
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4521
		return;
4522
	}
4523

    
4524
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4525
		interface_group_setup($groupar);
4526
	}
4527

    
4528
	return;
4529
}
4530

    
4531
function interface_group_setup(&$groupname /* The parameter is an array */) {
4532
	global $config;
4533

    
4534
	if (!is_array($groupname)) {
4535
		return;
4536
	}
4537
	$members = explode(" ", $groupname['members']);
4538
	foreach ($members as $ifs) {
4539
		$realif = get_real_interface($ifs);
4540
		if ($realif && does_interface_exist($realif)) {
4541
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4542
		}
4543
	}
4544

    
4545
	return;
4546
}
4547

    
4548
function is_interface_group($if) {
4549
	global $config;
4550

    
4551
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4552
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4553
			if ($groupentry['ifname'] === $if) {
4554
				return true;
4555
			}
4556
		}
4557
	}
4558

    
4559
	return false;
4560
}
4561

    
4562
function interface_group_add_member($interface, $groupname) {
4563
	$interface = get_real_interface($interface);
4564
	if (does_interface_exist($interface)) {
4565
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4566
	}
4567
}
4568

    
4569
/* COMPAT Function */
4570
function convert_friendly_interface_to_real_interface_name($interface) {
4571
	return get_real_interface($interface);
4572
}
4573

    
4574
/* COMPAT Function */
4575
function get_real_wan_interface($interface = "wan") {
4576
	return get_real_interface($interface);
4577
}
4578

    
4579
/* COMPAT Function */
4580
function get_current_wan_address($interface = "wan") {
4581
	return get_interface_ip($interface);
4582
}
4583

    
4584
/*
4585
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4586
 */
4587
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4588
	global $config;
4589

    
4590
	/* XXX: For speed reasons reference directly the interface array */
4591
	$ifdescrs = &$config['interfaces'];
4592
	//$ifdescrs = get_configured_interface_list(false, true);
4593

    
4594
	foreach ($ifdescrs as $if => $ifname) {
4595
		if ($if == $interface || $ifname['if'] == $interface) {
4596
			return $if;
4597
		}
4598

    
4599
		if (get_real_interface($if) == $interface) {
4600
			return $if;
4601
		}
4602

    
4603
		if ($checkparent == false) {
4604
			continue;
4605
		}
4606

    
4607
		$int = get_parent_interface($if, true);
4608
		if (is_array($int)) {
4609
			foreach ($int as $iface) {
4610
				if ($iface == $interface) {
4611
					return $if;
4612
				}
4613
			}
4614
		}
4615
	}
4616

    
4617
	if ($interface == "enc0") {
4618
		return 'IPsec';
4619
	}
4620
}
4621

    
4622
/* attempt to resolve interface to friendly descr */
4623
function convert_friendly_interface_to_friendly_descr($interface) {
4624
	global $config;
4625

    
4626
	switch ($interface) {
4627
		case "l2tp":
4628
			$ifdesc = "L2TP";
4629
			break;
4630
		case "pptp":
4631
			$ifdesc = "PPTP";
4632
			break;
4633
		case "pppoe":
4634
			$ifdesc = "PPPoE";
4635
			break;
4636
		case "openvpn":
4637
			$ifdesc = "OpenVPN";
4638
			break;
4639
		case "lo0":
4640
			$ifdesc = "Loopback";
4641
			break;
4642
		case "enc0":
4643
		case "ipsec":
4644
		case "IPsec":
4645
			$ifdesc = "IPsec";
4646
			break;
4647
		default:
4648
			if (isset($config['interfaces'][$interface])) {
4649
				if (empty($config['interfaces'][$interface]['descr'])) {
4650
					$ifdesc = strtoupper($interface);
4651
				} else {
4652
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4653
				}
4654
				break;
4655
			} else if (substr($interface, 0, 4) == '_vip') {
4656
				if (is_array($config['virtualip']['vip'])) {
4657
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
4658
						if ($vip['mode'] == "carp") {
4659
							if ($interface == "_vip{$vip['uniqid']}") {
4660
								return "{$vip['subnet']} - {$vip['descr']}";
4661
							}
4662
						}
4663
					}
4664
				}
4665
			} else if (substr($interface, 0, 5) == '_lloc') {
4666
				return get_interface_linklocal($interface);
4667
			} else {
4668
				/* if list */
4669
				$ifdescrs = get_configured_interface_with_descr(false, true);
4670
				foreach ($ifdescrs as $if => $ifname) {
4671
					if ($if == $interface || $ifname == $interface) {
4672
						return $ifname;
4673
					}
4674
				}
4675
			}
4676
			break;
4677
	}
4678

    
4679
	return $ifdesc;
4680
}
4681

    
4682
function convert_real_interface_to_friendly_descr($interface) {
4683

    
4684
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4685

    
4686
	if (!empty($ifdesc)) {
4687
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4688
	}
4689

    
4690
	return $interface;
4691
}
4692

    
4693
/*
4694
 *  get_parent_interface($interface):
4695
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4696
 *				or virtual interface (i.e. vlan)
4697
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4698
 *			-- returns $interface passed in if $interface parent is not found
4699
 *			-- returns empty array if an invalid interface is passed
4700
 *	(Only handles ppps and vlans now.)
4701
 */
4702
function get_parent_interface($interface, $avoidrecurse = false) {
4703
	global $config;
4704

    
4705
	$parents = array();
4706
	//Check that we got a valid interface passed
4707
	$realif = get_real_interface($interface);
4708
	if ($realif == NULL) {
4709
		return $parents;
4710
	}
4711

    
4712
	// If we got a real interface, find it's friendly assigned name
4713
	if ($interface == $realif && $avoidrecurse == false) {
4714
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4715
	}
4716

    
4717
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4718
		$ifcfg = $config['interfaces'][$interface];
4719
		switch ($ifcfg['ipaddr']) {
4720
			case "ppp":
4721
			case "pppoe":
4722
			case "pptp":
4723
			case "l2tp":
4724
				if (empty($parents)) {
4725
					if (is_array($config['ppps']['ppp'])) {
4726
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4727
							if ($ifcfg['if'] == $ppp['if']) {
4728
								$ports = explode(',', $ppp['ports']);
4729
								foreach ($ports as $pid => $parent_if) {
4730
									$parents[$pid] = get_real_interface($parent_if);
4731
								}
4732
								break;
4733
							}
4734
						}
4735
					}
4736
				}
4737
				break;
4738
			case "dhcp":
4739
			case "static":
4740
			default:
4741
				// Handle _vlans
4742
				if (strpos($realif, '_vlan') !== FALSE) {
4743
					if (is_array($config['vlans']['vlan'])) {
4744
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4745
							if ($ifcfg['if'] == $vlan['vlanif']) {
4746
								$parents[0] = $vlan['if'];
4747
								break;
4748
							}
4749
						}
4750
					}
4751
				}
4752
				break;
4753
		}
4754
	}
4755

    
4756
	if (empty($parents)) {
4757
		// Handle _vlans not assigned to an interface
4758
		if (strpos($realif, '_vlan') !== FALSE) {
4759
			if (is_array($config['vlans']['vlan'])) {
4760
				foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4761
					if ($realif == $vlan['vlanif']) {
4762
						$parents[0] = $vlan['if'];
4763
						break;
4764
					}
4765
				}
4766
			}
4767
		}
4768
	}
4769

    
4770
	if (empty($parents)) {
4771
		$parents[0] = $realif;
4772
	}
4773

    
4774
	return $parents;
4775
}
4776

    
4777
/*
4778
 *  get_parent_physical_interface($interface):
4779
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
4780
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
4781
 */
4782
function get_parent_physical_interface($interface) {
4783
	global $config;
4784

    
4785
	$realif = get_parent_interface($interface);
4786

    
4787
	if (substr($realif[0], 0, 4) == "lagg") {
4788
		foreach ($config['laggs']['lagg'] as $lagg) {
4789
			if ($realif[0] == $lagg['laggif']) {
4790
				return explode(",", $lagg['members']);
4791
			}
4792
		}
4793
	} else {
4794
		return $realif;
4795
	}
4796
}
4797

    
4798
function interface_is_wireless_clone($wlif) {
4799
	if (!stristr($wlif, "_wlan")) {
4800
		return false;
4801
	} else {
4802
		return true;
4803
	}
4804
}
4805

    
4806
function interface_get_wireless_base($wlif) {
4807
	if (!stristr($wlif, "_wlan")) {
4808
		return $wlif;
4809
	} else {
4810
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4811
	}
4812
}
4813

    
4814
function interface_get_wireless_clone($wlif) {
4815
	if (!stristr($wlif, "_wlan")) {
4816
		return $wlif . "_wlan0";
4817
	} else {
4818
		return $wlif;
4819
	}
4820
}
4821

    
4822
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4823
	global $config, $g;
4824

    
4825
	$wanif = NULL;
4826

    
4827
	switch ($interface) {
4828
		case "l2tp":
4829
			$wanif = "l2tp";
4830
			break;
4831
		case "pptp":
4832
			$wanif = "pptp";
4833
			break;
4834
		case "pppoe":
4835
			$wanif = "pppoe";
4836
			break;
4837
		case "openvpn":
4838
			$wanif = "openvpn";
4839
			break;
4840
		case "IPsec":
4841
		case "ipsec":
4842
		case "enc0":
4843
			$wanif = "enc0";
4844
			break;
4845
		case "ppp":
4846
			$wanif = "ppp";
4847
			break;
4848
		default:
4849
			if (substr($interface, 0, 4) == '_vip') {
4850
				$wanif = get_configured_vip_interface($interface);
4851
				if (!empty($wanif)) {
4852
					$wanif = get_real_interface($wanif);
4853
				}
4854
				break;
4855
			} else if (substr($interface, 0, 5) == '_lloc') {
4856
				$interface = substr($interface, 5);
4857
			} else if (strstr($interface, "_vlan") ||
4858
			    does_interface_exist($interface, $flush)) {
4859
				/*
4860
				 * If a real interface was already passed simply
4861
				 * pass the real interface back.  This encourages
4862
				 * the usage of this function in more cases so that
4863
				 * we can combine logic for more flexibility.
4864
				 */
4865
				$wanif = $interface;
4866
				break;
4867
			}
4868

    
4869
			if (empty($config['interfaces'][$interface])) {
4870
				break;
4871
			}
4872

    
4873
			$cfg = &$config['interfaces'][$interface];
4874

    
4875
			if ($family == "inet6") {
4876
				switch ($cfg['ipaddrv6']) {
4877
					case "6rd":
4878
					case "6to4":
4879
						$wanif = "{$interface}_stf";
4880
						break;
4881
					case 'pppoe':
4882
					case 'ppp':
4883
					case 'l2tp':
4884
					case 'pptp':
4885
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4886
							$wanif = interface_get_wireless_clone($cfg['if']);
4887
						} else {
4888
							$wanif = $cfg['if'];
4889
						}
4890
						break;
4891
					default:
4892
						switch ($cfg['ipaddr']) {
4893
							case 'pppoe':
4894
							case 'ppp':
4895
							case 'l2tp':
4896
							case 'pptp':
4897
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
4898
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) || isset($cfg['ipv6usev4iface'])) {
4899
									$wanif = $cfg['if'];
4900
								} else {
4901
									$parents = get_parent_interface($interface);
4902
									if (!empty($parents[0])) {
4903
										$wanif = $parents[0];
4904
									} else {
4905
										$wanif = $cfg['if'];
4906
									}
4907
								}
4908
								break;
4909
							default:
4910
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4911
									$wanif = interface_get_wireless_clone($cfg['if']);
4912
								} else {
4913
									$wanif = $cfg['if'];
4914
								}
4915
								break;
4916
						}
4917
						break;
4918
				}
4919
			} else {
4920
				// Wireless cloned NIC support (FreeBSD 8+)
4921
				// interface name format: $parentnic_wlanparentnic#
4922
				// example: ath0_wlan0
4923
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4924
					$wanif = interface_get_wireless_clone($cfg['if']);
4925
				} else {
4926
					$wanif = $cfg['if'];
4927
				}
4928
			}
4929
			break;
4930
	}
4931

    
4932
	return $wanif;
4933
}
4934

    
4935
/* Guess the physical interface by providing a IP address */
4936
function guess_interface_from_ip($ipaddress) {
4937

    
4938
	$family = '';
4939
	if (is_ipaddrv4($ipaddress)) {
4940
		$family = 'inet';
4941
	}
4942
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4943
		$family = 'inet6';
4944
	}
4945

    
4946
	if (empty($family)) {
4947
		return false;
4948
	}
4949

    
4950
	/* create a route table we can search */
4951
	$output = '';
4952
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4953
	$output[0] = trim($output[0], " \n");
4954
	if (!empty($output[0])) {
4955
		return $output[0];
4956
	}
4957

    
4958
	return false;
4959
}
4960

    
4961
/*
4962
 * find_ip_interface($ip): return the interface where an ip is defined
4963
 *   (or if $bits is specified, where an IP within the subnet is defined)
4964
 */
4965
function find_ip_interface($ip, $bits = null) {
4966
	if (!is_ipaddr($ip)) {
4967
		return false;
4968
	}
4969

    
4970
	$isv6ip = is_ipaddrv6($ip);
4971

    
4972
	/* if list */
4973
	$ifdescrs = get_configured_interface_list();
4974

    
4975
	foreach ($ifdescrs as $ifdescr => $ifname) {
4976
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4977
		if (is_null($ifip)) {
4978
			continue;
4979
		}
4980
		if (is_null($bits)) {
4981
			if ($ip == $ifip) {
4982
				$int = get_real_interface($ifname);
4983
				return $int;
4984
			}
4985
		} else {
4986
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4987
				$int = get_real_interface($ifname);
4988
				return $int;
4989
			}
4990
		}
4991
	}
4992

    
4993
	return false;
4994
}
4995

    
4996
/*
4997
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4998
 *   (or if $bits is specified, where an IP within the subnet is found)
4999
 */
5000
function find_virtual_ip_alias($ip, $bits = null) {
5001
	global $config;
5002

    
5003
	if (!is_array($config['virtualip']['vip'])) {
5004
		return false;
5005
	}
5006
	if (!is_ipaddr($ip)) {
5007
		return false;
5008
	}
5009

    
5010
	$isv6ip = is_ipaddrv6($ip);
5011

    
5012
	foreach ($config['virtualip']['vip'] as $vip) {
5013
		if ($vip['mode'] === "ipalias") {
5014
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
5015
				continue;
5016
			}
5017
			if (is_null($bits)) {
5018
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
5019
					return $vip;
5020
				}
5021
			} else {
5022
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5023
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5024
					return $vip;
5025
				}
5026
			}
5027
		}
5028
	}
5029
	return false;
5030
}
5031

    
5032
function link_interface_to_track6($int, $action = "") {
5033
	global $config;
5034

    
5035
	if (empty($int)) {
5036
		return;
5037
	}
5038

    
5039
	if (is_array($config['interfaces'])) {
5040
		$list = array();
5041
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5042
			if (!isset($ifcfg['enable'])) {
5043
				continue;
5044
			}
5045
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5046
				if ($action == "update") {
5047
					interface_track6_configure($ifname, $ifcfg);
5048
				} else if ($action == "") {
5049
					$list[$ifname] = $ifcfg;
5050
				}
5051
			}
5052
		}
5053
		return $list;
5054
	}
5055
}
5056

    
5057
function interface_find_child_cfgmtu($realiface) {
5058
	global $config;
5059

    
5060
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5061
	$vlans = link_interface_to_vlans($realiface);
5062
	$qinqs = link_interface_to_qinqs($realiface);
5063
	$bridge = link_interface_to_bridge($realiface);
5064
	if (!empty($interface)) {
5065
		$gifs = link_interface_to_gif($interface);
5066
		$gres = link_interface_to_gre($interface);
5067
	} else {
5068
		$gifs = array();
5069
		$gres = array();
5070
	}
5071

    
5072
	$mtu = 0;
5073
	if (is_array($vlans)) {
5074
		foreach ($vlans as $vlan) {
5075
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5076
			if (empty($ifass)) {
5077
				continue;
5078
			}
5079
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5080
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5081
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5082
				}
5083
			}
5084
		}
5085
	}
5086
	if (is_array($qinqs)) {
5087
		foreach ($qinqs as $qinq) {
5088
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5089
			if (empty($ifass)) {
5090
				continue;
5091
			}
5092
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5093
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5094
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5095
				}
5096
			}
5097
		}
5098
	}
5099
	if (is_array($gifs)) {
5100
		foreach ($gifs as $gif) {
5101
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5102
			if (empty($ifass)) {
5103
				continue;
5104
			}
5105
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5106
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5107
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5108
				}
5109
			}
5110
		}
5111
	}
5112
	if (is_array($gres)) {
5113
		foreach ($gres as $gre) {
5114
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5115
			if (empty($ifass)) {
5116
				continue;
5117
			}
5118
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5119
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5120
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5121
				}
5122
			}
5123
		}
5124
	}
5125
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5126
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5127
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5128
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5129
		}
5130
	}
5131
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5132

    
5133
	return $mtu;
5134
}
5135

    
5136
function link_interface_to_vlans($int, $action = "") {
5137
	global $config;
5138

    
5139
	if (empty($int)) {
5140
		return;
5141
	}
5142

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

    
5160
function link_interface_to_qinqs($int, $action = "") {
5161
	global $config;
5162

    
5163
	if (empty($int)) {
5164
		return;
5165
	}
5166

    
5167
	if (is_array($config['qinqs']['qinqentry'])) {
5168
		$ifaces = array();
5169
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5170
			if ($int == $qinq['if']) {
5171
				if ($action == "update") {
5172
					interfaces_bring_up($int);
5173
				} else {
5174
					$ifaces[$qinq['tag']] = $qinq;
5175
				}
5176
			}
5177
		}
5178
		if (!empty($ifaces)) {
5179
			return $ifaces;
5180
		}
5181
	}
5182
}
5183

    
5184
function link_interface_to_vips($int, $action = "", $vhid = '') {
5185
	global $config;
5186

    
5187
	$updatevips = false;
5188
	if (is_array($config['virtualip']['vip'])) {
5189
		$result = array();
5190
		foreach ($config['virtualip']['vip'] as $vip) {
5191
			if (substr($vip['interface'], 0, 4) == "_vip") {
5192
				$iface = get_configured_vip_interface($vip['interface']);
5193
			} else {
5194
				$iface = $vip['interface'];
5195
			}
5196
			if ($int != $iface) {
5197
				continue;
5198
			}
5199
			if ($action == "update") {
5200
				$updatevips = true;
5201
			} else {
5202
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5203
				    substr($vip['interface'], 0, 4) == "_vip") {
5204
					$result[] = $vip;
5205
				}
5206
			}
5207
		}
5208
		if ($updatevips === true) {
5209
			interfaces_vips_configure($int);
5210
		}
5211
		return $result;
5212
	}
5213

    
5214
	return NULL;
5215
}
5216

    
5217
/****f* interfaces/link_interface_to_bridge
5218
 * NAME
5219
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5220
 * INPUTS
5221
 *   $ip
5222
 * RESULT
5223
 *   bridge[0-99]
5224
 ******/
5225
function link_interface_to_bridge($int) {
5226
	global $config;
5227

    
5228
	if (is_array($config['bridges']['bridged'])) {
5229
		foreach ($config['bridges']['bridged'] as $bridge) {
5230
			if (in_array($int, explode(',', $bridge['members']))) {
5231
				return "{$bridge['bridgeif']}";
5232
			}
5233
		}
5234
	}
5235
}
5236

    
5237
function link_interface_to_group($int) {
5238
	global $config;
5239

    
5240
	$result = array();
5241

    
5242
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5243
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5244
			if (in_array($int, explode(" ", $group['members']))) {
5245
				$result[$group['ifname']] = $int;
5246
			}
5247
		}
5248
	}
5249

    
5250
	return $result;
5251
}
5252

    
5253
function link_interface_to_gre($interface) {
5254
	global $config;
5255

    
5256
	$result = array();
5257

    
5258
	if (is_array($config['gres']['gre'])) {
5259
		foreach ($config['gres']['gre'] as $gre) {
5260
			if ($gre['if'] == $interface) {
5261
				$result[] = $gre;
5262
			}
5263
		}
5264
	}
5265

    
5266
	return $result;
5267
}
5268

    
5269
function link_interface_to_gif($interface) {
5270
	global $config;
5271

    
5272
	$result = array();
5273

    
5274
	if (is_array($config['gifs']['gif'])) {
5275
		foreach ($config['gifs']['gif'] as $gif) {
5276
			if ($gif['if'] == $interface) {
5277
				$result[] = $gif;
5278
			}
5279
		}
5280
	}
5281

    
5282
	return $result;
5283
}
5284

    
5285
/*
5286
 * find_interface_ip($interface): return the interface ip (first found)
5287
 */
5288
function find_interface_ip($interface, $flush = false) {
5289
	global $interface_ip_arr_cache;
5290
	global $interface_sn_arr_cache;
5291

    
5292
	$interface = str_replace("\n", "", $interface);
5293

    
5294
	if (!does_interface_exist($interface)) {
5295
		return;
5296
	}
5297

    
5298
	/* Setup IP cache */
5299
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5300
		$ifinfo = pfSense_get_interface_addresses($interface);
5301
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5302
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5303
	}
5304

    
5305
	return $interface_ip_arr_cache[$interface];
5306
}
5307

    
5308
/*
5309
 * find_interface_ipv6($interface): return the interface ip (first found)
5310
 */
5311
function find_interface_ipv6($interface, $flush = false) {
5312
	global $interface_ipv6_arr_cache;
5313
	global $interface_snv6_arr_cache;
5314
	global $config;
5315

    
5316
	$interface = trim($interface);
5317
	$interface = get_real_interface($interface);
5318

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

    
5323
	/* Setup IP cache */
5324
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5325
		$ifinfo = pfSense_get_interface_addresses($interface);
5326
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5327
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5328
	}
5329

    
5330
	return $interface_ipv6_arr_cache[$interface];
5331
}
5332

    
5333
/*
5334
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5335
 */
5336
function find_interface_ipv6_ll($interface, $flush = false) {
5337
	global $interface_llv6_arr_cache;
5338
	global $config;
5339

    
5340
	$interface = str_replace("\n", "", $interface);
5341

    
5342
	if (!does_interface_exist($interface)) {
5343
		return;
5344
	}
5345

    
5346
	/* Setup IP cache */
5347
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5348
		$ifinfo = pfSense_getall_interface_addresses($interface);
5349
		foreach ($ifinfo as $line) {
5350
			if (strstr($line, ":")) {
5351
				$parts = explode("/", $line);
5352
				if (is_linklocal($parts[0])) {
5353
					$ifinfo['linklocal'] = $parts[0];
5354
				}
5355
			}
5356
		}
5357
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5358
	}
5359
	return $interface_llv6_arr_cache[$interface];
5360
}
5361

    
5362
function find_interface_subnet($interface, $flush = false) {
5363
	global $interface_sn_arr_cache;
5364
	global $interface_ip_arr_cache;
5365

    
5366
	$interface = str_replace("\n", "", $interface);
5367
	if (does_interface_exist($interface) == false) {
5368
		return;
5369
	}
5370

    
5371
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5372
		$ifinfo = pfSense_get_interface_addresses($interface);
5373
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5374
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5375
	}
5376

    
5377
	return $interface_sn_arr_cache[$interface];
5378
}
5379

    
5380
function find_interface_subnetv6($interface, $flush = false) {
5381
	global $interface_snv6_arr_cache;
5382
	global $interface_ipv6_arr_cache;
5383

    
5384
	$interface = str_replace("\n", "", $interface);
5385
	if (does_interface_exist($interface) == false) {
5386
		return;
5387
	}
5388

    
5389
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5390
		$ifinfo = pfSense_get_interface_addresses($interface);
5391
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5392
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5393
	}
5394

    
5395
	return $interface_snv6_arr_cache[$interface];
5396
}
5397

    
5398
function ip_in_interface_alias_subnet($interface, $ipalias) {
5399
	global $config;
5400

    
5401
	if (empty($interface) || !is_ipaddr($ipalias)) {
5402
		return false;
5403
	}
5404
	if (is_array($config['virtualip']['vip'])) {
5405
		foreach ($config['virtualip']['vip'] as $vip) {
5406
			switch ($vip['mode']) {
5407
				case "ipalias":
5408
					if ($vip['interface'] <> $interface) {
5409
						break;
5410
					}
5411
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5412
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5413
						return true;
5414
					}
5415
					break;
5416
			}
5417
		}
5418
	}
5419

    
5420
	return false;
5421
}
5422

    
5423
function get_possible_listen_ips($include_ipv6_link_local=false) {
5424

    
5425
	$interfaces = get_configured_interface_with_descr();
5426
	foreach ($interfaces as $iface => $ifacename) {
5427
		if ($include_ipv6_link_local) {
5428
			/* This is to avoid going though added ll below */
5429
			if (substr($iface, 0, 5) == '_lloc') {
5430
				continue;
5431
			}
5432
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5433
			if (!empty($llip)) {
5434
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5435
			}
5436
		}
5437
	}
5438
	$viplist = get_configured_vip_list();
5439
	foreach ($viplist as $vip => $address) {
5440
		$interfaces[$vip] = $address;
5441
		if (get_vip_descr($address)) {
5442
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5443
		}
5444
	}
5445

    
5446
	$interfaces['lo0'] = 'Localhost';
5447

    
5448
	return $interfaces;
5449
}
5450

    
5451
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5452
	global $config;
5453

    
5454
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5455
	foreach (array('server', 'client') as $mode) {
5456
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5457
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5458
				if (!isset($setting['disable'])) {
5459
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5460
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5461
				}
5462
			}
5463
		}
5464
	}
5465
	return $sourceips;
5466
}
5467

    
5468
function get_interface_ip($interface = "wan") {
5469

    
5470
	if (substr($interface, 0, 4) == '_vip') {
5471
		return get_configured_vip_ipv4($interface);
5472
	} else if (substr($interface, 0, 5) == '_lloc') {
5473
		/* No link-local address for v4. */
5474
		return null;
5475
	}
5476

    
5477
	$realif = get_failover_interface($interface, 'inet');
5478
	if (!$realif) {
5479
		return null;
5480
	}
5481

    
5482
	if (substr($realif, 0, 4) == '_vip') {
5483
		return get_configured_vip_ipv4($realif);
5484
	} else if (substr($realif, 0, 5) == '_lloc') {
5485
		/* No link-local address for v4. */
5486
		return null;
5487
	}
5488

    
5489
	if (is_array($config['interfaces'][$interface]) &&
5490
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5491
		return ($config['interfaces'][$interface]['ipaddr']);
5492
	}
5493

    
5494
	/*
5495
	 * Beaware that find_interface_ip() is our last option, it will
5496
	 * return the first IP it find on interface, not necessarily the
5497
	 * main IP address.
5498
	 */
5499
	$curip = find_interface_ip($realif);
5500
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5501
		return $curip;
5502
	} else {
5503
		return null;
5504
	}
5505
}
5506

    
5507
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5508
	global $config;
5509

    
5510
	if (substr($interface, 0, 4) == '_vip') {
5511
		return get_configured_vip_ipv6($interface);
5512
	} else if (substr($interface, 0, 5) == '_lloc') {
5513
		return get_interface_linklocal($interface);
5514
	}
5515

    
5516
	$realif = get_failover_interface($interface, 'inet6');
5517
	if (!$realif) {
5518
		return null;
5519
	}
5520

    
5521
	if (substr($realif, 0, 4) == '_vip') {
5522
		return get_configured_vip_ipv6($realif);
5523
	} else if (substr($realif, 0, 5) == '_lloc') {
5524
		return get_interface_linklocal($realif);
5525
	}
5526

    
5527
	if (is_array($config['interfaces'][$interface])) {
5528
		switch ($config['interfaces'][$interface]['ipaddr']) {
5529
			case 'pppoe':
5530
			case 'l2tp':
5531
			case 'pptp':
5532
			case 'ppp':
5533
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5534
					$realif = get_real_interface($interface, 'inet6', false);
5535
				}
5536
				break;
5537
		}
5538
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5539
			return ($config['interfaces'][$interface]['ipaddrv6']);
5540
		}
5541
	}
5542

    
5543
	/*
5544
	 * Beaware that find_interface_ip() is our last option, it will
5545
	 * return the first IP it find on interface, not necessarily the
5546
	 * main IP address.
5547
	 */
5548
	$curip = find_interface_ipv6($realif, $flush);
5549
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5550
		return $curip;
5551
	} else {
5552
		/*
5553
		 * NOTE: On the case when only the prefix is requested,
5554
		 * the communication on WAN will be done over link-local.
5555
		 */
5556
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
5557
			$curip = find_interface_ipv6_ll($realif, $flush);
5558
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5559
				return $curip;
5560
			}
5561
		}
5562
	}
5563
	return null;
5564
}
5565

    
5566
function get_interface_linklocal($interface = "wan") {
5567

    
5568
	$realif = get_failover_interface($interface, 'inet6');
5569
	if (!$realif) {
5570
		return null;
5571
	}
5572

    
5573
	if (substr($interface, 0, 4) == '_vip') {
5574
		$realif = get_real_interface($interface);
5575
	} else if (substr($interface, 0, 5) == '_lloc') {
5576
		$realif = get_real_interface(substr($interface, 5));
5577
	}
5578

    
5579
	$curip = find_interface_ipv6_ll($realif);
5580
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5581
		return $curip;
5582
	} else {
5583
		return null;
5584
	}
5585
}
5586

    
5587
function get_interface_subnet($interface = "wan") {
5588

    
5589
	if (substr($interface, 0, 4) == '_vip') {
5590
		return (get_configured_vip_subnetv4($interface));
5591
	}
5592

    
5593
	$realif = get_real_interface($interface);
5594
	if (!$realif) {
5595
		return (NULL);
5596
	}
5597

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

    
5603
	return (NULL);
5604
}
5605

    
5606
function get_interface_subnetv6($interface = "wan") {
5607

    
5608
	if (substr($interface, 0, 4) == '_vip') {
5609
		return (get_configured_vip_subnetv6($interface));
5610
	} else if (substr($interface, 0, 5) == '_lloc') {
5611
		$interface = substr($interface, 5);
5612
	}
5613

    
5614
	$realif = get_real_interface($interface, 'inet6');
5615
	if (!$realif) {
5616
		return (NULL);
5617
	}
5618

    
5619
	$cursn = find_interface_subnetv6($realif);
5620
	if (!empty($cursn)) {
5621
		return ($cursn);
5622
	}
5623

    
5624
	return (NULL);
5625
}
5626

    
5627
/* return outside interfaces with a gateway */
5628
function get_interfaces_with_gateway() {
5629
	global $config;
5630

    
5631
	$ints = array();
5632

    
5633
	/* loop interfaces, check config for outbound */
5634
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5635
		switch ($ifname['ipaddr']) {
5636
			case "dhcp":
5637
			case "pppoe":
5638
			case "pptp":
5639
			case "l2tp":
5640
			case "ppp":
5641
				$ints[$ifdescr] = $ifdescr;
5642
				break;
5643
			default:
5644
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5645
				    !empty($ifname['gateway'])) {
5646
					$ints[$ifdescr] = $ifdescr;
5647
				}
5648
				break;
5649
		}
5650
	}
5651
	return $ints;
5652
}
5653

    
5654
/* return true if interface has a gateway */
5655
function interface_has_gateway($friendly) {
5656
	global $config;
5657

    
5658
	if (!empty($config['interfaces'][$friendly])) {
5659
		$ifname = &$config['interfaces'][$friendly];
5660
		switch ($ifname['ipaddr']) {
5661
			case "dhcp":
5662
			case "pppoe":
5663
			case "pptp":
5664
			case "l2tp":
5665
			case "ppp":
5666
				return true;
5667
			break;
5668
			default:
5669
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5670
					return true;
5671
				}
5672
				$tunnelif = substr($ifname['if'], 0, 3);
5673
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5674
					if (find_interface_ip($ifname['if'])) {
5675
						return true;
5676
					}
5677
				}
5678
				if (!empty($ifname['gateway'])) {
5679
					return true;
5680
				}
5681
			break;
5682
		}
5683
	}
5684

    
5685
	return false;
5686
}
5687

    
5688
/* return true if interface has a gateway */
5689
function interface_has_gatewayv6($friendly) {
5690
	global $config;
5691

    
5692
	if (!empty($config['interfaces'][$friendly])) {
5693
		$ifname = &$config['interfaces'][$friendly];
5694
		switch ($ifname['ipaddrv6']) {
5695
			case "slaac":
5696
			case "dhcp6":
5697
			case "6to4":
5698
			case "6rd":
5699
				return true;
5700
				break;
5701
			default:
5702
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5703
					return true;
5704
				}
5705
				$tunnelif = substr($ifname['if'], 0, 3);
5706
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5707
					if (find_interface_ipv6($ifname['if'])) {
5708
						return true;
5709
					}
5710
				}
5711
				if (!empty($ifname['gatewayv6'])) {
5712
					return true;
5713
				}
5714
				break;
5715
		}
5716
	}
5717

    
5718
	return false;
5719
}
5720

    
5721
/****f* interfaces/is_altq_capable
5722
 * NAME
5723
 *   is_altq_capable - Test if interface is capable of using ALTQ
5724
 * INPUTS
5725
 *   $int            - string containing interface name
5726
 * RESULT
5727
 *   boolean         - true or false
5728
 ******/
5729

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

    
5744
	$int_family = remove_ifindex($int);
5745

    
5746
	if (in_array($int_family, $capable)) {
5747
		return true;
5748
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5749
		return true;
5750
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5751
		return true;
5752
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5753
		return true;
5754
	} else {
5755
		return false;
5756
	}
5757
}
5758

    
5759
/****f* interfaces/is_interface_wireless
5760
 * NAME
5761
 *   is_interface_wireless - Returns if an interface is wireless
5762
 * RESULT
5763
 *   $tmp       - Returns if an interface is wireless
5764
 ******/
5765
function is_interface_wireless($interface) {
5766
	global $config, $g;
5767

    
5768
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5769
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5770
		if (preg_match($g['wireless_regex'], $interface)) {
5771
			if (isset($config['interfaces'][$friendly])) {
5772
				$config['interfaces'][$friendly]['wireless'] = array();
5773
			}
5774
			return true;
5775
		}
5776
		return false;
5777
	} else {
5778
		return true;
5779
	}
5780
}
5781

    
5782
function get_wireless_modes($interface) {
5783
	/* return wireless modes and channels */
5784
	$wireless_modes = array();
5785

    
5786
	$cloned_interface = get_real_interface($interface);
5787

    
5788
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5789
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5790
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5791
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5792

    
5793
		$interface_channels = "";
5794
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5795
		$interface_channel_count = count($interface_channels);
5796

    
5797
		$c = 0;
5798
		while ($c < $interface_channel_count) {
5799
			$channel_line = explode(",", $interface_channels["$c"]);
5800
			$wireless_mode = trim($channel_line[0]);
5801
			$wireless_channel = trim($channel_line[1]);
5802
			if (trim($wireless_mode) != "") {
5803
				/* if we only have 11g also set 11b channels */
5804
				if ($wireless_mode == "11g") {
5805
					if (!isset($wireless_modes["11b"])) {
5806
						$wireless_modes["11b"] = array();
5807
					}
5808
				} else if ($wireless_mode == "11g ht") {
5809
					if (!isset($wireless_modes["11b"])) {
5810
						$wireless_modes["11b"] = array();
5811
					}
5812
					if (!isset($wireless_modes["11g"])) {
5813
						$wireless_modes["11g"] = array();
5814
					}
5815
					$wireless_mode = "11ng";
5816
				} else if ($wireless_mode == "11a ht") {
5817
					if (!isset($wireless_modes["11a"])) {
5818
						$wireless_modes["11a"] = array();
5819
					}
5820
					$wireless_mode = "11na";
5821
				}
5822
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5823
			}
5824
			$c++;
5825
		}
5826
	}
5827
	return($wireless_modes);
5828
}
5829

    
5830
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5831
function get_wireless_channel_info($interface) {
5832
	$wireless_channels = array();
5833

    
5834
	$cloned_interface = get_real_interface($interface);
5835

    
5836
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5837
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5838
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5839
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5840

    
5841
		$interface_channels = "";
5842
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5843

    
5844
		foreach ($interface_channels as $channel_line) {
5845
			$channel_line = explode(",", $channel_line);
5846
			if (!isset($wireless_channels[$channel_line[0]])) {
5847
				$wireless_channels[$channel_line[0]] = $channel_line;
5848
			}
5849
		}
5850
	}
5851
	return($wireless_channels);
5852
}
5853

    
5854
function set_interface_mtu($interface, $mtu) {
5855

    
5856
	/* LAGG interface must be destroyed and re-created to change MTU */
5857
	if (substr($interface, 0, 4) == 'lagg') {
5858
		if (isset($config['laggs']['lagg']) &&
5859
		    is_array($config['laggs']['lagg'])) {
5860
			foreach ($config['laggs']['lagg'] as $lagg) {
5861
				if ($lagg['laggif'] == $interface) {
5862
					interface_lagg_configure($lagg);
5863
					break;
5864
				}
5865
			}
5866
		}
5867
	} else {
5868
		pfSense_interface_mtu($interface, $mtu);
5869
	}
5870
}
5871

    
5872
/****f* interfaces/get_interface_mtu
5873
 * NAME
5874
 *   get_interface_mtu - Return the mtu of an interface
5875
 * RESULT
5876
 *   $tmp       - Returns the mtu of an interface
5877
 ******/
5878
function get_interface_mtu($interface) {
5879
	$mtu = pfSense_interface_getmtu($interface);
5880
	return $mtu['mtu'];
5881
}
5882

    
5883
function get_interface_mac($interface) {
5884
	$macinfo = pfSense_get_interface_addresses($interface);
5885
	return $macinfo["macaddr"];
5886
}
5887

    
5888
function get_interface_vendor_mac($interface) {
5889
	$macinfo = pfSense_get_interface_addresses($interface);
5890
	return $macinfo["hwaddr"] ?: '';
5891
}
5892

    
5893
/****f* pfsense-utils/generate_random_mac_address
5894
 * NAME
5895
 *   generate_random_mac - generates a random mac address
5896
 * INPUTS
5897
 *   none
5898
 * RESULT
5899
 *   $mac - a random mac address
5900
 ******/
5901
function generate_random_mac_address() {
5902
	$mac = "02";
5903
	for ($x = 0; $x < 5; $x++) {
5904
		$mac .= ":" . dechex(rand(16, 255));
5905
	}
5906
	return $mac;
5907
}
5908

    
5909
/****f* interfaces/is_jumbo_capable
5910
 * NAME
5911
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5912
 * INPUTS
5913
 *   $int             - string containing interface name
5914
 * RESULT
5915
 *   boolean          - true or false
5916
 ******/
5917
function is_jumbo_capable($iface) {
5918
	$iface = trim($iface);
5919
	$capable = pfSense_get_interface_addresses($iface);
5920

    
5921
	if (isset($capable['caps']['vlanmtu'])) {
5922
		return true;
5923
	}
5924

    
5925
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5926
	if (substr($iface, 0, 4) == "lagg") {
5927
		return true;
5928
	}
5929

    
5930
	return false;
5931
}
5932

    
5933
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5934
	global $g;
5935

    
5936
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5937

    
5938
	if (!empty($iface) && !empty($pppif)) {
5939
		$cron_cmd = <<<EOD
5940
#!/bin/sh
5941
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5942
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5943

    
5944
EOD;
5945

    
5946
		@file_put_contents($cron_file, $cron_cmd);
5947
		chmod($cron_file, 0755);
5948
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5949
	} else {
5950
		unlink_if_exists($cron_file);
5951
	}
5952
}
5953

    
5954
function get_interface_default_mtu($type = "ethernet") {
5955
	switch ($type) {
5956
		case "gre":
5957
			return 1476;
5958
			break;
5959
		case "gif":
5960
			return 1280;
5961
			break;
5962
		case "tun":
5963
		case "vlan":
5964
		case "tap":
5965
		case "ethernet":
5966
		default:
5967
			return 1500;
5968
			break;
5969
	}
5970

    
5971
	/* Never reached */
5972
	return 1500;
5973
}
5974

    
5975
function get_vip_descr($ipaddress) {
5976
	global $config;
5977

    
5978
	foreach ($config['virtualip']['vip'] as $vip) {
5979
		if ($vip['subnet'] == $ipaddress) {
5980
			return ($vip['descr']);
5981
		}
5982
	}
5983
	return "";
5984
}
5985

    
5986
function interfaces_staticarp_configure($if) {
5987
	global $config, $g;
5988
	if (isset($config['system']['developerspew'])) {
5989
		$mt = microtime();
5990
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5991
	}
5992

    
5993
	$ifcfg = $config['interfaces'][$if];
5994

    
5995
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5996
		return 0;
5997
	}
5998

    
5999
	/* Enable staticarp, if enabled */
6000
	if (isset($config['dhcpd'][$if]['staticarp'])) {
6001
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
6002
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6003
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
6004
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6005
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6006
			}
6007
		}
6008
	} else {
6009
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
6010
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6011
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
6012
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6013
				if (isset($arpent['arp_table_static_entry'])) {
6014
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6015
				}
6016
			}
6017
		}
6018
	}
6019

    
6020
	return 0;
6021
}
6022

    
6023
function get_failover_interface($interface, $family = "all") {
6024
	global $config;
6025

    
6026
	/* shortcut to get_real_interface if we find it in the config */
6027
	if (is_array($config['interfaces'][$interface])) {
6028
		return get_real_interface($interface, $family);
6029
	}
6030

    
6031
	/* compare against gateway groups */
6032
	$a_groups = return_gateway_groups_array();
6033
	if (is_array($a_groups[$interface])) {
6034
		/* we found a gateway group, fetch the interface or vip */
6035
		if (!empty($a_groups[$interface][0]['vip'])) {
6036
			return $a_groups[$interface][0]['vip'];
6037
		} else {
6038
			return $a_groups[$interface][0]['int'];
6039
		}
6040
	}
6041
	/* fall through to get_real_interface */
6042
	/* XXX: Really needed? */
6043
	return get_real_interface($interface, $family);
6044
}
6045

    
6046
/****f* interfaces/interface_has_dhcp
6047
 * NAME
6048
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6049
 * INPUTS
6050
 *   interface or gateway group name
6051
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6052
 * RESULT
6053
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6054
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6055
 ******/
6056
function interface_has_dhcp($interface, $family = 4) {
6057
	global $config;
6058

    
6059
	if ($config['interfaces'][$interface]) {
6060
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6061
			return true;
6062
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6063
			return true;
6064
		} else {
6065
			return false;
6066
		}
6067
	}
6068

    
6069
	if (!is_array($config['gateways']['gateway_group'])) {
6070
		return false;
6071
	}
6072

    
6073
	if ($family == 6) {
6074
		$dhcp_string = "_DHCP6";
6075
	} else {
6076
		$dhcp_string = "_DHCP";
6077
	}
6078

    
6079
	foreach ($config['gateways']['gateway_group'] as $group) {
6080
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6081
			continue;
6082
		}
6083
		foreach ($group['item'] as $item) {
6084
			$item_data = explode("|", $item);
6085
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6086
				return true;
6087
			}
6088
		}
6089
	}
6090

    
6091
	return false;
6092
}
6093

    
6094
function remove_ifindex($ifname) {
6095
	return preg_replace("/[0-9]+$/", "", $ifname);
6096
}
6097

    
6098
?>
(27-27/67)