Project

General

Profile

Bug #6227 ยป interfaces.inc

Chris Rowe, 04/21/2016 02:01 PM

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

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

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

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

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

    
83
	return $interface_arr_cache;
84
}
85

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

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

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

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

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

    
116

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

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

    
139
	return false;
140
}
141

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
269
	interfaces_bring_up($vlanif);
270

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

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

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

    
285
	return $vlanif;
286
}
287

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

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

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

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

    
308
	$vlanif = interface_vlan_configure($vlan);
309

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

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

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

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

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

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

    
364
	return $vlanif;
365
}
366

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

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

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

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

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

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

    
409
	return $vlanif;
410
}
411

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

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

    
419
	$iflist = get_configured_interface_list();
420

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

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

    
444
}
445

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

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

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

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

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

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

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

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

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

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

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

    
549
	$checklist = get_configured_interface_list();
550

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

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

    
572
	interface_bridge_configure_advanced($bridge);
573

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
773
	/* Check if MTU was defined for this lagg interface */
774
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
775
	
776
	if ($lagg_mtu == 0 &&
777
	    is_array($config['interfaces'])) {
778
		foreach ($config['interfaces'] as $tmpinterface) {
779
			if ($tmpinterface['if'] == $lagg['laggif'] &&
780
			    !empty($tmpinterface['mtu'])) {
781
				$lagg_mtu = $tmpinterface['mtu'];
782
				break;
783
			}
784
		}
785
	}
786
	
787
	/* Just in case anything is not working well */
788
	if ($lagg_mtu == 0) {
789
		$lagg_mtu = 1500;
790
	}
791

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

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

    
807
	interfaces_bring_up($laggif);
808

    
809
	return $laggif;
810
}
811

    
812
function interfaces_gre_configure($checkparent = 0, $realif = "") {
813
	global $config;
814

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

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

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

    
850
	if (!is_array($gre)) {
851
		return -1;
852
	}
853

    
854
	$realif = get_real_interface($gre['if']);
855
	$realifip = get_interface_ip($gre['if']);
856
	$realifip6 = get_interface_ipv6($gre['if']);
857

    
858
	/* make sure the parent interface is up */
859
	interfaces_bring_up($realif);
860

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

    
869
	/* Do not change the order here for more see gre(4) NOTES section. */
870
	if (is_ipaddrv6($gre['remote-addr'])) {
871
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
872
	} else {
873
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
874
	}
875
	if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
876
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
877
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
878
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
879
	} else {
880
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
881
	}
882
	if (isset($gre['link0'])) {
883
		pfSense_interface_flags($greif, IFF_LINK0);
884
	}
885
	if (isset($gre['link1'])) {
886
		pfSense_interface_flags($greif, IFF_LINK1);
887
	}
888
	if (isset($gre['link2'])) {
889
		pfSense_interface_flags($greif, IFF_LINK2);
890
	}
891

    
892
	if ($greif) {
893
		interfaces_bring_up($greif);
894
	} else {
895
		log_error(gettext("Could not bring greif up -- variable not defined."));
896
	}
897

    
898
	if (isset($gre['link1']) && $gre['link1']) {
899
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
900
	}
901
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
902
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
903
	}
904
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
905
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
906
	}
907

    
908
	interfaces_bring_up($greif);
909

    
910
	return $greif;
911
}
912

    
913
function interfaces_gif_configure($checkparent = 0, $realif = "") {
914
	global $config;
915

    
916
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
917
		foreach ($config['gifs']['gif'] as $i => $gif) {
918
			if (empty($gif['gifif'])) {
919
				$gre['gifif'] = "gif{$i}";
920
			}
921
			if (!empty($realif) && $realif != $gif['gifif']) {
922
				continue;
923
			}
924

    
925
			if ($checkparent == 1) {
926
				if (substr($gif['if'], 0, 4) == '_vip') {
927
					continue;
928
				}
929
				if (substr($gif['if'], 0, 5) == '_lloc') {
930
					continue;
931
				}
932
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
933
					continue;
934
				}
935
			}
936
			else if ($checkparent == 2) {
937
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
938
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
939
					continue;
940
				}
941
			}
942
			/* XXX: Maybe we should report any errors?! */
943
			interface_gif_configure($gif);
944
		}
945
	}
