Project

General

Profile

Feature #6899 » interfaces.inc

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

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

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

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

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

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

    
83
	return $interface_arr_cache;
84
}
85

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

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

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

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

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

    
116

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

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

    
139
	return false;
140
}
141

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
269
	interfaces_bring_up($vlanif);
270

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

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

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

    
285
	return $vlanif;
286
}
287

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

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

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

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

    
308
	$vlanif = interface_vlan_configure($vlan);
309

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

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

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

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

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

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

    
364
	return $vlanif;
365
}
366

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

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

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

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

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

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

    
409
	return $vlanif;
410
}
411

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

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

    
419
	$iflist = get_configured_interface_list();
420

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

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

    
444
}
445

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

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

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

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

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

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

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

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

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

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

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

    
549
	$checklist = get_configured_interface_list();
550

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

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

    
572
	interface_bridge_configure_advanced($bridge);
573

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
804
	interfaces_bring_up($laggif);
805

    
806
	return $laggif;
807
}
808

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

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

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

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

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

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

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

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

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

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

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

    
896
	interfaces_bring_up($greif);
897

    
898
	return $greif;
899
}
900

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

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

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

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

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

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

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

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

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

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

    
1032

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

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

    
1047
	interfaces_bring_up($gifif);
1048

    
1049
	return $gifif;
1050
}
1051

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

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

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

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

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

    
1067
	interfaces_qinq_configure();
1068

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

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

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

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

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

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

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

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

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

    
1131
		interface_configure($if, $reload);
1132

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

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

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

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

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

    
1155
		interface_configure($if, $reload);
1156

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

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

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

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

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

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

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

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

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

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

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

    
1205
	return 0;
1206
}
1207

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1432
	return;
1433
}
1434

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

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

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

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

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

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

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

    
1484
	return false;
1485
}
1486

    
1487
function interfaces_ptpid_next() {
1488

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

    
1494
	return $ptpid;
1495
}
1496

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

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

    
1509
	return NULL;
1510
}
1511

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

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

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

    
1522
	$itemhash = getMPDCRONSettings($pppif);
1523

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

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

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

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

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

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

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

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

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

    
1685
				if (!is_ipaddr($localips[$pid])) {
1686
					log_error(sprintf(gettext("Could not get a Local IP address for PPTP/L2TP link on %s in interfaces_ppps_configure. Using 0.0.0.0 ip!"), $port));
1687
					$localips[$pid] = "0.0.0.0";
1688
				}
1689
				if(!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])){
1690
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1691
				}
1692
				if (!is_ipaddr($gateways[$pid])) {
1693
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $dhcp_gateway, $gway));
1694
					return 0;
1695
				}
1696
				pfSense_ngctl_attach(".", $port);
1697
				break;
1698
			case "ppp":
1699
				if (!file_exists("{$port}")) {
1700
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1701
					return 0;
1702
				}
1703
				break;
1704
			default:
1705
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1706
				break;
1707
		}
1708
	}
1709

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

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

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

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

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

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

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

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

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

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

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

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

    
1816
EOD;
1817

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

    
1822
EOD;
1823
	}
1824

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

    
1833
EOD;
1834

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

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

    
1845
EOD;
1846
	}
1847

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

    
1853
EOD;
1854
	}
1855

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

    
1860
EOD;
1861
	}
1862

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

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

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

    
1878
EOD;
1879
		}
1880

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

    
1885
EOD;
1886
		}
1887

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

    
1892
EOD;
1893
		}
1894

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

    
1900
EOD;
1901

    
1902

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

    
1907
EOD;
1908
		}
1909

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

    
1923
EOD;
1924
		}
1925

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

    
1930
EOD;
1931
		}
1932

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

    
1937
EOD;
1938
		}
1939

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

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

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

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

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

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

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

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

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

    
2004
EOD;
2005
		}
2006

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

    
2012
EOD;
2013
		}
2014

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

    
2018

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

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

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

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

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

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

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

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

    
2129
	return 1;
2130
}
2131

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

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

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

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

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

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

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

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

    
2177
		sleep(1);
2178

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2442
	return $realif;
2443
}
2444

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2803
EOD;
2804

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

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

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

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

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

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

    
2839
EOD;
2840
						}
2841
					}
2842
				}
2843

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3006
	unset($wlcmd_args, $wlcmd);
3007

    
3008

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

    
3013
	return 0;
3014

    
3015
}
3016

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

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

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

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

    
3036
	return intval($pid);
3037
}
3038

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

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

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

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

    
3064
	return intval($pid);
3065
}
3066

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

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

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

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

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

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

    
3130
	return $mtu;
3131
}
3132

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

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

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

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

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

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

    
3173
	return $mtu;
3174
}
3175

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3332
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3333

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

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

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

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

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

    
3421
	interface_netgraph_needed($interface);
3422

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

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

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

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

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

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

    
3460
		if ($reloadall == true) {
3461

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3566
		services_dhcpd_configure("inet6");
3567
	}
3568

    
3569
	return 0;
3570
}
3571

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

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

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

    
3586
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3587
	if (empty(