Project

General

Profile

Download (173 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * interfaces.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 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
		/* restart dns servers (defering dhcpd reload) */
1194
		if (isset($config['dnsmasq']['enable'])) {
1195
			services_dnsmasq_configure(false);
1196
		}
1197
		if (isset($config['unbound']['enable'])) {
1198
			services_unbound_configure(false);
1199
		}
1200

    
1201
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1202
		services_dhcpd_configure();
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
			kill_dhcp6client_process($realif);
1336
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1337
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1338
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1339
			if (does_interface_exist($realifv6)) {
1340
				$ip6 = find_interface_ipv6($realifv6);
1341
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1342
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1343
				}
1344
				interface_vip_cleanup($interface, "inet6");
1345
				if ($destroy == true) {
1346
					pfSense_interface_flags($realif, -IFF_UP);
1347
				}
1348
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1349
			}
1350
			$track6 = link_interface_to_track6($interface);
1351
			break;
1352
		case "6rd":
1353
		case "6to4":
1354
			$realif = "{$interface}_stf";
1355
			if (does_interface_exist("$realif")) {
1356
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1357
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1358
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1359
					$destroy = true;
1360
				} else {
1361
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1362
					$ip6 = get_interface_ipv6($interface);
1363
					if (is_ipaddrv6($ip6)) {
1364
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1365
					}
1366
				}
1367
				interface_vip_cleanup($interface, "inet6");
1368
				if ($destroy == true) {
1369
					pfSense_interface_flags($realif, -IFF_UP);
1370
				}
1371
			}
1372
			$track6 = link_interface_to_track6($interface);
1373
			break;
1374
		default:
1375
			if (does_interface_exist("$realif")) {
1376
				$ip6 = get_interface_ipv6($interface);
1377
				if (is_ipaddrv6($ip6)) {
1378
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1379
				}
1380
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1381
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1382
				}
1383
				interface_vip_cleanup($interface, "inet6");
1384
				if ($destroy == true) {
1385
					pfSense_interface_flags($realif, -IFF_UP);
1386
				}
1387
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1388
			}
1389
			$track6 = link_interface_to_track6($interface);
1390
			break;
1391
	}
1392

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

    
1401
	$old_router = '';
1402
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1403
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1404
	}
1405

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

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

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

    
1428
	return;
1429
}
1430

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

    
1441
	$viparr = &$config['virtualip']['vip'];
1442
	foreach ($viparr as $vip) {
1443
		if ($vip['mode'] == "carp") {
1444
			interface_carp_configure($vip);
1445
		}
1446
	}
1447
}
1448

    
1449
function interface_isppp_type($interface) {
1450
	global $config;
1451

    
1452
	if (!is_array($config['interfaces'][$interface])) {
1453
		return false;
1454
	}
1455

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

    
1469
function interfaces_ptpid_used($ptpid) {
1470
	global $config;
1471

    
1472
	if (is_array($config['ppps']['ppp'])) {
1473
		foreach ($config['ppps']['ppp'] as & $settings) {
1474
			if ($ptpid == $settings['ptpid']) {
1475
				return true;
1476
			}
1477
		}
1478
	}
1479

    
1480
	return false;
1481
}
1482

    
1483
function interfaces_ptpid_next() {
1484

    
1485
	$ptpid = 0;
1486
	while (interfaces_ptpid_used($ptpid)) {
1487
		$ptpid++;
1488
	}
1489

    
1490
	return $ptpid;
1491
}
1492

    
1493
function getMPDCRONSettings($pppif) {
1494
	global $config;
1495

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

    
1505
	return NULL;
1506
}
1507

    
1508
function handle_pppoe_reset($post_array) {
1509
	global $config, $g;
1510

    
1511
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1512
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1513

    
1514
	if (!is_array($config['cron']['item'])) {
1515
		$config['cron']['item'] = array();
1516
	}
1517

    
1518
	$itemhash = getMPDCRONSettings($pppif);
1519

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

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

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

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

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

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

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

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

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

    
1681
				if (!is_ipaddr($localips[$pid])) {
1682
					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));
1683
					$localips[$pid] = "0.0.0.0";
1684
				}
1685
				if (!is_ipaddr($gateways[$pid])) {
1686
					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));
1687
					return 0;
1688
				}
1689
				pfSense_ngctl_attach(".", $port);
1690
				break;
1691
			case "ppp":
1692
				if (!file_exists("{$port}")) {
1693
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1694
					return 0;
1695
				}
1696
				break;
1697
			default:
1698
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1699
				break;
1700
		}
1701
	}
1702

    
1703
	if (is_array($ports) && count($ports) > 1) {
1704
		$multilink = "enable";
1705
	} else {
1706
		$multilink = "disable";
1707
	}
1708

    
1709
	if ($type == "modem") {
1710
		if (is_ipaddr($ppp['localip'])) {
1711
			$localip = $ppp['localip'];
1712
		} else {
1713
			$localip = '0.0.0.0';
1714
		}
1715

    
1716
		if (is_ipaddr($ppp['gateway'])) {
1717
			$gateway = $ppp['gateway'];
1718
		} else {
1719
			$gateway = "10.64.64.{$pppid}";
1720
		}
1721
		$ranges = "{$localip}/0 {$gateway}/0";
1722

    
1723
		if (empty($ppp['apnum'])) {
1724
			$ppp['apnum'] = 1;
1725
		}
1726
	} else {
1727
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1728
	}
1729

    
1730
	if (isset($ppp['ondemand'])) {
1731
		$ondemand = "enable";
1732
	} else {
1733
		$ondemand = "disable";
1734
	}
1735
	if (!isset($ppp['idletimeout'])) {
1736
		$ppp['idletimeout'] = 0;
1737
	}
1738

    
1739
	if (empty($ppp['username']) && $type == "modem") {
1740
		$ppp['username'] = "user";
1741
		$ppp['password'] = "none";
1742
	}
1743
	if (empty($ppp['password']) && $type == "modem") {
1744
		$passwd = "none";
1745
	} else {
1746
		$passwd = base64_decode($ppp['password']);
1747
	}
1748

    
1749
	$bandwidths = explode(',', $ppp['bandwidth']);
1750
	$defaultmtu = "1492";
1751
	if (!empty($ifcfg['mtu'])) {
1752
		$defaultmtu = intval($ifcfg['mtu']);
1753
	}
1754
	if (isset($ppp['mtu'])) {
1755
		$mtus = explode(',', $ppp['mtu']);
1756
	}
1757
	if (isset($ppp['mru'])) {
1758
		$mrus = explode(',', $ppp['mru']);
1759
	}
1760
	if (isset($ppp['mrru'])) {
1761
		$mrrus = explode(',', $ppp['mrru']);
1762
	}
1763

    
1764
	// Construct the mpd.conf file
1765
	$mpdconf = <<<EOD
1766
startup:
1767
	# configure the console
1768
	set console close
1769
	# configure the web server
1770
	set web close
1771

    
1772
default:
1773
{$ppp['type']}client:
1774
	create bundle static {$interface}
1775
	set bundle enable ipv6cp
1776
	set iface name {$pppif}
1777

    
1778
EOD;
1779
	$setdefaultgw = false;
1780
	$founddefaultgw = false;
1781
	if (is_array($config['gateways']['gateway_item'])) {
1782
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1783
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1784
				$setdefaultgw = true;
1785
				break;
1786
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1787
				$founddefaultgw = true;
1788
				break;
1789
			}
1790
		}
1791
	}
1792

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

    
1803
EOD;
1804
	}
1805
	$mpdconf .= <<<EOD
1806
	set iface {$ondemand} on-demand
1807
	set iface idle {$ppp['idletimeout']}
1808

    
1809
EOD;
1810

    
1811
	if (isset($ppp['ondemand'])) {
1812
		$mpdconf .= <<<EOD
1813
	set iface addrs 10.10.1.1 10.10.1.2
1814

    
1815
EOD;
1816
	}
1817

    
1818
	if (isset($ppp['tcpmssfix'])) {
1819
		$tcpmss = "disable";
1820
	} else {
1821
		$tcpmss = "enable";
1822
	}
1823
	$mpdconf .= <<<EOD
1824
	set iface {$tcpmss} tcpmssfix
1825

    
1826
EOD;
1827

    
1828
	$mpdconf .= <<<EOD
1829
	set iface up-script /usr/local/sbin/ppp-linkup
1830
	set iface down-script /usr/local/sbin/ppp-linkdown
1831
	set ipcp ranges {$ranges}
1832

    
1833
EOD;
1834
	if (isset($ppp['vjcomp'])) {
1835
		$mpdconf .= <<<EOD
1836
	set ipcp no vjcomp
1837

    
1838
EOD;
1839
	}
1840

    
1841
	if (isset($config['system']['dnsallowoverride'])) {
1842
		$mpdconf .= <<<EOD
1843
	set ipcp enable req-pri-dns
1844
	set ipcp enable req-sec-dns
1845

    
1846
EOD;
1847
	}
1848

    
1849
	if (!isset($ppp['verbose_log'])) {
1850
		$mpdconf .= <<<EOD
1851
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1852

    
1853
EOD;
1854
	}
1855

    
1856
	foreach ($ports as $pid => $port) {
1857
		$port = get_real_interface($port);
1858
		$mpdconf .= <<<EOD
1859

    
1860
	create link static {$interface}_link{$pid} {$type}
1861
	set link action bundle {$interface}
1862
	set link {$multilink} multilink
1863
	set link keep-alive 10 60
1864
	set link max-redial 0
1865

    
1866
EOD;
1867
		if (isset($ppp['shortseq'])) {
1868
			$mpdconf .= <<<EOD
1869
	set link no shortseq
1870

    
1871
EOD;
1872
		}
1873

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

    
1878
EOD;
1879
		}
1880

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

    
1885
EOD;
1886
		}
1887

    
1888
		$mpdconf .= <<<EOD
1889
	set link disable chap pap
1890
	set link accept chap pap eap
1891
	set link disable incoming
1892

    
1893
EOD;
1894

    
1895

    
1896
		if (!empty($bandwidths[$pid])) {
1897
			$mpdconf .= <<<EOD
1898
	set link bandwidth {$bandwidths[$pid]}
1899

    
1900
EOD;
1901
		}
1902

    
1903
		if (empty($mtus[$pid])) {
1904
			$mtus[$pid] = $defaultmtu;
1905
		}
1906
		if ($type == "pppoe") {
1907
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
1908
				$mtus[$pid] = get_interface_mtu($port) - 8;
1909
			}
1910
		}
1911
		if (! ($type == "pppoe" && $mtus[$pid] > 1492) ) {
1912
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
1913
			$mpdconf .= <<<EOD
1914
	set link mtu {$mtus[$pid]}
1915

    
1916
EOD;
1917
		}
1918

    
1919
		if (!empty($mrus[$pid])) {
1920
			$mpdconf .= <<<EOD
1921
	set link mru {$mrus[$pid]}
1922

    
1923
EOD;
1924
		}
1925

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

    
1930
EOD;
1931
		}
1932

    
1933
		$mpdconf .= <<<EOD
1934
	set auth authname "{$ppp['username']}"
1935
	set auth password {$passwd}
1936

    
1937
EOD;
1938
		if ($type == "modem") {
1939
			$mpdconf .= <<<EOD
1940
	set modem device {$ppp['ports']}
1941
	set modem script DialPeer
1942
	set modem idle-script Ringback
1943
	set modem watch -cd
1944
	set modem var \$DialPrefix "DT"
1945
	set modem var \$Telephone "{$ppp['phone']}"
1946

    
1947
EOD;
1948
		}
1949
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1950
			$mpdconf .= <<<EOD
1951
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1952

    
1953
EOD;
1954
		}
1955
		if (isset($ppp['initstr']) && $type == "modem") {
1956
			$initstr = base64_decode($ppp['initstr']);
1957
			$mpdconf .= <<<EOD
1958
	set modem var \$InitString "{$initstr}"
1959

    
1960
EOD;
1961
		}
1962
		if (isset($ppp['simpin']) && $type == "modem") {
1963
			if ($ppp['pin-wait'] == "") {
1964
				$ppp['pin-wait'] = 0;
1965
			}
1966
			$mpdconf .= <<<EOD
1967
	set modem var \$SimPin "{$ppp['simpin']}"
1968
	set modem var \$PinWait "{$ppp['pin-wait']}"
1969

    
1970
EOD;
1971
		}
1972
		if (isset($ppp['apn']) && $type == "modem") {
1973
			$mpdconf .= <<<EOD
1974
	set modem var \$APN "{$ppp['apn']}"
1975
	set modem var \$APNum "{$ppp['apnum']}"
1976

    
1977
EOD;
1978
		}
1979
		if ($type == "pppoe") {
1980
			// Send a null service name if none is set.
1981
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1982
			$mpdconf .= <<<EOD
1983
	set pppoe service "{$provider}"
1984

    
1985
EOD;
1986
		}
