Project

General

Profile

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

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

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

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

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

    
81
	return $interface_arr_cache;
82
}
83

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

    
91
	if (!$interface) {
92
		return false;
93
	}
94

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

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

    
110
	if (!$vip) {
111
		return false;
112
	}
113

    
114

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

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

    
137
	return false;
138
}
139

    
140
function interface_netgraph_needed($interface = "wan") {
141
	global $config;
142

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

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

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

    
198
function interfaces_loopback_configure() {
199
	global $g;
200

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

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

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

    
235
function interface_vlan_configure(&$vlan) {
236
	global $config, $g;
237

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

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

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

    
257
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
258
		pfSense_interface_destroy($vlanif);
259
	}
260

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

    
265
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
266

    
267
	interfaces_bring_up($vlanif);
268

    
269
	/* invalidate interface cache */
270
	get_interface_arr(true);
271

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

    
275
	return $vlanif;
276
}
277

    
278
function interface_qinq_configure(&$vlan, $fd = NULL) {
279
	global $config, $g;
280

    
281
	if (!is_array($vlan)) {
282
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
283
		return;
284
	}
285

    
286
	$qinqif = $vlan['if'];
287
	$tag = $vlan['tag'];
288
	if (empty($qinqif)) {
289
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
290
		return;
291
	}
292

    
293
	if (!does_interface_exist($qinqif)) {
294
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
295
		return;
296
	}
297

    
298
	$vlanif = interface_vlan_configure($vlan);
299

    
300
	if ($fd == NULL) {
301
		$exec = true;
302
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
303
	} else {
304
		$exec = false;
305
	}
306
	/* make sure the parent is converted to ng_vlan(4) and is up */
307
	interfaces_bring_up($qinqif);
308

    
309
	pfSense_ngctl_attach(".", $qinqif);
310
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
311
		fwrite($fd, "shutdown {$qinqif}qinq:\n");
312
		exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
313
		if (empty($result)) {
314
			fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
315
			fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
316
			fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
317
		}
318
	} else {
319
		fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
320
		fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
321
		fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
322
	}
323

    
324
	/* invalidate interface cache */
325
	get_interface_arr(true);
326

    
327
	if (!stristr($qinqif, "_vlan")) {
328
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
329
	}
330

    
331
	$macaddr = get_interface_mac($qinqif);
332
	if (!empty($vlan['members'])) {
333
		$members = explode(" ", $vlan['members']);
334
		foreach ($members as $qtag) {
335
			$qinq = array();
336
			$qinq['tag'] = $qtag;
337
			$qinq['if'] = $vlanif;
338
			interface_qinq2_configure($qinq, $fd, $macaddr);
339
		}
340
	}
341
	if ($exec == true) {
342
		fclose($fd);
343
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
344
	}
345

    
346
	interfaces_bring_up($qinqif);
347
	if (!empty($vlan['members'])) {
348
		$members = explode(" ", $vlan['members']);
349
		foreach ($members as $qif) {
350
			interfaces_bring_up("{$vlanif}_{$qif}");
351
		}
352
	}
353

    
354
	return $vlanif;
355
}
356

    
357
function interfaces_qinq_configure() {
358
	global $config, $g;
359
	if (platform_booting()) {
360
		echo gettext("Configuring QinQ interfaces...");
361
	}
362
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
363
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
364
			/* XXX: Maybe we should report any errors?! */
365
			interface_qinq_configure($qinq);
366
		}
367
	}
368
	if (platform_booting()) {
369
		echo gettext("done.") . "\n";
370
	}
371
}
372

    
373
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
374
	global $config, $g;
375

    
376
	if (!is_array($qinq)) {
377
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
378
		return;
379
	}
380

    
381
	$if = $qinq['if'];
382
	$tag = $qinq['tag'];
383
	$vlanif = "{$if}_{$tag}";
384
	if (empty($if)) {
385
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
386
		return;
387
	}
388

    
389
	fwrite($fd, "shutdown {$if}h{$tag}:\n");
390
	fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
391
	fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
392
	fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
393
	fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
394
	fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
395

    
396
	/* invalidate interface cache */
397
	get_interface_arr(true);
398

    
399
	return $vlanif;
400
}
401

    
402
function interfaces_create_wireless_clones() {
403
	global $config, $g;
404

    
405
	if (platform_booting()) {
406
		echo gettext("Creating wireless clone interfaces...");
407
	}
408

    
409
	$iflist = get_configured_interface_list();
410

    
411
	foreach ($iflist as $if) {
412
		$realif = $config['interfaces'][$if]['if'];
413
		if (is_interface_wireless($realif)) {
414
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
415
		}
416
	}
417

    
418
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
419
		foreach ($config['wireless']['clone'] as $clone) {
420
			if (empty($clone['cloneif'])) {
421
				continue;
422
			}
423
			if (does_interface_exist($clone['cloneif'])) {
424
				continue;
425
			}
426
			/* XXX: Maybe we should report any errors?! */
427
			interface_wireless_clone($clone['cloneif'], $clone);
428
		}
429
	}
430
	if (platform_booting()) {
431
		echo gettext("done.") . "\n";
432
	}
433

    
434
}
435

    
436
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
437
	global $config;
438

    
439
	$i = 0;
440
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
441
		foreach ($config['bridges']['bridged'] as $bridge) {
442
			if (empty($bridge['bridgeif'])) {
443
				$bridge['bridgeif'] = "bridge{$i}";
444
			}
445
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
446
				continue;
447
			}
448

    
449
			if ($checkmember == 1) {
450
				/* XXX: It should not be possible no? */
451
				if (strstr($bridge['if'], '_vip')) {
452
					continue;
453
				}
454
				$members = explode(',', $bridge['members']);
455
				foreach ($members as $member) {
456
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6") {
457
						continue 2;
458
					}
459
				}
460
			}
461
			else if ($checkmember == 2) {
462
				$members = explode(',', $bridge['members']);
463
				foreach ($members as $member) {
464
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6") {
465
						continue 2;
466
					}
467
				}
468
			}
469
			/* XXX: Maybe we should report any errors?! */
470
			interface_bridge_configure($bridge, $checkmember);
471
			$i++;
472
		}
473
	}
474
}
475

    
476
function interface_bridge_configure(&$bridge, $checkmember = 0) {
477
	global $config, $g;
478

    
479
	if (!is_array($bridge)) {
480
		return;
481
	}
482

    
483
	if (empty($bridge['members'])) {
484
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
485
		return;
486
	}
487

    
488
	$members = explode(',', $bridge['members']);
489
	if (!count($members)) {
490
		return;
491
	}
492

    
493
	/* Calculate smaller mtu and enforce it */
494
	$smallermtu = 0;
495
	$commonrx = true;
496
	$commontx = true;
497
	$foundgif = false;
498
	foreach ($members as $member) {
499
		$realif = get_real_interface($member);
500
		$mtu = get_interface_mtu($realif);
501
		if (substr($realif, 0, 3) == "gif") {
502
			$foundgif = true;
503
			if ($checkmember == 1) {
504
				return;
505
			}
506
			if ($mtu <= 1500) {
507
				continue;
508
			}
509
		}
510
		if ($smallermtu == 0 && !empty($mtu)) {
511
			$smallermtu = $mtu;
512
		} else if (!empty($mtu) && $mtu < $smallermtu) {
513
			$smallermtu = $mtu;
514
		}
515
	}
516
	if ($foundgif == false && $checkmember == 2) {
517
		return;
518
	}
519

    
520
	/* Just in case anything is not working well */
521
	if ($smallermtu == 0) {
522
		$smallermtu = 1500;
523
	}
524

    
525
	if (platform_booting() || !empty($bridge['bridgeif'])) {
526
		pfSense_interface_destroy($bridge['bridgeif']);
527
		pfSense_interface_create($bridge['bridgeif']);
528
		$bridgeif = escapeshellarg($bridge['bridgeif']);
529
	} else {
530
		$bridgeif = pfSense_interface_create("bridge");
531
		$bridge['bridgeif'] = $bridgeif;
532
	}
533

    
534
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
535
	if ($bridgemtu > $smallermtu) {
536
		$smallermtu = $bridgemtu;
537
	}
538

    
539
	$checklist = get_configured_interface_list();
540

    
541
	/* Add interfaces to bridge */
542
	foreach ($members as $member) {
543
		if (empty($checklist[$member])) {
544
			continue;
545
		}
546
		$realif = get_real_interface($member);
547
		if (!$realif) {
548
			log_error(gettext("realif not defined in interfaces bridge - up"));
549
			continue;
550
		}
551
		/* make sure the parent interface is up */
552
		pfSense_interface_mtu($realif, $smallermtu);
553
		interfaces_bring_up($realif);
554
		enable_hardware_offloading($member);
555
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
556
	}
557

    
558
	if (isset($bridge['enablestp'])) {
559
		/* Choose spanning tree proto */
560
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
561

    
562
		if (!empty($bridge['stp'])) {
563
			$stpifs = explode(',', $bridge['stp']);
564
			foreach ($stpifs as $stpif) {
565
				$realif = get_real_interface($stpif);
566
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
567
			}
568
		}
569
		if (!empty($bridge['maxage'])) {
570
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
571
		}
572
		if (!empty($bridge['fwdelay'])) {
573
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
574
		}
575
		if (!empty($bridge['hellotime'])) {
576
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
577
		}
578
		if (!empty($bridge['priority'])) {
579
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
580
		}
581
		if (!empty($bridge['holdcnt'])) {
582
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
583
		}
584
		if (!empty($bridge['ifpriority'])) {
585
			$pconfig = explode(",", $bridge['ifpriority']);
586
			$ifpriority = array();
587
			foreach ($pconfig as $cfg) {
588
				$embcfg = explode_assoc(":", $cfg);
589
				foreach ($embcfg as $key => $value) {
590
					$ifpriority[$key] = $value;
591
				}
592
			}
593
			foreach ($ifpriority as $key => $value) {
594
				$realif = get_real_interface($key);
595
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
596
			}
597
		}
598
		if (!empty($bridge['ifpathcost'])) {
599
			$pconfig = explode(",", $bridge['ifpathcost']);
600
			$ifpathcost = array();
601
			foreach ($pconfig as $cfg) {
602
				$embcfg = explode_assoc(":", $cfg);
603
				foreach ($embcfg as $key => $value) {
604
					$ifpathcost[$key] = $value;
605
				}
606
			}
607
			foreach ($ifpathcost as $key => $value) {
608
				$realif = get_real_interface($key);
609
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
610
			}
611
		}
612
	}
613

    
614
	if ($bridge['maxaddr'] <> "") {
615
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
616
	}
617
	if ($bridge['timeout'] <> "") {
618
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
619
	}
620
	if ($bridge['span'] <> "") {
621
		$realif = get_real_interface($bridge['span']);
622
		mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
623
	}
624
	if (!empty($bridge['edge'])) {
625
		$edgeifs = explode(',', $bridge['edge']);
626
		foreach ($edgeifs as $edgeif) {
627
			$realif = get_real_interface($edgeif);
628
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
629
		}
630
	}
631
	if (!empty($bridge['autoedge'])) {
632
		$edgeifs = explode(',', $bridge['autoedge']);
633
		foreach ($edgeifs as $edgeif) {
634
			$realif = get_real_interface($edgeif);
635
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
636
		}
637
	}
638
	if (!empty($bridge['ptp'])) {
639
		$ptpifs = explode(',', $bridge['ptp']);
640
		foreach ($ptpifs as $ptpif) {
641
			$realif = get_real_interface($ptpif);
642
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
643
		}
644
	}
645
	if (!empty($bridge['autoptp'])) {
646
		$ptpifs = explode(',', $bridge['autoptp']);
647
		foreach ($ptpifs as $ptpif) {
648
			$realif = get_real_interface($ptpif);
649
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
650
		}
651
	}
652
	if (!empty($bridge['static'])) {
653
		$stickyifs = explode(',', $bridge['static']);
654
		foreach ($stickyifs as $stickyif) {
655
			$realif = get_real_interface($stickyif);
656
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
657
		}
658
	}
659
	if (!empty($bridge['private'])) {
660
		$privateifs = explode(',', $bridge['private']);
661
		foreach ($privateifs as $privateif) {
662
			$realif = get_real_interface($privateif);
663
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
664
		}
665
	}
666

    
667
	if ($bridge['bridgeif']) {
668
		interfaces_bring_up($bridge['bridgeif']);
669
	} else {
670
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
671
	}
672
}
673

    
674
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
675

    
676
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
677
		return;
678
	}
679

    
680
	if ($flagsapplied == false) {
681
		$mtu = get_interface_mtu($bridgeif);
682
		$mtum = get_interface_mtu($interface);
683
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
684
			pfSense_interface_mtu($interface, $mtu);
685
		}
686

    
687
		hardware_offloading_applyflags($interface);
688
		interfaces_bring_up($interface);
689
	}
690

    
691
	pfSense_bridge_add_member($bridgeif, $interface);
692
}
693

    
694
function interfaces_lagg_configure($realif = "") {
695
	global $config, $g;
696
	if (platform_booting()) {
697
		echo gettext("Configuring LAGG interfaces...");
698
	}
699
	$i = 0;
700
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
701
		foreach ($config['laggs']['lagg'] as $lagg) {
702
			if (empty($lagg['laggif'])) {
703
				$lagg['laggif'] = "lagg{$i}";
704
			}
705
			if (!empty($realif) && $realif != $lagg['laggif']) {
706
				continue;
707
			}
708
			/* XXX: Maybe we should report any errors?! */
709
			interface_lagg_configure($lagg);
710
			$i++;
711
		}
712
	}
713
	if (platform_booting()) {
714
		echo gettext("done.") . "\n";
715
	}
716
}
717

    
718
function interface_lagg_configure($lagg) {
719
	global $config, $g;
720

    
721
	if (!is_array($lagg)) {
722
		return -1;
723
	}
724

    
725
	$members = explode(',', $lagg['members']);
726
	if (!count($members)) {
727
		return -1;
728
	}
729

    
730
	if (platform_booting() || !(empty($lagg['laggif']))) {
731
		pfSense_interface_destroy($lagg['laggif']);
732
		pfSense_interface_create($lagg['laggif']);
733
		$laggif = $lagg['laggif'];
734
	} else {
735
		$laggif = pfSense_interface_create("lagg");
736
	}
737

    
738
	/* Check if MTU was defined for this lagg interface */
739
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
740
	if ($lagg_mtu == 0) {
741
		/* Calculate smaller mtu and enforce it */
742
		$smallermtu = 0;
743
		foreach ($members as $member) {
744
			$mtu = get_interface_mtu($member);
745
			if (empty($mtu)) {
746
				continue;
747
			}
748
			if ($smallermtu == 0 || $mtu < $smallermtu) {
749
				$smallermtu = $mtu;
750
			}
751
		}
752
		$lagg_mtu = $smallermtu;
753
	}
754

    
755
	/* Just in case anything is not working well */
756
	if ($lagg_mtu == 0) {
757
		$lagg_mtu = 1500;
758
	}
759

    
760
	foreach ($members as $member) {
761
		if (!does_interface_exist($member)) {
762
			continue;
763
		}
764
		/* make sure the parent interface is up */
765
		pfSense_interface_mtu($member, $lagg_mtu);
766
		interfaces_bring_up($member);
767
		hardware_offloading_applyflags($member);
768
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
769
	}
770
	pfSense_interface_capabilities($laggif, -$flags_off);
771
	pfSense_interface_capabilities($laggif, $flags_on);
772

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

    
775
	interfaces_bring_up($laggif);
776

    
777
	return $laggif;
778
}
779

    
780
function interfaces_gre_configure($checkparent = 0, $realif = "") {
781
	global $config;
782

    
783
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
784
		foreach ($config['gres']['gre'] as $i => $gre) {
785
			if (empty($gre['greif'])) {
786
				$gre['greif'] = "gre{$i}";
787
			}
788
			if (!empty($realif) && $realif != $gre['greif']) {
789
				continue;
790
			}
791

    
792
			if ($checkparent == 1) {
793
				if (substr($gre['if'], 0, 4) == '_vip') {
794
					continue;
795
				}
796
				if (substr($gre['if'], 0, 5) == '_lloc') {
797
					continue;
798
				}
799
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6") {
800
					continue;
801
				}
802
			} else if ($checkparent == 2) {
803
				if ((substr($gre['if'], 0, 4) != '_vip' && substr($gre['if'], 0, 5) != '_lloc') &&
804
				    (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")) {
805
					continue;
806
				}
807
			}
808
			/* XXX: Maybe we should report any errors?! */
809
			interface_gre_configure($gre);
810
		}
811
	}
812
}
813

    
814
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
815
function interface_gre_configure(&$gre, $grekey = "") {
816
	global $config, $g;
817

    
818
	if (!is_array($gre)) {
819
		return -1;
820
	}
821

    
822
	$realif = get_real_interface($gre['if']);
823
	$realifip = get_interface_ip($gre['if']);
824
	$realifip6 = get_interface_ipv6($gre['if']);
825

    
826
	/* make sure the parent interface is up */
827
	interfaces_bring_up($realif);
828

    
829
	if (platform_booting() || !(empty($gre['greif']))) {
830
		pfSense_interface_destroy($gre['greif']);
831
		pfSense_interface_create($gre['greif']);
832
		$greif = $gre['greif'];
833
	} else {
834
		$greif = pfSense_interface_create("gre");
835
	}
836

    
837
	/* Do not change the order here for more see gre(4) NOTES section. */
838
	if (is_ipaddrv6($gre['remote-addr'])) {
839
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
840
	} else {
841
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
842
	}
843
	if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
844
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
845
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
846
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
847
	} else {
848
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
849
	}
850
	if (isset($gre['link0'])) {
851
		pfSense_interface_flags($greif, IFF_LINK0);
852
	}
853
	if (isset($gre['link1'])) {
854
		pfSense_interface_flags($greif, IFF_LINK1);
855
	}
856
	if (isset($gre['link2'])) {
857
		pfSense_interface_flags($greif, IFF_LINK2);
858
	}
859

    
860
	if ($greif) {
861
		interfaces_bring_up($greif);
862
	} else {
863
		log_error(gettext("Could not bring greif up -- variable not defined."));
864
	}
865

    
866
	if (isset($gre['link1']) && $gre['link1']) {
867
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
868
	}
869
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
870
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
871
	}
872
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
873
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
874
	}
875

    
876
	interfaces_bring_up($greif);
877

    
878
	return $greif;
879
}
880

    
881
function interfaces_gif_configure($checkparent = 0, $realif = "") {
882
	global $config;
883

    
884
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
885
		foreach ($config['gifs']['gif'] as $i => $gif) {
886
			if (empty($gif['gifif'])) {
887
				$gre['gifif'] = "gif{$i}";
888
			}
889
			if (!empty($realif) && $realif != $gif['gifif']) {
890
				continue;
891
			}
892

    
893
			if ($checkparent == 1) {
894
				if (substr($gif['if'], 0, 4) == '_vip') {
895
					continue;
896
				}
897
				if (substr($gif['if'], 0, 5) == '_lloc') {
898
					continue;
899
				}
900
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
901
					continue;
902
				}
903
			}
904
			else if ($checkparent == 2) {
905
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
906
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
907
					continue;
908
				}
909
			}
910
			/* XXX: Maybe we should report any errors?! */
911
			interface_gif_configure($gif);
912
		}
913
	}