946
}
947

    
948
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
949
function interface_gif_configure(&$gif, $gifkey = "") {
950
	global $config, $g;
951

    
952
	if (!is_array($gif)) {
953
		return -1;
954
	}
955

    
956
	$realif = get_real_interface($gif['if']);
957
	$ipaddr = get_interface_ip($gif['if']);
958

    
959
	if (is_ipaddrv4($gif['remote-addr'])) {
960
		if (is_ipaddrv4($ipaddr)) {
961
			$realifip = $ipaddr;
962
		} else {
963
			$realifip = get_interface_ip($gif['if']);
964
		}
965
		$realifgw = get_interface_gateway($gif['if']);
966
	} else if (is_ipaddrv6($gif['remote-addr'])) {
967
		if (is_ipaddrv6($ipaddr)) {
968
			$realifip = $ipaddr;
969
		} else {
970
			$realifip = get_interface_ipv6($gif['if']);
971
		}
972
		$realifgw = get_interface_gateway_v6($gif['if']);
973
	}
974
	/* make sure the parent interface is up */
975
	if ($realif) {
976
		interfaces_bring_up($realif);
977
	} else {
978
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
979
	}
980

    
981
	if (platform_booting() || !(empty($gif['gifif']))) {
982
		pfSense_interface_destroy($gif['gifif']);
983
		pfSense_interface_create($gif['gifif']);
984
		$gifif = $gif['gifif'];
985
	} else {
986
		$gifif = pfSense_interface_create("gif");
987
	}
988

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

    
1028
	if (!platform_booting()) {
1029
		$iflist = get_configured_interface_list();
1030
		foreach ($iflist as $ifname) {
1031
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1032
				if (get_interface_gateway($ifname)) {
1033
					system_routing_configure($ifname);
1034
					break;
1035
				}
1036
				if (get_interface_gateway_v6($ifname)) {
1037
					system_routing_configure($ifname);
1038
					break;
1039
				}
1040
			}
1041
		}
1042
	}
1043

    
1044

    
1045
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1046
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1047
	}
1048
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1049
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1050
	}
1051

    
1052
	if (is_ipaddrv4($realifgw)) {
1053
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1054
	}
1055
	if (is_ipaddrv6($realifgw)) {
1056
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1057
	}
1058

    
1059
	interfaces_bring_up($gifif);
1060

    
1061
	return $gifif;
1062
}
1063

    
1064
function interfaces_configure() {
1065
	global $config, $g;
1066

    
1067
	/* Set up our loopback interface */
1068
	interfaces_loopback_configure();
1069

    
1070
	/* create the unconfigured wireless clones */
1071
	interfaces_create_wireless_clones();
1072

    
1073
	/* set up LAGG virtual interfaces */
1074
	interfaces_lagg_configure();
1075

    
1076
	/* set up VLAN virtual interfaces */
1077
	interfaces_vlan_configure();
1078

    
1079
	interfaces_qinq_configure();
1080

    
1081
	$iflist = get_configured_interface_with_descr();
1082
	$delayed_list = array();
1083
	$bridge_list = array();
1084
	$track6_list = array();
1085

    
1086
	/* This is needed to speedup interfaces on bootup. */
1087
	$reload = false;
1088
	if (!platform_booting()) {
1089
		$reload = true;
1090
	}
1091

    
1092
	foreach ($iflist as $if => $ifname) {
1093
		$realif = $config['interfaces'][$if]['if'];
1094
		if (strstr($realif, "bridge")) {
1095
			$bridge_list[$if] = $ifname;
1096
		} else if (strstr($realif, "gre")) {
1097
			$delayed_list[$if] = $ifname;
1098
		} else if (strstr($realif, "gif")) {
1099
			$delayed_list[$if] = $ifname;
1100
		} else if (strstr($realif, "ovpn")) {
1101
			//echo "Delaying OpenVPN interface configuration...done.\n";
1102
			continue;
1103
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1104
			$track6_list[$if] = $ifname;
1105
		} else {
1106
			if (platform_booting()) {
1107
				printf(gettext("Configuring %s interface..."), $ifname);
1108
			}
1109

    
1110
			if ($g['debug']) {
1111
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1112
			}
1113
			interface_configure($if, $reload);
1114
			if (platform_booting()) {
1115
				echo gettext("done.") . "\n";
1116
			}
1117
		}
1118
	}
1119

    
1120
	/*
1121
	 * NOTE: The following function parameter consists of
1122
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1123
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1124
	 */
1125

    
1126
	/* set up GRE virtual interfaces */
1127
	interfaces_gre_configure(1);
1128

    
1129
	/* set up GIF virtual interfaces */
1130
	interfaces_gif_configure(1);
1131

    
1132
	/* set up BRIDGe virtual interfaces */
1133
	interfaces_bridge_configure(1);
1134

    
1135
	foreach ($track6_list as $if => $ifname) {
1136
		if (platform_booting()) {
1137
			printf(gettext("Configuring %s interface..."), $ifname);
1138
		}
1139
		if ($g['debug']) {
1140
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1141
		}
1142

    
1143
		interface_configure($if, $reload);
1144

    
1145
		if (platform_booting()) {
1146
			echo gettext("done.") . "\n";
1147
		}
1148
	}
1149

    
1150
	/* bring up vip interfaces */
1151
	interfaces_vips_configure();
1152

    
1153
	/* set up GRE virtual interfaces */
1154
	interfaces_gre_configure(2);
1155

    
1156
	/* set up GIF virtual interfaces */
1157
	interfaces_gif_configure(2);
1158

    
1159
	foreach ($delayed_list as $if => $ifname) {
1160
		if (platform_booting()) {
1161
			printf(gettext("Configuring %s interface..."), $ifname);
1162
		}
1163
		if ($g['debug']) {
1164
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1165
		}
1166

    
1167
		interface_configure($if, $reload);
1168

    
1169
		if (platform_booting()) {
1170
			echo gettext("done.") . "\n";
1171
		}
1172
	}
1173

    
1174
	/* set up BRIDGe virtual interfaces */
1175
	interfaces_bridge_configure(2);
1176

    
1177
	foreach ($bridge_list as $if => $ifname) {
1178
		if (platform_booting()) {
1179
			printf(gettext("Configuring %s interface..."), $ifname);
1180
		}
1181
		if ($g['debug']) {
1182
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1183
		}
1184

    
1185
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct. 
1186
		// redmine #3997
1187
		interface_reconfigure($if, $reload);
1188
		interfaces_vips_configure($if);
1189

    
1190
		if (platform_booting()) {
1191
			echo gettext("done.") . "\n";
1192
		}
1193
	}
1194

    
1195
	/* configure interface groups */
1196
	interfaces_group_setup();
1197

    
1198
	if (!platform_booting()) {
1199
		/* reconfigure static routes (kernel may have deleted them) */
1200
		system_routing_configure();
1201

    
1202
		/* reload IPsec tunnels */
1203
		vpn_ipsec_configure();
1204

    
1205
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1206
		services_dhcpd_configure();
1207

    
1208
		/* restart dnsmasq or unbound */
1209
		if (isset($config['dnsmasq']['enable'])) {
1210
			services_dnsmasq_configure();
1211
		} elseif (isset($config['unbound']['enable'])) {
1212
			services_unbound_configure();
1213
		}
1214
	}
1215

    
1216
	return 0;
1217
}
1218

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1443
	return;