1987
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
1988
			$mpdconf .= <<<EOD
1989
	set pppoe max-payload {$mtus[$pid]}
1990

    
1991
EOD;
1992
		}
1993
		if ($type == "pppoe") {
1994
			$mpdconf .= <<<EOD
1995
	set pppoe iface {$port}
1996

    
1997
EOD;
1998
		}
1999

    
2000
		if ($type == "pptp" || $type == "l2tp") {
2001
			$mpdconf .= <<<EOD
2002
	set {$type} self {$localips[$pid]}
2003
	set {$type} peer {$gateways[$pid]}
2004

    
2005
EOD;
2006
		}
2007

    
2008
		$mpdconf .= "\topen\n";
2009
	} //end foreach ($port)
2010

    
2011

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

    
2027
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2028
	if (isset($ppp['uptime'])) {
2029
		if (!file_exists("/conf/{$pppif}.log")) {
2030
			conf_mount_rw();
2031
			file_put_contents("/conf/{$pppif}.log", '');
2032
			conf_mount_ro();
2033
		}
2034
	} else {
2035
		if (file_exists("/conf/{$pppif}.log")) {
2036
			conf_mount_rw();
2037
			@unlink("/conf/{$pppif}.log");
2038
			conf_mount_ro();
2039
		}
2040
	}
2041

    
2042
	/* clean up old lock files */
2043
	foreach ($ports as $port) {
2044
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2045
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2046
		}
2047
	}
2048

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

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

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

    
2092
	/* Remove all temporary bogon IPv4 addresses */
2093
	if (is_array($tempaddr)) {
2094
		foreach ($tempaddr as $tempiface) {
2095
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2096
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2097
			}
2098
		}
2099
		unset ($tempaddr);
2100
	}
2101

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

    
2122
	return 1;
2123
}
2124

    
2125
function interfaces_sync_setup() {
2126
	global $g, $config;
2127

    
2128
	if (isset($config['system']['developerspew'])) {
2129
		$mt = microtime();
2130
		echo "interfaces_sync_setup() being called $mt\n";
2131
	}
2132

    
2133
	if (platform_booting()) {
2134
		echo gettext("Configuring CARP settings...");
2135
		mute_kernel_msgs();
2136
	}
2137

    
2138
	/* suck in configuration items */
2139
	if ($config['hasync']) {
2140
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2141
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2142
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2143
	} else {
2144
		unset($pfsyncinterface);
2145
		unset($pfsyncenabled);
2146
	}
2147

    
2148
	set_sysctl(array(
2149
		"net.inet.carp.preempt" => "1",
2150
		"net.inet.carp.log" => "1")
2151
	);
2152

    
2153
	if (!empty($pfsyncinterface)) {
2154
		$carp_sync_int = get_real_interface($pfsyncinterface);
2155
	} else {
2156
		unset($carp_sync_int);
2157
	}
2158

    
2159
	/* setup pfsync interface */
2160
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2161
		if (is_ipaddr($pfsyncpeerip)) {
2162
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2163
		} else {
2164
			$syncpeer = "-syncpeer";
2165
		}
2166

    
2167
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2168
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2169

    
2170
		sleep(1);
2171

    
2172
		/* 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
2173
		 * for existing sessions.
2174
		 */
2175
		log_error(gettext("waiting for pfsync..."));
2176
		$i = 0;
2177
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2178
			$i++;
2179
			sleep(1);
2180
		}
2181
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2182
		log_error(gettext("Configuring CARP settings finalize..."));
2183
	} else {
2184
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2185
	}
2186

    
2187
	$carplist = get_configured_vip_list('all', VIP_CARP);
2188
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2189
		set_single_sysctl("net.inet.carp.allow", "1");
2190
	} else {
2191
		set_single_sysctl("net.inet.carp.allow", "0");
2192
	}
2193

    
2194
	if (platform_booting()) {
2195
		unmute_kernel_msgs();
2196
		echo gettext("done.") . "\n";
2197
	}
2198
}
2199

    
2200
function interface_proxyarp_configure($interface = "") {
2201
	global $config, $g;
2202
	if (isset($config['system']['developerspew'])) {
2203
		$mt = microtime();
2204
		echo "interface_proxyarp_configure() being called $mt\n";
2205
	}
2206

    
2207
	/* kill any running choparp */
2208
	if (empty($interface)) {
2209
		killbyname("choparp");
2210
	} else {
2211
		$vipif = get_real_interface($interface);
2212
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2213
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2214
		}
2215
	}
2216

    
2217
	$paa = array();
2218
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2219

    
2220
		/* group by interface */
2221
		foreach ($config['virtualip']['vip'] as $vipent) {
2222
			if ($vipent['mode'] === "proxyarp") {
2223
				if ($vipent['interface']) {
2224
					$proxyif = $vipent['interface'];
2225
				} else {
2226
					$proxyif = "wan";
2227
				}
2228

    
2229
				if (!empty($interface) && $interface != $proxyif) {
2230
					continue;
2231
				}
2232

    
2233
				if (!is_array($paa[$proxyif])) {
2234
					$paa[$proxyif] = array();
2235
				}
2236

    
2237
				$paa[$proxyif][] = $vipent;
2238
			}
2239
		}
2240
	}
2241

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

    
2277
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2278
	global $g, $config;
2279

    
2280
	if (is_array($config['virtualip']['vip'])) {
2281
		foreach ($config['virtualip']['vip'] as $vip) {
2282

    
2283
			$iface = $vip['interface'];
2284
			if (substr($iface, 0, 4) == "_vip")
2285
				$iface = get_configured_vip_interface($vip['interface']);
2286
			if ($iface != $interface)
2287
				continue;
2288
			if ($type == VIP_CARP) {
2289
				if ($vip['mode'] != "carp")
2290
					continue;
2291
			} elseif ($type == VIP_IPALIAS) {
2292
				if ($vip['mode'] != "ipalias")
2293
					continue;
2294
			} else {
2295
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2296
					continue;
2297
			}
2298

    
2299
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2300
				interface_vip_bring_down($vip);
2301
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2302
				interface_vip_bring_down($vip);
2303
			else if ($inet == "all")
2304
				interface_vip_bring_down($vip);
2305
		}
2306
	}
2307
}
2308

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

    
2357
function interface_ipalias_configure(&$vip) {
2358
	global $config;
2359

    
2360
	if ($vip['mode'] != 'ipalias') {
2361
		return;
2362
	}
2363

    
2364
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2365
	if ($realif != "lo0") {
2366
		$if = convert_real_interface_to_friendly_interface_name($realif);
2367
		if (!isset($config['interfaces'][$if])) {
2368
			return;
2369
		}
2370

    
2371
		if (!isset($config['interfaces'][$if]['enable'])) {
2372
			return;
2373
		}
2374
	}
2375

    
2376
	$af = 'inet';
2377
	if (is_ipaddrv6($vip['subnet'])) {
2378
		$af = 'inet6';
2379
	}
2380
	$iface = $vip['interface'];
2381
	$vhid = '';
2382
	if (substr($vip['interface'], 0, 4) == "_vip") {
2383
		$carpvip = get_configured_vip($vip['interface']);
2384
		$iface = $carpvip['interface'];
2385
		$vhid = "vhid {$carpvip['vhid']}";
2386
	}
2387
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2388
	unset($iface, $af, $realif, $carpvip, $vhid);
2389
}
2390

    
2391
function interface_carp_configure(&$vip) {
2392
	global $config, $g;
2393
	if (isset($config['system']['developerspew'])) {
2394
		$mt = microtime();
2395
		echo "interface_carp_configure() being called $mt\n";
2396
	}
2397

    
2398
	if ($vip['mode'] != "carp") {
2399
		return;
2400
	}
2401

    
2402
	/* NOTE: Maybe its useless nowadays */
2403
	$realif = get_real_interface($vip['interface']);
2404
	if (!does_interface_exist($realif)) {
2405
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2406
		return;
2407
	}
2408

    
2409
	$vip_password = $vip['password'];
2410
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2411
	if ($vip['password'] != "") {
2412
		$password = " pass {$vip_password}";
2413
	}
2414

    
2415
	$advbase = "";
2416
	if (!empty($vip['advbase'])) {
2417
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2418
	}
2419

    
2420
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2421
	if ($carp_maintenancemode) {
2422
		$advskew = "advskew 254";
2423
	} else {
2424
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2425
	}
2426

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

    
2429
	if (is_ipaddrv4($vip['subnet'])) {
2430
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2431
	} else if (is_ipaddrv6($vip['subnet'])) {
2432
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2433
	}
2434

    
2435
	return $realif;
2436
}
2437

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

    
2480
	if ($needs_clone == true) {
2481
		/* remove previous instance if it exists */
2482
		if (does_interface_exist($realif)) {
2483
			pfSense_interface_destroy($realif);
2484
		}
2485

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

    
2502
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2503
	global $config, $g;
2504

    
2505
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2506
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2507
				 'regdomain', 'regcountry', 'reglocation');
2508

    
2509
	if (!is_interface_wireless($ifcfg['if'])) {
2510
		return;
2511
	}
2512

    
2513
	$baseif = interface_get_wireless_base($ifcfg['if']);
2514

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

    
2542
	// Read or write settings at shared area
2543
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2544
		foreach ($shared_settings as $setting) {
2545
			if ($sync_changes) {
2546
				if (isset($ifcfg['wireless'][$setting])) {
2547
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2548
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2549
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2550
				}
2551
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2552
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2553
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2554
				} else if (isset($ifcfg['wireless'][$setting])) {
2555
					unset($ifcfg['wireless'][$setting]);
2556
				}
2557
			}
2558
		}
2559
	}
2560

    
2561
	// Sync the mode on the clone creation page with the configured mode on the interface
2562
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2563
		foreach ($config['wireless']['clone'] as &$clone) {
2564
			if ($clone['cloneif'] == $ifcfg['if']) {
2565
				if ($sync_changes) {
2566
					$clone['mode'] = $ifcfg['wireless']['mode'];
2567
				} else {
2568
					$ifcfg['wireless']['mode'] = $clone['mode'];
2569
				}
2570
				break;
2571
			}
2572
		}
2573
		unset($clone);
2574
	}
2575
}
2576

    
2577
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2578
	global $config, $g;
2579

    
2580
	/*    open up a shell script that will be used to output the commands.
2581
	 *    since wireless is changing a lot, these series of commands are fragile
2582
	 *    and will sometimes need to be verified by a operator by executing the command
2583
	 *    and returning the output of the command to the developers for inspection.  please
2584
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2585
	 */
2586

    
2587
	// Remove script file
2588
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2589

    
2590
	// Clone wireless nic if needed.
2591
	interface_wireless_clone($if, $wl);
2592

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

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

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

    
2602
	/* set values for /path/program */
2603
	$hostapd = "/usr/sbin/hostapd";
2604
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2605
	$ifconfig = "/sbin/ifconfig";
2606
	$sysctl = "/sbin/sysctl";
2607
	$killall = "/usr/bin/killall";
2608

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

    
2611
	$wlcmd = array();
2612
	$wl_sysctl = array();
2613
	/* Make sure it's up */
2614
	$wlcmd[] = "up";
2615
	/* Set a/b/g standard */
2616
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2617
	/* skip mode entirely for "auto" */
2618
	if ($wlcfg['standard'] != "auto") {
2619
		$wlcmd[] = "mode " . escapeshellarg($standard);
2620
	}
2621

    
2622
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2623
	 * to prevent massive packet loss under certain conditions. */
2624
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2625
		$wlcmd[] = "-ampdu";
2626
	}
2627

    
2628
	/* Set ssid */
2629
	if ($wlcfg['ssid']) {
2630
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2631
	}
2632

    
2633
	/* Set 802.11g protection mode */
2634
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2635

    
2636
	/* set wireless channel value */
2637
	if (isset($wlcfg['channel'])) {
2638
		if ($wlcfg['channel'] == "0") {
2639
			$wlcmd[] = "channel any";
2640
		} else {
2641
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2642
		}
2643
	}
2644

    
2645
	/* Set antenna diversity value */
2646
	if (isset($wlcfg['diversity'])) {
2647
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2648
	}
2649

    
2650
	/* Set txantenna value */
2651
	if (isset($wlcfg['txantenna'])) {
2652
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2653
	}
2654

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

    
2660
	/* set Distance value */
2661
	if ($wlcfg['distance']) {
2662
		$distance = escapeshellarg($wlcfg['distance']);
2663
	}
2664

    
2665
	/* Set wireless hostap mode */
2666
	if ($wlcfg['mode'] == "hostap") {
2667
		$wlcmd[] = "mediaopt hostap";
2668
	} else {
2669
		$wlcmd[] = "-mediaopt hostap";
2670
	}
2671

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

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

    
2681
	/* handle hide ssid option */