914
}
915

    
916
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
917
function interface_gif_configure(&$gif, $gifkey = "") {
918
	global $config, $g;
919

    
920
	if (!is_array($gif)) {
921
		return -1;
922
	}
923

    
924
	$realif = get_real_interface($gif['if']);
925
	$ipaddr = get_interface_ip($gif['if']);
926

    
927
	if (is_ipaddrv4($gif['remote-addr'])) {
928
		if (is_ipaddrv4($ipaddr)) {
929
			$realifip = $ipaddr;
930
		} else {
931
			$realifip = get_interface_ip($gif['if']);
932
		}
933
		$realifgw = get_interface_gateway($gif['if']);
934
	} else if (is_ipaddrv6($gif['remote-addr'])) {
935
		if (is_ipaddrv6($ipaddr)) {
936
			$realifip = $ipaddr;
937
		} else {
938
			$realifip = get_interface_ipv6($gif['if']);
939
		}
940
		$realifgw = get_interface_gateway_v6($gif['if']);
941
	}
942
	/* make sure the parent interface is up */
943
	if ($realif) {
944
		interfaces_bring_up($realif);
945
	} else {
946
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
947
	}
948

    
949
	if (platform_booting() || !(empty($gif['gifif']))) {
950
		pfSense_interface_destroy($gif['gifif']);
951
		pfSense_interface_create($gif['gifif']);
952
		$gifif = $gif['gifif'];
953
	} else {
954
		$gifif = pfSense_interface_create("gif");
955
	}
956

    
957
	/* Do not change the order here for more see gif(4) NOTES section. */
958
	if (is_ipaddrv6($gif['remote-addr'])) {
959
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
960
	} else {
961
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
962
	}
963
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
964
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
965
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
966
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
967
	} else {
968
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
969
	}
970
	if (isset($gif['link0'])) {
971
		pfSense_interface_flags($gifif, IFF_LINK0);
972
	}
973
	if (isset($gif['link1'])) {
974
		pfSense_interface_flags($gifif, IFF_LINK1);
975
	}
976
	if ($gifif) {
977
		interfaces_bring_up($gifif);
978
	} else {
979
		log_error(gettext("could not bring gifif up -- variable not defined"));
980
	}
981

    
982
	if (!platform_booting()) {
983
		$iflist = get_configured_interface_list();
984
		foreach ($iflist as $ifname) {
985
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
986
				if (get_interface_gateway($ifname)) {
987
					system_routing_configure($ifname);
988
					break;
989
				}
990
				if (get_interface_gateway_v6($ifname)) {
991
					system_routing_configure($ifname);
992
					break;
993
				}
994
			}
995
		}
996
	}
997

    
998

    
999
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1000
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1001
	}
1002
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1003
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1004
	}
1005

    
1006
	if (is_ipaddrv4($realifgw)) {
1007
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1008
	}
1009
	if (is_ipaddrv6($realifgw)) {
1010
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1011
	}
1012

    
1013
	interfaces_bring_up($gifif);
1014

    
1015
	return $gifif;
1016
}
1017

    
1018
function interfaces_configure() {
1019
	global $config, $g;
1020

    
1021
	/* Set up our loopback interface */
1022
	interfaces_loopback_configure();
1023

    
1024
	/* create the unconfigured wireless clones */
1025
	interfaces_create_wireless_clones();
1026

    
1027
	/* set up LAGG virtual interfaces */
1028
	interfaces_lagg_configure();
1029

    
1030
	/* set up VLAN virtual interfaces */
1031
	interfaces_vlan_configure();
1032

    
1033
	interfaces_qinq_configure();
1034

    
1035
	$iflist = get_configured_interface_with_descr();
1036
	$delayed_list = array();
1037
	$bridge_list = array();
1038
	$track6_list = array();
1039

    
1040
	/* This is needed to speedup interfaces on bootup. */
1041
	$reload = false;
1042
	if (!platform_booting()) {
1043
		$reload = true;
1044
	}
1045

    
1046
	foreach ($iflist as $if => $ifname) {
1047
		$realif = $config['interfaces'][$if]['if'];
1048
		if (strstr($realif, "bridge")) {
1049
			$bridge_list[$if] = $ifname;
1050
		} else if (strstr($realif, "gre")) {
1051
			$delayed_list[$if] = $ifname;
1052
		} else if (strstr($realif, "gif")) {
1053
			$delayed_list[$if] = $ifname;
1054
		} else if (strstr($realif, "ovpn")) {
1055
			//echo "Delaying OpenVPN interface configuration...done.\n";
1056
			continue;
1057
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1058
			$track6_list[$if] = $ifname;
1059
		} else {
1060
			if (platform_booting()) {
1061
				printf(gettext("Configuring %s interface..."), $ifname);
1062
			}
1063

    
1064
			if ($g['debug']) {
1065
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1066
			}
1067
			interface_configure($if, $reload);
1068
			if (platform_booting()) {
1069
				echo gettext("done.") . "\n";
1070
			}
1071
		}
1072
	}
1073

    
1074
	/*
1075
	 * NOTE: The following function parameter consists of
1076
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1077
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1078
	 */
1079

    
1080
	/* set up GRE virtual interfaces */
1081
	interfaces_gre_configure(1);
1082

    
1083
	/* set up GIF virtual interfaces */
1084
	interfaces_gif_configure(1);
1085

    
1086
	/* set up BRIDGe virtual interfaces */
1087
	interfaces_bridge_configure(1);
1088

    
1089
	foreach ($track6_list as $if => $ifname) {
1090
		if (platform_booting()) {
1091
			printf(gettext("Configuring %s interface..."), $ifname);
1092
		}
1093
		if ($g['debug']) {
1094
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1095
		}
1096

    
1097
		interface_configure($if, $reload);
1098

    
1099
		if (platform_booting()) {
1100
			echo gettext("done.") . "\n";
1101
		}
1102
	}
1103

    
1104
	/* bring up vip interfaces */
1105
	interfaces_vips_configure();
1106

    
1107
	/* set up GRE virtual interfaces */
1108
	interfaces_gre_configure(2);
1109

    
1110
	/* set up GIF virtual interfaces */
1111
	interfaces_gif_configure(2);
1112

    
1113
	foreach ($delayed_list as $if => $ifname) {
1114
		if (platform_booting()) {
1115
			printf(gettext("Configuring %s interface..."), $ifname);
1116
		}
1117
		if ($g['debug']) {
1118
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1119
		}
1120

    
1121
		interface_configure($if, $reload);
1122

    
1123
		if (platform_booting()) {
1124
			echo gettext("done.") . "\n";
1125
		}
1126
	}
1127

    
1128
	/* set up BRIDGe virtual interfaces */
1129
	interfaces_bridge_configure(2);
1130

    
1131
	foreach ($bridge_list as $if => $ifname) {
1132
		if (platform_booting()) {
1133
			printf(gettext("Configuring %s interface..."), $ifname);
1134
		}
1135
		if ($g['debug']) {
1136
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1137
		}
1138

    
1139
		interface_configure($if, $reload);
1140

    
1141
		if (platform_booting()) {
1142
			echo gettext("done.") . "\n";
1143
		}
1144
	}
1145

    
1146
	/* configure interface groups */
1147
	interfaces_group_setup();
1148

    
1149
	if (!platform_booting()) {
1150
		/* reconfigure static routes (kernel may have deleted them) */
1151
		system_routing_configure();
1152

    
1153
		/* reload IPsec tunnels */
1154
		vpn_ipsec_configure();
1155

    
1156
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1157
		services_dhcpd_configure();
1158

    
1159
		/* restart dnsmasq or unbound */
1160
		if (isset($config['dnsmasq']['enable'])) {
1161
			services_dnsmasq_configure();
1162
		} elseif (isset($config['unbound']['enable'])) {
1163
			services_unbound_configure();
1164
		}
1165
	}
1166

    
1167
	return 0;
1168
}
1169

    
1170
function interface_reconfigure($interface = "wan", $reloadall = false) {
1171
	interface_bring_down($interface);
1172
	interface_configure($interface, $reloadall);
1173
}
1174

    
1175
function interface_vip_bring_down($vip) {
1176
	global $g;
1177

    
1178
	if (strpos($vip['interface'], '_vip')) {
1179
		if (is_ipaddrv6($vip['subnet'])) {
1180
			$family = 'inet6';
1181
		} else {
1182
			$family = 'inet';
1183
		}
1184

    
1185
		$carpvip = get_configured_carp_interface_list($vip['interface'], $family, 'vip');
1186
		$iface = $carpvip['interface'];
1187
	} else {
1188
		$iface = $vip['interface'];
1189
	}
1190

    
1191
	$vipif = get_real_interface($iface);
1192
	switch ($vip['mode']) {
1193
		case "proxyarp":
1194
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1195
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1196
			}
1197
			break;
1198
		case "ipalias":
1199
			if (does_interface_exist($vipif)) {
1200
				if (is_ipaddrv6($vip['subnet'])) {
1201
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1202
				} else {
1203
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1204
				}
1205
			}
1206
			break;
1207
		case "carp":
1208
			/* XXX: Is enough to delete ip address? */
1209
			if (does_interface_exist($vipif)) {
1210
				if (is_ipaddrv6($vip['subnet'])) {
1211
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1212
				} else {
1213
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1214
				}
1215
			}
1216
			break;
1217
	}
1218
}
1219

    
1220
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1221
	global $config, $g;
1222

    
1223
	if (!isset($config['interfaces'][$interface])) {
1224
		return;
1225
	}
1226

    
1227
	if ($g['debug']) {
1228
		log_error("Calling interface down for interface {$interface}, destroy is " . (($destroy) ? 'true' : 'false'));
1229
	}
1230

    
1231
	/*
1232
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1233
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1234
	 * Keep this in mind while doing changes here!
1235
	 */
1236
	if ($ifacecfg === false) {
1237
		$ifcfg = $config['interfaces'][$interface];
1238
		$ppps = $config['ppps']['ppp'];
1239
		$realif = get_real_interface($interface);
1240
		$realifv6 = get_real_interface($interface, "inet6", true);
1241
	} elseif (!is_array($ifacecfg)) {
1242
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1243
		$ifcfg = $config['interfaces'][$interface];
1244
		$ppps = $config['ppps']['ppp'];
1245
		$realif = get_real_interface($interface);
1246
		$realifv6 = get_real_interface($interface, "inet6", true);
1247
	} else {
1248
		$ifcfg = $ifacecfg['ifcfg'];
1249
		$ppps = $ifacecfg['ppps'];
1250
		if (isset($ifacecfg['ifcfg']['realif'])) {
1251
			$realif = $ifacecfg['ifcfg']['realif'];
1252
			/* XXX: Any better way? */
1253
			$realifv6 = $realif;
1254
		} else {
1255
			$realif = get_real_interface($interface);
1256
			$realifv6 = get_real_interface($interface, "inet6", true);
1257
		}
1258
	}
1259

    
1260
	switch ($ifcfg['ipaddr']) {
1261
		case "ppp":
1262
		case "pppoe":
1263
		case "pptp":
1264
		case "l2tp":
1265
			if (is_array($ppps) && count($ppps)) {
1266
				foreach ($ppps as $pppid => $ppp) {
1267
					if ($realif == $ppp['if']) {
1268
						if (isset($ppp['ondemand']) && !$destroy) {
1269
							send_event("interface reconfigure {$interface}");
1270
							break;
1271
						}
1272
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1273
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1274
							sleep(2);
1275
						}
1276
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1277
						break;
1278
					}
1279
				}
1280
			}
1281
			break;
1282
		case "dhcp":
1283
			kill_dhclient_process($realif);
1284
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1285
			if (does_interface_exist("$realif")) {
1286
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1287
				interface_ipalias_cleanup($interface);
1288
				if ($destroy == true) {
1289
					pfSense_interface_flags($realif, -IFF_UP);
1290
				}
1291
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1292
			}
1293
			break;
1294
		default:
1295
			if (does_interface_exist("$realif")) {
1296
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1297
				interface_ipalias_cleanup($interface);
1298
				if ($destroy == true) {
1299
					pfSense_interface_flags($realif, -IFF_UP);
1300
				}
1301
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1302
			}
1303
			break;
1304
	}
1305

    
1306
	$track6 = array();
1307
	switch ($ifcfg['ipaddrv6']) {
1308
		case "slaac":
1309
		case "dhcp6":
1310
			$pidv6 = find_dhcp6c_process($realif);
1311
			if ($pidv6) {
1312
				posix_kill($pidv6, SIGTERM);
1313
			}
1314
			sleep(3);
1315
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1316
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1317
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1318
			if (does_interface_exist($realifv6)) {
1319
				$ip6 = find_interface_ipv6($realifv6);
1320
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1321
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1322
				}
1323
				interface_ipalias_cleanup($interface, "inet6");
1324
				if ($destroy == true) {
1325
					pfSense_interface_flags($realif, -IFF_UP);
1326
				}
1327
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1328
			}
1329
			$track6 = link_interface_to_track6($interface);
1330
			break;
1331
		case "6rd":
1332
		case "6to4":
1333
			$realif = "{$interface}_stf";
1334
			if (does_interface_exist("$realif")) {
1335
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1336
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1337
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1338
					$destroy = true;
1339
				} else {
1340
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1341
					$ip6 = get_interface_ipv6($interface);
1342
					if (is_ipaddrv6($ip6)) {
1343
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1344
					}
1345
				}
1346
				interface_ipalias_cleanup($interface, "inet6");
1347
				if ($destroy == true) {
1348
					pfSense_interface_flags($realif, -IFF_UP);
1349
				}
1350
			}
1351
			$track6 = link_interface_to_track6($interface);
1352
			break;
1353
		default:
1354
			if (does_interface_exist("$realif")) {
1355
				$ip6 = get_interface_ipv6($interface);
1356
				if (is_ipaddrv6($ip6)) {
1357
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1358
				}
1359
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1360
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1361
				}
1362
				interface_ipalias_cleanup($interface, "inet6");
1363
				if ($destroy == true) {
1364
					pfSense_interface_flags($realif, -IFF_UP);
1365
				}
1366
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1367
			}
1368
			$track6 = link_interface_to_track6($interface);
1369
			break;
1370
	}
1371

    
1372
	if (!empty($track6) && is_array($track6)) {
1373
		if (!function_exists('services_dhcpd_configure')) {
1374
			require_once('services.inc');
1375
		}
1376
		/* Bring down radvd and dhcp6 on these interfaces */
1377
		services_dhcpd_configure('inet6', $track6);
1378
	}
1379

    
1380
	$old_router = '';
1381
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1382
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1383
	}
1384

    
1385
	/* remove interface up file if it exists */
1386
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1387
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1388
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1389
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1390
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1391
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1392
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1393

    
1394
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1395
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1396
	if (is_array($ifcfg['wireless'])) {
1397
		kill_hostapd($realif);
1398
		mwexec(kill_wpasupplicant($realif));
1399
	}
1400

    
1401
	if ($destroy == true) {
1402
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1403
			pfSense_interface_destroy($realif);
1404
		}
1405
	}
1406

    
1407
	return;
1408
}
1409

    
1410
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1411
	global $config;
1412
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1413
		unset($config["virtualip_carp_maintenancemode"]);
1414
		write_config("Leave CARP maintenance mode");
1415
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1416
		$config["virtualip_carp_maintenancemode"] = true;
1417
		write_config("Enter CARP maintenance mode");
1418
	}
1419

    
1420
	$viparr = &$config['virtualip']['vip'];
1421
	foreach ($viparr as $vip) {
1422
		if ($vip['mode'] == "carp") {
1423
			interface_carp_configure($vip);
1424
		}
1425
	}
1426
}
1427

    
1428
function interface_isppp_type($interface) {
1429
	global $config;
1430

    
1431
	if (!is_array($config['interfaces'][$interface])) {
1432
		return false;
1433
	}
1434

    
1435
	switch ($config['interfaces'][$interface]['ipaddr']) {
1436
		case 'pptp':
1437
		case 'l2tp':
1438
		case 'pppoe':
1439
		case 'ppp':
1440
			return true;
1441
			break;
1442
		default:
1443
			return false;
1444
			break;
1445
	}
1446
}
1447

    
1448
function interfaces_ptpid_used($ptpid) {
1449
	global $config;
1450

    
1451
	if (is_array($config['ppps']['ppp'])) {
1452
		foreach ($config['ppps']['ppp'] as & $settings) {
1453
			if ($ptpid == $settings['ptpid']) {
1454
				return true;
1455
			}
1456
		}
1457
	}
1458

    
1459
	return false;
1460
}
1461

    
1462
function interfaces_ptpid_next() {
1463

    
1464
	$ptpid = 0;
1465
	while (interfaces_ptpid_used($ptpid)) {
1466
		$ptpid++;
1467
	}
1468

    
1469
	return $ptpid;
1470
}
1471

    
1472
function getMPDCRONSettings($pppif) {
1473
	global $config;
1474

    
1475
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1476
	if (is_array($config['cron']['item'])) {
1477
		foreach ($config['cron']['item'] as $i => $item) {
1478
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1479
				return array("ID" => $i, "ITEM" => $item);
1480
			}
1481
		}
1482
	}
1483

    
1484
	return NULL;
1485
}
1486

    
1487
function handle_pppoe_reset($post_array) {
1488
	global $config, $g;
1489

    
1490
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1491
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1492

    
1493
	if (!is_array($config['cron']['item'])) {
1494
		$config['cron']['item'] = array();
1495
	}
1496

    
1497
	$itemhash = getMPDCRONSettings($pppif);
1498

    
1499
	// reset cron items if necessary and return
1500
	if (empty($post_array['pppoe-reset-type'])) {
1501
		if (isset($itemhash)) {
1502
			unset($config['cron']['item'][$itemhash['ID']]);
1503
		}
1504
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1505
		return;
1506
	}
1507

    
1508
	if (empty($itemhash)) {
1509
		$itemhash = array();
1510
	}
1511
	$item = array();
1512
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1513
		$item['minute'] = $post_array['pppoe_resetminute'];
1514
		$item['hour'] = $post_array['pppoe_resethour'];
1515
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1516
			$date = explode("/", $post_array['pppoe_resetdate']);
1517
			$item['mday'] = $date[1];
1518
			$item['month'] = $date[0];
1519
		} else {
1520
			$item['mday'] = "*";
1521
			$item['month'] = "*";
1522
		}
1523
		$item['wday'] = "*";
1524
		$item['who'] = "root";
1525
		$item['command'] = $cron_cmd_file;
1526
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1527
		switch ($post_array['pppoe_pr_preset_val']) {
1528
			case "monthly":
1529
				$item['minute'] = "0";
1530
				$item['hour'] = "0";
1531
				$item['mday'] = "1";
1532
				$item['month'] = "*";
1533
				$item['wday'] = "*";
1534
				break;
1535
			case "weekly":
1536
				$item['minute'] = "0";
1537
				$item['hour'] = "0";
1538
				$item['mday'] = "*";
1539
				$item['month'] = "*";
1540
				$item['wday'] = "0";
1541
				break;
1542
			case "daily":
1543
				$item['minute'] = "0";
1544
				$item['hour'] = "0";
1545
				$item['mday'] = "*";
1546
				$item['month'] = "*";
1547
				$item['wday'] = "*";
1548
				break;
1549
			case "hourly":
1550
				$item['minute'] = "0";
1551
				$item['hour'] = "*";
1552
				$item['mday'] = "*";
1553
				$item['month'] = "*";
1554
				$item['wday'] = "*";
1555
				break;
1556
		} // end switch
1557
		$item['who'] = "root";
1558
		$item['command'] = $cron_cmd_file;
1559
	}
1560
	if (empty($item)) {
1561
		return;
1562
	}
1563
	if (isset($itemhash['ID'])) {
1564
		$config['cron']['item'][$itemhash['ID']] = $item;
1565
	} else {
1566
		$config['cron']['item'][] = $item;
1567
	}
1568
}
1569

    
1570
/*
1571
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1572
 * It writes the mpd config file to /var/etc every time the link is opened.
1573
 */
1574
function interface_ppps_configure($interface) {
1575
	global $config, $g;
1576

    
1577
	/* Return for unassigned interfaces. This is a minimum requirement. */
1578
	if (empty($config['interfaces'][$interface])) {
1579
		return 0;
1580
	}
1581
	$ifcfg = $config['interfaces'][$interface];
1582
	if (!isset($ifcfg['enable'])) {
1583
		return 0;
1584
	}
1585

    
1586
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1587
	if (!is_dir("/var/spool/lock")) {
1588
		mkdir("/var/spool/lock", 0777, true);
1589
	}
1590
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1591
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1592
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1593
	}
1594

    
1595
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1596
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1597
			if ($ifcfg['if'] == $ppp['if']) {
1598
				break;
1599
			}
