Project

General

Profile

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

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

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

    
72
/*
73
 * Validate comma-separated list of IPv4 addresses
74
 */
75
function validate_ipv4_list($value) {
76
	$value = trim($value);
77

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

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

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

    
90
	return true;
91
}
92

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

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

    
104
	return $interface_arr_cache;
105
}
106

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

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

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

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

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

    
137

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

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

    
160
	return false;
161
}
162

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
290
	interfaces_bring_up($vlanif);
291

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

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

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

    
306
	return $vlanif;
307
}
308

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

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

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

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

    
329
	$vlanif = interface_vlan_configure($vlan);
330

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

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

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

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

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

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

    
385
	return $vlanif;
386
}
387

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

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

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

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

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

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

    
430
	return $vlanif;
431
}
432

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

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

    
440
	$iflist = get_configured_interface_list();
441

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

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

    
465
}
466

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

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

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

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

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

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

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

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

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

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

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

    
570
	$checklist = get_configured_interface_list();
571

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

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

    
593
	interface_bridge_configure_advanced($bridge);
594

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
825
	interfaces_bring_up($laggif);
826

    
827
	return $laggif;
828
}
829

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

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

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

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

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

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

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

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

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

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

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

    
917
	interfaces_bring_up($greif);
918

    
919
	return $greif;
920
}
921

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

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

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

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

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

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

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

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

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

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

    
1053

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

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

    
1068
	interfaces_bring_up($gifif);
1069

    
1070
	return $gifif;
1071
}
1072

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

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

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

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

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

    
1088
	interfaces_qinq_configure();
1089

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

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

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

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

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

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

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

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

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

    
1152
		interface_configure($if, $reload);
1153

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

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

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

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

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

    
1176
		interface_configure($if, $reload);
1177

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

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

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

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

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

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

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

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

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

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

    
1226
	return 0;
1227
}
1228

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1449
	return;
1450
}
1451

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

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

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

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

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

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

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

    
1501
	return false;
1502
}
1503

    
1504
function interfaces_ptpid_next() {
1505

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

    
1511
	return $ptpid;
1512
}
1513

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

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

    
1526
	return NULL;
1527
}
1528

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

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

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

    
1539
	$itemhash = getMPDCRONSettings($pppif);
1540

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1833
EOD;
1834

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

    
1839
EOD;
1840
	}
1841

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

    
1850
EOD;
1851

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

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

    
1862
EOD;
1863
	}
1864

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

    
1870
EOD;
1871
	}
1872

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

    
1877
EOD;
1878
	}
1879

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

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

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

    
1895
EOD;
1896
		}
1897

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

    
1902
EOD;
1903
		}
1904

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

    
1909
EOD;
1910
		}
1911

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

    
1917
EOD;
1918

    
1919

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

    
1924
EOD;
1925
		}
1926

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

    
1940
EOD;
1941
		}
1942

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

    
1947
EOD;
1948
		}
1949

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

    
1954
EOD;
1955
		}
1956

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

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

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

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

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

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

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

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

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

    
2021
EOD;
2022
		}
2023

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

    
2029
EOD;
2030
		}
2031

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

    
2035

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

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

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

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

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

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

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

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

    
2146
	return 1;
2147
}
2148

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

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

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

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

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

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

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

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

    
2194
		sleep(1);
2195

    
2196
		/* XXX: Handle an issue with pfsync(4) and carp(4). In a cluster carp will come up before pfsync(4) has updated and so will cause issues
2197
		 * for existing sessions.
2198
		 */
2199
		log_error(gettext("waiting for pfsync..."));
2200
		$i = 0;
2201
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2202
			$i++;
2203
			sleep(1);
2204
		}
2205
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2206
		log_error(gettext("Configuring CARP settings finalize..."));
2207
	} else {
2208
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2209
	}
2210

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2463
	return $realif;
2464
}
2465

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2822
EOD;
2823

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

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

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

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

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

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

    
2858
EOD;
2859
						}
2860
					}
2861
				}
2862

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3026
	unset($wlcmd_args, $wlcmd);
3027

    
3028

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

    
3033
	return 0;
3034

    
3035
}
3036

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

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

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

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

    
3056
	return intval($pid);
3057
}
3058

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

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

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

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

    
3084
	return intval($pid);
3085
}
3086

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

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

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

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

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

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

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

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

    
3161
	return $mtu;
3162
}
3163

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

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

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

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

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

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

    
3204
	return $mtu;
3205
}
3206

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3367
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3368

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

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

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

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

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

    
3456
	interface_netgraph_needed($interface);
3457

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

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

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

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

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

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

    
3495
		if ($reloadall == true) {
3496

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3605
	return 0;
3606
}
3607

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

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

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

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

    
3628
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3629
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3630
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not valid, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
3631
		return;
3632
	}
3633
	$hexwanv4 = return_hex_ipv4($ip4address);
3634

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

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

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

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

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

    
3659
	$lanif = get_real_interface($interface);
3660
	$oip = find_interface_ipv6($lanif);
3661
	if (is_ipaddrv6($oip)) {
3662
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3663
	}