2682
	if (isset($wlcfg['hidessid']['enable'])) {
2683
		$wlcmd[] = "hidessid";
2684
	} else {
2685
		$wlcmd[] = "-hidessid";
2686
	}
2687

    
2688
	/* handle pureg (802.11g) only option */
2689
	if (isset($wlcfg['pureg']['enable'])) {
2690
		$wlcmd[] = "mode 11g pureg";
2691
	} else {
2692
		$wlcmd[] = "-pureg";
2693
	}
2694

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

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

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

    
2716
	/* handle txpower setting */
2717
	// or don't. this has issues at the moment.
2718
	/*
2719
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2720
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2721
	}*/
2722

    
2723
	/* handle wme option */
2724
	if (isset($wlcfg['wme']['enable'])) {
2725
		$wlcmd[] = "wme";
2726
	} else {
2727
		$wlcmd[] = "-wme";
2728
	}
2729

    
2730
	/* Enable wpa if it's configured. No WEP support anymore. */
2731
	if (isset($wlcfg['wpa']['enable'])) {
2732
		$wlcmd[] = "authmode wpa wepmode off ";
2733
	} else {
2734
		$wlcmd[] = "authmode open wepmode off ";
2735
	}
2736

    
2737
	kill_hostapd($if);
2738
	mwexec(kill_wpasupplicant("{$if}"));
2739

    
2740
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2741
	conf_mount_rw();
2742

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

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

    
2796
EOD;
2797

    
2798
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2799
					$wpa .= <<<EOD
2800
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
2801
rsn_preauth=1
2802
rsn_preauth_interfaces={$if}
2803

    
2804
EOD;
2805
				}
2806
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2807
					$wpa .= "ieee8021x=1\n";
2808

    
2809
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2810
						$auth_server_port = "1812";
2811
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2812
							$auth_server_port = intval($wlcfg['auth_server_port']);
2813
						}
2814
						$wpa .= <<<EOD
2815

    
2816
auth_server_addr={$wlcfg['auth_server_addr']}
2817
auth_server_port={$auth_server_port}
2818
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2819

    
2820
EOD;
2821
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2822
							$auth_server_port2 = "1812";
2823
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2824
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2825
							}
2826

    
2827
							$wpa .= <<<EOD
2828
auth_server_addr={$wlcfg['auth_server_addr2']}
2829
auth_server_port={$auth_server_port2}
2830
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2831

    
2832
EOD;
2833
						}
2834
					}
2835
				}
2836

    
2837
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2838
				unset($wpa);
2839
			}
2840
			break;
2841
	}
2842

    
2843
	/*
2844
	 *    all variables are set, lets start up everything
2845
	 */
2846

    
2847
	$baseif = interface_get_wireless_base($if);
2848
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2849
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2850

    
2851
	/* set sysctls for the wireless interface */
2852
	if (!empty($wl_sysctl)) {
2853
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2854
		foreach ($wl_sysctl as $wl_sysctl_line) {
2855
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2856
		}
2857
	}
2858

    
2859
	/* set ack timers according to users preference (if he/she has any) */
2860
	if ($distance) {
2861
		fwrite($fd_set, "# Enable ATH distance settings\n");
2862
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2863
	}
2864

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

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

    
2881
			/* add line to script to restore spoofed mac after running hostapd */
2882
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2883
				if ($wl['spoofmac']) {
2884
					$if_curmac = $wl['spoofmac'];
2885
				} else {
2886
					$if_curmac = get_interface_mac($if);
2887
				}
2888
				if (is_macaddr($if_curmac)) {
2889
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2890
						" link " . escapeshellarg($if_curmac) . "\n");
2891
				}
2892
			}
2893
		}
2894
	}
2895

    
2896
	fclose($fd_set);
2897
	conf_mount_ro();
2898

    
2899
	/* Making sure regulatory settings have actually changed
2900
	 * before applying, because changing them requires bringing
2901
	 * down all wireless networks on the interface. */
2902
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2903
	$ifconfig_str = implode($output);
2904
	unset($output);
2905
	$reg_changing = false;
2906

    
2907
	/* special case for the debug country code */
2908
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
2909
		$reg_changing = true;
2910
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
2911
		$reg_changing = true;
2912
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
2913
		$reg_changing = true;
2914
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
2915
		$reg_changing = true;
2916
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
2917
		$reg_changing = true;
2918
	}
2919

    
2920
	if ($reg_changing) {
2921
		/* set regulatory domain */
2922
		if ($wlcfg['regdomain']) {
2923
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2924
		}
2925

    
2926
		/* set country */
2927
		if ($wlcfg['regcountry']) {
2928
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2929
		}
2930

    
2931
		/* set location */
2932
		if ($wlcfg['reglocation']) {
2933
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2934
		}
2935

    
2936
		$wlregcmd_args = implode(" ", $wlregcmd);
2937

    
2938
		/* build a complete list of the wireless clones for this interface */
2939
		$clone_list = array();
2940
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2941
			$clone_list[] = interface_get_wireless_clone($baseif);
2942
		}
2943
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2944
			foreach ($config['wireless']['clone'] as $clone) {
2945
				if ($clone['if'] == $baseif) {
2946
					$clone_list[] = $clone['cloneif'];
2947
				}
2948
			}
2949
		}
2950

    
2951
		/* find which clones are up and bring them down */
2952
		$clones_up = array();
2953
		foreach ($clone_list as $clone_if) {
2954
			$clone_status = pfSense_get_interface_addresses($clone_if);
2955
			if ($clone_status['status'] == 'up') {
2956
				$clones_up[] = $clone_if;
2957
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2958
			}
2959
		}
2960

    
2961
		/* apply the regulatory settings */
2962
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2963
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2964

    
2965
		/* bring the clones back up that were previously up */
2966
		foreach ($clones_up as $clone_if) {
2967
			interfaces_bring_up($clone_if);
2968

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

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

    
2988
	 * The mode must be specified in a separate command before ifconfig
2989
	 * will allow the mode and channel at the same time in the next. */
2990
	//mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2991
	//fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
2992

    
2993
	/* configure wireless */
2994
	$wlcmd_args = implode(" ", $wlcmd);
2995
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2996
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
2997
	fclose($wlan_setup_log);
2998

    
2999
	unset($wlcmd_args, $wlcmd);
3000

    
3001

    
3002
	sleep(1);
3003
	/* execute hostapd and wpa_supplicant if required in shell */
3004
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3005

    
3006
	return 0;
3007

    
3008
}
3009

    
3010
function kill_hostapd($interface) {
3011
	global $g;
3012

    
3013
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3014
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3015
	}
3016
}
3017

    
3018
function kill_wpasupplicant($interface) {
3019
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3020
}
3021

    
3022
function find_dhclient_process($interface) {
3023
	if ($interface) {
3024
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3025
	} else {
3026
		$pid = 0;
3027
	}
3028

    
3029
	return intval($pid);
3030
}
3031

    
3032
function kill_dhclient_process($interface) {
3033
	if (empty($interface) || !does_interface_exist($interface)) {
3034
		return;
3035
	}
3036

    
3037
	$i = 0;
3038
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3039
		/* 3rd time make it die for sure */
3040
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3041
		posix_kill($pid, $sig);
3042
		sleep(1);
3043
		$i++;
3044
	}
3045
	unset($i);
3046
}
3047

    
3048
function find_dhcp6c_process($interface) {
3049
	global $g;
3050

    
3051
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3052
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3053
	} else {
3054
		return(false);
3055
	}
3056

    
3057
	return intval($pid);
3058
}
3059

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

    
3065
	if (($pid = find_dhcp6c_process($interface)) != 0) {
3066
		mwexec("kill -9 {$pid}");
3067
		sleep(1);
3068
	}
3069
}
3070

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

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

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

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

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

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

    
3134
	return $mtu;
3135
}
3136

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

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

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

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

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

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

    
3177
	return $mtu;
3178
}
3179

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

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

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

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

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

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

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

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

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

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

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

    
3256
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3257
			/*   this is not a valid mac address.  generate a
3258
			 *   temporary mac address so the machine can get online.
3259
			 */
3260
			echo gettext("Generating new MAC address.");
3261
			$random_mac = generate_random_mac_address();
3262
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3263
				" link " . escapeshellarg($random_mac));
3264
			$wancfg['spoofmac'] = $random_mac;
3265
			write_config();
3266
			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");
3267
		}
3268
	}
3269

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

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

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

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

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

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

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

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

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

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

    
3336
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3337

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

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

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

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

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

    
3425
	interface_netgraph_needed($interface);
3426

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

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

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

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

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

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

    
3464
		if ($reloadall == true) {
3465

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

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

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

    
3476
			if (isset($config['unbound']['enable'])) {
3477
				services_unbound_configure();
3478
			}
3479

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

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

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

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

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

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

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

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

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

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

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

    
3562
		/* restart dns servers (defering dhcpd reload) */
3563
		if (isset($config['unbound']['enable'])) {
3564
			services_unbound_configure(false);
3565
		}
3566
		if (isset($config['dnsmasq']['enable'])) {
3567
			services_dnsmasq_configure(false);
3568
		}
3569

    
3570
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
3571
		services_dhcpd_configure("inet6");
3572
	}
3573

    
3574
	return 0;
3575
}
3576

    
3577
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3578
	global $config, $g;
3579
	global $interface_ipv6_arr_cache;
3580
	global $interface_snv6_arr_cache;
3581

    
3582
	if (!is_array($lancfg)) {
3583
		return;
3584
	}
3585

    
3586
	/* If the interface is not configured via another, exit */
3587
	if (empty($lancfg['track6-interface'])) {
3588
		return;
3589
	}
3590

    
3591
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3592
	if (empty($wancfg)) {
3593
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3594
		return;
3595
	}
3596

    
3597
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3598
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3599
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not valid, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
3600
		return;
3601
	}
3602
	$hexwanv4 = return_hex_ipv4($ip4address);
3603

    
3604
	/* create the long prefix notation for math, save the prefix length */
3605
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3606
	$rd6prefixlen = $rd6prefix[1];
3607
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3608

    
3609
	/* binary presentation of the prefix for all 128 bits. */
3610
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3611

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

    
3617
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3618
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3619
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3620
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3621
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3622
	/* fill the rest out with zeros */
3623
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3624

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

    
3628
	$lanif = get_real_interface($interface);
3629
	$oip = find_interface_ipv6($lanif);
3630
	if (is_ipaddrv6($oip)) {
3631
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3632
	}
3633
	unset($interface_ipv6_arr_cache[$lanif]);
3634
	unset($interface_snv6_arr_cache[$lanif]);