1600
		}
1601
	}
1602
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
1603
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1604
		return 0;
1605
	}
1606
	$pppif = $ifcfg['if'];
1607
	if ($ppp['type'] == "ppp") {
1608
		$type = "modem";
1609
	} else {
1610
		$type = $ppp['type'];
1611
	}
1612
	$upper_type = strtoupper($ppp['type']);
1613

    
1614
	/* XXX: This does not make sense and may create trouble
1615
	 * comment it for now to be removed later on.
1616
	if (platform_booting()) {
1617
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1618
		echo "starting {$pppif} link...";
1619
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1620
			return 0;
1621
	}
1622
	*/
1623

    
1624
	$ports = explode(',', $ppp['ports']);
1625
	if ($type != "modem") {
1626
		foreach ($ports as $pid => $port) {
1627
			$ports[$pid] = get_real_interface($port);
1628
			if (empty($ports[$pid])) {
1629
				return 0;
1630
			}
1631
		}
1632
	}
1633
	$localips = explode(',', $ppp['localip']);
1634
	$gateways = explode(',', $ppp['gateway']);
1635
	$subnets = explode(',', $ppp['subnet']);
1636

    
1637
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1638
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1639
	 */
1640
	foreach ($ports as $pid => $port) {
1641
		switch ($ppp['type']) {
1642
			case "pppoe":
1643
				/* Bring the parent interface up */
1644
				interfaces_bring_up($port);
1645
				pfSense_ngctl_attach(".", $port);
1646
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1647
				mwexec("/usr/sbin/ngctl msg {$port}: setautosrc 1");
1648
				break;
1649
			case "pptp":
1650
			case "l2tp":
1651
				/* configure interface */
1652
				if (is_ipaddr($localips[$pid])) {
1653
					// Manually configure interface IP/subnet
1654
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1655
					interfaces_bring_up($port);
1656
				} else if (empty($localips[$pid])) {
1657
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1658
				}
1659

    
1660
				if (!is_ipaddr($localips[$pid])) {
1661
					log_error("Could not get a Local IP address for PPTP/L2TP link on {$port} in interfaces_ppps_configure. Using 0.0.0.0 ip!");
1662
					$localips[$pid] = "0.0.0.0";
1663
				}
1664
				if (!is_ipaddr($gateways[$pid])) {
1665
					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));
1666
					return 0;
1667
				}
1668
				pfSense_ngctl_attach(".", $port);
1669
				break;
1670
			case "ppp":
1671
				if (!file_exists("{$port}")) {
1672
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1673
					return 0;
1674
				}
1675
				break;
1676
			default:
1677
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1678
				break;
1679
		}
1680
	}
1681

    
1682
	if (is_array($ports) && count($ports) > 1) {
1683
		$multilink = "enable";
1684
	} else {
1685
		$multilink = "disable";
1686
	}
1687

    
1688
	if ($type == "modem") {
1689
		if (is_ipaddr($ppp['localip'])) {
1690
			$localip = $ppp['localip'];
1691
		} else {
1692
			$localip = '0.0.0.0';
1693
		}
1694

    
1695
		if (is_ipaddr($ppp['gateway'])) {
1696
			$gateway = $ppp['gateway'];
1697
		} else {
1698
			$gateway = "10.64.64.{$pppid}";
1699
		}
1700
		$ranges = "{$localip}/0 {$gateway}/0";
1701

    
1702
		if (empty($ppp['apnum'])) {
1703
			$ppp['apnum'] = 1;
1704
		}
1705
	} else {
1706
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1707
	}
1708

    
1709
	if (isset($ppp['ondemand'])) {
1710
		$ondemand = "enable";
1711
	} else {
1712
		$ondemand = "disable";
1713
	}
1714
	if (!isset($ppp['idletimeout'])) {
1715
		$ppp['idletimeout'] = 0;
1716
	}
1717

    
1718
	if (empty($ppp['username']) && $type == "modem") {
1719
		$ppp['username'] = "user";
1720
		$ppp['password'] = "none";
1721
	}
1722
	if (empty($ppp['password']) && $type == "modem") {
1723
		$passwd = "none";
1724
	} else {
1725
		$passwd = base64_decode($ppp['password']);
1726
	}
1727

    
1728
	$bandwidths = explode(',', $ppp['bandwidth']);
1729
	$defaultmtu = "1492";
1730
	if (!empty($ifcfg['mtu'])) {
1731
		$defaultmtu = intval($ifcfg['mtu']);
1732
	}
1733
	$mtus = explode(',', $ppp['mtu']);
1734
	$mrus = explode(',', $ppp['mru']);
1735

    
1736
	if (isset($ppp['mrru'])) {
1737
		$mrrus = explode(',', $ppp['mrru']);
1738
	}
1739

    
1740
	// Construct the mpd.conf file
1741
	$mpdconf = <<<EOD
1742
startup:
1743
	# configure the console
1744
	set console close
1745
	# configure the web server
1746
	set web close
1747

    
1748
default:
1749
{$ppp['type']}client:
1750
	create bundle static {$interface}
1751
	set bundle enable ipv6cp
1752
	set iface name {$pppif}
1753

    
1754
EOD;
1755
	$setdefaultgw = false;
1756
	$founddefaultgw = false;
1757
	if (is_array($config['gateways']['gateway_item'])) {
1758
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1759
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1760
				$setdefaultgw = true;
1761
				break;
1762
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1763
				$founddefaultgw = true;
1764
				break;
1765
			}
1766
		}
1767
	}
1768

    
1769
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1770
		$setdefaultgw = true;
1771
		$mpdconf .= <<<EOD
1772
	set iface route default
1773

    
1774
EOD;
1775
	}
1776
	$mpdconf .= <<<EOD
1777
	set iface {$ondemand} on-demand
1778
	set iface idle {$ppp['idletimeout']}
1779

    
1780
EOD;
1781

    
1782
	if (isset($ppp['ondemand'])) {
1783
		$mpdconf .= <<<EOD
1784
	set iface addrs 10.10.1.1 10.10.1.2
1785

    
1786
EOD;
1787
	}
1788

    
1789
	if (isset($ppp['tcpmssfix'])) {
1790
		$tcpmss = "disable";
1791
	} else {
1792
		$tcpmss = "enable";
1793
	}
1794
	$mpdconf .= <<<EOD
1795
	set iface {$tcpmss} tcpmssfix
1796

    
1797
EOD;
1798

    
1799
	$mpdconf .= <<<EOD
1800
	set iface up-script /usr/local/sbin/ppp-linkup
1801
	set iface down-script /usr/local/sbin/ppp-linkdown
1802
	set ipcp ranges {$ranges}
1803

    
1804
EOD;
1805
	if (isset($ppp['vjcomp'])) {
1806
		$mpdconf .= <<<EOD
1807
	set ipcp no vjcomp
1808

    
1809
EOD;
1810
	}
1811

    
1812
	if (isset($config['system']['dnsallowoverride'])) {
1813
		$mpdconf .= <<<EOD
1814
	set ipcp enable req-pri-dns
1815
	set ipcp enable req-sec-dns
1816

    
1817
EOD;
1818
	}
1819

    
1820
	if (!isset($ppp['verbose_log'])) {
1821
		$mpdconf .= <<<EOD
1822
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1823

    
1824
EOD;
1825
	}
1826

    
1827
	foreach ($ports as $pid => $port) {
1828
		$port = get_real_interface($port);
1829
		$mpdconf .= <<<EOD
1830

    
1831
	create link static {$interface}_link{$pid} {$type}
1832
	set link action bundle {$interface}
1833
	set link {$multilink} multilink
1834
	set link keep-alive 10 60
1835
	set link max-redial 0
1836

    
1837
EOD;
1838
		if (isset($ppp['shortseq'])) {
1839
			$mpdconf .= <<<EOD
1840
	set link no shortseq
1841

    
1842
EOD;
1843
		}
1844

    
1845
		if (isset($ppp['acfcomp'])) {
1846
			$mpdconf .= <<<EOD
1847
	set link no acfcomp
1848

    
1849
EOD;
1850
		}
1851

    
1852
		if (isset($ppp['protocomp'])) {
1853
			$mpdconf .= <<<EOD
1854
	set link no protocomp
1855

    
1856
EOD;
1857
		}
1858

    
1859
		$mpdconf .= <<<EOD
1860
	set link disable chap pap
1861
	set link accept chap pap eap
1862
	set link disable incoming
1863

    
1864
EOD;
1865

    
1866

    
1867
		if (!empty($bandwidths[$pid])) {
1868
			$mpdconf .= <<<EOD
1869
	set link bandwidth {$bandwidths[$pid]}
1870

    
1871
EOD;
1872
		}
1873

    
1874
		if (empty($mtus[$pid])) {
1875
			$mtus[$pid] = $defaultmtu;
1876
		}
1877
		if ($type == "pppoe") {
1878
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
1879
				$mtus[$pid] = get_interface_mtu($port) - 8;
1880
			}
1881
		}
1882
		if (! ($type == "pppoe" && $mtus[$pid] > 1492) ) {
1883
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
1884
			$mpdconf .= <<<EOD
1885
	set link mtu {$mtus[$pid]}
1886

    
1887
EOD;
1888
		}
1889

    
1890
		if (!empty($mrus[$pid])) {
1891
			$mpdconf .= <<<EOD
1892
	set link mru {$mrus[$pid]}
1893

    
1894
EOD;
1895
		}
1896

    
1897
		if (!empty($mrrus[$pid])) {
1898
			$mpdconf .= <<<EOD
1899
	set link mrru {$mrrus[$pid]}
1900

    
1901
EOD;
1902
		}
1903

    
1904
		$mpdconf .= <<<EOD
1905
	set auth authname "{$ppp['username']}"
1906
	set auth password {$passwd}
1907

    
1908
EOD;
1909
		if ($type == "modem") {
1910
			$mpdconf .= <<<EOD
1911
	set modem device {$ppp['ports']}
1912
	set modem script DialPeer
1913
	set modem idle-script Ringback
1914
	set modem watch -cd
1915
	set modem var \$DialPrefix "DT"
1916
	set modem var \$Telephone "{$ppp['phone']}"
1917

    
1918
EOD;
1919
		}
1920
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1921
			$mpdconf .= <<<EOD
1922
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1923

    
1924
EOD;
1925
		}
1926
		if (isset($ppp['initstr']) && $type == "modem") {
1927
			$initstr = base64_decode($ppp['initstr']);
1928
			$mpdconf .= <<<EOD
1929
	set modem var \$InitString "{$initstr}"
1930

    
1931
EOD;
1932
		}
1933
		if (isset($ppp['simpin']) && $type == "modem") {
1934
			if ($ppp['pin-wait'] == "") {
1935
				$ppp['pin-wait'] = 0;
1936
			}
1937
			$mpdconf .= <<<EOD
1938
	set modem var \$SimPin "{$ppp['simpin']}"
1939
	set modem var \$PinWait "{$ppp['pin-wait']}"
1940

    
1941
EOD;
1942
		}
1943
		if (isset($ppp['apn']) && $type == "modem") {
1944
			$mpdconf .= <<<EOD
1945
	set modem var \$APN "{$ppp['apn']}"
1946
	set modem var \$APNum "{$ppp['apnum']}"
1947

    
1948
EOD;
1949
		}
1950
		if ($type == "pppoe") {
1951
			// Send a null service name if none is set.
1952
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1953
			$mpdconf .= <<<EOD
1954
	set pppoe service "{$provider}"
1955

    
1956
EOD;
1957
		}
1958
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
1959
			$mpdconf .= <<<EOD
1960
	set pppoe max-payload {$mtus[$pid]}
1961

    
1962
EOD;
1963
		}
1964
		if ($type == "pppoe") {
1965
			$mpdconf .= <<<EOD
1966
	set pppoe iface {$port}
1967

    
1968
EOD;
1969
		}
1970

    
1971
		if ($type == "pptp" || $type == "l2tp") {
1972
			$mpdconf .= <<<EOD
1973
	set {$type} self {$localips[$pid]}
1974
	set {$type} peer {$gateways[$pid]}
1975

    
1976
EOD;
1977
		}
1978

    
1979
		$mpdconf .= "\topen\n";
1980
	} //end foreach ($port)
1981

    
1982

    
1983
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1984
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
1985
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1986
	} else {
1987
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1988
		if (!$fd) {
1989
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1990
			return 0;
1991
		}
1992
		// Write out mpd_ppp.conf
1993
		fwrite($fd, $mpdconf);
1994
		fclose($fd);
1995
		unset($mpdconf);
1996
	}
1997

    
1998
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1999
	if (isset($ppp['uptime'])) {
2000
		if (!file_exists("/conf/{$pppif}.log")) {
2001
			conf_mount_rw();
2002
			file_put_contents("/conf/{$pppif}.log", '');
2003
			conf_mount_ro();
2004
		}
2005
	} else {
2006
		if (file_exists("/conf/{$pppif}.log")) {
2007
			conf_mount_rw();
2008
			@unlink("/conf/{$pppif}.log");
2009
			conf_mount_ro();
2010
		}
2011
	}
2012

    
2013
	/* clean up old lock files */
2014
	foreach ($ports as $port) {
2015
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2016
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2017
		}
2018
	}
2019

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

    
2024
	// Check for PPPoE periodic reset request
2025
	if ($type == "pppoe") {
2026
		if (!empty($ppp['pppoe-reset-type'])) {
2027
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2028
		} else {
2029
			interface_setup_pppoe_reset_file($ppp['if']);
2030
		}
2031
	}
2032
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
2033
	$i = 0;
2034
	while ($i < 3) {
2035
		sleep(10);
2036
		if (does_interface_exist($ppp['if'], true)) {
2037
			break;
2038
		}
2039
		$i++;
2040
	}
2041

    
2042
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2043
	/* We should be able to launch the right version for each modem */
2044
	/* We can also guess the mondev from the manufacturer */
2045
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2046
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2047
	foreach ($ports as $port) {
2048
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2049
			$mondev = substr(basename($port), 0, -1);
2050
			$devlist = glob("/dev/{$mondev}?");
2051
			$mondev = basename(end($devlist));
2052
		}
2053
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2054
			$mondev = substr(basename($port), 0, -1) . "1";
2055
		}
2056
		if ($mondev != '') {
2057
			log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
2058
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2059
		}
2060
	}
2061

    
2062
	return 1;
2063
}
2064

    
2065
function interfaces_sync_setup() {
2066
	global $g, $config;
2067

    
2068
	if (isset($config['system']['developerspew'])) {
2069
		$mt = microtime();
2070
		echo "interfaces_sync_setup() being called $mt\n";
2071
	}
2072

    
2073
	if (platform_booting()) {
2074
		echo gettext("Configuring CARP settings...");
2075
		mute_kernel_msgs();
2076
	}
2077

    
2078
	/* suck in configuration items */
2079
	if ($config['hasync']) {
2080
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2081
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2082
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2083
	} else {
2084
		unset($pfsyncinterface);
2085
		unset($pfsyncenabled);
2086
	}
2087

    
2088
	set_sysctl(array(
2089
		"net.inet.carp.preempt" => "1",
2090
		"net.inet.carp.log" => "1")
2091
	);
2092

    
2093
	if (!empty($pfsyncinterface)) {
2094
		$carp_sync_int = get_real_interface($pfsyncinterface);
2095
	} else {
2096
		unset($carp_sync_int);
2097
	}
2098

    
2099
	/* setup pfsync interface */
2100
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2101
		if (is_ipaddr($pfsyncpeerip)) {
2102
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2103
		} else {
2104
			$syncpeer = "-syncpeer";
2105
		}
2106

    
2107
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2108
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2109

    
2110
		sleep(1);
2111

    
2112
		/* 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
2113
		 * for existing sessions.
2114
		 */
2115
		log_error("waiting for pfsync...");
2116
		$i = 0;
2117
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2118
			$i++;
2119
			sleep(1);
2120
		}
2121
		log_error("pfsync done in $i seconds.");
2122
		log_error("Configuring CARP settings finalize...");
2123
	} else {
2124
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2125
	}
2126

    
2127
	if ($config['virtualip']['vip']) {
2128
		set_single_sysctl("net.inet.carp.allow", "1");
2129
	} else {
2130
		set_single_sysctl("net.inet.carp.allow", "0");
2131
	}
2132

    
2133
	if (platform_booting()) {
2134
		unmute_kernel_msgs();
2135
		echo gettext("done.") . "\n";
2136
	}
2137
}
2138

    
2139
function interface_proxyarp_configure($interface = "") {
2140
	global $config, $g;
2141
	if (isset($config['system']['developerspew'])) {
2142
		$mt = microtime();
2143
		echo "interface_proxyarp_configure() being called $mt\n";
2144
	}
2145

    
2146
	/* kill any running choparp */
2147
	if (empty($interface)) {
2148
		killbyname("choparp");
2149
	} else {
2150
		$vipif = get_real_interface($interface);
2151
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2152
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2153
		}
2154
	}
2155

    
2156
	$paa = array();
2157
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2158

    
2159
		/* group by interface */
2160
		foreach ($config['virtualip']['vip'] as $vipent) {
2161
			if ($vipent['mode'] === "proxyarp") {
2162
				if ($vipent['interface']) {
2163
					$proxyif = $vipent['interface'];
2164
				} else {
2165
					$proxyif = "wan";
2166
				}
2167

    
2168
				if (!empty($interface) && $interface != $proxyif) {
2169
					continue;
2170
				}
2171

    
2172
				if (!is_array($paa[$proxyif])) {
2173
					$paa[$proxyif] = array();
2174
				}
2175

    
2176
				$paa[$proxyif][] = $vipent;
2177
			}
2178
		}
2179
	}
2180

    
2181
	if (!empty($interface)) {
2182
		if (is_array($paa[$interface])) {
2183
			$paaifip = get_interface_ip($interface);
2184
			if (!is_ipaddr($paaifip)) {
2185
				return;
2186
			}
2187
			$args = get_real_interface($interface) . " auto";
2188
			foreach ($paa[$interface] as $paent) {
2189
				if (isset($paent['subnet'])) {
2190
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2191
				} else if (isset($paent['range'])) {
2192
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2193
				}
2194
			}
2195
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2196
		}
2197
	} else if (count($paa) > 0) {
2198
		foreach ($paa as $paif => $paents) {
2199
			$paaifip = get_interface_ip($paif);
2200
			if (!is_ipaddr($paaifip)) {
2201
				continue;
2202
			}
2203
			$args = get_real_interface($paif) . " auto";
2204
			foreach ($paents as $paent) {
2205
				if (isset($paent['subnet'])) {
2206
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2207
				} else if (isset($paent['range'])) {
2208
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2209
				}
2210
			}
2211
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2212
		}
2213
	}
2214
}
2215

    
2216
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2217
	global $g, $config;
2218

    
2219
	if (is_array($config['virtualip']['vip'])) {
2220
		foreach ($config['virtualip']['vip'] as $vip) {
2221
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2222
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet'])) {
2223
					interface_vip_bring_down($vip);
2224
				} else if ($inet == "inet4" && is_ipaddrv4($vip['subnet'])) {
2225
					interface_vip_bring_down($vip);
2226
				}
2227
			}
2228
		}
2229
	}