1444
}
1445

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

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

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

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

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

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

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

    
1495
	return false;
1496
}
1497

    
1498
function interfaces_ptpid_next() {
1499

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

    
1505
	return $ptpid;
1506
}
1507

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

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

    
1520
	return NULL;
1521
}
1522

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

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

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

    
1533
	$itemhash = getMPDCRONSettings($pppif);
1534

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1822
EOD;
1823

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

    
1828
EOD;
1829
	}
1830

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

    
1839
EOD;
1840

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

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

    
1851
EOD;
1852
	}
1853

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

    
1859
EOD;
1860
	}
1861

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

    
1866
EOD;
1867
	}
1868

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

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

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

    
1884
EOD;
1885
		}
1886

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

    
1891
EOD;
1892
		}
1893

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

    
1898
EOD;
1899
		}
1900

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

    
1906
EOD;
1907

    
1908

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

    
1913
EOD;
1914
		}
1915

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

    
1929
EOD;
1930
		}
1931

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

    
1936
EOD;
1937
		}
1938

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

    
1943
EOD;
1944
		}
1945

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

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

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

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

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

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

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

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

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

    
2010
EOD;
2011
		}
2012

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

    
2018
EOD;
2019
		}
2020

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

    
2024

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

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

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

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

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

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

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

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

    
2134
	return 1;
2135
}
2136

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

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

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

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

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

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

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

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

    
2182
		sleep(1);
2183

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2447
	return $realif;
2448
}
2449

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2808
EOD;
2809

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

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

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

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

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

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

    
2844
EOD;
2845
						}
2846
					}
2847
				}
2848

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3011
	unset($wlcmd_args, $wlcmd);
3012

    
3013

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

    
3018
	return 0;
3019

    
3020
}
3021

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

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

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

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

    
3041
	return intval($pid);
3042
}
3043

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

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

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

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

    
3069
	return intval($pid);
3070
}
3071

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

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

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

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

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

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

    
3135
	return $mtu;
3136
}
3137

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

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

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

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

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

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

    
3178
	return $mtu;
3179
}
3180

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3337
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3338

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

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

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

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

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

    
3426
	interface_netgraph_needed($interface);
3427

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

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

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

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

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

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

    
3465
		if ($reloadall == true) {
3466

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

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

    
3473
			/* restart dnsmasq or unbound */
3474
			if (isset($config['dnsmasq']['enable'])) {
3475
				services_dnsmasq_configure();
3476
			} elseif (isset($config['unbound']['enable'])) {
3477
				services_unbound_configure();
3478
			}
3479

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

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

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

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

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

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

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

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

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

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

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

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

    
3566
		services_dhcpd_configure("inet6");
3567
	}
3568

    
3569
	return 0;
3570
}
3571

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

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

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

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