3635
	log_error(sprintf(gettext('rd6 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $rd6lan, $lancfg['track6-interface'], $ip4address));
3636
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3637

    
3638
	return 0;
3639
}
3640

    
3641
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3642
	global $config, $g;
3643
	global $interface_ipv6_arr_cache;
3644
	global $interface_snv6_arr_cache;
3645

    
3646
	if (!is_array($lancfg)) {
3647
		return;
3648
	}
3649

    
3650
	/* If the interface is not configured via another, exit */
3651
	if (empty($lancfg['track6-interface'])) {
3652
		return;
3653
	}
3654

    
3655
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3656
	if (empty($wancfg)) {
3657
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3658
		return;
3659
	}
3660

    
3661
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3662
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3663
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
3664
		return;
3665
	}
3666
	$hexwanv4 = return_hex_ipv4($ip4address);
3667

    
3668
	/* create the long prefix notation for math, save the prefix length */
3669
	$sixto4prefix = "2002::";
3670
	$sixto4prefixlen = 16;
3671
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3672

    
3673
	/* binary presentation of the prefix for all 128 bits. */
3674
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3675

    
3676
	/* just save the left prefix length bits */
3677
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3678
	/* add the v4 address */
3679
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3680
	/* add the custom prefix id */
3681
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3682
	/* fill the rest out with zeros */
3683
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3684

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

    
3688
	$lanif = get_real_interface($interface);
3689
	$oip = find_interface_ipv6($lanif);
3690
	if (is_ipaddrv6($oip)) {
3691
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3692
	}
3693
	unset($interface_ipv6_arr_cache[$lanif]);
3694
	unset($interface_snv6_arr_cache[$lanif]);
3695
	log_error(sprintf(gettext('sixto4 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $sixto4lan, $lancfg['track6-interface'], $ip4address));
3696
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3697

    
3698
	return 0;
3699
}
3700

    
3701
function interface_6rd_configure($interface = "wan", $wancfg) {
3702
	global $config, $g;
3703

    
3704
	/* because this is a tunnel interface we can only function
3705
	 *	with a public IPv4 address on the interface */
3706

    
3707
	if (!is_array($wancfg)) {
3708
		return;
3709
	}
3710

    
3711
	if (!is_module_loaded('if_stf.ko')) {
3712
		mwexec('/sbin/kldload if_stf.ko');
3713
	}
3714

    
3715
	$wanif = get_real_interface($interface);
3716
	$ip4address = find_interface_ip($wanif);
3717
	if (!is_ipaddrv4($ip4address)) {
3718
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3719
		return false;
3720
	}
3721
	$hexwanv4 = return_hex_ipv4($ip4address);
3722

    
3723
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3724
		$wancfg['prefix-6rd-v4plen'] = 0;
3725
	}
3726

    
3727
	/* create the long prefix notation for math, save the prefix length */
3728
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3729
	$rd6prefixlen = $rd6prefix[1];
3730
	$brgw = explode('.', $wancfg['gateway-6rd']);
3731
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3732
	$rd6brgw .= str_pad(decbin($brgw[0]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[1]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[2]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[3]), 8, '0', STR_PAD_LEFT);
3733
	if (strlen($rd6brgw) < 128) {
3734
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3735
	}
3736
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3737
	unset($brgw);
3738
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3739

    
3740
	/* binary presentation of the prefix for all 128 bits. */
3741
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3742

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

    
3750
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3751
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3752

    
3753

    
3754
	/* XXX: need to extend to support variable prefix size for v4 */
3755
	if (!is_module_loaded("if_stf")) {
3756
		mwexec("/sbin/kldload if_stf.ko");
3757
	}
3758
	$stfiface = "{$interface}_stf";
3759
	if (does_interface_exist($stfiface)) {
3760
		pfSense_interface_destroy($stfiface);
3761
	}
3762
	$tmpstfiface = pfSense_interface_create("stf");
3763
	pfSense_interface_rename($tmpstfiface, $stfiface);
3764
	pfSense_interface_flags($stfiface, IFF_LINK2);
3765
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3766
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3767
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3768
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3769
	}
3770
	if ($g['debug']) {
3771
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3772
	}
3773

    
3774
	/* write out a default router file */
3775
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3776
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3777

    
3778
	$ip4gateway = get_interface_gateway($interface);
3779
	if (is_ipaddrv4($ip4gateway)) {
3780
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3781
	}
3782

    
3783
	/* configure dependent interfaces */
3784
	if (!platform_booting()) {
3785
		link_interface_to_track6($interface, "update");
3786
	}
3787

    
3788
	return 0;
3789
}
3790

    
3791
function interface_6to4_configure($interface = "wan", $wancfg) {
3792
	global $config, $g;
3793

    
3794
	/* because this is a tunnel interface we can only function
3795
	 *	with a public IPv4 address on the interface */
3796

    
3797
	if (!is_array($wancfg)) {
3798
		return;
3799
	}
3800

    
3801
	$wanif = get_real_interface($interface);
3802
	$ip4address = find_interface_ip($wanif);
3803
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3804
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3805
		return false;
3806
	}
3807

    
3808
	/* create the long prefix notation for math, save the prefix length */
3809
	$stfprefixlen = 16;
3810
	$stfprefix = Net_IPv6::uncompress("2002::");
3811
	$stfarr = explode(":", $stfprefix);
3812
	$v4prefixlen = "0";
3813

    
3814
	/* we need the hex form of the interface IPv4 address */
3815
	$ip4arr = explode(".", $ip4address);
3816
	$hexwanv4 = "";
3817
	foreach ($ip4arr as $octet) {
3818
		$hexwanv4 .= sprintf("%02x", $octet);
3819
	}
3820

    
3821
	/* we need the hex form of the broker IPv4 address */
3822
	$ip4arr = explode(".", "192.88.99.1");
3823
	$hexbrv4 = "";
3824
	foreach ($ip4arr as $octet) {
3825
		$hexbrv4 .= sprintf("%02x", $octet);
3826
	}
3827

    
3828
	/* binary presentation of the prefix for all 128 bits. */
3829
	$stfprefixbin = "";
3830
	foreach ($stfarr as $element) {
3831
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3832
	}
3833
	/* just save the left prefix length bits */
3834
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3835

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

    
3840
	/* for the local subnet too. */
3841
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3842
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3843

    
3844
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3845
	$stfbrarr = array();
3846
	$stfbrbinarr = array();
3847
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3848
	foreach ($stfbrbinarr as $bin) {
3849
		$stfbrarr[] = dechex(bindec($bin));
3850
	}
3851
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3852

    
3853
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3854
	$stflanarr = array();
3855
	$stflanbinarr = array();
3856
	$stflanbinarr = str_split($stflanbin, 16);
3857
	foreach ($stflanbinarr as $bin) {
3858
		$stflanarr[] = dechex(bindec($bin));
3859
	}
3860
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3861
	$stflanarr[7] = 1;
3862
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3863

    
3864
	/* setup the stf interface */
3865
	if (!is_module_loaded("if_stf")) {
3866
		mwexec("/sbin/kldload if_stf.ko");
3867
	}
3868
	$stfiface = "{$interface}_stf";
3869
	if (does_interface_exist($stfiface)) {
3870
		pfSense_interface_destroy($stfiface);
3871
	}
3872
	$tmpstfiface = pfSense_interface_create("stf");
3873
	pfSense_interface_rename($tmpstfiface, $stfiface);
3874
	pfSense_interface_flags($stfiface, IFF_LINK2);
3875
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3876

    
3877
	if ($g['debug']) {
3878
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3879
	}
3880

    
3881
	/* write out a default router file */
3882
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3883
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3884

    
3885
	$ip4gateway = get_interface_gateway($interface);
3886
	if (is_ipaddrv4($ip4gateway)) {
3887
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3888
	}
3889

    
3890
	if (!platform_booting()) {
3891
		link_interface_to_track6($interface, "update");
3892
	}
3893

    
3894
	return 0;
3895
}
3896

    
3897
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3898
	global $config, $g;
3899

    
3900
	if (!is_array($wancfg)) {
3901
		return;
3902
	}
3903

    
3904
	$wanif = get_real_interface($interface, "inet6");
3905
	$dhcp6cconf = "";
3906

    
3907
	if ($wancfg['adv_dhcp6_config_file_override']) {
3908
		// DHCP6 Config File Override
3909
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3910
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3911
		// DHCP6 Config File Advanced
3912
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3913
	} else {
3914
		// DHCP6 Config File Basic
3915
		$dhcp6cconf .= "interface {$wanif} {\n";
3916

    
3917
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3918
		if ($wancfg['ipaddrv6'] == "slaac") {
3919
			$dhcp6cconf .= "\tinformation-only;\n";
3920
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3921
			$dhcp6cconf .= "\trequest domain-name;\n";
3922
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3923
			$dhcp6cconf .= "};\n";
3924
		} else {
3925
			$trackiflist = array();
3926
			$iflist = link_interface_to_track6($interface);
3927
			foreach ($iflist as $ifname => $ifcfg) {
3928
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3929
					$trackiflist[$ifname] = $ifcfg;
3930
				}
3931
			}
3932

    
3933
			/* skip address request if this is set */
3934
			if (!isset($wancfg['dhcp6prefixonly'])) {
3935
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3936
			}
3937
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3938
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3939
			}
3940

    
3941
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3942
			$dhcp6cconf .= "\trequest domain-name;\n";
3943
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3944
			$dhcp6cconf .= "};\n";
3945

    
3946
			if (!isset($wancfg['dhcp6prefixonly'])) {
3947
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3948
			}
3949

    
3950
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3951
				/* Setup the prefix delegation */
3952
				$dhcp6cconf .= "id-assoc pd 0 {\n";
3953
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3954
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
3955
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
3956
				}
3957
				foreach ($trackiflist as $friendly => $ifcfg) {
3958
					if ($g['debug']) {
3959
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3960
					}
3961
					$realif = get_real_interface($friendly);
3962
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
3963
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
3964
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3965
					$dhcp6cconf .= "\t};\n";
3966
				}
3967
				unset($preflen, $iflist, $ifcfg, $ifname);
3968
				$dhcp6cconf .= "};\n";
3969
			}
3970
			unset($trackiflist);
3971
		}
3972
	}
3973

    
3974
	/* wide-dhcp6c works for now. */
3975
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3976
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3977
		unset($dhcp6cconf);
3978
		return 1;
3979
	}
3980
	unset($dhcp6cconf);
3981

    
3982
	$dhcp6cscript = "#!/bin/sh\n";
3983
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3984
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3985
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3986
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3987
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3988
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3989
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3990
		unset($dhcp6cscript);
3991
		return 1;
3992
	}
3993
	unset($dhcp6cscript);
3994
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3995

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

    
4002
	/* non ipoe Process */
4003
	if (!isset($wancfg['dhcp6withoutra'])) {
4004
		$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
4005
		$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4006
		$rtsoldscript .= "\t/bin/sleep 1\n";
4007
		$rtsoldscript .= "fi\n";
4008
	} else {
4009
		$rtsoldscript .= "\t/bin/sleep 1\n";
4010
	}
4011
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4012

    
4013
	/* add the start of dhcp6c to the rtsold script if we are going to wait for ra */
4014
	if (!isset($wancfg['dhcp6withoutra'])) {
4015
		$rtsoldscript .= "/usr/local/sbin/dhcp6c {$debugOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4016
		$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4017
	}
4018
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4019
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4020
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4021
		unset($rtsoldscript);
4022
		return 1;
4023
	}
4024
	unset($rtsoldscript);
4025
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4026

    
4027
	/* accept router advertisements for this interface */
4028
	log_error("Accept router advertisements on interface {$wanif} ");
4029
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4030

    
4031
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
4032
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4033
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4034
		sleep(2);
4035
	}
4036

    
4037
	/* start dhcp6c here if we don't want to wait for ra */
4038
	if (isset($wancfg['dhcp6withoutra'])) {
4039
		kill_dhcp6client_process($wanif);
4040

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

    
4046
	/* NOTE: will be called from rtsold invoked script
4047
	 * link_interface_to_track6($interface, "update");
4048
	 */
4049

    
4050
	return 0;
4051
}
4052

    
4053
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4054
	global $g;
4055

    
4056
	$send_options = "";
4057
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4058
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4059
		foreach ($options as $option) {
4060
			$send_options .= "\tsend " . trim($option) . ";\n";
4061
		}
4062
	}
4063

    
4064
	$request_options = "";
4065
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4066
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4067
		foreach ($options as $option) {
4068
			$request_options .= "\trequest " . trim($option) . ";\n";
4069
		}
4070
	}
4071

    
4072
	$information_only = "";
4073
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4074
		$information_only = "\tinformation-only;\n";
4075
	}
4076

    
4077
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4078
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4079
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4080
	}
4081

    
4082
	$interface_statement  = "interface";
4083
	$interface_statement .= " {$wanif}";
4084
	$interface_statement .= " {\n";
4085
	$interface_statement .= "$send_options";
4086
	$interface_statement .= "$request_options";
4087
	$interface_statement .= "$information_only";
4088
	$interface_statement .= "$script";
4089
	$interface_statement .= "};\n";
4090

    
4091
	$id_assoc_statement_address = "";
4092
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4093
		$id_assoc_statement_address .= "id-assoc";
4094
		$id_assoc_statement_address .= " na";
4095
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4096
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4097
		}
4098
		$id_assoc_statement_address .= " { ";
4099

    
4100
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4101
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4102
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4103
			$id_assoc_statement_address .= "\n\taddress";
4104
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4105
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4106
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4107
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4108
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4109
			}
4110
			$id_assoc_statement_address .= ";\n";
4111
		}
4112

    
4113
		$id_assoc_statement_address .= "};\n";
4114
	}
4115

    
4116
	$id_assoc_statement_prefix = "";
4117
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4118
		$id_assoc_statement_prefix .= "id-assoc";
4119
		$id_assoc_statement_prefix .= " pd";
4120
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4121
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4122
		}
4123
		$id_assoc_statement_prefix .= " { ";
4124

    
4125
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4126
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4127
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4128
			$id_assoc_statement_prefix .= "\n\tprefix";
4129
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4130
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4131
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4132
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4133
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4134
			}
4135
			$id_assoc_statement_prefix .= ";";
4136
		}
4137

    
4138
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4139
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4140
			$id_assoc_statement_prefix .= " {$wanif}";
4141
			$id_assoc_statement_prefix .= " {\n";
4142
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4143
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4144
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4145
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4146
			}
4147
			$id_assoc_statement_prefix .= "\t};";
4148
		}
4149

    
4150
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4151
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4152
			$id_assoc_statement_prefix .= "\n";
4153
		}
4154

    
4155
		$id_assoc_statement_prefix .= "};\n";
4156
	}
4157

    
4158
	$authentication_statement = "";
4159
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4160
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4161
		$authentication_statement .= "authentication";
4162
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4163
		$authentication_statement .= " {\n";
4164
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4165
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4166
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4167
		}
4168
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4169
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4170
		}
4171
		$authentication_statement .= "};\n";
4172
	}