2230
}
2231

    
2232
function interfaces_vips_configure($interface = "") {
2233
	global $g, $config;
2234
	if (isset($config['system']['developerspew'])) {
2235
		$mt = microtime();
2236
		echo "interfaces_vips_configure() being called $mt\n";
2237
	}
2238
	$paa = array();
2239
	if (is_array($config['virtualip']['vip'])) {
2240
		$carp_setuped = false;
2241
		$anyproxyarp = false;
2242
		foreach ($config['virtualip']['vip'] as $vip) {
2243
			switch ($vip['mode']) {
2244
				case "proxyarp":
2245
					/* nothing it is handled on interface_proxyarp_configure() */
2246
					if ($interface <> "" && $vip['interface'] <> $interface) {
2247
						continue;
2248
					}
2249
					$anyproxyarp = true;
2250
					break;
2251
				case "ipalias":
2252
					if ($interface <> "" && $vip['interface'] <> $interface) {
2253
						continue;
2254
					}
2255
					interface_ipalias_configure($vip);
2256
					break;
2257
				case "carp":
2258
					if ($interface <> "" && $vip['interface'] <> $interface) {
2259
						continue;
2260
					}
2261
					if ($carp_setuped == false) {
2262
						$carp_setuped = true;
2263
					}
2264
					interface_carp_configure($vip);
2265
					break;
2266
			}
2267
		}
2268
		if ($carp_setuped == true) {
2269
			interfaces_sync_setup();
2270
		}
2271
		if ($anyproxyarp == true) {
2272
			interface_proxyarp_configure();
2273
		}
2274
	}
2275
}
2276

    
2277
function interface_ipalias_configure(&$vip) {
2278
	global $config;
2279

    
2280
	if ($vip['mode'] != 'ipalias') {
2281
		return;
2282
	}
2283

    
2284
	if ($vip['interface'] != 'lo0' && stripos($vip['interface'], '_vip') === false) {
2285
		if (!isset($config['interfaces'][$vip['interface']])) {
2286
			return;
2287
		}
2288

    
2289
		if (!isset($config['interfaces'][$vip['interface']]['enable'])) {
2290
			return;
2291
		}
2292
	}
2293

    
2294
	$af = 'inet';
2295
	if (is_ipaddrv6($vip['subnet'])) {
2296
		$af = 'inet6';
2297
	}
2298
	$iface = $vip['interface'];
2299
	$vipadd = '';
2300
	if (strpos($vip['interface'], '_vip')) {
2301
		$carpvip = get_configured_carp_interface_list($vip['interface'], $af, 'vip');
2302
		$iface = $carpvip['interface'];
2303
		$vipadd = "vhid {$carpvip['vhid']}";
2304
	}
2305
	$if = get_real_interface($iface);
2306
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vipadd}");
2307
	unset($iface, $af, $if, $carpvip, $vipadd);
2308
}
2309

    
2310
function interface_reload_carps($cif) {
2311
	global $config;
2312

    
2313
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2314
	if (empty($carpifs)) {
2315
		return;
2316
	}
2317

    
2318
	$carps = explode(" ", $carpifs);
2319
	if (is_array($config['virtualip']['vip'])) {
2320
		$viparr = &$config['virtualip']['vip'];
2321
		foreach ($viparr as $vip) {
2322
			if (in_array($vip['carpif'], $carps)) {
2323
				switch ($vip['mode']) {
2324
					case "carp":
2325
						interface_vip_bring_down($vip);
2326
						sleep(1);
2327
						interface_carp_configure($vip);
2328
						break;
2329
					case "ipalias":
2330
						interface_vip_bring_down($vip);
2331
						sleep(1);
2332
						interface_ipalias_configure($vip);
2333
						break;
2334
				}
2335
			}
2336
		}
2337
	}
2338
}
2339

    
2340
function interface_carp_configure(&$vip) {
2341
	global $config, $g;
2342
	if (isset($config['system']['developerspew'])) {
2343
		$mt = microtime();
2344
		echo "interface_carp_configure() being called $mt\n";
2345
	}
2346

    
2347
	if ($vip['mode'] != "carp") {
2348
		return;
2349
	}
2350

    
2351
	/* NOTE: Maybe its useless nowadays */
2352
	$realif = get_real_interface($vip['interface']);
2353
	if (!does_interface_exist($realif)) {
2354
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2355
		return;
2356
	}
2357

    
2358
	$vip_password = $vip['password'];
2359
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2360
	if ($vip['password'] != "") {
2361
		$password = " pass {$vip_password}";
2362
	}
2363

    
2364
	$advbase = "";
2365
	if (!empty($vip['advbase'])) {
2366
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2367
	}
2368

    
2369
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2370
	if ($carp_maintenancemode) {
2371
		$advskew = "advskew 254";
2372
	} else {
2373
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2374
	}
2375

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

    
2378
	if (is_ipaddrv4($vip['subnet'])) {
2379
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2380
	} else if (is_ipaddrv6($vip['subnet'])) {
2381
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2382
	}
2383

    
2384
	return $realif;
2385
}
2386

    
2387
function interface_wireless_clone($realif, $wlcfg) {
2388
	global $config, $g;
2389
	/*   Check to see if interface has been cloned as of yet.
2390
	 *   If it has not been cloned then go ahead and clone it.
2391
	 */
2392
	$needs_clone = false;
2393
	if (is_array($wlcfg['wireless'])) {
2394
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2395
	} else {
2396
		$wlcfg_mode = $wlcfg['mode'];
2397
	}
2398
	switch ($wlcfg_mode) {
2399
		case "hostap":
2400
			$mode = "wlanmode hostap";
2401
			break;
2402
		case "adhoc":
2403
			$mode = "wlanmode adhoc";
2404
			break;
2405
		default:
2406
			$mode = "";
2407
			break;
2408
	}
2409
	$baseif = interface_get_wireless_base($wlcfg['if']);
2410
	if (does_interface_exist($realif)) {
2411
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2412
		$ifconfig_str = implode($output);
2413
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2414
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2415
			$needs_clone = true;
2416
		}
2417
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2418
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2419
			$needs_clone = true;
2420
		}
2421
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2422
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2423
			$needs_clone = true;
2424
		}
2425
	} else {
2426
		$needs_clone = true;
2427
	}
2428

    
2429
	if ($needs_clone == true) {
2430
		/* remove previous instance if it exists */
2431
		if (does_interface_exist($realif)) {
2432
			pfSense_interface_destroy($realif);
2433
		}
2434

    
2435
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2436
		// Create the new wlan interface. FreeBSD returns the new interface name.
2437
		// example:  wlan2
2438
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2439
		if ($ret <> 0) {
2440
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2441
			return false;
2442
		}
2443
		$newif = trim($out[0]);
2444
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2445
		pfSense_interface_rename($newif, $realif);
2446
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2447
	}
2448
	return true;
2449
}
2450

    
2451
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2452
	global $config, $g;
2453

    
2454
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2455
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2456
				 'regdomain', 'regcountry', 'reglocation');
2457

    
2458
	if (!is_interface_wireless($ifcfg['if'])) {
2459
		return;
2460
	}
2461

    
2462
	$baseif = interface_get_wireless_base($ifcfg['if']);
2463

    
2464
	// Sync shared settings for assigned clones
2465
	$iflist = get_configured_interface_list(false, true);
2466
	foreach ($iflist as $if) {
2467
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2468
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2469
				foreach ($shared_settings as $setting) {
2470
					if ($sync_changes) {
2471
						if (isset($ifcfg['wireless'][$setting])) {
2472
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2473
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2474
							unset($config['interfaces'][$if]['wireless'][$setting]);
2475
						}
2476
					} else {
2477
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2478
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2479
						} else if (isset($ifcfg['wireless'][$setting])) {
2480
							unset($ifcfg['wireless'][$setting]);
2481
						}
2482
					}
2483
				}
2484
				if (!$sync_changes) {
2485
					break;
2486
				}
2487
			}
2488
		}
2489
	}
2490

    
2491
	// Read or write settings at shared area
2492
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2493
		foreach ($shared_settings as $setting) {
2494
			if ($sync_changes) {
2495
				if (isset($ifcfg['wireless'][$setting])) {
2496
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2497
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2498
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2499
				}
2500
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2501
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2502
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2503
				} else if (isset($ifcfg['wireless'][$setting])) {
2504
					unset($ifcfg['wireless'][$setting]);
2505
				}
2506
			}
2507
		}
2508
	}
2509

    
2510
	// Sync the mode on the clone creation page with the configured mode on the interface
2511
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2512
		foreach ($config['wireless']['clone'] as &$clone) {
2513
			if ($clone['cloneif'] == $ifcfg['if']) {
2514
				if ($sync_changes) {
2515
					$clone['mode'] = $ifcfg['wireless']['mode'];
2516
				} else {
2517
					$ifcfg['wireless']['mode'] = $clone['mode'];
2518
				}
2519
				break;
2520
			}
2521
		}
2522
		unset($clone);
2523
	}
2524
}
2525

    
2526
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2527
	global $config, $g;
2528

    
2529
	/*    open up a shell script that will be used to output the commands.
2530
	 *    since wireless is changing a lot, these series of commands are fragile
2531
	 *    and will sometimes need to be verified by a operator by executing the command
2532
	 *    and returning the output of the command to the developers for inspection.  please
2533
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2534
	 */
2535

    
2536
	// Remove script file
2537
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2538

    
2539
	// Clone wireless nic if needed.
2540
	interface_wireless_clone($if, $wl);
2541

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

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

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

    
2551
	/* set values for /path/program */
2552
	$hostapd = "/usr/sbin/hostapd";
2553
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2554
	$ifconfig = "/sbin/ifconfig";
2555
	$sysctl = "/sbin/sysctl";
2556
	$killall = "/usr/bin/killall";
2557

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

    
2560
	$wlcmd = array();
2561
	$wl_sysctl = array();
2562
	/* Make sure it's up */
2563
	$wlcmd[] = "up";
2564
	/* Set a/b/g standard */
2565
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2566
	/* skip mode entirely for "auto" */
2567
	if ($wlcfg['standard'] != "auto") {
2568
		$wlcmd[] = "mode " . escapeshellarg($standard);
2569
	}
2570

    
2571
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2572
	 * to prevent massive packet loss under certain conditions. */
2573
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2574
		$wlcmd[] = "-ampdu";
2575
	}
2576

    
2577
	/* Set ssid */
2578
	if ($wlcfg['ssid']) {
2579
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2580
	}
2581

    
2582
	/* Set 802.11g protection mode */
2583
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2584

    
2585
	/* set wireless channel value */
2586
	if (isset($wlcfg['channel'])) {
2587
		if ($wlcfg['channel'] == "0") {
2588
			$wlcmd[] = "channel any";
2589
		} else {
2590
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2591
		}
2592
	}
2593

    
2594
	/* Set antenna diversity value */
2595
	if (isset($wlcfg['diversity'])) {
2596
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2597
	}
2598

    
2599
	/* Set txantenna value */
2600
	if (isset($wlcfg['txantenna'])) {
2601
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2602
	}
2603

    
2604
	/* Set rxantenna value */
2605
	if (isset($wlcfg['rxantenna'])) {
2606
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2607
	}
2608

    
2609
	/* set Distance value */
2610
	if ($wlcfg['distance']) {
2611
		$distance = escapeshellarg($wlcfg['distance']);
2612
	}
2613

    
2614
	/* Set wireless hostap mode */
2615
	if ($wlcfg['mode'] == "hostap") {
2616
		$wlcmd[] = "mediaopt hostap";
2617
	} else {
2618
		$wlcmd[] = "-mediaopt hostap";
2619
	}
2620

    
2621
	/* Set wireless adhoc mode */
2622
	if ($wlcfg['mode'] == "adhoc") {
2623
		$wlcmd[] = "mediaopt adhoc";
2624
	} else {
2625
		$wlcmd[] = "-mediaopt adhoc";
2626
	}
2627

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

    
2630
	/* handle hide ssid option */
2631
	if (isset($wlcfg['hidessid']['enable'])) {
2632
		$wlcmd[] = "hidessid";
2633
	} else {
2634
		$wlcmd[] = "-hidessid";
2635
	}
2636

    
2637
	/* handle pureg (802.11g) only option */
2638
	if (isset($wlcfg['pureg']['enable'])) {
2639
		$wlcmd[] = "mode 11g pureg";
2640
	} else {
2641
		$wlcmd[] = "-pureg";
2642
	}
2643

    
2644
	/* handle puren (802.11n) only option */
2645
	if (isset($wlcfg['puren']['enable'])) {
2646
		$wlcmd[] = "puren";
2647
	} else {
2648
		$wlcmd[] = "-puren";
2649
	}
2650

    
2651
	/* enable apbridge option */
2652
	if (isset($wlcfg['apbridge']['enable'])) {
2653
		$wlcmd[] = "apbridge";
2654
	} else {
2655
		$wlcmd[] = "-apbridge";
2656
	}
2657

    
2658
	/* handle turbo option */
2659
	if (isset($wlcfg['turbo']['enable'])) {
2660
		$wlcmd[] = "mediaopt turbo";
2661
	} else {
2662
		$wlcmd[] = "-mediaopt turbo";
2663
	}
2664

    
2665
	/* handle txpower setting */
2666
	// or don't. this has issues at the moment.
2667
	/*
2668
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2669
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2670
	}*/
2671

    
2672
	/* handle wme option */
2673
	if (isset($wlcfg['wme']['enable'])) {
2674
		$wlcmd[] = "wme";
2675
	} else {
2676
		$wlcmd[] = "-wme";
2677
	}
2678

    
2679
	/* Enable wpa if it's configured. No WEP support anymore. */
2680
	if (isset($wlcfg['wpa']['enable'])) {
2681
		$wlcmd[] = "authmode wpa wepmode off ";
2682
	} else {
2683
		$wlcmd[] = "authmode open wepmode off ";
2684
	}
2685

    
2686
	kill_hostapd($if);
2687
	mwexec(kill_wpasupplicant("{$if}"));
2688

    
2689
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2690
	conf_mount_rw();
2691

    
2692
	switch ($wlcfg['mode']) {
2693
		case 'bss':
2694
			if (isset($wlcfg['wpa']['enable'])) {
2695
				$wpa .= <<<EOD
2696
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2697
ctrl_interface_group=0
2698
ap_scan=1
2699
#fast_reauth=1
2700
network={
2701
ssid="{$wlcfg['ssid']}"
2702
scan_ssid=1
2703
priority=5
2704
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2705
psk="{$wlcfg['wpa']['passphrase']}"
2706
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2707
group={$wlcfg['wpa']['wpa_pairwise']}
2708
}
2709
EOD;
2710

    
2711
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2712
				unset($wpa);
2713
			}
2714
			break;
2715
		case 'hostap':
2716
			if (!empty($wlcfg['wpa']['passphrase'])) {
2717
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2718
			} else {
2719
				$wpa_passphrase = "";
2720
			}
2721
			if (isset($wlcfg['wpa']['enable'])) {
2722
				$wpa .= <<<EOD
2723
interface={$if}
2724
driver=bsd
2725
logger_syslog=-1
2726
logger_syslog_level=0
2727
logger_stdout=-1
2728
logger_stdout_level=0
2729
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2730
ctrl_interface={$g['varrun_path']}/hostapd
2731
ctrl_interface_group=wheel
2732
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2733
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2734
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2735
ssid={$wlcfg['ssid']}
2736
debug={$wlcfg['wpa']['debug_mode']}
2737
wpa={$wlcfg['wpa']['wpa_mode']}
2738
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2739
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2740
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2741
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2742
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2743
{$wpa_passphrase}
2744

    
2745
EOD;
2746

    
2747
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2748
					$wpa .= <<<EOD
2749
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2750
rsn_preauth=1
2751
rsn_preauth_interfaces={$if}
2752

    
2753
EOD;
2754
				}
2755
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2756
					$wpa .= "ieee8021x=1\n";
2757

    
2758
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2759
						$auth_server_port = "1812";
2760
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2761
							$auth_server_port = intval($wlcfg['auth_server_port']);
2762
						}
2763
						$wpa .= <<<EOD
2764

    
2765
auth_server_addr={$wlcfg['auth_server_addr']}
2766
auth_server_port={$auth_server_port}
2767
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2768

    
2769
EOD;
2770
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2771
							$auth_server_port2 = "1812";
2772
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2773
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2774
							}
2775

    
2776
							$wpa .= <<<EOD
2777
auth_server_addr={$wlcfg['auth_server_addr2']}
2778
auth_server_port={$auth_server_port2}
2779
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2780

    
2781
EOD;
2782
						}
2783
					}
2784
				}
2785

    
2786
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2787
				unset($wpa);
2788
			}
2789
			break;
2790
	}
2791

    
2792
	/*
2793
	 *    all variables are set, lets start up everything
2794
	 */
2795

    
2796
	$baseif = interface_get_wireless_base($if);
2797
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2798
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2799

    
2800
	/* set sysctls for the wireless interface */
2801
	if (!empty($wl_sysctl)) {
2802
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2803
		foreach ($wl_sysctl as $wl_sysctl_line) {
2804
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2805
		}
2806
	}
2807

    
2808
	/* set ack timers according to users preference (if he/she has any) */
2809
	if ($distance) {
2810
		fwrite($fd_set, "# Enable ATH distance settings\n");
2811
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2812
	}
2813

    
2814
	if (isset($wlcfg['wpa']['enable'])) {
2815
		if ($wlcfg['mode'] == "bss") {
2816
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2817
		}
2818
		if ($wlcfg['mode'] == "hostap") {
2819
			/* add line to script to restore old mac to make hostapd happy */
2820
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2821
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2822
				if (is_macaddr($if_oldmac)) {
2823
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2824
						" link " . escapeshellarg($if_oldmac) . "\n");
2825
				}
2826
			}
2827

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

    
2830
			/* add line to script to restore spoofed mac after running hostapd */
2831
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2832
				if ($wl['spoofmac']) {
2833
					$if_curmac = $wl['spoofmac'];
2834
				} else {
2835
					$if_curmac = get_interface_mac($if);
2836
				}
2837
				if (is_macaddr($if_curmac)) {
2838
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2839
						" link " . escapeshellarg($if_curmac) . "\n");
2840
				}
2841
			}
2842
		}
2843
	}
2844

    
2845
	fclose($fd_set);
2846
	conf_mount_ro();
2847

    
2848
	/* Making sure regulatory settings have actually changed
2849
	 * before applying, because changing them requires bringing
2850
	 * down all wireless networks on the interface. */
2851
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2852
	$ifconfig_str = implode($output);
2853
	unset($output);
2854
	$reg_changing = false;
2855

    
2856
	/* special case for the debug country code */
2857
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
2858
		$reg_changing = true;
2859
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
2860
		$reg_changing = true;
2861
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
2862
		$reg_changing = true;
2863
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
2864
		$reg_changing = true;
2865
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
2866
		$reg_changing = true;
2867
	}
2868

    
2869
	if ($reg_changing) {
2870
		/* set regulatory domain */
2871
		if ($wlcfg['regdomain']) {
2872
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2873
		}
2874

    
2875
		/* set country */
2876
		if ($wlcfg['regcountry']) {
2877
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2878
		}
2879

    
2880
		/* set location */
2881
		if ($wlcfg['reglocation']) {
2882
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2883
		}
2884

    
2885
		$wlregcmd_args = implode(" ", $wlregcmd);
2886

    
2887
		/* build a complete list of the wireless clones for this interface */
2888
		$clone_list = array();
2889
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2890
			$clone_list[] = interface_get_wireless_clone($baseif);
2891
		}
2892
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2893
			foreach ($config['wireless']['clone'] as $clone) {
2894
				if ($clone['if'] == $baseif) {
2895
					$clone_list[] = $clone['cloneif'];
2896
				}
2897
			}
2898
		}
2899

    
2900
		/* find which clones are up and bring them down */
2901
		$clones_up = array();
2902
		foreach ($clone_list as $clone_if) {
2903
			$clone_status = pfSense_get_interface_addresses($clone_if);
2904
			if ($clone_status['status'] == 'up') {
2905
				$clones_up[] = $clone_if;
2906
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2907
			}
2908
		}
2909

    
2910
		/* apply the regulatory settings */
2911
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2912
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2913

    
2914
		/* bring the clones back up that were previously up */
2915
		foreach ($clones_up as $clone_if) {
2916
			interfaces_bring_up($clone_if);
2917

    
2918
			/*
2919
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2920
			 * is in infrastructure mode, and WPA is enabled.
2921
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2922
			 */
2923
			if ($clone_if != $if) {
2924
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2925
				if ((!empty($friendly_if)) &&
2926
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
2927
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
2928
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2929
				}
2930
			}
2931
		}
2932
	}
2933

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

    
2937
	 * The mode must be specified in a separate command before ifconfig
2938
	 * will allow the mode and channel at the same time in the next. */
2939
	//mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2940
	//fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