3664
	unset($interface_ipv6_arr_cache[$lanif]);
3665
	unset($interface_snv6_arr_cache[$lanif]);
3666
	log_error(sprintf(gettext('rd6 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $rd6lan, $lancfg['track6-interface'], $ip4address));
3667
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3668

    
3669
	return 0;
3670
}
3671

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

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

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

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

    
3692
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3693
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3694
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
3695
		return;
3696
	}
3697
	$hexwanv4 = return_hex_ipv4($ip4address);
3698

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

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

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

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

    
3719
	$lanif = get_real_interface($interface);
3720
	$oip = find_interface_ipv6($lanif);
3721
	if (is_ipaddrv6($oip)) {
3722
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3723
	}
3724
	unset($interface_ipv6_arr_cache[$lanif]);
3725
	unset($interface_snv6_arr_cache[$lanif]);
3726
	log_error(sprintf(gettext('sixto4 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $sixto4lan, $lancfg['track6-interface'], $ip4address));
3727
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3728

    
3729
	return 0;
3730
}
3731

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

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

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

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

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

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

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

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

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

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

    
3784

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

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

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

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

    
3819
	return 0;
3820
}
3821

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3925
	return 0;
3926
}
3927

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4046

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

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

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

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

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

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

    
4084
	return 0;
4085
}
4086

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

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

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

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

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

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

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

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

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

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

    
4159
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4160
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4161
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4162
			$id_assoc_statement_prefix .= "\n\tprefix";
4163
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4164
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4165
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4166
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4167
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4168
			}
4169
			$id_assoc_statement_prefix .= ";";
4170
		}
4171

    
4172
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4173
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4174
			$id_assoc_statement_prefix .= " {$wanif}";
4175
			$id_assoc_statement_prefix .= " {\n";
4176
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4177
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4178
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4179
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4180
			}
4181
			$id_assoc_statement_prefix .= "\t};";
4182
		}
4183

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

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

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

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

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

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

    
4233
	return $dhcp6cconf;
4234
}
4235

    
4236

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

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

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

    
4249

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

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

    
4254
	return $dhcp6cconf;
4255
}
4256

    
4257

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

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

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

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

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

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

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

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

    
4306
}
4307

    
4308
EOD;
4309

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

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

    
4324
EOD;
4325
	}
4326

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

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

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

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

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

    
4348
	return 0;
4349
}
4350

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

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

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

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

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

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

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

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

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

    
4419
	return $dhclientconf;
4420
}
4421

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

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

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

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

    
4439

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

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

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

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

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

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

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

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

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

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

    
4492
	return $dhclientconf;
4493
}
4494

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

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

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

    
4506
	return;
4507
}
4508

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

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

    
4523
	return;
4524
}
4525

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

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

    
4537
	return false;
4538
}
4539

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4657
	return $ifdesc;
4658
}
4659

    
4660
function convert_real_interface_to_friendly_descr($interface) {
4661

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

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

    
4668
	return $interface;
4669
}
4670

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

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

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

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

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

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

    
4752
	return $parents;
4753
}
4754

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

    
4763
	$realif = get_parent_interface($interface);
4764

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

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

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

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

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

    
4803
	$wanif = NULL;
4804

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

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

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

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

    
4909
	return $wanif;
4910
}
4911

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

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

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

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

    
4935
	return false;
4936
}
4937

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

    
4947
	$isv6ip = is_ipaddrv6($ip);
4948

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

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

    
4970
	return false;
4971
}
4972

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

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

    
4987
	$isv6ip = is_ipaddrv6($ip);
4988

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

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

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

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

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

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

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

    
5110
	return $mtu;
5111
}
5112

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

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

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

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

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

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

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

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

    
5191
	return NULL;
5192
}
5193

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

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

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

    
5217
	$result = array();
5218

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

    
5227
	return $result;
5228
}
5229

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

    
5233
	$result = array();
5234

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

    
5243
	return $result;
5244
}
5245

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

    
5249
	$result = array();
5250

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

    
5259
	return $result;
5260
}
5261

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
5397
	return false;
5398
}
5399

    
5400
function get_possible_listen_ips($include_ipv6_link_local=false) {
5401

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

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

    
5425
	return $interfaces;
5426
}
5427

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
5580
	return (NULL);
5581
}
5582

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

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

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

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

    
5601
	return (NULL);
5602
}
5603

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

    
5608
	$ints = array();
5609

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

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

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

    
5662
	return false;
5663
}
5664

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

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

    
5695
	return false;
5696
}
5697

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

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

    
5721
	$int_family = remove_ifindex($int);
5722

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

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

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

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

    
5763
	$cloned_interface = get_real_interface($interface);
5764

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

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

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

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

    
5811
	$cloned_interface = get_real_interface($interface);
5812

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

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

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

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

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

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

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

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

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

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

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

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

    
5907
	return false;
5908
}
5909

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

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

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

    
5921
EOD;
5922

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

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

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

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

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

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

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

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

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

    
5997
	return 0;
5998
}
5999

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

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

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

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

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

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

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

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

    
6068
	return false;
6069
}
6070

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

    
6075
?>
(25-25/65)