4173

    
4174
	$key_info_statement = "";
4175
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4176
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4177
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4178
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4179
		$key_info_statement .= "keyinfo";
4180
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4181
		$key_info_statement .= " {\n";
4182
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4183
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4184
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4185
		if (preg_match("/((([0-9]{4}-)?[0-9]{2}[0-9]{2} )?[0-9]{2}:[0-9]{2})||(foreever)/", $wancfg['adv_dhcp6_key_info_statement_expire'])) {
4186
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4187
		}
4188
		$key_info_statement .= "};\n";
4189
	}
4190

    
4191
	$dhcp6cconf  = $interface_statement;
4192
	$dhcp6cconf .= $id_assoc_statement_address;
4193
	$dhcp6cconf .= $id_assoc_statement_prefix;
4194
	$dhcp6cconf .= $authentication_statement;
4195
	$dhcp6cconf .= $key_info_statement;
4196

    
4197
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4198

    
4199
	return $dhcp6cconf;
4200
}
4201

    
4202

    
4203
function DHCP6_Config_File_Override($wancfg, $wanif) {
4204

    
4205
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4206

    
4207
	if ($dhcp6cconf === false) {
4208
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4209
		return '';
4210
	} else {
4211
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4212
	}
4213
}
4214

    
4215

    
4216
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4217

    
4218
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4219

    
4220
	return $dhcp6cconf;
4221
}
4222

    
4223

    
4224
function interface_dhcp_configure($interface = "wan") {
4225
	global $config, $g;
4226

    
4227
	$wancfg = $config['interfaces'][$interface];
4228
	$wanif = $wancfg['if'];
4229
	if (empty($wancfg)) {
4230
		$wancfg = array();
4231
	}
4232

    
4233
	/* generate dhclient_wan.conf */
4234
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4235
	if (!$fd) {
4236
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4237
		return 1;
4238
	}
4239

    
4240
	if ($wancfg['dhcphostname']) {
4241
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4242
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4243
	} else {
4244
		$dhclientconf_hostname = "";
4245
	}
4246

    
4247
	$wanif = get_real_interface($interface);
4248
	if (empty($wanif)) {
4249
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4250
		return 0;
4251
	}
4252
	$dhclientconf = "";
4253

    
4254
	$dhclientconf .= <<<EOD
4255
interface "{$wanif}" {
4256
timeout 60;
4257
retry 15;
4258
select-timeout 0;
4259
initial-interval 1;
4260
	{$dhclientconf_hostname}
4261
	script "/sbin/dhclient-script";
4262
EOD;
4263

    
4264
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4265
		$dhclientconf .= <<<EOD
4266

    
4267
	reject {$wancfg['dhcprejectfrom']};
4268
EOD;
4269
	}
4270
	$dhclientconf .= <<<EOD
4271

    
4272
}
4273

    
4274
EOD;
4275

    
4276
	// DHCP Config File Advanced
4277
	if ($wancfg['adv_dhcp_config_advanced']) {
4278
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4279
	}
4280

    
4281
	if (is_ipaddr($wancfg['alias-address'])) {
4282
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4283
		$dhclientconf .= <<<EOD
4284
alias {
4285
	interface "{$wanif}";
4286
	fixed-address {$wancfg['alias-address']};
4287
	option subnet-mask {$subnetmask};
4288
}
4289

    
4290
EOD;
4291
	}
4292

    
4293
	// DHCP Config File Override
4294
	if ($wancfg['adv_dhcp_config_file_override']) {
4295
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4296
	}
4297

    
4298
	fwrite($fd, $dhclientconf);
4299
	fclose($fd);
4300

    
4301
	/* bring wan interface up before starting dhclient */
4302
	if ($wanif) {
4303
		interfaces_bring_up($wanif);
4304
	} else {
4305
		log_error(sprintf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4306
	}
4307

    
4308
	/* Make sure dhclient is not running */
4309
	kill_dhclient_process($wanif);
4310

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

    
4314
	return 0;
4315
}
4316

    
4317
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4318

    
4319
	$hostname = "";
4320
	if ($wancfg['dhcphostname'] != '') {
4321
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4322
	}
4323

    
4324
	/* DHCP Protocol Timings */
4325
	$protocol_timings = array ('adv_dhcp_pt_timeout' => "timeout", 'adv_dhcp_pt_retry' => "retry", 'adv_dhcp_pt_select_timeout' => "select-timeout", 'adv_dhcp_pt_reboot' => "reboot", 'adv_dhcp_pt_backoff_cutoff' => "backoff-cutoff", 'adv_dhcp_pt_initial_interval' => "initial-interval");
4326
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4327
		$pt_variable = "{$Protocol_Timing}";
4328
		${$pt_variable} = "";
4329
		if ($wancfg[$Protocol_Timing] != "") {
4330
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4331
		}
4332
	}
4333

    
4334
	$send_options = "";
4335
	if ($wancfg['adv_dhcp_send_options'] != '') {
4336
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp_send_options']);
4337
		foreach ($options as $option) {
4338
			$send_options .= "\tsend " . trim($option) . ";\n";
4339
		}
4340
	}
4341

    
4342
	$request_options = "";
4343
	if ($wancfg['adv_dhcp_request_options'] != '') {
4344
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4345
	}
4346

    
4347
	$required_options = "";
4348
	if ($wancfg['adv_dhcp_required_options'] != '') {
4349
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4350
	}
4351

    
4352
	$option_modifiers = "";
4353
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4354
		$modifiers = DHCP_Config_Option_Split($wancfg['adv_dhcp_option_modifiers']);
4355
		foreach ($modifiers as $modifier) {
4356
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4357
		}
4358
	}
4359

    
4360
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4361
	$dhclientconf .= "\n";
4362
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4363
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4364
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4365
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4366
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4367
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4368
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4369
	$dhclientconf .= "\n";
4370
	$dhclientconf .= "# DHCP Protocol Options\n";
4371
	$dhclientconf .= "{$hostname}";
4372
	$dhclientconf .= "{$send_options}";
4373
	$dhclientconf .= "{$request_options}";
4374
	$dhclientconf .= "{$required_options}";
4375
	$dhclientconf .= "{$option_modifiers}";
4376
	$dhclientconf .= "\n";
4377
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4378
		$dhclientconf .= "reject {$wancfg['dhcprejectfrom']};\n";
4379
	}
4380
	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4381
	$dhclientconf .= "}\n";
4382

    
4383
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4384

    
4385
	return $dhclientconf;
4386
}
4387

    
4388
function DHCP_Config_Option_Split($option_string) {
4389
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4390
	return $matches ? $matches[0] : [];
4391
}
4392

    
4393
function DHCP_Config_File_Override($wancfg, $wanif) {
4394

    
4395
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4396

    
4397
	if ($dhclientconf === false) {
4398
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading.\n"), $wancfg['adv_dhcp_config_file_override_path']));
4399
		return '';
4400
	} else {
4401
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4402
	}
4403
}
4404

    
4405

    
4406
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4407

    
4408
	/* Apply Interface Substitutions */
4409
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4410

    
4411
	/* Apply Hostname Substitutions */
4412
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4413

    
4414
	/* Arrays of MAC Address Types, Cases, Delimiters */
4415
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4416
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4417
	$various_mac_cases      = array("U", "L");
4418
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4419

    
4420
	/* Apply MAC Address Substitutions */
4421
	foreach ($various_mac_types as $various_mac_type) {
4422
		foreach ($various_mac_cases as $various_mac_case) {
4423
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4424

    
4425
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4426
				if ($res !== false) {
4427

    
4428
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4429
					if ("$various_mac_case" == "U") {
4430
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4431
					}
4432
					if ("$various_mac_case" == "L") {
4433
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4434
					}
4435

    
4436
					if ("$various_mac_type" == "mac_addr_hex") {
4437
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4438
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4439
						$dhcpclientconf_mac_hex = "";
4440
						$delimiter = "";
4441
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4442
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4443
							$delimiter = ":";
4444
						}
4445
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4446
					}
4447

    
4448
					/* MAC Address Delimiter Substitutions */
4449
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4450

    
4451
					/* Apply MAC Address Substitutions */
4452
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4453
				}
4454
			}
4455
		}
4456
	}
4457

    
4458
	return $dhclientconf;
4459
}
4460

    
4461
function interfaces_group_setup() {
4462
	global $config;
4463

    
4464
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4465
		return;
4466
	}
4467

    
4468
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4469
		interface_group_setup($groupar);
4470
	}
4471

    
4472
	return;
4473
}
4474

    
4475
function interface_group_setup(&$groupname /* The parameter is an array */) {
4476
	global $config;
4477

    
4478
	if (!is_array($groupname)) {
4479
		return;
4480
	}
4481
	$members = explode(" ", $groupname['members']);
4482
	foreach ($members as $ifs) {
4483
		$realif = get_real_interface($ifs);
4484
		if ($realif && does_interface_exist($realif)) {
4485
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4486
		}
4487
	}
4488

    
4489
	return;
4490
}
4491

    
4492
function is_interface_group($if) {
4493
	global $config;
4494

    
4495
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4496
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4497
			if ($groupentry['ifname'] === $if) {
4498
				return true;
4499
			}
4500
		}
4501
	}
4502

    
4503
	return false;
4504
}
4505

    
4506
function interface_group_add_member($interface, $groupname) {
4507
	$interface = get_real_interface($interface);
4508
	if (does_interface_exist($interface)) {
4509
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4510
	}
4511
}
4512

    
4513
/* COMPAT Function */
4514
function convert_friendly_interface_to_real_interface_name($interface) {
4515
	return get_real_interface($interface);
4516
}
4517

    
4518
/* COMPAT Function */
4519
function get_real_wan_interface($interface = "wan") {
4520
	return get_real_interface($interface);
4521
}
4522

    
4523
/* COMPAT Function */
4524
function get_current_wan_address($interface = "wan") {
4525
	return get_interface_ip($interface);
4526
}
4527

    
4528
/*
4529
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4530
 */
4531
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4532
	global $config;
4533

    
4534
	/* XXX: For speed reasons reference directly the interface array */
4535
	$ifdescrs = &$config['interfaces'];
4536
	//$ifdescrs = get_configured_interface_list(false, true);
4537

    
4538
	foreach ($ifdescrs as $if => $ifname) {
4539
		if ($if == $interface || $ifname['if'] == $interface) {
4540
			return $if;
4541
		}
4542

    
4543
		if (get_real_interface($if) == $interface) {
4544
			return $if;
4545
		}
4546

    
4547
		if ($checkparent == false) {
4548
			continue;
4549
		}
4550

    
4551
		$int = get_parent_interface($if, true);
4552
		if (is_array($int)) {
4553
			foreach ($int as $iface) {
4554
				if ($iface == $interface) {
4555
					return $if;
4556
				}
4557
			}
4558
		}
4559
	}
4560

    
4561
	if ($interface == "enc0") {
4562
		return 'IPsec';
4563
	}
4564
}
4565

    
4566
/* attempt to resolve interface to friendly descr */
4567
function convert_friendly_interface_to_friendly_descr($interface) {
4568
	global $config;
4569

    
4570
	switch ($interface) {
4571
		case "l2tp":
4572
			$ifdesc = "L2TP";
4573
			break;
4574
		case "pptp":
4575
			$ifdesc = "PPTP";
4576
			break;
4577
		case "pppoe":
4578
			$ifdesc = "PPPoE";
4579
			break;
4580
		case "openvpn":
4581
			$ifdesc = "OpenVPN";
4582
			break;
4583
		case "lo0":
4584
			$ifdesc = "Loopback";
4585
			break;
4586
		case "enc0":
4587
		case "ipsec":
4588
		case "IPsec":
4589
			$ifdesc = "IPsec";
4590
			break;
4591
		default:
4592
			if (isset($config['interfaces'][$interface])) {
4593
				if (empty($config['interfaces'][$interface]['descr'])) {
4594
					$ifdesc = strtoupper($interface);
4595
				} else {
4596
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4597
				}
4598
				break;
4599
			} else if (substr($interface, 0, 4) == '_vip') {
4600
				if (is_array($config['virtualip']['vip'])) {
4601
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
4602
						if ($vip['mode'] == "carp") {
4603
							if ($interface == "_vip{$vip['uniqid']}") {
4604
								return "{$vip['subnet']} - {$vip['descr']}";
4605
							}
4606
						}
4607
					}
4608
				}
4609
			} else if (substr($interface, 0, 5) == '_lloc') {
4610
				return get_interface_linklocal($interface);
4611
			} else {
4612
				/* if list */
4613
				$ifdescrs = get_configured_interface_with_descr(false, true);
4614
				foreach ($ifdescrs as $if => $ifname) {
4615
					if ($if == $interface || $ifname == $interface) {
4616
						return $ifname;
4617
					}
4618
				}
4619
			}
4620
			break;
4621
	}
4622

    
4623
	return $ifdesc;