2941

    
2942
	/* configure wireless */
2943
	$wlcmd_args = implode(" ", $wlcmd);
2944
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2945
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
2946
	fclose($wlan_setup_log);
2947

    
2948
	unset($wlcmd_args, $wlcmd);
2949

    
2950

    
2951
	sleep(1);
2952
	/* execute hostapd and wpa_supplicant if required in shell */
2953
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2954

    
2955
	return 0;
2956

    
2957
}
2958

    
2959
function kill_hostapd($interface) {
2960
	global $g;
2961

    
2962
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
2963
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2964
	}
2965
}
2966

    
2967
function kill_wpasupplicant($interface) {
2968
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2969
}
2970

    
2971
function find_dhclient_process($interface) {
2972
	if ($interface) {
2973
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2974
	} else {
2975
		$pid = 0;
2976
	}
2977

    
2978
	return intval($pid);
2979
}
2980

    
2981
function kill_dhclient_process($interface) {
2982
	if (empty($interface) || !does_interface_exist($interface)) {
2983
		return;
2984
	}
2985

    
2986
	$i = 0;
2987
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2988
		/* 3rd time make it die for sure */
2989
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2990
		posix_kill($pid, $sig);
2991
		sleep(1);
2992
		$i++;
2993
	}
2994
	unset($i);
2995
}
2996

    
2997
function find_dhcp6c_process($interface) {
2998
	global $g;
2999

    
3000
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3001
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3002
	} else {
3003
		return(false);
3004
	}
3005

    
3006
	return intval($pid);
3007
}
3008

    
3009
function interface_virtual_create($interface) {
3010
	global $config;
3011

    
3012
	if (strstr($interface, "_vlan")) {
3013
		interfaces_vlan_configure($vlan);
3014
	} else if (substr($interface, 0, 3) == "gre") {
3015
		interfaces_gre_configure(0, $interface);
3016
	} else if (substr($interface, 0, 3) == "gif") {
3017
		interfaces_gif_configure(0, $interface);
3018
	} else if (substr($interface, 0, 5) == "ovpns") {
3019
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3020
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3021
				if ($interface == "ovpns{$server['vpnid']}") {
3022
					if (!function_exists('openvpn_resync')) {
3023
						require_once('openvpn.inc');
3024
					}
3025
					log_error("OpenVPN: Resync server {$server['description']}");
3026
					openvpn_resync('server', $server);
3027
				}
3028
			}
3029
			unset($server);
3030
		}
3031
	} else if (substr($interface, 0, 5) == "ovpnc") {
3032
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3033
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3034
				if ($interface == "ovpnc{$client['vpnid']}") {
3035
					if (!function_exists('openvpn_resync')) {
3036
						require_once('openvpn.inc');
3037
					}
3038
					log_error("OpenVPN: Resync server {$client['description']}");
3039
					openvpn_resync('client', $client);
3040
				}
3041
			}
3042
			unset($client);
3043
		}
3044
	} else if (substr($interface, 0, 4) == "lagg") {
3045
		interfaces_lagg_configure($interface);
3046
	} else if (substr($interface, 0, 6) == "bridge") {
3047
		interfaces_bridge_configure(0, $interface);
3048
	}
3049
}
3050

    
3051
function interface_vlan_mtu_configured($realhwif, $mtu) {
3052
	global $config;
3053

    
3054
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3055
		foreach ($config['vlans']['vlan'] as $vlan) {
3056
			if ($vlan['if'] != $realhwif) {
3057
				continue;
3058
			}
3059
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3060
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3061
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu) {
3062
					$mtu = $config['interfaces'][$assignedport]['mtu'];
3063
				}
3064
			}
3065
			$pppoe_mtu = interface_mtu_wanted_for_pppoe($vlan['vlanif']);
3066
			if ($pppoe_mtu > $mtu) {
3067
				$mtu = $pppoe_mtu;
3068
			}
3069
		}
3070
	}
3071

    
3072
	return $mtu;
3073
}
3074

    
3075
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
3076
	global $config;
3077

    
3078
	if (!is_array($vlanifs)) {
3079
		return;
3080
	}
3081

    
3082
	/* All vlans need to use the same mtu value as their parent. */
3083
	foreach ($vlanifs as $vlan) {
3084
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3085
		$pppoe_mtu = interface_mtu_wanted_for_pppoe($vlan['vlanif']);
3086
		if (!empty($assignedport)) {
3087
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
3088
				pfSense_interface_mtu($vlan['vlanif'], $config['interfaces'][$assignedport]['mtu']);
3089
			} else if ($pppoe_mtu != 0) {
3090
				pfSense_interface_mtu($vlan['vlanif'], $pppoe_mtu);
3091
			} else {
3092
				if (get_interface_mtu($vlan['vlanif']) != (($mtu > 1500) ? 1500 : $mtu)) {
3093
					pfSense_interface_mtu($vlan['vlanif'], (($mtu > 1500) ? 1500 : $mtu));
3094
				}
3095
			}
3096
		} else {
3097
			if ($pppoe_mtu != 0) {
3098
				pfSense_interface_mtu($vlan['vlanif'], $pppoe_mtu);
3099
			} else if (get_interface_mtu($vlan['vlanif']) != (($mtu > 1500) ? 1500 : $mtu)) {
3100
				pfSense_interface_mtu($vlan['vlanif'], (($mtu > 1500) ? 1500 : $mtu));
3101
			}
3102
		}
3103
	}
3104
}
3105

    
3106
function interface_mtu_wanted_for_pppoe($realif) {
3107
	global $config;
3108

    
3109
	$mtu = 0;
3110

    
3111
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp'])) {
3112
		return $mtu;
3113
	}
3114

    
3115
	foreach ($config['ppps']['ppp'] as $ppp) {
3116
		if ($ppp['type'] != "pppoe") {
3117
			continue;
3118
		}
3119

    
3120
		$ports = explode(',', $ppp['ports']);
3121
		$mtu_wanted = 1500;
3122
		foreach ($ports as $pid => $port) {
3123
			if (get_real_interface($port) != $realif) {
3124
				continue;
3125
			}
3126

    
3127
			if (!empty($ppp['mtu'])) {
3128
				$mtus = explode(',', $ppp['mtu']);
3129
			} else {
3130
				$mtus = array();
3131
			}
3132
			// there is an MTU configured on the port in question
3133
			if (!empty($mtus[$pid])) {
3134
				$mtu_wanted = intval($mtus[$pid]) + 8;
3135
			// or use the MTU configured on the interface ...
3136
			} elseif (is_array($config['interfaces'])) {
3137
				foreach ($config['interfaces'] as $interface) {
3138
					if ($interface['if'] == $ppp['if'] &&
3139
					    !empty($interface['mtu'])) {
3140
						$mtu_wanted = intval($interface['mtu']) + 8;
3141
						break;
3142
					}
3143
				}
3144
			}
3145
			unset($mtus);
3146

    
3147
			if ($mtu_wanted > $mtu) {
3148
				$mtu = $mtu_wanted;
3149
			}
3150
		}
3151
	}
3152

    
3153
	return $mtu;
3154
}
3155

    
3156
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3157
	global $config, $g;
3158
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3159
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3160

    
3161
	$wancfg = $config['interfaces'][$interface];
3162

    
3163
	if (!isset($wancfg['enable'])) {
3164
		return;
3165
	}
3166

    
3167
	$realif = get_real_interface($interface);
3168
	$realhwif_array = get_parent_interface($interface);
3169
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3170
	$realhwif = $realhwif_array[0];
3171

    
3172
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3173
		/* remove all IPv4 and IPv6 addresses */
3174
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3175
		if (is_array($tmpifaces)) {
3176
			foreach ($tmpifaces as $tmpiface) {
3177
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3178
					if (!is_linklocal($tmpiface)) {
3179
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3180
					}
3181
				} else {
3182
					if (is_subnetv4($tmpiface)) {
3183
						$tmpip = explode('/', $tmpiface);
3184
						$tmpip = $tmpip[0];
3185
					} else {
3186
						$tmpip = $tmpiface;
3187
					}
3188
					pfSense_interface_deladdress($realif, $tmpip);
3189
				}
3190
			}
3191
		}
3192

    
3193
		/* only bring down the interface when both v4 and v6 are set to NONE */
3194
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3195
			interface_bring_down($interface);
3196
		}
3197
	}
3198

    
3199
	$interface_to_check = $realif;
3200
	if (interface_isppp_type($interface)) {
3201
		$interface_to_check = $realhwif;
3202
	}
3203

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

    
3209
	/* Disable Accepting router advertisements unless specifically requested */
3210
	if ($g['debug']) {
3211
		log_error("Deny router advertisements for interface {$interface}");
3212
	}
3213
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3214

    
3215
	/* wireless configuration? */
3216
	if (is_array($wancfg['wireless'])) {
3217
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3218
	}
3219

    
3220
	$mac = get_interface_mac($realhwif);
3221
	/*
3222
	 * Don't try to reapply the spoofed MAC if it's already applied.
3223
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3224
	 * the interface config again, which attempts to spoof the MAC again,
3225
	 * which cycles the link again...
3226
	 */
3227
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
3228
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3229
			" link " . escapeshellarg($wancfg['spoofmac']));
3230
	} else {
3231

    
3232
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3233
			/*   this is not a valid mac address.  generate a
3234
			 *   temporary mac address so the machine can get online.
3235
			 */
3236
			echo gettext("Generating new MAC address.");
3237
			$random_mac = generate_random_mac_address();
3238
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3239
				" link " . escapeshellarg($random_mac));
3240
			$wancfg['spoofmac'] = $random_mac;
3241
			write_config();
3242
			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");
3243
		}
3244
	}
3245

    
3246
	/* media */
3247
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3248
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3249
		if ($wancfg['media']) {
3250
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3251
		}
3252
		if ($wancfg['mediaopt']) {
3253
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3254
		}
3255
		mwexec($cmd);
3256
	}
3257

    
3258
	/* Apply hw offloading policies as configured */
3259
	enable_hardware_offloading($interface);
3260

    
3261
	/* invalidate interface/ip/sn cache */
3262
	get_interface_arr(true);
3263
	unset($interface_ip_arr_cache[$realif]);
3264
	unset($interface_sn_arr_cache[$realif]);
3265
	unset($interface_ipv6_arr_cache[$realif]);
3266
	unset($interface_snv6_arr_cache[$realif]);
3267

    
3268
	$tunnelif = substr($realif, 0, 3);
3269

    
3270
	if (does_interface_exist($wancfg['if'])) {
3271
		interfaces_bring_up($wancfg['if']);
3272
	}
3273

    
3274
	$mtuif = $realif;
3275
	$mtuhwif = $realhwif;
3276
	$wantedmtu = 0;
3277

    
3278
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3279
	if (interface_isppp_type($interface)) {
3280
		$mtuif = $realhwif;
3281
		$mtuhwif_array = get_parent_interface($mtuif);
3282
		$mtuhwif = $mtuhwif_array[0];
3283
		$parent_mtu_configured = false;
3284
		if (is_array($config['interfaces'])) {
3285
			foreach ($config['interfaces'] as $tmpinterface) {
3286
				if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3287
					$parent_mtu_configured = true;
3288
					break;
3289
				}
3290
			}
3291
		}
3292
		if (!$parent_mtu_configured) {
3293
			$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3294
		}
3295
	}
3296

    
3297
	if (is_array($config['interfaces'])) {
3298
		foreach ($config['interfaces'] as $tmpinterface) {
3299
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3300
				$wantedmtu = $tmpinterface['mtu'];
3301
				break;
3302
			}
3303
		}
3304
	}
3305

    
3306
	// Set the MTU to 1500 if no explicit MTU configured
3307
	if ($wantedmtu == 0) {
3308
		$wantedmtu = 1500; /* Default */
3309
	}
3310

    
3311
	if (stristr($mtuif, "_vlan")) {
3312
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3313
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3314
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3315
			if ($wancfg['mtu'] > $parentmtu) {
3316
				log_error("There is a conflict on MTU between parent {$mtuhwif} and VLAN({$mtuif})");
3317
			}
3318
		} else {
3319
			$parentmtu = 0;
3320
		}
3321

    
3322
		$parentmtu = interface_vlan_mtu_configured($mtuhwif, $parentmtu);
3323

    
3324
		if (get_interface_mtu($mtuhwif) != $parentmtu) {
3325
			pfSense_interface_mtu($mtuhwif, $parentmtu);
3326
		}
3327

    
3328
		/* All vlans need to use the same mtu value as their parent. */
3329
		interface_vlan_adapt_mtu(link_interface_to_vlans($mtuhwif), $parentmtu);
3330
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3331
		/* LAGG interface must be destroyed and re-created to change MTU */
3332
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3333
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3334
				foreach ($config['laggs']['lagg'] as $lagg) {
3335
					if ($lagg['laggif'] == $mtuif) {
3336
						interface_lagg_configure($lagg);
3337
						break;
3338
					}
3339
				}
3340
			}
3341
		}
3342
	} else {
3343
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3344
			pfSense_interface_mtu($mtuif, $wantedmtu);
3345
		}
3346

    
3347
		/* This case is needed when the parent of vlans is being configured */
3348
		$vlans = link_interface_to_vlans($mtuif);
3349
		if (is_array($vlans)) {
3350
			interface_vlan_adapt_mtu($vlans, $wantedmtu);
3351
		}
3352
		unset($vlans);
3353
	}
3354
	/* XXX: What about gre/gif/.. ? */
3355

    
3356
	switch ($wancfg['ipaddr']) {
3357
		case 'dhcp':
3358
			interface_dhcp_configure($interface);
3359
			break;
3360
		case 'pppoe':
3361
		case 'l2tp':
3362
		case 'pptp':
3363
		case 'ppp':
3364
			interface_ppps_configure($interface);
3365
			break;
3366
		default:
3367
			/* XXX: Kludge for now related to #3280 */
3368
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3369
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3370
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3371
				}
3372
			}
3373
			break;
3374
	}
3375

    
3376
	switch ($wancfg['ipaddrv6']) {
3377
		case 'slaac':
3378
		case 'dhcp6':
3379
			interface_dhcpv6_configure($interface, $wancfg);
3380
			break;
3381
		case '6rd':
3382
			interface_6rd_configure($interface, $wancfg);
3383
			break;
3384
		case '6to4':
3385
			interface_6to4_configure($interface, $wancfg);
3386
			break;
3387
		case 'track6':
3388
			interface_track6_configure($interface, $wancfg, $linkupevent);
3389
			break;
3390
		default:
3391
			/* XXX: Kludge for now related to #3280 */
3392
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3393
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3394
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3395
					// FIXME: Add IPv6 Support to the pfSense module
3396
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3397
				}
3398
			}
3399
			break;
3400
	}
3401

    
3402
	interface_netgraph_needed($interface);
3403

    
3404
	if (!platform_booting()) {
3405
		link_interface_to_vips($interface, "update");
3406

    
3407
		if ($tunnelif != 'gre') {
3408
			unset($gre);
3409
			$gre = link_interface_to_gre($interface);
3410
			if (!empty($gre)) {
3411
				array_walk($gre, 'interface_gre_configure');
3412
			}
3413
		}
3414

    
3415
		if ($tunnelif != 'gif') {
3416
			unset($gif);
3417
			$gif = link_interface_to_gif ($interface);
3418
			if (!empty($gif)) {
3419
				array_walk($gif, 'interface_gif_configure');
3420
			}
3421
		}
3422

    
3423
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3424
			unset($bridgetmp);
3425
			$bridgetmp = link_interface_to_bridge($interface);
3426
			if (!empty($bridgetmp)) {
3427
				interface_bridge_add_member($bridgetmp, $realif);
3428
			}
3429
		}
3430

    
3431
		$grouptmp = link_interface_to_group($interface);
3432
		if (!empty($grouptmp)) {
3433
			array_walk($grouptmp, 'interface_group_add_member');
3434
		}
3435

    
3436
		if ($interface == "lan") {
3437
			/* make new hosts file */
3438
			system_hosts_generate();
3439
		}
3440

    
3441
		if ($reloadall == true) {
3442

    
3443
			/* reconfigure static routes (kernel may have deleted them) */
3444
			system_routing_configure($interface);
3445

    
3446
			/* reload ipsec tunnels */
3447
			send_event("service reload ipsecdns");
3448

    
3449
			/* restart dnsmasq or unbound */
3450
			if (isset($config['dnsmasq']['enable'])) {
3451
				services_dnsmasq_configure();
3452
			} elseif (isset($config['unbound']['enable'])) {
3453
				services_unbound_configure();
3454
			}
3455

    
3456
			/* update dyndns */
3457
			send_event("service reload dyndns {$interface}");
3458

    
3459
			/* reload captive portal */
3460
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3461
				require_once('captiveportal.inc');
3462
			}
3463
			captiveportal_init_rules_byinterface($interface);
3464
		}
3465
	}
3466

    
3467
	interfaces_staticarp_configure($interface);
3468
	return 0;
3469
}
3470

    
3471
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3472
	global $config, $g;
3473

    
3474
	if (!is_array($wancfg)) {
3475
		return;
3476
	}
3477

    
3478
	if (!isset($wancfg['enable'])) {
3479
		return;
3480
	}
3481

    
3482
	/* If the interface is not configured via another, exit */
3483
	if (empty($wancfg['track6-interface'])) {
3484
		return;
3485
	}
3486

    
3487
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3488
	$realif = get_real_interface($interface);
3489
	$linklocal = find_interface_ipv6_ll($realif);
3490
	if (!empty($linklocal)) {
3491
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3492
	}
3493
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3494
	/* XXX: Probably should remove? */
3495
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3496

    
3497
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3498
	if (!isset($trackcfg['enable'])) {
3499
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3500
		return;
3501
	}
3502

    
3503
	switch ($trackcfg['ipaddrv6']) {
3504
		case "6to4":
3505
			if ($g['debug']) {
3506
				log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3507
			}
3508
			interface_track6_6to4_configure($interface, $wancfg);
3509
			break;
3510
		case "6rd":
3511
			if ($g['debug']) {
3512
				log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3513
			}
3514
			interface_track6_6rd_configure($interface, $wancfg);
3515
			break;
3516
		case "dhcp6":
3517
			if ($linkupevent == true) {
3518
				/*
3519
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
3520
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3521
				 *
3522
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
3523
				 */
3524
				$parentrealif = get_real_interface($wancfg['track6-interface']);
3525
				$pidv6 = find_dhcp6c_process($parentrealif);
3526
				if ($pidv6) {
3527
					posix_kill($pidv6, SIGHUP);
3528
				}
3529
			}
3530
			break;
3531
	}
3532

    
3533
	if ($linkupevent == false) {
3534
		if (!function_exists('services_dhcpd_configure')) {
3535
			require_once("services.inc");
3536
		}
3537

    
3538
		if (isset($config['unbound']['enable'])) {
3539
			services_unbound_configure();
3540
		}
3541

    
3542
		services_dhcpd_configure("inet6");
3543
	}
3544

    
3545
	return 0;
3546
}
3547

    
3548
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3549
	global $config, $g;
3550
	global $interface_ipv6_arr_cache;
3551
	global $interface_snv6_arr_cache;
3552

    
3553
	if (!is_array($lancfg)) {
3554
		return;
3555
	}
3556

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

    
3562
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3563
	if (empty($wancfg)) {
3564
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3565
		return;
3566
	}
3567

    
3568
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3569
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3570
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not valid, not configuring 6RD tunnel");
3571
		return;
3572
	}
3573
	$hexwanv4 = return_hex_ipv4($ip4address);
3574

    
3575
	/* create the long prefix notation for math, save the prefix length */
3576
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3577
	$rd6prefixlen = $rd6prefix[1];
3578
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3579

    
3580
	/* binary presentation of the prefix for all 128 bits. */
3581
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3582

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

    
3588
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3589
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3590
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3591
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3592
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3593
	/* fill the rest out with zeros */
3594
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3595

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

    
3599
	$lanif = get_real_interface($interface);
3600
	$oip = find_interface_ipv6($lanif);
3601
	if (is_ipaddrv6($oip)) {
3602
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3603
	}
3604
	unset($interface_ipv6_arr_cache[$lanif]);
3605
	unset($interface_snv6_arr_cache[$lanif]);
3606
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3607
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3608

    
3609
	return 0;
3610
}
3611

    
3612
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3613
	global $config, $g;
3614
	global $interface_ipv6_arr_cache;
3615
	global $interface_snv6_arr_cache;
3616

    
3617
	if (!is_array($lancfg)) {
3618
		return;
3619
	}
3620

    
3621
	/* If the interface is not configured via another, exit */
3622
	if (empty($lancfg['track6-interface'])) {
3623
		return;
3624
	}
3625

    
3626
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3627
	if (empty($wancfg)) {
3628
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3629
		return;
3630
	}
3631

    
3632
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3633
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3634
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3635
		return;
3636
	}
3637
	$hexwanv4 = return_hex_ipv4($ip4address);
3638

    
3639
	/* create the long prefix notation for math, save the prefix length */
3640
	$sixto4prefix = "2002::";
3641
	$sixto4prefixlen = 16;
3642
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3643

    
3644
	/* binary presentation of the prefix for all 128 bits. */
3645
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3646

    
3647
	/* just save the left prefix length bits */
3648
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3649
	/* add the v4 address */
3650
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3651
	/* add the custom prefix id */
3652
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3653
	/* fill the rest out with zeros */
3654
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3655

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

    
3659
	$lanif = get_real_interface($interface);
3660
	$oip = find_interface_ipv6($lanif);
3661
	if (is_ipaddrv6($oip)) {
3662
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3663
	}
3664
	unset($interface_ipv6_arr_cache[$lanif]);
3665
	unset($interface_snv6_arr_cache[$lanif]);
3666
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3667
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3668

    
3669
	return 0;
3670
}
3671

    
3672
function interface_6rd_configure($interface = "wan", $wancfg) {
3673
	global $config, $g;
3674

    
3675
	/* because this is a tunnel interface we can only function
3676
	 *	with a public IPv4 address on the interface */
3677

    
3678
	if (!is_array($wancfg)) {
3679
		return;
3680
	}
3681

    
3682
	if (!is_module_loaded('if_stf.ko')) {
3683
		mwexec('/sbin/kldload if_stf.ko');
3684
	}
3685

    
3686
	$wanif = get_real_interface($interface);
3687
	$ip4address = find_interface_ip($wanif);
3688
	if (!is_ipaddrv4($ip4address)) {
3689
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3690
		return false;
3691
	}
3692
	$hexwanv4 = return_hex_ipv4($ip4address);
3693

    
3694
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3695
		$wancfg['prefix-6rd-v4plen'] = 0;
3696
	}
3697

    
3698
	/* create the long prefix notation for math, save the prefix length */
3699
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3700
	$rd6prefixlen = $rd6prefix[1];
3701
	$brgw = explode('.', $wancfg['gateway-6rd']);
3702
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3703
	$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);
3704
	if (strlen($rd6brgw) < 128) {
3705
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3706
	}
3707
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3708
	unset($brgw);
3709
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3710

    
3711
	/* binary presentation of the prefix for all 128 bits. */
3712
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3713

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

    
3721
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3722
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3723

    
3724

    
3725
	/* XXX: need to extend to support variable prefix size for v4 */
3726
	if (!is_module_loaded("if_stf")) {
3727
		mwexec("/sbin/kldload if_stf.ko");
3728
	}
3729
	$stfiface = "{$interface}_stf";
3730
	if (does_interface_exist($stfiface)) {
3731
		pfSense_interface_destroy($stfiface);
3732
	}
3733
	$tmpstfiface = pfSense_interface_create("stf");
3734
	pfSense_interface_rename($tmpstfiface, $stfiface);
3735
	pfSense_interface_flags($stfiface, IFF_LINK2);
3736
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3737
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3738
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3739
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3740
	}
3741
	if ($g['debug']) {
3742
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3743
	}
3744

    
3745
	/* write out a default router file */
3746
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3747
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3748

    
3749
	$ip4gateway = get_interface_gateway($interface);
3750
	if (is_ipaddrv4($ip4gateway)) {
3751
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3752
	}
3753

    
3754
	/* configure dependent interfaces */
3755
	if (!platform_booting()) {
3756
		link_interface_to_track6($interface, "update");
3757
	}
3758

    
3759
	return 0;
3760
}
3761

    
3762
function interface_6to4_configure($interface = "wan", $wancfg) {
3763
	global $config, $g;
3764

    
3765
	/* because this is a tunnel interface we can only function
3766
	 *	with a public IPv4 address on the interface */
3767

    
3768
	if (!is_array($wancfg)) {
3769
		return;
3770
	}
3771

    
3772
	$wanif = get_real_interface($interface);
3773
	$ip4address = find_interface_ip($wanif);
3774
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3775
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3776
		return false;
3777
	}
3778

    
3779
	/* create the long prefix notation for math, save the prefix length */
3780
	$stfprefixlen = 16;
3781
	$stfprefix = Net_IPv6::uncompress("2002::");
3782
	$stfarr = explode(":", $stfprefix);
3783
	$v4prefixlen = "0";
3784

    
3785
	/* we need the hex form of the interface IPv4 address */
3786
	$ip4arr = explode(".", $ip4address);
3787
	$hexwanv4 = "";
3788
	foreach ($ip4arr as $octet) {
3789
		$hexwanv4 .= sprintf("%02x", $octet);
3790
	}
3791

    
3792
	/* we need the hex form of the broker IPv4 address */
3793
	$ip4arr = explode(".", "192.88.99.1");
3794
	$hexbrv4 = "";
3795
	foreach ($ip4arr as $octet) {
3796
		$hexbrv4 .= sprintf("%02x", $octet);
3797
	}
3798

    
3799
	/* binary presentation of the prefix for all 128 bits. */
3800
	$stfprefixbin = "";
3801
	foreach ($stfarr as $element) {
3802
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3803
	}
3804
	/* just save the left prefix length bits */
3805
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3806

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

    
3811
	/* for the local subnet too. */
3812
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3813
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3814

    
3815
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3816
	$stfbrarr = array();
3817
	$stfbrbinarr = array();
3818
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3819
	foreach ($stfbrbinarr as $bin) {
3820
		$stfbrarr[] = dechex(bindec($bin));
3821
	}
3822
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3823

    
3824
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3825
	$stflanarr = array();
3826
	$stflanbinarr = array();
3827
	$stflanbinarr = str_split($stflanbin, 16);
3828
	foreach ($stflanbinarr as $bin) {
3829
		$stflanarr[] = dechex(bindec($bin));
3830
	}
3831
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3832
	$stflanarr[7] = 1;
3833
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3834

    
3835
	/* setup the stf interface */
3836
	if (!is_module_loaded("if_stf")) {
3837
		mwexec("/sbin/kldload if_stf.ko");
3838
	}
3839
	$stfiface = "{$interface}_stf";
3840
	if (does_interface_exist($stfiface)) {
3841
		pfSense_interface_destroy($stfiface);
3842
	}
3843
	$tmpstfiface = pfSense_interface_create("stf");
3844
	pfSense_interface_rename($tmpstfiface, $stfiface);
3845
	pfSense_interface_flags($stfiface, IFF_LINK2);
3846
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3847

    
3848
	if ($g['debug']) {
3849
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3850
	}
3851

    
3852
	/* write out a default router file */
3853
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3854
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3855

    
3856
	$ip4gateway = get_interface_gateway($interface);
3857
	if (is_ipaddrv4($ip4gateway)) {
3858
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3859
	}
3860

    
3861
	if (!platform_booting()) {
3862
		link_interface_to_track6($interface, "update");
3863
	}
3864

    
3865
	return 0;
3866
}
3867

    
3868
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3869
	global $config, $g;
3870

    
3871
	if (!is_array($wancfg)) {
3872
		return;
3873
	}
3874

    
3875
	$wanif = get_real_interface($interface, "inet6");
3876
	$dhcp6cconf = "";
3877

    
3878
	if ($wancfg['adv_dhcp6_config_file_override']) {
3879
		// DHCP6 Config File Override
3880
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3881
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3882
		// DHCP6 Config File Advanced
3883
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3884
	} else {
3885
		// DHCP6 Config File Basic
3886
		$dhcp6cconf .= "interface {$wanif} {\n";
3887

    
3888
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3889
		if ($wancfg['ipaddrv6'] == "slaac") {
3890
			$dhcp6cconf .= "\tinformation-only;\n";
3891
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3892
			$dhcp6cconf .= "\trequest domain-name;\n";
3893
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3894
			$dhcp6cconf .= "};\n";
3895
		} else {
3896
			$trackiflist = array();
3897
			$iflist = link_interface_to_track6($interface);
3898
			foreach ($iflist as $ifname => $ifcfg) {
3899
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3900
					$trackiflist[$ifname] = $ifcfg;
3901
				}
3902
			}
3903

    
3904
			/* skip address request if this is set */
3905
			if (!isset($wancfg['dhcp6prefixonly'])) {
3906
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3907
			}
3908
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3909
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3910
			}
3911

    
3912
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3913
			$dhcp6cconf .= "\trequest domain-name;\n";
3914
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3915
			$dhcp6cconf .= "};\n";
3916

    
3917
			if (!isset($wancfg['dhcp6prefixonly'])) {
3918
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3919
			}
3920

    
3921
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3922
				/* Setup the prefix delegation */
3923
				$dhcp6cconf .= "id-assoc pd 0 {\n";
3924
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3925
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
3926
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
3927
				}
3928
				foreach ($trackiflist as $friendly => $ifcfg) {
3929
					if ($g['debug']) {
3930
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3931
					}
3932
					$realif = get_real_interface($friendly);
3933
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
3934
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
3935
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3936
					$dhcp6cconf .= "\t};\n";
3937
				}
3938
				unset($preflen, $iflist, $ifcfg, $ifname);
3939
				$dhcp6cconf .= "};\n";
3940
			}
3941
			unset($trackiflist);
3942
		}
3943
	}
3944

    
3945
	/* wide-dhcp6c works for now. */
3946
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3947
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3948
		unset($dhcp6cconf);
3949
		return 1;
3950
	}
3951
	unset($dhcp6cconf);
3952

    
3953
	$dhcp6cscript = "#!/bin/sh\n";
3954
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3955
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3956
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3957
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3958
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3959
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3960
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3961
		unset($dhcp6cscript);
3962
		return 1;
3963
	}
3964
	unset($dhcp6cscript);
3965
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3966

    
3967
	$rtsoldscript = "#!/bin/sh\n";
3968
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3969
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3970
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3971
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Recieved RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
3972
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3973
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3974
	$rtsoldscript .= "\t/bin/sleep 1\n";
3975
	$rtsoldscript .= "fi\n";
3976
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3977
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3978
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3979
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3980
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3981
		unset($rtsoldscript);
3982
		return 1;
3983
	}
3984
	unset($rtsoldscript);
3985
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3986

    
3987
	/* accept router advertisements for this interface */
3988
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3989
	log_error("Accept router advertisements on interface {$wanif} ");
3990
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3991

    
3992
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3993
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3994
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3995
		sleep(2);
3996
	}
3997
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3998

    
3999
	/* NOTE: will be called from rtsold invoked script
4000
	 * link_interface_to_track6($interface, "update");
4001
	 */
4002

    
4003
	return 0;
4004
}
4005

    
4006
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4007
	global $g;
4008

    
4009
	$send_options = "";
4010
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4011
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_send_options']);
4012
		foreach ($options as $option) {
4013
			$send_options .= "\tsend " . trim($option) . ";\n";
4014
		}
4015
	}
4016

    
4017
	$request_options = "";
4018
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4019
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_request_options']);
4020
		foreach ($options as $option) {
4021
			$request_options .= "\trequest " . trim($option) . ";\n";
4022
		}
4023
	}
4024

    
4025
	$information_only = "";
4026
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4027
		$information_only = "\tinformation-only;\n";
4028
	}
4029

    
4030
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4031
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4032
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4033
	}
4034

    
4035
	$interface_statement  = "interface";
4036
	$interface_statement .= " {$wanif}";
4037
	$interface_statement .= " {\n";
4038
	$interface_statement .= "$send_options";
4039
	$interface_statement .= "$request_options";
4040
	$interface_statement .= "$information_only";
4041
	$interface_statement .= "$script";
4042
	$interface_statement .= "};\n";
4043

    
4044
	$id_assoc_statement_address = "";
4045
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4046
		$id_assoc_statement_address .= "id-assoc";
4047
		$id_assoc_statement_address .= " na";
4048
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4049
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4050
		}
4051
		$id_assoc_statement_address .= " { ";
4052

    
4053
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4054
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4055
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4056
			$id_assoc_statement_address .= "\n\taddress";
4057
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4058
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4059
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4060
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4061
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4062
			}
4063
			$id_assoc_statement_address .= ";\n";
4064
		}
4065

    
4066
		$id_assoc_statement_address .= "};\n";
4067
	}
4068

    
4069
	$id_assoc_statement_prefix = "";
4070
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4071
		$id_assoc_statement_prefix .= "id-assoc";
4072
		$id_assoc_statement_prefix .= " pd";
4073
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4074
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4075
		}
4076
		$id_assoc_statement_prefix .= " { ";
4077

    
4078
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4079
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4080
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4081
			$id_assoc_statement_prefix .= "\n\tprefix";
4082
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4083
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4084
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4085
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4086
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4087
			}
4088
			$id_assoc_statement_prefix .= ";";
4089
		}
4090

    
4091
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4092
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4093
			$id_assoc_statement_prefix .= " {$wanif}";
4094
			$id_assoc_statement_prefix .= " {\n";
4095
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4096
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4097
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4098
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4099
			}
4100
			$id_assoc_statement_prefix .= "\t};";
4101
		}
4102

    
4103
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4104
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4105
			$id_assoc_statement_prefix .= "\n";
4106
		}
4107

    
4108
		$id_assoc_statement_prefix .= "};\n";
4109
	}
4110

    
4111
	$authentication_statement = "";
4112
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4113
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4114
		$authentication_statement .= "authentication";
4115
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4116
		$authentication_statement .= " {\n";
4117
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4118
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4119
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4120
		}
4121
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4122
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4123
		}
4124
		$authentication_statement .= "};\n";
4125
	}
4126

    
4127
	$key_info_statement = "";
4128
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4129
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4130
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4131
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4132
		$key_info_statement .= "keyinfo";
4133
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4134
		$key_info_statement .= " {\n";
4135
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4136
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4137
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4138
		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'])) {
4139
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4140
		}
4141
		$key_info_statement .= "};\n";
4142
	}
4143

    
4144
	$dhcp6cconf  = $interface_statement;
4145
	$dhcp6cconf .= $id_assoc_statement_address;
4146
	$dhcp6cconf .= $id_assoc_statement_prefix;
4147
	$dhcp6cconf .= $authentication_statement;
4148
	$dhcp6cconf .= $key_info_statement;
4149

    
4150
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4151

    
4152
	return $dhcp6cconf;
4153
}
4154

    
4155

    
4156
function DHCP6_Config_File_Override($wancfg, $wanif) {
4157

    
4158
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4159

    
4160
	if ($dhcp6cconf === false) {
4161
		log_error("Error: cannot open {$wancfg['adv_dhcp6_config_file_override_path']} in DHCP6_Config_File_Override() for reading.\n");
4162
		return '';
4163
	} else {
4164
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4165
	}
4166
}
4167

    
4168

    
4169
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4170

    
4171
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4172

    
4173
	return $dhcp6cconf;
4174
}
4175

    
4176

    
4177
function interface_dhcp_configure($interface = "wan") {
4178
	global $config, $g;
4179

    
4180
	$wancfg = $config['interfaces'][$interface];
4181
	$wanif = $wancfg['if'];
4182
	if (empty($wancfg)) {
4183
		$wancfg = array();
4184
	}
4185

    
4186
	/* generate dhclient_wan.conf */
4187
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4188
	if (!$fd) {
4189
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
4190
		return 1;
4191
	}
4192

    
4193
	if ($wancfg['dhcphostname']) {
4194
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4195
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4196
	} else {
4197
		$dhclientconf_hostname = "";
4198
	}
4199

    
4200
	$wanif = get_real_interface($interface);
4201
	if (empty($wanif)) {
4202
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4203
		return 0;
4204
	}
4205
	$dhclientconf = "";
4206

    
4207
	$dhclientconf .= <<<EOD
4208
interface "{$wanif}" {
4209
timeout 60;
4210
retry 15;
4211
select-timeout 0;
4212
initial-interval 1;
4213
	{$dhclientconf_hostname}
4214
	script "/sbin/dhclient-script";
4215
EOD;
4216

    
4217
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4218
		$dhclientconf .= <<<EOD
4219

    
4220
	reject {$wancfg['dhcprejectfrom']};
4221
EOD;
4222
	}
4223
	$dhclientconf .= <<<EOD
4224

    
4225
}
4226

    
4227
EOD;
4228

    
4229
	// DHCP Config File Advanced
4230
	if ($wancfg['adv_dhcp_config_advanced']) {
4231
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4232
	}
4233

    
4234
	if (is_ipaddr($wancfg['alias-address'])) {
4235
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4236
		$dhclientconf .= <<<EOD
4237
alias {
4238
	interface "{$wanif}";
4239
	fixed-address {$wancfg['alias-address']};
4240
	option subnet-mask {$subnetmask};
4241
}
4242

    
4243
EOD;
4244
	}
4245

    
4246
	// DHCP Config File Override
4247
	if ($wancfg['adv_dhcp_config_file_override']) {
4248
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4249
	}
4250

    
4251
	fwrite($fd, $dhclientconf);
4252
	fclose($fd);
4253

    
4254
	/* bring wan interface up before starting dhclient */
4255
	if ($wanif) {
4256
		interfaces_bring_up($wanif);
4257
	} else {
4258
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4259
	}
4260

    
4261
	/* Make sure dhclient is not running */
4262
	kill_dhclient_process($wanif);
4263

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

    
4267
	return 0;
4268
}
4269

    
4270
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4271

    
4272
	$hostname = "";
4273
	if ($wancfg['dhcphostname'] != '') {
4274
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4275
	}
4276

    
4277
	/* DHCP Protocol Timings */
4278
	$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");
4279
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4280
		$pt_variable = "{$Protocol_Timing}";
4281
		${$pt_variable} = "";
4282
		if ($wancfg[$Protocol_Timing] != "") {
4283
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4284
		}
4285
	}
4286

    
4287
	$send_options = "";
4288
	if ($wancfg['adv_dhcp_send_options'] != '') {
4289
		$options = explode(',', $wancfg['adv_dhcp_send_options']);
4290
		foreach ($options as $option) {
4291
			$send_options .= "\tsend " . trim($option) . ";\n";
4292
		}
4293
	}
4294

    
4295
	$request_options = "";
4296
	if ($wancfg['adv_dhcp_request_options'] != '') {
4297
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4298
	}
4299

    
4300
	$required_options = "";
4301
	if ($wancfg['adv_dhcp_required_options'] != '') {
4302
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4303
	}
4304

    
4305
	$option_modifiers = "";
4306
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4307
		$modifiers = explode(',', $wancfg['adv_dhcp_option_modifiers']);
4308
		foreach ($modifiers as $modifier) {
4309
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4310
		}
4311
	}
4312

    
4313
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4314
	$dhclientconf .= "\n";
4315
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4316
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4317
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4318
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4319
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4320
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4321
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4322
	$dhclientconf .= "\n";
4323
	$dhclientconf .= "# DHCP Protocol Options\n";
4324
	$dhclientconf .= "{$hostname}";
4325
	$dhclientconf .= "{$send_options}";
4326
	$dhclientconf .= "{$request_options}";
4327
	$dhclientconf .= "{$required_options}";
4328
	$dhclientconf .= "{$option_modifiers}";
4329
	$dhclientconf .= "\n";
4330
	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4331
	$dhclientconf .= "}\n";
4332

    
4333
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4334

    
4335
	return $dhclientconf;