4624
}
4625

    
4626
function convert_real_interface_to_friendly_descr($interface) {
4627

    
4628
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4629

    
4630
	if (!empty($ifdesc)) {
4631
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4632
	}
4633

    
4634
	return $interface;
4635
}
4636

    
4637
/*
4638
 *  get_parent_interface($interface):
4639
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4640
 *				or virtual interface (i.e. vlan)
4641
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4642
 *			-- returns $interface passed in if $interface parent is not found
4643
 *			-- returns empty array if an invalid interface is passed
4644
 *	(Only handles ppps and vlans now.)
4645
 */
4646
function get_parent_interface($interface, $avoidrecurse = false) {
4647
	global $config;
4648

    
4649
	$parents = array();
4650
	//Check that we got a valid interface passed
4651
	$realif = get_real_interface($interface);
4652
	if ($realif == NULL) {
4653
		return $parents;
4654
	}
4655

    
4656
	// If we got a real interface, find it's friendly assigned name
4657
	if ($interface == $realif && $avoidrecurse == false) {
4658
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4659
	}
4660

    
4661
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4662
		$ifcfg = $config['interfaces'][$interface];
4663
		switch ($ifcfg['ipaddr']) {
4664
			case "ppp":
4665
			case "pppoe":
4666
			case "pptp":
4667
			case "l2tp":
4668
				if (empty($parents)) {
4669
					if (is_array($config['ppps']['ppp'])) {
4670
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4671
							if ($ifcfg['if'] == $ppp['if']) {
4672
								$ports = explode(',', $ppp['ports']);
4673
								foreach ($ports as $pid => $parent_if) {
4674
									$parents[$pid] = get_real_interface($parent_if);
4675
								}
4676
								break;
4677
							}
4678
						}
4679
					}
4680
				}
4681
				break;
4682
			case "dhcp":
4683
			case "static":
4684
			default:
4685
				// Handle _vlans
4686
				if (strpos($realif, '_vlan') !== FALSE) {
4687
					if (is_array($config['vlans']['vlan'])) {
4688
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4689
							if ($ifcfg['if'] == $vlan['vlanif']) {
4690
								$parents[0] = $vlan['if'];
4691
								break;
4692
							}
4693
						}
4694
					}
4695
				}
4696
				break;
4697
		}
4698
	}
4699

    
4700
	if (empty($parents)) {
4701
		// Handle _vlans not assigned to an interface
4702
		if (strpos($realif, '_vlan') !== FALSE) {
4703
			if (is_array($config['vlans']['vlan'])) {
4704
				foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4705
					if ($realif == $vlan['vlanif']) {
4706
						$parents[0] = $vlan['if'];
4707
						break;
4708
					}
4709
				}
4710
			}
4711
		}
4712
	}
4713

    
4714
	if (empty($parents)) {
4715
		$parents[0] = $realif;
4716
	}
4717

    
4718
	return $parents;
4719
}
4720

    
4721
/*
4722
 *  get_parent_physical_interface($interface):
4723
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
4724
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
4725
 */
4726
function get_parent_physical_interface($interface) {
4727
	global $config;
4728

    
4729
	$realif = get_parent_interface($interface);
4730

    
4731
	if (substr($realif[0], 0, 4) == "lagg") {
4732
		foreach ($config['laggs']['lagg'] as $lagg) {
4733
			if ($realif[0] == $lagg['laggif']) {
4734
				return explode(",", $lagg['members']);
4735
			}
4736
		}
4737
	} else {
4738
		return $realif;
4739
	}
4740
}
4741

    
4742
function interface_is_wireless_clone($wlif) {
4743
	if (!stristr($wlif, "_wlan")) {
4744
		return false;
4745
	} else {
4746
		return true;
4747
	}
4748
}
4749

    
4750
function interface_get_wireless_base($wlif) {
4751
	if (!stristr($wlif, "_wlan")) {
4752
		return $wlif;
4753
	} else {
4754
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4755
	}
4756
}
4757

    
4758
function interface_get_wireless_clone($wlif) {
4759
	if (!stristr($wlif, "_wlan")) {
4760
		return $wlif . "_wlan0";
4761
	} else {
4762
		return $wlif;
4763
	}
4764
}
4765

    
4766
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4767
	global $config, $g;
4768

    
4769
	$wanif = NULL;
4770

    
4771
	switch ($interface) {
4772
		case "l2tp":
4773
			$wanif = "l2tp";
4774
			break;
4775
		case "pptp":
4776
			$wanif = "pptp";
4777
			break;
4778
		case "pppoe":
4779
			$wanif = "pppoe";
4780
			break;
4781
		case "openvpn":
4782
			$wanif = "openvpn";
4783
			break;
4784
		case "IPsec":
4785
		case "ipsec":
4786
		case "enc0":
4787
			$wanif = "enc0";
4788
			break;
4789
		case "ppp":
4790
			$wanif = "ppp";
4791
			break;
4792
		default:
4793
			if (substr($interface, 0, 4) == '_vip') {
4794
				$wanif = get_configured_vip_interface($interface);
4795
				if (!empty($wanif)) {
4796
					$wanif = get_real_interface($wanif);
4797
				}
4798
				break;
4799
			} else if (substr($interface, 0, 5) == '_lloc') {
4800
				$interface = substr($interface, 5);
4801
			} else if (strstr($interface, "_vlan") ||
4802
			    does_interface_exist($interface, $flush)) {
4803
				/*
4804
				 * If a real interface was already passed simply
4805
				 * pass the real interface back.  This encourages
4806
				 * the usage of this function in more cases so that
4807
				 * we can combine logic for more flexibility.
4808
				 */
4809
				$wanif = $interface;
4810
				break;
4811
			}
4812

    
4813
			if (empty($config['interfaces'][$interface])) {
4814
				break;
4815
			}
4816

    
4817
			$cfg = &$config['interfaces'][$interface];
4818

    
4819
			if ($family == "inet6") {
4820
				switch ($cfg['ipaddrv6']) {
4821
					case "6rd":
4822
					case "6to4":
4823
						$wanif = "{$interface}_stf";
4824
						break;
4825
					case 'pppoe':
4826
					case 'ppp':
4827
					case 'l2tp':
4828
					case 'pptp':
4829
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4830
							$wanif = interface_get_wireless_clone($cfg['if']);
4831
						} else {
4832
							$wanif = $cfg['if'];
4833
						}
4834
						break;
4835
					default:
4836
						switch ($cfg['ipaddr']) {
4837
							case 'pppoe':
4838
							case 'ppp':
4839
							case 'l2tp':
4840
							case 'pptp':
4841
								if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false) {
4842
									$wanif = $cfg['if'];
4843
								} else {
4844
									$parents = get_parent_interface($interface);
4845
									if (!empty($parents[0])) {
4846
										$wanif = $parents[0];
4847
									} else {
4848
										$wanif = $cfg['if'];
4849
									}
4850
								}
4851
								break;
4852
							default:
4853
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4854
									$wanif = interface_get_wireless_clone($cfg['if']);
4855
								} else {
4856
									$wanif = $cfg['if'];
4857
								}
4858
								break;
4859
						}
4860
						break;
4861
				}
4862
			} else {
4863
				// Wireless cloned NIC support (FreeBSD 8+)
4864
				// interface name format: $parentnic_wlanparentnic#
4865
				// example: ath0_wlan0
4866
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4867
					$wanif = interface_get_wireless_clone($cfg['if']);
4868
				} else {
4869
					$wanif = $cfg['if'];
4870
				}
4871
			}
4872
			break;
4873
	}
4874

    
4875
	return $wanif;
4876
}
4877

    
4878
/* Guess the physical interface by providing a IP address */
4879
function guess_interface_from_ip($ipaddress) {
4880

    
4881
	$family = '';
4882
	if (is_ipaddrv4($ipaddress)) {
4883
		$family = 'inet';
4884
	}
4885
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4886
		$family = 'inet6';
4887
	}
4888

    
4889
	if (empty($family)) {
4890
		return false;
4891
	}
4892

    
4893
	/* create a route table we can search */
4894
	$output = '';
4895
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4896
	$output[0] = trim($output[0], " \n");
4897
	if (!empty($output[0])) {
4898
		return $output[0];
4899
	}
4900

    
4901
	return false;
4902
}
4903

    
4904
/*
4905
 * find_ip_interface($ip): return the interface where an ip is defined
4906
 *   (or if $bits is specified, where an IP within the subnet is defined)
4907
 */
4908
function find_ip_interface($ip, $bits = null) {
4909
	if (!is_ipaddr($ip)) {
4910
		return false;
4911
	}
4912

    
4913
	$isv6ip = is_ipaddrv6($ip);
4914

    
4915
	/* if list */
4916
	$ifdescrs = get_configured_interface_list();
4917

    
4918
	foreach ($ifdescrs as $ifdescr => $ifname) {
4919
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4920
		if (is_null($ifip)) {
4921
			continue;
4922
		}
4923
		if (is_null($bits)) {
4924
			if ($ip == $ifip) {
4925
				$int = get_real_interface($ifname);
4926
				return $int;
4927
			}
4928
		} else {
4929
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4930
				$int = get_real_interface($ifname);
4931
				return $int;
4932
			}
4933
		}
4934
	}
4935

    
4936
	return false;
4937
}
4938

    
4939
/*
4940
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4941
 *   (or if $bits is specified, where an IP within the subnet is found)
4942
 */
4943
function find_virtual_ip_alias($ip, $bits = null) {
4944
	global $config;
4945

    
4946
	if (!is_array($config['virtualip']['vip'])) {
4947
		return false;
4948
	}
4949
	if (!is_ipaddr($ip)) {
4950
		return false;
4951
	}
4952

    
4953
	$isv6ip = is_ipaddrv6($ip);
4954

    
4955
	foreach ($config['virtualip']['vip'] as $vip) {
4956
		if ($vip['mode'] === "ipalias") {
4957
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
4958
				continue;
4959
			}
4960
			if (is_null($bits)) {
4961
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4962
					return $vip;
4963
				}
4964
			} else {
4965
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
4966
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4967
					return $vip;
4968
				}
4969
			}
4970
		}
4971
	}
4972
	return false;
4973
}
4974

    
4975
function link_interface_to_track6($int, $action = "") {
4976
	global $config;
4977

    
4978
	if (empty($int)) {
4979
		return;
4980
	}
4981

    
4982
	if (is_array($config['interfaces'])) {
4983
		$list = array();
4984
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4985
			if (!isset($ifcfg['enable'])) {
4986
				continue;
4987
			}
4988
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4989
				if ($action == "update") {
4990
					interface_track6_configure($ifname, $ifcfg);
4991
				} else if ($action == "") {
4992
					$list[$ifname] = $ifcfg;
4993
				}
4994
			}
4995
		}
4996
		return $list;
4997
	}
4998
}
4999

    
5000
function interface_find_child_cfgmtu($realiface) {
5001
	global $config;
5002

    
5003
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5004
	$vlans = link_interface_to_vlans($realiface);
5005
	$qinqs = link_interface_to_qinqs($realiface);
5006
	$bridge = link_interface_to_bridge($realiface);
5007
	if (!empty($interface)) {
5008
		$gifs = link_interface_to_gif($interface);
5009
		$gres = link_interface_to_gre($interface);
5010
	} else {
5011
		$gifs = array();
5012
		$gres = array();
5013
	}
5014

    
5015
	$mtu = 0;
5016
	if (is_array($vlans)) {
5017
		foreach ($vlans as $vlan) {
5018
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5019
			if (empty($ifass)) {
5020
				continue;
5021
			}
5022
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5023
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5024
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5025
				}
5026
			}
5027
		}
5028
	}
5029
	if (is_array($qinqs)) {
5030
		foreach ($qinqs as $qinq) {
5031
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5032
			if (empty($ifass)) {
5033
				continue;
5034
			}
5035
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5036
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5037
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5038
				}
5039
			}
5040
		}
5041
	}
5042
	if (is_array($gifs)) {
5043
		foreach ($gifs as $gif) {
5044
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5045
			if (empty($ifass)) {
5046
				continue;
5047
			}
5048
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5049
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5050
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5051
				}
5052
			}
5053
		}
5054
	}
5055
	if (is_array($gres)) {
5056
		foreach ($gres as $gre) {
5057
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5058
			if (empty($ifass)) {
5059
				continue;
5060
			}
5061
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5062
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5063
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5064
				}
5065
			}
5066
		}
5067
	}
5068
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5069
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5070
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5071
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5072
		}
5073
	}
5074
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5075

    
5076
	return $mtu;