4336
}
4337

    
4338

    
4339
function DHCP_Config_File_Override($wancfg, $wanif) {
4340

    
4341
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4342

    
4343
	if ($dhclientconf === false) {
4344
		log_error("Error: cannot open {$wancfg['adv_dhcp_config_file_override_path']} in DHCP_Config_File_Override() for reading.\n");
4345
		return '';
4346
	} else {
4347
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4348
	}
4349
}
4350

    
4351

    
4352
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4353

    
4354
	/* Apply Interface Substitutions */
4355
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4356

    
4357
	/* Apply Hostname Substitutions */
4358
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4359

    
4360
	/* Arrays of MAC Address Types, Cases, Delimiters */
4361
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4362
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4363
	$various_mac_cases      = array("U", "L");
4364
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4365

    
4366
	/* Apply MAC Address Substitutions */
4367
	foreach ($various_mac_types as $various_mac_type) {
4368
		foreach ($various_mac_cases as $various_mac_case) {
4369
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4370

    
4371
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4372
				if ($res !== false) {
4373

    
4374
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4375
					if ("$various_mac_case" == "U") {
4376
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4377
					}
4378
					if ("$various_mac_case" == "L") {
4379
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4380
					}
4381

    
4382
					if ("$various_mac_type" == "mac_addr_hex") {
4383
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4384
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4385
						$dhcpclientconf_mac_hex = "";
4386
						$delimiter = "";
4387
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4388
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4389
							$delimiter = ":";
4390
						}
4391
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4392
					}
4393

    
4394
					/* MAC Address Delimiter Substitutions */
4395
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4396

    
4397
					/* Apply MAC Address Substitutions */
4398
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4399
				}
4400
			}
4401
		}
4402
	}
4403

    
4404
	return $dhclientconf;
4405
}
4406

    
4407
function interfaces_group_setup() {
4408
	global $config;
4409

    
4410
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4411
		return;
4412
	}
4413

    
4414
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4415
		interface_group_setup($groupar);
4416
	}
4417

    
4418
	return;
4419
}
4420

    
4421
function interface_group_setup(&$groupname /* The parameter is an array */) {
4422
	global $config;
4423

    
4424
	if (!is_array($groupname)) {
4425
		return;
4426
	}
4427
	$members = explode(" ", $groupname['members']);
4428
	foreach ($members as $ifs) {
4429
		$realif = get_real_interface($ifs);
4430
		if ($realif && does_interface_exist($realif)) {
4431
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4432
		}
4433
	}
4434

    
4435
	return;
4436
}
4437

    
4438
function is_interface_group($if) {
4439
	global $config;
4440

    
4441
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4442
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4443
			if ($groupentry['ifname'] === $if) {
4444
				return true;
4445
			}
4446
		}
4447
	}
4448

    
4449
	return false;
4450
}
4451

    
4452
function interface_group_add_member($interface, $groupname) {
4453
	$interface = get_real_interface($interface);
4454
	if (does_interface_exist($interface)) {
4455
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4456
	}
4457
}
4458

    
4459
/* COMPAT Function */
4460
function convert_friendly_interface_to_real_interface_name($interface) {
4461
	return get_real_interface($interface);
4462
}
4463

    
4464
/* COMPAT Function */
4465
function get_real_wan_interface($interface = "wan") {
4466
	return get_real_interface($interface);
4467
}
4468

    
4469
/* COMPAT Function */
4470
function get_current_wan_address($interface = "wan") {
4471
	return get_interface_ip($interface);
4472
}
4473

    
4474
/*
4475
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4476
 */
4477
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4478
	global $config;
4479

    
4480
	if (stripos($interface, "_vip")) {
4481
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
4482
			if ($vip['mode'] == "carp") {
4483
				if ($interface == "_vip{$vip['uniqid']}") {
4484
					return $vip['interface'];
4485
				}
4486
			}
4487
		}
4488
	}
4489

    
4490
	/* XXX: For speed reasons reference directly the interface array */
4491
	$ifdescrs = &$config['interfaces'];
4492
	//$ifdescrs = get_configured_interface_list(false, true);
4493

    
4494
	foreach ($ifdescrs as $if => $ifname) {
4495
		if ($if == $interface || $ifname['if'] == $interface) {
4496
			return $if;
4497
		}
4498

    
4499
		if (get_real_interface($if) == $interface) {
4500
			return $if;
4501
		}
4502

    
4503
		if ($checkparent == false) {
4504
			continue;
4505
		}
4506

    
4507
		$int = get_parent_interface($if, true);
4508
		if (is_array($int)) {
4509
			foreach ($int as $iface) {
4510
				if ($iface == $interface) {
4511
					return $if;
4512
				}
4513
			}
4514
		}
4515
	}
4516

    
4517
	if ($interface == "enc0") {
4518
		return 'IPsec';
4519
	}
4520
}
4521

    
4522
/* attempt to resolve interface to friendly descr */
4523
function convert_friendly_interface_to_friendly_descr($interface) {
4524
	global $config;
4525

    
4526
	switch ($interface) {
4527
		case "l2tp":
4528
			$ifdesc = "L2TP";
4529
			break;
4530
		case "pptp":
4531
			$ifdesc = "PPTP";
4532
			break;
4533
		case "pppoe":
4534
			$ifdesc = "PPPoE";
4535
			break;
4536
		case "openvpn":
4537
			$ifdesc = "OpenVPN";
4538
			break;
4539
		case "enc0":
4540
		case "ipsec":
4541
		case "IPsec":
4542
			$ifdesc = "IPsec";
4543
			break;
4544
		default:
4545
			if (isset($config['interfaces'][$interface])) {
4546
				if (empty($config['interfaces'][$interface]['descr'])) {
4547
					$ifdesc = strtoupper($interface);
4548
				} else {
4549
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4550
				}
4551
				break;
4552
			} else if (substr($interface, 0, 4) == '_vip') {
4553
				if (is_array($config['virtualip']['vip'])) {
4554
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
4555
						if ($vip['mode'] == "carp") {
4556
							if ($interface == "_vip{$vip['uniqid']}") {
4557
								return "{$vip['subnet']} - {$vip['descr']}";
4558
							}
4559
						}
4560
					}
4561
				}
4562
			} else if (substr($interface, 0, 5) == '_lloc') {
4563
				return get_interface_linklocal($interface);
4564
			} else {
4565
				/* if list */
4566
				$ifdescrs = get_configured_interface_with_descr(false, true);
4567
				foreach ($ifdescrs as $if => $ifname) {
4568
					if ($if == $interface || $ifname == $interface) {
4569
						return $ifname;
4570
					}
4571
				}
4572
			}
4573
			break;
4574
	}
4575

    
4576
	return $ifdesc;
4577
}
4578

    
4579
function convert_real_interface_to_friendly_descr($interface) {
4580

    
4581
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4582

    
4583
	if (!empty($ifdesc)) {
4584
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4585
	}
4586

    
4587
	return $interface;
4588
}
4589

    
4590
/*
4591
 *  get_parent_interface($interface):
4592
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4593
 *				or virtual interface (i.e. vlan)
4594
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4595
 *			-- returns $interface passed in if $interface parent is not found
4596
 *			-- returns empty array if an invalid interface is passed
4597
 *	(Only handles ppps and vlans now.)
4598
 */
4599
function get_parent_interface($interface, $avoidrecurse = false) {
4600
	global $config;
4601

    
4602
	$parents = array();
4603
	//Check that we got a valid interface passed
4604
	$realif = get_real_interface($interface);
4605
	if ($realif == NULL) {
4606
		return $parents;
4607
	}
4608

    
4609
	// If we got a real interface, find it's friendly assigned name
4610
	if ($interface == $realif && $avoidrecurse == false) {
4611
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4612
	}
4613

    
4614
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4615
		$ifcfg = $config['interfaces'][$interface];
4616
		switch ($ifcfg['ipaddr']) {
4617
			case "ppp":
4618
			case "pppoe":
4619
			case "pptp":
4620
			case "l2tp":
4621
				if (empty($parents)) {
4622
					if (is_array($config['ppps']['ppp'])) {
4623
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4624
							if ($ifcfg['if'] == $ppp['if']) {
4625
								$ports = explode(',', $ppp['ports']);
4626
								foreach ($ports as $pid => $parent_if) {
4627
									$parents[$pid] = get_real_interface($parent_if);
4628
								}
4629
								break;
4630
							}
4631
						}
4632
					}
4633
				}
4634
				break;
4635
			case "dhcp":
4636
			case "static":
4637
			default:
4638
				// Handle _vlans
4639
				if (strpos($realif, '_vlan') !== FALSE) {
4640
					if (is_array($config['vlans']['vlan'])) {
4641
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4642
							if ($ifcfg['if'] == $vlan['vlanif']) {
4643
								$parents[0] = $vlan['if'];
4644
								break;
4645
							}
4646
						}
4647
					}
4648
				}
4649
				break;
4650
		}
4651
	}
4652

    
4653
	if (empty($parents)) {
4654
		// Handle _vlans not assigned to an interface
4655
		if (strpos($realif, '_vlan') !== FALSE) {
4656
			if (is_array($config['vlans']['vlan'])) {
4657
				foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4658
					if ($realif == $vlan['vlanif']) {
4659
						$parents[0] = $vlan['if'];
4660
						break;
4661
					}
4662
				}
4663
			}
4664
		}
4665
	}
4666

    
4667
	if (empty($parents)) {
4668
		$parents[0] = $realif;
4669
	}
4670

    
4671
	return $parents;
4672
}
4673

    
4674
function interface_is_wireless_clone($wlif) {
4675
	if (!stristr($wlif, "_wlan")) {
4676
		return false;
4677
	} else {
4678
		return true;
4679
	}
4680
}
4681

    
4682
function interface_get_wireless_base($wlif) {
4683
	if (!stristr($wlif, "_wlan")) {
4684
		return $wlif;
4685
	} else {
4686
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4687
	}
4688
}
4689

    
4690
function interface_get_wireless_clone($wlif) {
4691
	if (!stristr($wlif, "_wlan")) {
4692
		return $wlif . "_wlan0";
4693
	} else {
4694
		return $wlif;
4695
	}
4696
}
4697

    
4698
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4699
	global $config, $g;
4700

    
4701
	$wanif = NULL;
4702

    
4703
	switch ($interface) {
4704
		case "l2tp":
4705
			$wanif = "l2tp";
4706
			break;
4707
		case "pptp":
4708
			$wanif = "pptp";
4709
			break;
4710
		case "pppoe":
4711
			$wanif = "pppoe";
4712
			break;
4713
		case "openvpn":
4714
			$wanif = "openvpn";
4715
			break;
4716
		case "IPsec":
4717
		case "ipsec":
4718
		case "enc0":
4719
			$wanif = "enc0";
4720
			break;
4721
		case "ppp":
4722
			$wanif = "ppp";
4723
			break;
4724
		default:
4725
			if (substr($interface, 0, 4) == '_vip') {
4726
				$wanif = get_configured_carp_interface_list($interface, $family, 'iface');
4727
				if (!empty($wanif)) {
4728
					$wanif = get_real_interface($wanif, $family);
4729
				}
4730
				break;
4731
			} else if (substr($interface, 0, 5) == '_lloc') {
4732
				$interface = substr($interface, 5);
4733
			} else if (does_interface_exist($interface, $flush)) {
4734
				/*
4735
				 * If a real interface was already passed simply
4736
				 * pass the real interface back.  This encourages
4737
				 * the usage of this function in more cases so that
4738
				 * we can combine logic for more flexibility.
4739
				 */
4740
				$wanif = $interface;
4741
				break;
4742
			}
4743

    
4744
			if (empty($config['interfaces'][$interface])) {
4745
				break;
4746
			}
4747

    
4748
			$cfg = &$config['interfaces'][$interface];
4749

    
4750
			if ($family == "inet6") {
4751
				switch ($cfg['ipaddrv6']) {
4752
					case "6rd":
4753
					case "6to4":
4754
						$wanif = "{$interface}_stf";
4755
						break;
4756
					case 'pppoe':
4757
					case 'ppp':
4758
					case 'l2tp':
4759
					case 'pptp':
4760
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4761
							$wanif = interface_get_wireless_clone($cfg['if']);
4762
						} else {
4763
							$wanif = $cfg['if'];
4764
						}
4765
						break;
4766
					default:
4767
						switch ($cfg['ipaddr']) {
4768
							case 'pppoe':
4769
							case 'ppp':
4770
							case 'l2tp':
4771
							case 'pptp':
4772
								if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false) {
4773
									$wanif = $cfg['if'];
4774
								} else {
4775
									$parents = get_parent_interface($interface);
4776
									if (!empty($parents[0])) {
4777
										$wanif = $parents[0];
4778
									} else {
4779
										$wanif = $cfg['if'];
4780
									}
4781
								}
4782
								break;
4783
							default:
4784
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4785
									$wanif = interface_get_wireless_clone($cfg['if']);
4786
								} else {
4787
									$wanif = $cfg['if'];
4788
								}
4789
								break;
4790
						}
4791
						break;
4792
				}
4793
			} else {
4794
				// Wireless cloned NIC support (FreeBSD 8+)
4795
				// interface name format: $parentnic_wlanparentnic#
4796
				// example: ath0_wlan0
4797
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4798
					$wanif = interface_get_wireless_clone($cfg['if']);
4799
				} else {
4800
					$wanif = $cfg['if'];
4801
				}
4802
			}
4803
			break;
4804
	}
4805

    
4806
	return $wanif;
4807
}
4808

    
4809
/* Guess the physical interface by providing a IP address */
4810
function guess_interface_from_ip($ipaddress) {
4811

    
4812
	$family = '';
4813
	if (is_ipaddrv4($ipaddress)) {
4814
		$family = 'inet';
4815
	}
4816
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4817
		$family = 'inet6';
4818
	}
4819

    
4820
	if (empty($family)) {
4821
		return false;
4822
	}
4823

    
4824
	/* create a route table we can search */
4825
	$output = '';
4826
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4827
	$output[0] = trim($output[0], " \n");
4828
	if (!empty($output[0])) {
4829
		return $output[0];
4830
	}
4831

    
4832
	return false;
4833
}
4834

    
4835
/*
4836
 * find_ip_interface($ip): return the interface where an ip is defined
4837
 *   (or if $bits is specified, where an IP within the subnet is defined)
4838
 */
4839
function find_ip_interface($ip, $bits = null) {
4840
	if (!is_ipaddr($ip)) {
4841
		return false;
4842
	}
4843

    
4844
	$isv6ip = is_ipaddrv6($ip);
4845

    
4846
	/* if list */
4847
	$ifdescrs = get_configured_interface_list();
4848

    
4849
	foreach ($ifdescrs as $ifdescr => $ifname) {
4850
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4851
		if (is_null($ifip)) {
4852
			continue;
4853
		}
4854
		if (is_null($bits)) {
4855
			if ($ip == $ifip) {
4856
				$int = get_real_interface($ifname);
4857
				return $int;
4858
			}
4859
		} else {
4860
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4861
				$int = get_real_interface($ifname);
4862
				return $int;
4863
			}
4864
		}
4865
	}
4866

    
4867
	return false;
4868
}
4869

    
4870
/*
4871
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4872
 *   (or if $bits is specified, where an IP within the subnet is found)
4873
 */
4874
function find_virtual_ip_alias($ip, $bits = null) {
4875
	global $config;
4876

    
4877
	if (!is_array($config['virtualip']['vip'])) {
4878
		return false;
4879
	}
4880
	if (!is_ipaddr($ip)) {
4881
		return false;
4882
	}
4883

    
4884
	$isv6ip = is_ipaddrv6($ip);
4885

    
4886
	foreach ($config['virtualip']['vip'] as $vip) {
4887
		if ($vip['mode'] === "ipalias") {
4888
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
4889
				continue;
4890
			}
4891
			if (is_null($bits)) {
4892
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4893
					return $vip;
4894
				}
4895
			} else {
4896
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
4897
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4898
					return $vip;
4899
				}
4900
			}
4901
		}
4902
	}
4903
	return false;
4904
}
4905

    
4906
/*
4907
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4908
 */
4909
function find_number_of_created_carp_interfaces() {
4910
	return `/sbin/ifconfig | /usr/bin/grep "carp:" | /usr/bin/wc -l`;
4911
}
4912

    
4913
/*
4914
 * find_carp_interface($ip): return the carp interface where an ip is defined
4915
 */
4916
function find_carp_interface($ip) {
4917
	global $config;
4918
	if (is_array($config['virtualip']['vip'])) {
4919
		foreach ($config['virtualip']['vip'] as $vip) {
4920
			if ($vip['mode'] == "carp") {
4921
				if (is_ipaddrv4($ip)) {
4922
					$carp_ip = get_interface_ip($vip['interface']);
4923
				}
4924
				if (is_ipaddrv6($ip)) {
4925
					$carp_ip = get_interface_ipv6($vip['interface']);
4926
				}
4927
				exec("/sbin/ifconfig", $output, $return);
4928
				foreach ($output as $line) {
4929
					$elements = preg_split("/[ ]+/i", $line);
4930
					if (strstr($elements[0], "vip")) {
4931
						$curif = str_replace(":", "", $elements[0]);
4932
					}
4933
					if (stristr($line, $ip)) {
4934
						$if = $curif;
4935
						continue;
4936
					}
4937
				}
4938

    
4939
				if ($if) {
4940
					return $if;
4941
				}
4942
			}
4943
		}
4944
	}
4945
}
4946

    
4947
function link_carp_interface_to_parent($interface) {
4948
	global $config;
4949

    
4950
	if (empty($interface)) {
4951
		return;
4952
	}
4953

    
4954
	$carp_ip = get_interface_ip($interface);
4955
	$carp_ipv6 = get_interface_ipv6($interface);
4956

    
4957
	if ((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6))) {
4958
		return;
4959
	}
4960

    
4961
	/* if list */
4962
	$ifdescrs = get_configured_interface_list();
4963
	foreach ($ifdescrs as $ifdescr => $ifname) {
4964
		/* check IPv4 */
4965
		if (is_ipaddrv4($carp_ip)) {
4966
			$interfaceip = get_interface_ip($ifname);
4967
			$subnet_bits = get_interface_subnet($ifname);
4968
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4969
			if (ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}")) {
4970
				return $ifname;
4971
			}
4972
		}
4973
		/* Check IPv6 */
4974
		if (is_ipaddrv6($carp_ipv6)) {
4975
			$interfaceipv6 = get_interface_ipv6($ifname);
4976
			$prefixlen = get_interface_subnetv6($ifname);
4977
			if (ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}")) {
4978
				return $ifname;
4979
			}
4980
		}
4981
	}
4982
	return "";
4983
}
4984

    
4985

    
4986
/****f* interfaces/link_ip_to_carp_interface
4987
 * NAME
4988
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4989
 * INPUTS
4990
 *   $ip
4991
 * RESULT
4992
 *   $carp_ints
4993
 ******/
4994
function link_ip_to_carp_interface($ip) {
4995
	global $config;
4996

    
4997
	if (!is_ipaddr($ip)) {
4998
		return;
4999
	}
5000

    
5001
	$carp_ints = "";
5002
	if (is_array($config['virtualip']['vip'])) {
5003
		$first = 0;
5004
		$carp_int = array();
5005
		foreach ($config['virtualip']['vip'] as $vip) {
5006
			if ($vip['mode'] == "carp") {
5007
				$carp_ip = $vip['subnet'];
5008
				$carp_sn = $vip['subnet_bits'];
5009
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
5010
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
5011
					$carp_int[] = get_real_interface($vip['interface']);
5012
				}
5013
			}
5014
		}
5015
		if (!empty($carp_int)) {
5016
			$carp_ints = implode(" ", array_unique($carp_int));
5017
		}
5018
	}
5019

    
5020
	return $carp_ints;
5021
}
5022

    
5023
function link_interface_to_track6($int, $action = "") {
5024
	global $config;
5025

    
5026
	if (empty($int)) {
5027
		return;
5028
	}
5029

    
5030
	if (is_array($config['interfaces'])) {
5031
		$list = array();
5032
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5033
			if (!isset($ifcfg['enable'])) {
5034
				continue;
5035
			}
5036
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5037
				if ($action == "update") {
5038
					interface_track6_configure($ifname, $ifcfg);
5039
				} else if ($action == "") {
5040
					$list[$ifname] = $ifcfg;
5041
				}
5042
			}
5043
		}
5044
		return $list;
5045
	}
5046
}
5047

    
5048
function interface_find_child_cfgmtu($realiface) {
5049
	global $config;
5050

    
5051
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5052
	$vlans = link_interface_to_vlans($realiface);
5053
	$bridge = link_interface_to_bridge($realiface);
5054
	if (!empty($interface)) {
5055
		$gifs = link_interface_to_gif($interface);
5056
		$gres = link_interface_to_gre($interface);
5057
	} else {
5058
		$gifs = array();
5059
		$gres = array();
5060
	}
5061

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

    
5110
	return $mtu;
5111
}
5112

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

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

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

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

    
5140
	if (is_array($config['virtualip']['vip'])) {
5141
		$result = array();
5142
		foreach ($config['virtualip']['vip'] as $vip) {
5143
			if ($int == $vip['interface']) {
5144
				if ($action == "update") {
5145
					interfaces_vips_configure($int);
5146
				} else {
5147
					if (empty($vhid) || ($vhid == $vip['vhid'])) {
5148
						$result[] = $vip;
5149
					}
5150
				}
5151
			}
5152
		}
5153
		return $result;
5154
	}
5155
}
5156

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

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

    
5177
function link_interface_to_group($int) {
5178
	global $config;
5179

    
5180
	$result = array();
5181

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

    
5190
	return $result;
5191
}
5192

    
5193
function link_interface_to_gre($interface) {
5194
	global $config;
5195

    
5196
	$result = array();
5197

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

    
5206
	return $result;
5207
}
5208

    
5209
function link_interface_to_gif($interface) {
5210
	global $config;
5211

    
5212
	$result = array();
5213

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

    
5222
	return $result;
5223
}
5224

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

    
5232
	$interface = str_replace("\n", "", $interface);
5233

    
5234
	if (!does_interface_exist($interface)) {
5235
		return;
5236
	}
5237

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

    
5245
	return $interface_ip_arr_cache[$interface];
5246
}
5247

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

    
5256
	$interface = trim($interface);
5257
	$interface = get_real_interface($interface);
5258

    
5259
	if (!does_interface_exist($interface)) {
5260
		return;
5261
	}
5262

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

    
5270
	return $interface_ipv6_arr_cache[$interface];
5271
}
5272

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

    
5280
	$interface = str_replace("\n", "", $interface);
5281

    
5282
	if (!does_interface_exist($interface)) {
5283
		return;
5284
	}
5285

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

    
5302
function find_interface_subnet($interface, $flush = false) {
5303
	global $interface_sn_arr_cache;
5304
	global $interface_ip_arr_cache;
5305

    
5306
	$interface = str_replace("\n", "", $interface);
5307
	if (does_interface_exist($interface) == false) {
5308
		return;
5309
	}
5310

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

    
5317
	return $interface_sn_arr_cache[$interface];
5318
}
5319

    
5320
function find_interface_subnetv6($interface, $flush = false) {
5321
	global $interface_snv6_arr_cache;
5322
	global $interface_ipv6_arr_cache;
5323

    
5324
	$interface = str_replace("\n", "", $interface);
5325
	if (does_interface_exist($interface) == false) {
5326
		return;
5327
	}
5328

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

    
5335
	return $interface_snv6_arr_cache[$interface];
5336
}
5337

    
5338
function ip_in_interface_alias_subnet($interface, $ipalias) {
5339
	global $config;
5340

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

    
5360
	return false;
5361
}
5362

    
5363
function get_possible_listen_ips($include_ipv6_link_local=false) {
5364

    
5365
	$interfaces = get_configured_interface_with_descr();
5366
	foreach ($interfaces as $iface => $ifacename) {
5367
		if ($include_ipv6_link_local) {
5368
			/* This is to avoid going though added ll below */
5369
			if (substr($iface, 0, 5) == '_lloc') {
5370
				continue;
5371
			}
5372
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5373
			if (!empty($llip)) {
5374
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5375
			}
5376
		}
5377
	}
5378
	/* XXX: Maybe use array_merge below? */
5379
	$carplist = get_configured_carp_interface_list();
5380
	foreach ($carplist as $cif => $carpip) {
5381
		if (get_vip_descr($carpip)) {
5382
			$interfaces[$cif] = $carpip . ' (' . get_vip_descr($carpip) . ')';
5383
		} else {
5384
			$interfaces[$cif] = $carpip;
5385
		}
5386
	}
5387
	$aliaslist = get_configured_ip_aliases_list();
5388
	foreach ($aliaslist as $aliasip => $aliasif) {
5389
		if (get_vip_descr($aliasip)) {
5390
			$interfaces[$aliasip] = $aliasip . ' (' . get_vip_descr($aliasip) . ')';
5391
		} else {
5392
			$interfaces[$aliasip] = $aliasip;
5393
		}
5394
	}
5395

    
5396
	$interfaces['lo0'] = 'Localhost';
5397

    
5398
	return $interfaces;
5399
}
5400

    
5401
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5402
	global $config;
5403

    
5404
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5405
	foreach (array('server', 'client') as $mode) {
5406
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5407
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5408
				if (!isset($setting['disable'])) {
5409
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5410
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " ".$mode.": ".htmlspecialchars($setting['description']);
5411
				}
5412
			}
5413
		}
5414
	}
5415
	return $sourceips;
5416
}
5417

    
5418
function get_interface_ip($interface = "wan") {
5419

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

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

    
5432
	$curip = find_interface_ip($realif);
5433
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5434
		return $curip;
5435
	} else {
5436
		return null;
5437
	}
5438
}
5439

    
5440
function get_interface_ipv6($interface = "wan", $flush = false) {
5441
	global $config;
5442

    
5443
	$realif = get_failover_interface($interface, 'inet6');
5444
	if (!$realif) {
5445
		return null;
5446
	}
5447

    
5448
	if (substr($interface, 0, 4) == '_vip') {
5449
		return get_configured_carp_interface_list($interface, 'inet6', 'ip');
5450
	} else if (substr($interface, 0, 5) == '_lloc') {
5451
		return get_interface_linklocal($interface);
5452
	}
5453

    
5454
	if (is_array($config['interfaces'][$interface])) {
5455
		switch ($config['interfaces'][$interface]['ipaddr']) {
5456
			case 'pppoe':
5457
			case 'l2tp':
5458
			case 'pptp':
5459
			case 'ppp':
5460
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5461
					$realif = get_real_interface($interface, 'inet6', false);
5462
				}
5463
				break;
5464
		}
5465
	}
5466

    
5467
	$curip = find_interface_ipv6($realif, $flush);
5468
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5469
		return $curip;
5470
	} else {
5471
		/*
5472
		 * NOTE: On the case when only the prefix is requested,
5473
		 * the communication on WAN will be done over link-local.
5474
		 */
5475
		if (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
5476
			$curip = find_interface_ipv6_ll($realif, $flush);
5477
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5478
				return $curip;
5479
			}
5480
		}
5481
	}
5482
	return null;
5483
}
5484

    
5485
function get_interface_linklocal($interface = "wan") {
5486

    
5487
	$realif = get_failover_interface($interface, 'inet6');
5488
	if (!$realif) {
5489
		return null;
5490
	}
5491

    
5492
	if (substr($interface, 0, 4) == '_vip') {
5493
		$realif = get_real_interface($interface);
5494
	} else if (substr($interface, 0, 5) == '_lloc') {
5495
		$realif = get_real_interface(substr($interface, 5));
5496
	}
5497

    
5498
	$curip = find_interface_ipv6_ll($realif);
5499
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5500
		return $curip;
5501
	} else {
5502
		return null;
5503
	}
5504
}
5505

    
5506
function get_interface_subnet($interface = "wan") {
5507

    
5508
	if (substr($interface, 0, 4) == '_vip') {
5509
		return get_configured_carp_interface_list($interface, 'inet', 'subnet');
5510
	}
5511

    
5512
	$realif = get_real_interface($interface);
5513
	if (!$realif) {
5514
		return null;
5515
	}
5516

    
5517
	$cursn = find_interface_subnet($realif);
5518
	if (!empty($cursn)) {
5519
		return $cursn;
5520
	}
5521

    
5522
	return null;
5523
}
5524

    
5525
function get_interface_subnetv6($interface = "wan") {
5526

    
5527
	if (substr($interface, 0, 4) == '_vip') {
5528
		return get_configured_carp_interface_list($interface, 'inet6', 'subnet');
5529
	} else if (substr($interface, 0, 5) == '_lloc') {
5530
		$interface = substr($interface, 5);
5531
	}
5532

    
5533
	$realif = get_real_interface($interface, 'inet6');
5534
	if (!$realif) {
5535
		return null;
5536
	}
5537

    
5538
	$cursn = find_interface_subnetv6($realif);
5539
	if (!empty($cursn)) {
5540
		return $cursn;
5541
	}
5542

    
5543
	return null;
5544
}
5545

    
5546
/* return outside interfaces with a gateway */
5547
function get_interfaces_with_gateway() {
5548
	global $config;
5549

    
5550
	$ints = array();
5551

    
5552
	/* loop interfaces, check config for outbound */
5553
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5554
		switch ($ifname['ipaddr']) {
5555
			case "dhcp":
5556
			case "pppoe":
5557
			case "pptp":
5558
			case "l2tp":
5559
			case "ppp":
5560
				$ints[$ifdescr] = $ifdescr;
5561
				break;
5562
			default:
5563
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5564
				    !empty($ifname['gateway'])) {
5565
					$ints[$ifdescr] = $ifdescr;
5566
				}
5567
				break;
5568
		}
5569
	}
5570
	return $ints;
5571
}
5572

    
5573
/* return true if interface has a gateway */
5574
function interface_has_gateway($friendly) {
5575
	global $config;
5576

    
5577
	if (!empty($config['interfaces'][$friendly])) {
5578
		$ifname = &$config['interfaces'][$friendly];
5579
		switch ($ifname['ipaddr']) {
5580
			case "dhcp":
5581
			case "pppoe":
5582
			case "pptp":
5583
			case "l2tp":
5584
			case "ppp":
5585
				return true;
5586
			break;
5587
			default:
5588
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5589
					return true;
5590
				}
5591
				$tunnelif = substr($ifname['if'], 0, 3);
5592
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5593
					if (find_interface_ip($ifname['if'])) {
5594
						return true;
5595
					}
5596
				}
5597
				if (!empty($ifname['gateway'])) {
5598
					return true;
5599
				}
5600
			break;
5601
		}
5602
	}
5603

    
5604
	return false;
5605
}
5606

    
5607
/* return true if interface has a gateway */
5608
function interface_has_gatewayv6($friendly) {
5609
	global $config;
5610

    
5611
	if (!empty($config['interfaces'][$friendly])) {
5612
		$ifname = &$config['interfaces'][$friendly];
5613
		switch ($ifname['ipaddrv6']) {
5614
			case "slaac":
5615
			case "dhcp6":
5616
			case "6to4":
5617
			case "6rd":
5618
				return true;
5619
				break;
5620
			default:
5621
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5622
					return true;
5623
				}
5624
				$tunnelif = substr($ifname['if'], 0, 3);
5625
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5626
					if (find_interface_ipv6($ifname['if'])) {
5627
						return true;
5628
					}
5629
				}
5630
				if (!empty($ifname['gatewayv6'])) {
5631
					return true;
5632
				}
5633
				break;
5634
		}
5635
	}
5636

    
5637
	return false;
5638
}
5639

    
5640
/****f* interfaces/is_altq_capable
5641
 * NAME
5642
 *   is_altq_capable - Test if interface is capable of using ALTQ
5643
 * INPUTS
5644
 *   $int            - string containing interface name
5645
 * RESULT
5646
 *   boolean         - true or false
5647
 ******/
5648

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

    
5663
	$int_family = remove_ifindex($int);
5664

    
5665
	if (in_array($int_family, $capable)) {
5666
		return true;
5667
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5668
		return true;
5669
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5670
		return true;
5671
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5672
		return true;
5673
	} else {
5674
		return false;
5675
	}
5676
}
5677

    
5678
/****f* interfaces/is_interface_wireless
5679
 * NAME
5680
 *   is_interface_wireless - Returns if an interface is wireless
5681
 * RESULT
5682
 *   $tmp       - Returns if an interface is wireless
5683
 ******/
5684
function is_interface_wireless($interface) {
5685
	global $config, $g;
5686

    
5687
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5688
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5689
		if (preg_match($g['wireless_regex'], $interface)) {
5690
			if (isset($config['interfaces'][$friendly])) {
5691
				$config['interfaces'][$friendly]['wireless'] = array();
5692
			}
5693
			return true;
5694
		}
5695
		return false;
5696
	} else {
5697
		return true;
5698
	}
5699
}
5700

    
5701
function get_wireless_modes($interface) {
5702
	/* return wireless modes and channels */
5703
	$wireless_modes = array();
5704

    
5705
	$cloned_interface = get_real_interface($interface);
5706

    
5707
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5708
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5709
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5710
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5711

    
5712
		$interface_channels = "";
5713
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5714
		$interface_channel_count = count($interface_channels);
5715

    
5716
		$c = 0;
5717
		while ($c < $interface_channel_count) {
5718
			$channel_line = explode(",", $interface_channels["$c"]);
5719
			$wireless_mode = trim($channel_line[0]);
5720
			$wireless_channel = trim($channel_line[1]);
5721
			if (trim($wireless_mode) != "") {
5722
				/* if we only have 11g also set 11b channels */
5723
				if ($wireless_mode == "11g") {
5724
					if (!isset($wireless_modes["11b"])) {
5725
						$wireless_modes["11b"] = array();
5726
					}
5727
				} else if ($wireless_mode == "11g ht") {
5728
					if (!isset($wireless_modes["11b"])) {
5729
						$wireless_modes["11b"] = array();
5730
					}
5731
					if (!isset($wireless_modes["11g"])) {
5732
						$wireless_modes["11g"] = array();
5733
					}
5734
					$wireless_mode = "11ng";
5735
				} else if ($wireless_mode == "11a ht") {
5736
					if (!isset($wireless_modes["11a"])) {
5737
						$wireless_modes["11a"] = array();
5738
					}
5739
					$wireless_mode = "11na";
5740
				}
5741
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5742
			}
5743
			$c++;
5744
		}
5745
	}
5746
	return($wireless_modes);
5747
}
5748

    
5749
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5750
function get_wireless_channel_info($interface) {
5751
	$wireless_channels = array();
5752

    
5753
	$cloned_interface = get_real_interface($interface);
5754

    
5755
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5756
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5757
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5758
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5759

    
5760
		$interface_channels = "";
5761
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5762

    
5763
		foreach ($interface_channels as $channel_line) {
5764
			$channel_line = explode(",", $channel_line);
5765
			if (!isset($wireless_channels[$channel_line[0]])) {
5766
				$wireless_channels[$channel_line[0]] = $channel_line;
5767
			}
5768
		}
5769
	}
5770
	return($wireless_channels);
5771
}
5772

    
5773
/****f* interfaces/get_interface_mtu
5774
 * NAME
5775
 *   get_interface_mtu - Return the mtu of an interface
5776
 * RESULT
5777
 *   $tmp       - Returns the mtu of an interface
5778
 ******/
5779
function get_interface_mtu($interface) {
5780
	$mtu = pfSense_interface_getmtu($interface);
5781
	return $mtu['mtu'];
5782
}
5783

    
5784
function get_interface_mac($interface) {
5785

    
5786
	$macinfo = pfSense_get_interface_addresses($interface);
5787
	return $macinfo["macaddr"];
5788
}
5789

    
5790
/****f* pfsense-utils/generate_random_mac_address
5791
 * NAME
5792
 *   generate_random_mac - generates a random mac address
5793
 * INPUTS
5794
 *   none
5795
 * RESULT
5796
 *   $mac - a random mac address
5797
 ******/
5798
function generate_random_mac_address() {
5799
	$mac = "02";
5800
	for ($x = 0; $x < 5; $x++) {
5801
		$mac .= ":" . dechex(rand(16, 255));
5802
	}
5803
	return $mac;
5804
}
5805

    
5806
/****f* interfaces/is_jumbo_capable
5807
 * NAME
5808
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5809
 * INPUTS
5810
 *   $int             - string containing interface name
5811
 * RESULT
5812
 *   boolean          - true or false
5813
 ******/
5814
function is_jumbo_capable($iface) {
5815
	$iface = trim($iface);
5816
	$capable = pfSense_get_interface_addresses($iface);
5817

    
5818
	if (isset($capable['caps']['vlanmtu'])) {
5819
		return true;
5820
	}
5821

    
5822
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5823
	if (substr($iface, 0, 4) == "lagg") {
5824
		return true;
5825
	}
5826

    
5827
	return false;
5828
}
5829

    
5830
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5831
	global $g;
5832

    
5833
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5834

    
5835
	if (!empty($iface) && !empty($pppif)) {
5836
		$cron_cmd = <<<EOD
5837
#!/bin/sh
5838
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5839
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5840

    
5841
EOD;
5842

    
5843
		@file_put_contents($cron_file, $cron_cmd);
5844
		chmod($cron_file, 0755);
5845
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5846
	} else {
5847
		unlink_if_exists($cron_file);
5848
	}
5849
}
5850

    
5851
function get_interface_default_mtu($type = "ethernet") {
5852
	switch ($type) {
5853
		case "gre":
5854
			return 1476;
5855
			break;
5856
		case "gif":
5857
			return 1280;
5858
			break;
5859
		case "tun":
5860
		case "vlan":
5861
		case "tap":
5862
		case "ethernet":
5863
		default:
5864
			return 1500;
5865
			break;
5866
	}
5867

    
5868
	/* Never reached */
5869
	return 1500;
5870
}
5871

    
5872
function get_vip_descr($ipaddress) {
5873
	global $config;
5874

    
5875
	foreach ($config['virtualip']['vip'] as $vip) {
5876
		if ($vip['subnet'] == $ipaddress) {
5877
			return ($vip['descr']);
5878
		}
5879
	}
5880
	return "";
5881
}
5882

    
5883
function interfaces_staticarp_configure($if) {
5884
	global $config, $g;
5885
	if (isset($config['system']['developerspew'])) {
5886
		$mt = microtime();
5887
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5888
	}
5889

    
5890
	$ifcfg = $config['interfaces'][$if];
5891

    
5892
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5893
		return 0;
5894
	}
5895

    
5896
	/* Enable staticarp, if enabled */
5897
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5898
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5899
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5900
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5901
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5902
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5903
			}
5904
		}
5905
	} else {
5906
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5907
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5908
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5909
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5910
				if (isset($arpent['arp_table_static_entry'])) {
5911
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5912
				}
5913
			}
5914
		}
5915
	}
5916

    
5917
	return 0;
5918
}
5919

    
5920
function get_failover_interface($interface, $family = "all") {
5921
	global $config;
5922

    
5923
	/* shortcut to get_real_interface if we find it in the config */
5924
	if (is_array($config['interfaces'][$interface])) {
5925
		return get_real_interface($interface, $family);
5926
	}
5927

    
5928
	/* compare against gateway groups */
5929
	$a_groups = return_gateway_groups_array();
5930
	if (is_array($a_groups[$interface])) {
5931
		/* we found a gateway group, fetch the interface or vip */
5932
		if (!empty($a_groups[$interface][0]['vip'])) {
5933
			return $a_groups[$interface][0]['vip'];
5934
		} else {
5935
			return $a_groups[$interface][0]['int'];
5936
		}
5937
	}
5938
	/* fall through to get_real_interface */
5939
	/* XXX: Really needed? */
5940
	return get_real_interface($interface, $family);
5941
}
5942

    
5943
function remove_ifindex($ifname) {
5944
	return preg_replace("/[0-9]+$/", "", $ifname);
5945
}
5946

    
5947
?>
(25-25/65)