5077
}
5078

    
5079
function link_interface_to_vlans($int, $action = "") {
5080
	global $config;
5081

    
5082
	if (empty($int)) {
5083
		return;
5084
	}
5085

    
5086
	if (is_array($config['vlans']['vlan'])) {
5087
		$ifaces = array();
5088
		foreach ($config['vlans']['vlan'] as $vlan) {
5089
			if ($int == $vlan['if']) {
5090
				if ($action == "update") {
5091
					interfaces_bring_up($int);
5092
				} else {
5093
					$ifaces[$vlan['tag']] = $vlan;
5094
				}
5095
			}
5096
		}
5097
		if (!empty($ifaces)) {
5098
			return $ifaces;
5099
		}
5100
	}
5101
}
5102

    
5103
function link_interface_to_qinqs($int, $action = "") {
5104
	global $config;
5105

    
5106
	if (empty($int)) {
5107
		return;
5108
	}
5109

    
5110
	if (is_array($config['qinqs']['qinqentry'])) {
5111
		$ifaces = array();
5112
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5113
			if ($int == $qinq['if']) {
5114
				if ($action == "update") {
5115
					interfaces_bring_up($int);
5116
				} else {
5117
					$ifaces[$qinq['tag']] = $qinq;
5118
				}
5119
			}
5120
		}
5121
		if (!empty($ifaces)) {
5122
			return $ifaces;
5123
		}
5124
	}
5125
}
5126

    
5127
function link_interface_to_vips($int, $action = "", $vhid = '') {
5128
	global $config;
5129

    
5130
	$updatevips = false;
5131
	if (is_array($config['virtualip']['vip'])) {
5132
		$result = array();
5133
		foreach ($config['virtualip']['vip'] as $vip) {
5134
			if (substr($vip['interface'], 0, 4) == "_vip") {
5135
				$iface = get_configured_vip_interface($vip['interface']);
5136
			} else {
5137
				$iface = $vip['interface'];
5138
			}
5139
			if ($int != $iface) {
5140
				continue;
5141
			}
5142
			if ($action == "update") {
5143
				$updatevips = true;
5144
			} else {
5145
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5146
				    substr($vip['interface'], 0, 4) == "_vip") {
5147
					$result[] = $vip;
5148
				}
5149
			}
5150
		}
5151
		if ($updatevips === true) {
5152
			interfaces_vips_configure($int);
5153
		}
5154
		return $result;
5155
	}
5156

    
5157
	return NULL;
5158
}
5159

    
5160
/****f* interfaces/link_interface_to_bridge
5161
 * NAME
5162
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5163
 * INPUTS
5164
 *   $ip
5165
 * RESULT
5166
 *   bridge[0-99]
5167
 ******/
5168
function link_interface_to_bridge($int) {
5169
	global $config;
5170

    
5171
	if (is_array($config['bridges']['bridged'])) {
5172
		foreach ($config['bridges']['bridged'] as $bridge) {
5173
			if (in_array($int, explode(',', $bridge['members']))) {
5174
				return "{$bridge['bridgeif']}";
5175
			}
5176
		}
5177
	}
5178
}
5179

    
5180
function link_interface_to_group($int) {
5181
	global $config;
5182

    
5183
	$result = array();
5184

    
5185
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5186
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5187
			if (in_array($int, explode(" ", $group['members']))) {
5188
				$result[$group['ifname']] = $int;
5189
			}
5190
		}
5191
	}
5192

    
5193
	return $result;
5194
}
5195

    
5196
function link_interface_to_gre($interface) {
5197
	global $config;
5198

    
5199
	$result = array();
5200

    
5201
	if (is_array($config['gres']['gre'])) {
5202
		foreach ($config['gres']['gre'] as $gre) {
5203
			if ($gre['if'] == $interface) {
5204
				$result[] = $gre;
5205
			}
5206
		}
5207
	}
5208

    
5209
	return $result;
5210
}
5211

    
5212
function link_interface_to_gif($interface) {
5213
	global $config;
5214

    
5215
	$result = array();
5216

    
5217
	if (is_array($config['gifs']['gif'])) {
5218
		foreach ($config['gifs']['gif'] as $gif) {
5219
			if ($gif['if'] == $interface) {
5220
				$result[] = $gif;
5221
			}
5222
		}
5223
	}
5224

    
5225
	return $result;
5226
}
5227

    
5228
/*
5229
 * find_interface_ip($interface): return the interface ip (first found)
5230
 */
5231
function find_interface_ip($interface, $flush = false) {
5232
	global $interface_ip_arr_cache;
5233
	global $interface_sn_arr_cache;
5234

    
5235
	$interface = str_replace("\n", "", $interface);
5236

    
5237
	if (!does_interface_exist($interface)) {
5238
		return;
5239
	}
5240

    
5241
	/* Setup IP cache */
5242
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5243
		$ifinfo = pfSense_get_interface_addresses($interface);
5244
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5245
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5246
	}
5247

    
5248
	return $interface_ip_arr_cache[$interface];
5249
}
5250

    
5251
/*
5252
 * find_interface_ipv6($interface): return the interface ip (first found)
5253
 */
5254
function find_interface_ipv6($interface, $flush = false) {
5255
	global $interface_ipv6_arr_cache;
5256
	global $interface_snv6_arr_cache;
5257
	global $config;
5258

    
5259
	$interface = trim($interface);
5260
	$interface = get_real_interface($interface);
5261

    
5262
	if (!does_interface_exist($interface)) {
5263
		return;
5264
	}
5265

    
5266
	/* Setup IP cache */
5267
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5268
		$ifinfo = pfSense_get_interface_addresses($interface);
5269
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5270
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5271
	}
5272

    
5273
	return $interface_ipv6_arr_cache[$interface];
5274
}
5275

    
5276
/*
5277
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5278
 */
5279
function find_interface_ipv6_ll($interface, $flush = false) {
5280
	global $interface_llv6_arr_cache;
5281
	global $config;
5282

    
5283
	$interface = str_replace("\n", "", $interface);
5284

    
5285
	if (!does_interface_exist($interface)) {
5286
		return;
5287
	}
5288

    
5289
	/* Setup IP cache */
5290
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5291
		$ifinfo = pfSense_getall_interface_addresses($interface);
5292
		foreach ($ifinfo as $line) {
5293
			if (strstr($line, ":")) {
5294
				$parts = explode("/", $line);
5295
				if (is_linklocal($parts[0])) {
5296
					$ifinfo['linklocal'] = $parts[0];
5297
				}
5298
			}
5299
		}
5300
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5301
	}
5302
	return $interface_llv6_arr_cache[$interface];
5303
}
5304

    
5305
function find_interface_subnet($interface, $flush = false) {
5306
	global $interface_sn_arr_cache;
5307
	global $interface_ip_arr_cache;
5308

    
5309
	$interface = str_replace("\n", "", $interface);
5310
	if (does_interface_exist($interface) == false) {
5311
		return;
5312
	}
5313

    
5314
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5315
		$ifinfo = pfSense_get_interface_addresses($interface);
5316
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5317
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5318
	}
5319

    
5320
	return $interface_sn_arr_cache[$interface];
5321
}
5322

    
5323
function find_interface_subnetv6($interface, $flush = false) {
5324
	global $interface_snv6_arr_cache;
5325
	global $interface_ipv6_arr_cache;
5326

    
5327
	$interface = str_replace("\n", "", $interface);
5328
	if (does_interface_exist($interface) == false) {
5329
		return;
5330
	}
5331

    
5332
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5333
		$ifinfo = pfSense_get_interface_addresses($interface);
5334
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5335
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5336
	}
5337

    
5338
	return $interface_snv6_arr_cache[$interface];
5339
}
5340

    
5341
function ip_in_interface_alias_subnet($interface, $ipalias) {
5342
	global $config;
5343

    
5344
	if (empty($interface) || !is_ipaddr($ipalias)) {
5345
		return false;
5346
	}
5347
	if (is_array($config['virtualip']['vip'])) {
5348
		foreach ($config['virtualip']['vip'] as $vip) {
5349
			switch ($vip['mode']) {
5350
				case "ipalias":
5351
					if ($vip['interface'] <> $interface) {
5352
						break;
5353
					}
5354
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5355
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5356
						return true;
5357
					}
5358
					break;
5359
			}
5360
		}
5361
	}
5362

    
5363
	return false;
5364
}
5365

    
5366
function get_possible_listen_ips($include_ipv6_link_local=false) {
5367

    
5368
	$interfaces = get_configured_interface_with_descr();
5369
	foreach ($interfaces as $iface => $ifacename) {
5370
		if ($include_ipv6_link_local) {
5371
			/* This is to avoid going though added ll below */
5372
			if (substr($iface, 0, 5) == '_lloc') {
5373
				continue;
5374
			}
5375
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5376
			if (!empty($llip)) {
5377
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5378
			}
5379
		}
5380
	}
5381
	$viplist = get_configured_vip_list();
5382
	foreach ($viplist as $vip => $address) {
5383
		$interfaces[$vip] = $address;
5384
		if (get_vip_descr($address)) {
5385
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5386
		}
5387
	}
5388

    
5389
	$interfaces['lo0'] = 'Localhost';
5390

    
5391
	return $interfaces;
5392
}
5393

    
5394
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5395
	global $config;
5396

    
5397
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5398
	foreach (array('server', 'client') as $mode) {
5399
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5400
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5401
				if (!isset($setting['disable'])) {
5402
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5403
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5404
				}
5405
			}
5406
		}
5407
	}
5408
	return $sourceips;
5409
}
5410

    
5411
function get_interface_ip($interface = "wan") {
5412

    
5413
	if (substr($interface, 0, 4) == '_vip') {
5414
		return get_configured_vip_ipv4($interface);
5415
	} else if (substr($interface, 0, 5) == '_lloc') {
5416
		/* No link-local address for v4. */
5417
		return null;
5418
	}
5419

    
5420
	$realif = get_failover_interface($interface, 'inet');
5421
	if (!$realif) {
5422
		return null;
5423
	}
5424

    
5425
	if (substr($realif, 0, 4) == '_vip') {
5426
		return get_configured_vip_ipv4($realif);
5427
	} else if (substr($realif, 0, 5) == '_lloc') {
5428
		/* No link-local address for v4. */
5429
		return null;
5430
	}
5431

    
5432
	if (is_array($config['interfaces'][$interface]) &&
5433
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5434
		return ($config['interfaces'][$interface]['ipaddr']);
5435
	}
5436

    
5437
	/*
5438
	 * Beaware that find_interface_ip() is our last option, it will
5439
	 * return the first IP it find on interface, not necessarily the
5440
	 * main IP address.
5441
	 */
5442
	$curip = find_interface_ip($realif);
5443
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5444
		return $curip;
5445
	} else {
5446
		return null;
5447
	}
5448
}
5449

    
5450
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5451
	global $config;
5452

    
5453
	if (substr($interface, 0, 4) == '_vip') {
5454
		return get_configured_vip_ipv6($interface);
5455
	} else if (substr($interface, 0, 5) == '_lloc') {
5456
		return get_interface_linklocal($interface);
5457
	}
5458

    
5459
	$realif = get_failover_interface($interface, 'inet6');
5460
	if (!$realif) {
5461
		return null;
5462
	}
5463

    
5464
	if (substr($realif, 0, 4) == '_vip') {
5465
		return get_configured_vip_ipv6($realif);
5466
	} else if (substr($realif, 0, 5) == '_lloc') {
5467
		return get_interface_linklocal($realif);
5468
	}
5469

    
5470
	if (is_array($config['interfaces'][$interface])) {
5471
		switch ($config['interfaces'][$interface]['ipaddr']) {
5472
			case 'pppoe':
5473
			case 'l2tp':
5474
			case 'pptp':
5475
			case 'ppp':
5476
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5477
					$realif = get_real_interface($interface, 'inet6', false);
5478
				}
5479
				break;
5480
		}
5481
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5482
			return ($config['interfaces'][$interface]['ipaddrv6']);
5483
		}
5484
	}
5485

    
5486
	/*
5487
	 * Beaware that find_interface_ip() is our last option, it will
5488
	 * return the first IP it find on interface, not necessarily the
5489
	 * main IP address.
5490
	 */
5491
	$curip = find_interface_ipv6($realif, $flush);
5492
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5493
		return $curip;
5494
	} else {
5495
		/*
5496
		 * NOTE: On the case when only the prefix is requested,
5497
		 * the communication on WAN will be done over link-local.
5498
		 */
5499
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
5500
			$curip = find_interface_ipv6_ll($realif, $flush);
5501
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5502
				return $curip;
5503
			}
5504
		}
5505
	}
5506
	return null;
5507
}
5508

    
5509
function get_interface_linklocal($interface = "wan") {
5510

    
5511
	$realif = get_failover_interface($interface, 'inet6');
5512
	if (!$realif) {
5513
		return null;
5514
	}
5515

    
5516
	if (substr($interface, 0, 4) == '_vip') {
5517
		$realif = get_real_interface($interface);
5518
	} else if (substr($interface, 0, 5) == '_lloc') {
5519
		$realif = get_real_interface(substr($interface, 5));
5520
	}
5521

    
5522
	$curip = find_interface_ipv6_ll($realif);
5523
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5524
		return $curip;
5525
	} else {
5526
		return null;
5527
	}
5528
}
5529

    
5530
function get_interface_subnet($interface = "wan") {
5531

    
5532
	if (substr($interface, 0, 4) == '_vip') {
5533
		return (get_configured_vip_subnetv4($interface));
5534
	}
5535

    
5536
	$realif = get_real_interface($interface);
5537
	if (!$realif) {
5538
		return (NULL);
5539
	}
5540

    
5541
	$cursn = find_interface_subnet($realif);
5542
	if (!empty($cursn)) {
5543
		return ($cursn);
5544
	}
5545

    
5546
	return (NULL);
5547
}
5548

    
5549
function get_interface_subnetv6($interface = "wan") {
5550

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

    
5557
	$realif = get_real_interface($interface, 'inet6');
5558
	if (!$realif) {
5559
		return (NULL);
5560
	}
5561

    
5562
	$cursn = find_interface_subnetv6($realif);
5563
	if (!empty($cursn)) {
5564
		return ($cursn);
5565
	}
5566

    
5567
	return (NULL);
5568
}
5569

    
5570
/* return outside interfaces with a gateway */
5571
function get_interfaces_with_gateway() {
5572
	global $config;
5573

    
5574
	$ints = array();
5575

    
5576
	/* loop interfaces, check config for outbound */
5577
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5578
		switch ($ifname['ipaddr']) {
5579
			case "dhcp":
5580
			case "pppoe":
5581
			case "pptp":
5582
			case "l2tp":
5583
			case "ppp":
5584
				$ints[$ifdescr] = $ifdescr;
5585
				break;
5586
			default:
5587
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5588
				    !empty($ifname['gateway'])) {
5589
					$ints[$ifdescr] = $ifdescr;
5590
				}
5591
				break;
5592
		}
5593
	}
5594
	return $ints;
5595
}
5596

    
5597
/* return true if interface has a gateway */
5598
function interface_has_gateway($friendly) {
5599
	global $config;
5600

    
5601
	if (!empty($config['interfaces'][$friendly])) {
5602
		$ifname = &$config['interfaces'][$friendly];
5603
		switch ($ifname['ipaddr']) {
5604
			case "dhcp":
5605
			case "pppoe":
5606
			case "pptp":
5607
			case "l2tp":
5608
			case "ppp":
5609
				return true;
5610
			break;
5611
			default:
5612
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5613
					return true;
5614
				}
5615
				$tunnelif = substr($ifname['if'], 0, 3);
5616
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5617
					if (find_interface_ip($ifname['if'])) {
5618
						return true;
5619
					}
5620
				}
5621
				if (!empty($ifname['gateway'])) {
5622
					return true;
5623
				}
5624
			break;
5625
		}
5626
	}
5627

    
5628
	return false;
5629
}
5630

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

    
5635
	if (!empty($config['interfaces'][$friendly])) {
5636
		$ifname = &$config['interfaces'][$friendly];
5637
		switch ($ifname['ipaddrv6']) {
5638
			case "slaac":
5639
			case "dhcp6":
5640
			case "6to4":
5641
			case "6rd":
5642
				return true;
5643
				break;
5644
			default:
5645
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5646
					return true;
5647
				}
5648
				$tunnelif = substr($ifname['if'], 0, 3);
5649
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5650
					if (find_interface_ipv6($ifname['if'])) {
5651
						return true;
5652
					}
5653
				}
5654
				if (!empty($ifname['gatewayv6'])) {
5655
					return true;
5656
				}
5657
				break;
5658
		}
5659
	}
5660

    
5661
	return false;
5662
}
5663

    
5664
/****f* interfaces/is_altq_capable
5665
 * NAME
5666
 *   is_altq_capable - Test if interface is capable of using ALTQ
5667
 * INPUTS
5668
 *   $int            - string containing interface name
5669
 * RESULT
5670
 *   boolean         - true or false
5671
 ******/
5672

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

    
5687
	$int_family = remove_ifindex($int);
5688

    
5689
	if (in_array($int_family, $capable)) {
5690
		return true;
5691
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5692
		return true;
5693
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5694
		return true;
5695
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5696
		return true;
5697
	} else {
5698
		return false;
5699
	}
5700
}
5701

    
5702
/****f* interfaces/is_interface_wireless
5703
 * NAME
5704
 *   is_interface_wireless - Returns if an interface is wireless
5705
 * RESULT
5706
 *   $tmp       - Returns if an interface is wireless
5707
 ******/
5708
function is_interface_wireless($interface) {
5709
	global $config, $g;
5710

    
5711
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5712
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5713
		if (preg_match($g['wireless_regex'], $interface)) {
5714
			if (isset($config['interfaces'][$friendly])) {
5715
				$config['interfaces'][$friendly]['wireless'] = array();
5716
			}
5717
			return true;
5718
		}
5719
		return false;
5720
	} else {
5721
		return true;
5722
	}
5723
}
5724

    
5725
function get_wireless_modes($interface) {
5726
	/* return wireless modes and channels */
5727
	$wireless_modes = array();
5728

    
5729
	$cloned_interface = get_real_interface($interface);
5730

    
5731
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5732
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5733
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5734
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5735

    
5736
		$interface_channels = "";
5737
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5738
		$interface_channel_count = count($interface_channels);
5739

    
5740
		$c = 0;
5741
		while ($c < $interface_channel_count) {
5742
			$channel_line = explode(",", $interface_channels["$c"]);
5743
			$wireless_mode = trim($channel_line[0]);
5744
			$wireless_channel = trim($channel_line[1]);
5745
			if (trim($wireless_mode) != "") {
5746
				/* if we only have 11g also set 11b channels */
5747
				if ($wireless_mode == "11g") {
5748
					if (!isset($wireless_modes["11b"])) {
5749
						$wireless_modes["11b"] = array();
5750
					}
5751
				} else if ($wireless_mode == "11g ht") {
5752
					if (!isset($wireless_modes["11b"])) {
5753
						$wireless_modes["11b"] = array();
5754
					}
5755
					if (!isset($wireless_modes["11g"])) {
5756
						$wireless_modes["11g"] = array();
5757
					}
5758
					$wireless_mode = "11ng";
5759
				} else if ($wireless_mode == "11a ht") {
5760
					if (!isset($wireless_modes["11a"])) {
5761
						$wireless_modes["11a"] = array();
5762
					}
5763
					$wireless_mode = "11na";
5764
				}
5765
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5766
			}
5767
			$c++;
5768
		}
5769
	}
5770
	return($wireless_modes);
5771
}
5772

    
5773
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5774
function get_wireless_channel_info($interface) {
5775
	$wireless_channels = array();
5776

    
5777
	$cloned_interface = get_real_interface($interface);
5778

    
5779
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5780
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5781
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5782
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5783

    
5784
		$interface_channels = "";
5785
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5786

    
5787
		foreach ($interface_channels as $channel_line) {
5788
			$channel_line = explode(",", $channel_line);
5789
			if (!isset($wireless_channels[$channel_line[0]])) {
5790
				$wireless_channels[$channel_line[0]] = $channel_line;
5791
			}
5792
		}
5793
	}
5794
	return($wireless_channels);
5795
}
5796

    
5797
function set_interface_mtu($interface, $mtu) {
5798

    
5799
	/* LAGG interface must be destroyed and re-created to change MTU */
5800
	if (substr($interface, 0, 4) == 'lagg') {
5801
		if (isset($config['laggs']['lagg']) &&
5802
		    is_array($config['laggs']['lagg'])) {
5803
			foreach ($config['laggs']['lagg'] as $lagg) {
5804
				if ($lagg['laggif'] == $interface) {
5805
					interface_lagg_configure($lagg);
5806
					break;
5807
				}
5808
			}
5809
		}
5810
	} else {
5811
		pfSense_interface_mtu($interface, $mtu);
5812
	}
5813
}
5814

    
5815
/****f* interfaces/get_interface_mtu
5816
 * NAME
5817
 *   get_interface_mtu - Return the mtu of an interface
5818
 * RESULT
5819
 *   $tmp       - Returns the mtu of an interface
5820
 ******/
5821
function get_interface_mtu($interface) {
5822
	$mtu = pfSense_interface_getmtu($interface);
5823
	return $mtu['mtu'];
5824
}
5825

    
5826
function get_interface_mac($interface) {
5827

    
5828
	$macinfo = pfSense_get_interface_addresses($interface);
5829
	return $macinfo["macaddr"];
5830
}
5831

    
5832
/****f* pfsense-utils/generate_random_mac_address
5833
 * NAME
5834
 *   generate_random_mac - generates a random mac address
5835
 * INPUTS
5836
 *   none
5837
 * RESULT
5838
 *   $mac - a random mac address
5839
 ******/
5840
function generate_random_mac_address() {
5841
	$mac = "02";
5842
	for ($x = 0; $x < 5; $x++) {
5843
		$mac .= ":" . dechex(rand(16, 255));
5844
	}
5845
	return $mac;
5846
}
5847

    
5848
/****f* interfaces/is_jumbo_capable
5849
 * NAME
5850
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5851
 * INPUTS
5852
 *   $int             - string containing interface name
5853
 * RESULT
5854
 *   boolean          - true or false
5855
 ******/
5856
function is_jumbo_capable($iface) {
5857
	$iface = trim($iface);
5858
	$capable = pfSense_get_interface_addresses($iface);
5859

    
5860
	if (isset($capable['caps']['vlanmtu'])) {
5861
		return true;
5862
	}
5863

    
5864
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5865
	if (substr($iface, 0, 4) == "lagg") {
5866
		return true;
5867
	}
5868

    
5869
	return false;
5870
}
5871

    
5872
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5873
	global $g;
5874

    
5875
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5876

    
5877
	if (!empty($iface) && !empty($pppif)) {
5878
		$cron_cmd = <<<EOD
5879
#!/bin/sh
5880
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5881
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5882

    
5883
EOD;
5884

    
5885
		@file_put_contents($cron_file, $cron_cmd);
5886
		chmod($cron_file, 0755);
5887
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5888
	} else {
5889
		unlink_if_exists($cron_file);
5890
	}
5891
}
5892

    
5893
function get_interface_default_mtu($type = "ethernet") {
5894
	switch ($type) {
5895
		case "gre":
5896
			return 1476;
5897
			break;
5898
		case "gif":
5899
			return 1280;
5900
			break;
5901
		case "tun":
5902
		case "vlan":
5903
		case "tap":
5904
		case "ethernet":
5905
		default:
5906
			return 1500;
5907
			break;
5908
	}
5909

    
5910
	/* Never reached */
5911
	return 1500;
5912
}
5913

    
5914
function get_vip_descr($ipaddress) {
5915
	global $config;
5916

    
5917
	foreach ($config['virtualip']['vip'] as $vip) {
5918
		if ($vip['subnet'] == $ipaddress) {
5919
			return ($vip['descr']);
5920
		}
5921
	}
5922
	return "";
5923
}
5924

    
5925
function interfaces_staticarp_configure($if) {
5926
	global $config, $g;
5927
	if (isset($config['system']['developerspew'])) {
5928
		$mt = microtime();
5929
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5930
	}
5931

    
5932
	$ifcfg = $config['interfaces'][$if];
5933

    
5934
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5935
		return 0;
5936
	}
5937

    
5938
	/* Enable staticarp, if enabled */
5939
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5940
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5941
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5942
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5943
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5944
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5945
			}
5946
		}
5947
	} else {
5948
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5949
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5950
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5951
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5952
				if (isset($arpent['arp_table_static_entry'])) {
5953
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5954
				}
5955
			}
5956
		}
5957
	}
5958

    
5959
	return 0;
5960
}
5961

    
5962
function get_failover_interface($interface, $family = "all") {
5963
	global $config;
5964

    
5965
	/* shortcut to get_real_interface if we find it in the config */
5966
	if (is_array($config['interfaces'][$interface])) {
5967
		return get_real_interface($interface, $family);
5968
	}
5969

    
5970
	/* compare against gateway groups */
5971
	$a_groups = return_gateway_groups_array();
5972
	if (is_array($a_groups[$interface])) {
5973
		/* we found a gateway group, fetch the interface or vip */
5974
		if (!empty($a_groups[$interface][0]['vip'])) {
5975
			return $a_groups[$interface][0]['vip'];
5976
		} else {
5977
			return $a_groups[$interface][0]['int'];
5978
		}
5979
	}
5980
	/* fall through to get_real_interface */
5981
	/* XXX: Really needed? */
5982
	return get_real_interface($interface, $family);
5983
}
5984

    
5985
function remove_ifindex($ifname) {
5986
	return preg_replace("/[0-9]+$/", "", $ifname);
5987
}
5988

    
5989
?>
(25-25/65)