Project

General

Profile

Download (171 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
 * function interfaces_wireless_configure is Copyright (C) 2005 Espen Johansen
55
 *
56
 */
57

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

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

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

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

    
83
	return $interface_arr_cache;
84
}
85

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

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

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

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

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

    
116

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

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

    
139
	return false;
140
}
141

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
269
	interfaces_bring_up($vlanif);
270

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

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

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

    
285
	return $vlanif;
286
}
287

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

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

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

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

    
308
	$vlanif = interface_vlan_configure($vlan);
309

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

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

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

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

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

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

    
364
	return $vlanif;
365
}
366

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

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

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

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

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

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

    
409
	return $vlanif;
410
}
411

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

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

    
419
	$iflist = get_configured_interface_list();
420

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

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

    
444
}
445

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

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

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

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

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

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

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

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

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

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

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

    
549
	$checklist = get_configured_interface_list();
550

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

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

    
572
	interface_bridge_configure_advanced($bridge);
573

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
804
	interfaces_bring_up($laggif);
805

    
806
	return $laggif;
807
}
808

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

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

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

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

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

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

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

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

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

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

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

    
896
	interfaces_bring_up($greif);
897

    
898
	return $greif;
899
}
900

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

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

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

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

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

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

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

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

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

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

    
1032

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

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

    
1047
	interfaces_bring_up($gifif);
1048

    
1049
	return $gifif;
1050
}
1051

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

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

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

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

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

    
1067
	interfaces_qinq_configure();
1068

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

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

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

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

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

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

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

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

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

    
1131
		interface_configure($if, $reload);
1132

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

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

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

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

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

    
1155
		interface_configure($if, $reload);
1156

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

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

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

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

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

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

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

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

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

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

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

    
1205
	return 0;
1206
}
1207

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1432
	return;
1433
}
1434

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

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

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

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

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

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

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

    
1484
	return false;
1485
}
1486

    
1487
function interfaces_ptpid_next() {
1488

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

    
1494
	return $ptpid;
1495
}
1496

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

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

    
1509
	return NULL;
1510
}
1511

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

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

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

    
1522
	$itemhash = getMPDCRONSettings($pppif);
1523

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

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

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

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

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

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

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

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

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

    
1685
				if (!is_ipaddr($localips[$pid])) {
1686
					log_error(sprintf(gettext("Could not get a Local IP address for PPTP/L2TP link on %s in interfaces_ppps_configure. Using 0.0.0.0 ip!"), $port));
1687
					$localips[$pid] = "0.0.0.0";
1688
				}
1689
				if (!is_ipaddr($gateways[$pid])) {
1690
					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));
1691
					return 0;
1692
				}
1693
				pfSense_ngctl_attach(".", $port);
1694
				break;
1695
			case "ppp":
1696
				if (!file_exists("{$port}")) {
1697
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1698
					return 0;
1699
				}
1700
				break;
1701
			default:
1702
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1703
				break;
1704
		}
1705
	}
1706

    
1707
	if (is_array($ports) && count($ports) > 1) {
1708
		$multilink = "enable";
1709
	} else {
1710
		$multilink = "disable";
1711
	}
1712

    
1713
	if ($type == "modem") {
1714
		if (is_ipaddr($ppp['localip'])) {
1715
			$localip = $ppp['localip'];
1716
		} else {
1717
			$localip = '0.0.0.0';
1718
		}
1719

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

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

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

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

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

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

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

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

    
1797
/* Omit this, we maintain the default route by other means, and it causes problems with
1798
 * default gateway switching. See redmine #1837
1799
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1800
		$setdefaultgw = true;
1801
		$mpdconf .= <<<EOD
1802
	set iface route default
1803

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

    
1811
EOD;
1812

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

    
1817
EOD;
1818
	}
1819

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

    
1828
EOD;
1829

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

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

    
1840
EOD;
1841
	}
1842

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

    
1848
EOD;
1849
	}
1850

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

    
1855
EOD;
1856
	}
1857

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

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

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

    
1873
EOD;
1874
		}
1875

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

    
1880
EOD;
1881
		}
1882

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

    
1887
EOD;
1888
		}
1889

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

    
1895
EOD;
1896

    
1897

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

    
1902
EOD;
1903
		}
1904

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

    
1918
EOD;
1919
		}
1920

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

    
1925
EOD;
1926
		}
1927

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

    
1932
EOD;
1933
		}
1934

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

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

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

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

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

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

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

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

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

    
1999
EOD;
2000
		}
2001

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

    
2007
EOD;
2008
		}
2009

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

    
2013

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

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

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

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

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

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

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

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

    
2124
	return 1;
2125
}
2126

    
2127
function interfaces_sync_setup() {
2128
	global $g, $config;
2129

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

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

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

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

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

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

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

    
2172
		sleep(1);
2173

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

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

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

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

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

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

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

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

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

    
2239
				$paa[$proxyif][] = $vipent;
2240
			}
2241
		}
2242
	}
2243

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

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

    
2282
	if (is_array($config['virtualip']['vip'])) {
2283
		foreach ($config['virtualip']['vip'] as $vip) {
2284

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

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

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

    
2359
function interface_ipalias_configure(&$vip) {
2360
	global $config;
2361

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

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

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

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

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

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

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

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

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

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

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

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

    
2437
	return $realif;
2438
}
2439

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

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

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

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

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

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

    
2515
	$baseif = interface_get_wireless_base($ifcfg['if']);
2516

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

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

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

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

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

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

    
2592
	// Clone wireless nic if needed.
2593
	interface_wireless_clone($if, $wl);
2594

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2739
	kill_hostapd($if);
2740
	mwexec(kill_wpasupplicant("{$if}"));
2741

    
2742
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2743
	conf_mount_rw();
2744

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

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

    
2798
EOD;
2799

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

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

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

    
2818
auth_server_addr={$wlcfg['auth_server_addr']}
2819
auth_server_port={$auth_server_port}
2820
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2821

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

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

    
2834
EOD;
2835
						}
2836
					}
2837
				}
2838

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

    
2845
	/*
2846
	 *    all variables are set, lets start up everything
2847
	 */
2848

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

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

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

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

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

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

    
2898
	fclose($fd_set);
2899
	conf_mount_ro();
2900

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

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

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

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

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

    
2938
		$wlregcmd_args = implode(" ", $wlregcmd);
2939

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

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

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

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

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

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

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

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

    
3001
	unset($wlcmd_args, $wlcmd);
3002

    
3003

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

    
3008
	return 0;
3009

    
3010
}
3011

    
3012
function kill_hostapd($interface) {
3013
	global $g;
3014

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

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

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

    
3031
	return intval($pid);
3032
}
3033

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

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

    
3050
function find_dhcp6c_process($interface) {
3051
	global $g;
3052

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

    
3059
	return intval($pid);
3060
}
3061

    
3062
function interface_virtual_create($interface) {
3063
	global $config;
3064

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

    
3104
function interface_vlan_mtu_configured($iface) {
3105
	global $config;
3106

    
3107
	$mtu = 0;
3108
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3109
		foreach ($config['vlans']['vlan'] as $vlan) {
3110

    
3111
			if ($vlan['vlanif'] != $iface)
3112
				continue;
3113

    
3114
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3115
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3116
				/* VLAN MTU */
3117
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3118
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3119
				/* Parent MTU */
3120
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3121
			}
3122
		}
3123
	}
3124

    
3125
	return $mtu;
3126
}
3127

    
3128
function interface_mtu_wanted_for_pppoe($realif) {
3129
	global $config;
3130

    
3131
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3132
		return 0;
3133

    
3134
	$mtu = 0;
3135
	foreach ($config['ppps']['ppp'] as $ppp) {
3136
		if ($ppp['type'] != "pppoe") {
3137
			continue;
3138
		}
3139

    
3140
		$mtus = array();
3141
		if (!empty($ppp['mtu'])) {
3142
			$mtus = explode(',', $ppp['mtu']);
3143
		}
3144
		$ports = explode(',', $ppp['ports']);
3145

    
3146
		foreach ($ports as $pid => $port) {
3147
			$parentifa = get_parent_interface($port);
3148
			$parentif = $parentifa[0];
3149
			if ($parentif != $realif)
3150
				continue;
3151

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

    
3168
	return $mtu;
3169
}
3170

    
3171
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3172
	global $config, $g;
3173
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3174
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3175

    
3176
	$wancfg = $config['interfaces'][$interface];
3177

    
3178
	if (!isset($wancfg['enable'])) {
3179
		return;
3180
	}
3181

    
3182
	$realif = get_real_interface($interface);
3183
	$realhwif_array = get_parent_interface($interface);
3184
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3185
	$realhwif = $realhwif_array[0];
3186

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

    
3208
		/* only bring down the interface when both v4 and v6 are set to NONE */
3209
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3210
			interface_bring_down($interface);
3211
		}
3212
	}
3213

    
3214
	$interface_to_check = $realif;
3215
	if (interface_isppp_type($interface)) {
3216
		$interface_to_check = $realhwif;
3217
	}
3218

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

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

    
3230
	/* wireless configuration? */
3231
	if (is_array($wancfg['wireless'])) {
3232
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3233
	}
3234

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

    
3247
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3248
			/*   this is not a valid mac address.  generate a
3249
			 *   temporary mac address so the machine can get online.
3250
			 */
3251
			echo gettext("Generating new MAC address.");
3252
			$random_mac = generate_random_mac_address();
3253
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3254
				" link " . escapeshellarg($random_mac));
3255
			$wancfg['spoofmac'] = $random_mac;
3256
			write_config();
3257
			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");
3258
		}
3259
	}
3260

    
3261
	/* media */
3262
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3263
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3264
		if ($wancfg['media']) {
3265
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3266
		}
3267
		if ($wancfg['mediaopt']) {
3268
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3269
		}
3270
		mwexec($cmd);
3271
	}
3272

    
3273
	/* Apply hw offloading policies as configured */
3274
	enable_hardware_offloading($interface);
3275

    
3276
	/* invalidate interface/ip/sn cache */
3277
	get_interface_arr(true);
3278
	unset($interface_ip_arr_cache[$realif]);
3279
	unset($interface_sn_arr_cache[$realif]);
3280
	unset($interface_ipv6_arr_cache[$realif]);
3281
	unset($interface_snv6_arr_cache[$realif]);
3282

    
3283
	$tunnelif = substr($realif, 0, 3);
3284

    
3285
	$mtuif = $realif;
3286
	$mtuhwif = $realhwif;
3287

    
3288
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3289
	if (interface_isppp_type($interface)) {
3290
		$mtuif = $realhwif;
3291
		$mtuhwif_array = get_parent_interface($mtuif);
3292
		$mtuhwif = $mtuhwif_array[0];
3293
	}
3294

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

    
3305
	/* MTU is not specified for interface, try the pppoe settings. */
3306
	if ($wantedmtu == 0) {
3307
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3308
	}
3309
	if ($wantedmtu == 0 && stristr($mtuif, "_vlan") && interface_isppp_type($interface)) {
3310
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3311
	}
3312

    
3313
	/* Set the MTU to 1500 if no explicit MTU configured. */
3314
	if ($wantedmtu == 0) {
3315
		$wantedmtu = 1500; /* Default */
3316
	}
3317

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

    
3327
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3328

    
3329
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3330
			$configuredmtu = $parentmtu;
3331
		if ($configuredmtu != 0)
3332
			$mtu = $configuredmtu;
3333
		else
3334
			$mtu = $wantedmtu;
3335

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

    
3361
	if (does_interface_exist($wancfg['if'])) {
3362
		interfaces_bring_up($wancfg['if']);
3363
	}
3364

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

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

    
3416
	interface_netgraph_needed($interface);
3417

    
3418
	if (!platform_booting()) {
3419
		link_interface_to_vips($interface, "update");
3420

    
3421
		if ($tunnelif != 'gre') {
3422
			unset($gre);
3423
			$gre = link_interface_to_gre($interface);
3424
			if (!empty($gre)) {
3425
				array_walk($gre, 'interface_gre_configure');
3426
			}
3427
		}
3428

    
3429
		if ($tunnelif != 'gif') {
3430
			unset($gif);
3431
			$gif = link_interface_to_gif ($interface);
3432
			if (!empty($gif)) {
3433
				array_walk($gif, 'interface_gif_configure');
3434
			}
3435
		}
3436

    
3437
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3438
			unset($bridgetmp);
3439
			$bridgetmp = link_interface_to_bridge($interface);
3440
			if (!empty($bridgetmp)) {
3441
				interface_bridge_add_member($bridgetmp, $realif);
3442
			}
3443
		}
3444

    
3445
		$grouptmp = link_interface_to_group($interface);
3446
		if (!empty($grouptmp)) {
3447
			array_walk($grouptmp, 'interface_group_add_member');
3448
		}
3449

    
3450
		if ($interface == "lan") {
3451
			/* make new hosts file */
3452
			system_hosts_generate();
3453
		}
3454

    
3455
		if ($reloadall == true) {
3456

    
3457
			/* reconfigure static routes (kernel may have deleted them) */
3458
			system_routing_configure($interface);
3459

    
3460
			/* reload ipsec tunnels */
3461
			send_event("service reload ipsecdns");
3462

    
3463
			if (isset($config['dnsmasq']['enable'])) {
3464
				services_dnsmasq_configure();
3465
			}
3466

    
3467
			if (isset($config['unbound']['enable'])) {
3468
				services_unbound_configure();
3469
			}
3470

    
3471
			/* update dyndns */
3472
			send_event("service reload dyndns {$interface}");
3473

    
3474
			/* reload captive portal */
3475
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3476
				require_once('captiveportal.inc');
3477
			}
3478
			captiveportal_init_rules_byinterface($interface);
3479
		}
3480
	}
3481

    
3482
	interfaces_staticarp_configure($interface);
3483
	return 0;
3484
}
3485

    
3486
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3487
	global $config, $g;
3488

    
3489
	if (!is_array($wancfg)) {
3490
		return;
3491
	}
3492

    
3493
	if (!isset($wancfg['enable'])) {
3494
		return;
3495
	}
3496

    
3497
	/* If the interface is not configured via another, exit */
3498
	if (empty($wancfg['track6-interface'])) {
3499
		return;
3500
	}
3501

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

    
3512
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3513
	if (!isset($trackcfg['enable'])) {
3514
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
3515
		return;
3516
	}
3517

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

    
3548
	if ($linkupevent == false && !platform_booting()) {
3549
		if (!function_exists('services_dhcpd_configure')) {
3550
			require_once("services.inc");
3551
		}
3552

    
3553
		if (isset($config['unbound']['enable'])) {
3554
			services_unbound_configure();
3555
		}
3556

    
3557
		if (isset($config['dnsmasq']['enable'])) {
3558
			services_dnsmasq_configure();
3559
		}
3560

    
3561
		services_dhcpd_configure("inet6");
3562
	}
3563

    
3564
	return 0;
3565
}
3566

    
3567
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3568
	global $config, $g;
3569
	global $interface_ipv6_arr_cache;
3570
	global $interface_snv6_arr_cache;
3571

    
3572
	if (!is_array($lancfg)) {
3573
		return;
3574
	}
3575

    
3576
	/* If the interface is not configured via another, exit */
3577
	if (empty($lancfg['track6-interface'])) {
3578
		return;
3579
	}
3580

    
3581
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3582
	if (empty($wancfg)) {
3583
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3584
		return;
3585
	}
3586

    
3587
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3588
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3589
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not valid, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
3590
		return;
3591
	}
3592
	$hexwanv4 = return_hex_ipv4($ip4address);
3593

    
3594
	/* create the long prefix notation for math, save the prefix length */
3595
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3596
	$rd6prefixlen = $rd6prefix[1];
3597
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3598

    
3599
	/* binary presentation of the prefix for all 128 bits. */
3600
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3601

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

    
3607
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3608
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3609
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3610
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3611
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3612
	/* fill the rest out with zeros */
3613
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3614

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

    
3618
	$lanif = get_real_interface($interface);
3619
	$oip = find_interface_ipv6($lanif);
3620
	if (is_ipaddrv6($oip)) {
3621
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3622
	}
3623
	unset($interface_ipv6_arr_cache[$lanif]);
3624
	unset($interface_snv6_arr_cache[$lanif]);
3625
	log_error(sprintf(gettext('rd6 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $rd6lan, $lancfg['track6-interface'], $ip4address));
3626
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3627

    
3628
	return 0;
3629
}
3630

    
3631
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3632
	global $config, $g;
3633
	global $interface_ipv6_arr_cache;
3634
	global $interface_snv6_arr_cache;
3635

    
3636
	if (!is_array($lancfg)) {
3637
		return;
3638
	}
3639

    
3640
	/* If the interface is not configured via another, exit */
3641
	if (empty($lancfg['track6-interface'])) {
3642
		return;
3643
	}
3644

    
3645
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3646
	if (empty($wancfg)) {
3647
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3648
		return;
3649
	}
3650

    
3651
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3652
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3653
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
3654
		return;
3655
	}
3656
	$hexwanv4 = return_hex_ipv4($ip4address);
3657

    
3658
	/* create the long prefix notation for math, save the prefix length */
3659
	$sixto4prefix = "2002::";
3660
	$sixto4prefixlen = 16;
3661
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3662

    
3663
	/* binary presentation of the prefix for all 128 bits. */
3664
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3665

    
3666
	/* just save the left prefix length bits */
3667
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3668
	/* add the v4 address */
3669
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3670
	/* add the custom prefix id */
3671
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3672
	/* fill the rest out with zeros */
3673
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3674

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

    
3678
	$lanif = get_real_interface($interface);
3679
	$oip = find_interface_ipv6($lanif);
3680
	if (is_ipaddrv6($oip)) {
3681
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3682
	}
3683
	unset($interface_ipv6_arr_cache[$lanif]);
3684
	unset($interface_snv6_arr_cache[$lanif]);
3685
	log_error(sprintf(gettext('sixto4 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $sixto4lan, $lancfg['track6-interface'], $ip4address));
3686
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3687

    
3688
	return 0;
3689
}
3690

    
3691
function interface_6rd_configure($interface = "wan", $wancfg) {
3692
	global $config, $g;
3693

    
3694
	/* because this is a tunnel interface we can only function
3695
	 *	with a public IPv4 address on the interface */
3696

    
3697
	if (!is_array($wancfg)) {
3698
		return;
3699
	}
3700

    
3701
	if (!is_module_loaded('if_stf.ko')) {
3702
		mwexec('/sbin/kldload if_stf.ko');
3703
	}
3704

    
3705
	$wanif = get_real_interface($interface);
3706
	$ip4address = find_interface_ip($wanif);
3707
	if (!is_ipaddrv4($ip4address)) {
3708
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3709
		return false;
3710
	}
3711
	$hexwanv4 = return_hex_ipv4($ip4address);
3712

    
3713
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3714
		$wancfg['prefix-6rd-v4plen'] = 0;
3715
	}
3716

    
3717
	/* create the long prefix notation for math, save the prefix length */
3718
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3719
	$rd6prefixlen = $rd6prefix[1];
3720
	$brgw = explode('.', $wancfg['gateway-6rd']);
3721
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3722
	$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);
3723
	if (strlen($rd6brgw) < 128) {
3724
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3725
	}
3726
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3727
	unset($brgw);
3728
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3729

    
3730
	/* binary presentation of the prefix for all 128 bits. */
3731
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3732

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

    
3740
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3741
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3742

    
3743

    
3744
	/* XXX: need to extend to support variable prefix size for v4 */
3745
	if (!is_module_loaded("if_stf")) {
3746
		mwexec("/sbin/kldload if_stf.ko");
3747
	}
3748
	$stfiface = "{$interface}_stf";
3749
	if (does_interface_exist($stfiface)) {
3750
		pfSense_interface_destroy($stfiface);
3751
	}
3752
	$tmpstfiface = pfSense_interface_create("stf");
3753
	pfSense_interface_rename($tmpstfiface, $stfiface);
3754
	pfSense_interface_flags($stfiface, IFF_LINK2);
3755
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3756
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3757
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3758
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3759
	}
3760
	if ($g['debug']) {
3761
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3762
	}
3763

    
3764
	/* write out a default router file */
3765
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3766
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3767

    
3768
	$ip4gateway = get_interface_gateway($interface);
3769
	if (is_ipaddrv4($ip4gateway)) {
3770
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3771
	}
3772

    
3773
	/* configure dependent interfaces */
3774
	if (!platform_booting()) {
3775
		link_interface_to_track6($interface, "update");
3776
	}
3777

    
3778
	return 0;
3779
}
3780

    
3781
function interface_6to4_configure($interface = "wan", $wancfg) {
3782
	global $config, $g;
3783

    
3784
	/* because this is a tunnel interface we can only function
3785
	 *	with a public IPv4 address on the interface */
3786

    
3787
	if (!is_array($wancfg)) {
3788
		return;
3789
	}
3790

    
3791
	$wanif = get_real_interface($interface);
3792
	$ip4address = find_interface_ip($wanif);
3793
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3794
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3795
		return false;
3796
	}
3797

    
3798
	/* create the long prefix notation for math, save the prefix length */
3799
	$stfprefixlen = 16;
3800
	$stfprefix = Net_IPv6::uncompress("2002::");
3801
	$stfarr = explode(":", $stfprefix);
3802
	$v4prefixlen = "0";
3803

    
3804
	/* we need the hex form of the interface IPv4 address */
3805
	$ip4arr = explode(".", $ip4address);
3806
	$hexwanv4 = "";
3807
	foreach ($ip4arr as $octet) {
3808
		$hexwanv4 .= sprintf("%02x", $octet);
3809
	}
3810

    
3811
	/* we need the hex form of the broker IPv4 address */
3812
	$ip4arr = explode(".", "192.88.99.1");
3813
	$hexbrv4 = "";
3814
	foreach ($ip4arr as $octet) {
3815
		$hexbrv4 .= sprintf("%02x", $octet);
3816
	}
3817

    
3818
	/* binary presentation of the prefix for all 128 bits. */
3819
	$stfprefixbin = "";
3820
	foreach ($stfarr as $element) {
3821
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3822
	}
3823
	/* just save the left prefix length bits */
3824
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3825

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

    
3830
	/* for the local subnet too. */
3831
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3832
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3833

    
3834
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3835
	$stfbrarr = array();
3836
	$stfbrbinarr = array();
3837
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3838
	foreach ($stfbrbinarr as $bin) {
3839
		$stfbrarr[] = dechex(bindec($bin));
3840
	}
3841
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3842

    
3843
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3844
	$stflanarr = array();
3845
	$stflanbinarr = array();
3846
	$stflanbinarr = str_split($stflanbin, 16);
3847
	foreach ($stflanbinarr as $bin) {
3848
		$stflanarr[] = dechex(bindec($bin));
3849
	}
3850
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3851
	$stflanarr[7] = 1;
3852
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3853

    
3854
	/* setup the stf interface */
3855
	if (!is_module_loaded("if_stf")) {
3856
		mwexec("/sbin/kldload if_stf.ko");
3857
	}
3858
	$stfiface = "{$interface}_stf";
3859
	if (does_interface_exist($stfiface)) {
3860
		pfSense_interface_destroy($stfiface);
3861
	}
3862
	$tmpstfiface = pfSense_interface_create("stf");
3863
	pfSense_interface_rename($tmpstfiface, $stfiface);
3864
	pfSense_interface_flags($stfiface, IFF_LINK2);
3865
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3866

    
3867
	if ($g['debug']) {
3868
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3869
	}
3870

    
3871
	/* write out a default router file */
3872
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3873
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3874

    
3875
	$ip4gateway = get_interface_gateway($interface);
3876
	if (is_ipaddrv4($ip4gateway)) {
3877
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3878
	}
3879

    
3880
	if (!platform_booting()) {
3881
		link_interface_to_track6($interface, "update");
3882
	}
3883

    
3884
	return 0;
3885
}
3886

    
3887
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3888
	global $config, $g;
3889

    
3890
	if (!is_array($wancfg)) {
3891
		return;
3892
	}
3893

    
3894
	$wanif = get_real_interface($interface, "inet6");
3895
	$dhcp6cconf = "";
3896

    
3897
	if ($wancfg['adv_dhcp6_config_file_override']) {
3898
		// DHCP6 Config File Override
3899
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3900
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3901
		// DHCP6 Config File Advanced
3902
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3903
	} else {
3904
		// DHCP6 Config File Basic
3905
		$dhcp6cconf .= "interface {$wanif} {\n";
3906

    
3907
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3908
		if ($wancfg['ipaddrv6'] == "slaac") {
3909
			$dhcp6cconf .= "\tinformation-only;\n";
3910
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3911
			$dhcp6cconf .= "\trequest domain-name;\n";
3912
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3913
			$dhcp6cconf .= "};\n";
3914
		} else {
3915
			$trackiflist = array();
3916
			$iflist = link_interface_to_track6($interface);
3917
			foreach ($iflist as $ifname => $ifcfg) {
3918
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3919
					$trackiflist[$ifname] = $ifcfg;
3920
				}
3921
			}
3922

    
3923
			/* skip address request if this is set */
3924
			if (!isset($wancfg['dhcp6prefixonly'])) {
3925
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3926
			}
3927
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3928
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3929
			}
3930

    
3931
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3932
			$dhcp6cconf .= "\trequest domain-name;\n";
3933
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3934
			$dhcp6cconf .= "};\n";
3935

    
3936
			if (!isset($wancfg['dhcp6prefixonly'])) {
3937
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3938
			}
3939

    
3940
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3941
				/* Setup the prefix delegation */
3942
				$dhcp6cconf .= "id-assoc pd 0 {\n";
3943
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3944
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
3945
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
3946
				}
3947
				foreach ($trackiflist as $friendly => $ifcfg) {
3948
					if ($g['debug']) {
3949
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3950
					}
3951
					$realif = get_real_interface($friendly);
3952
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
3953
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
3954
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3955
					$dhcp6cconf .= "\t};\n";
3956
				}
3957
				unset($preflen, $iflist, $ifcfg, $ifname);
3958
				$dhcp6cconf .= "};\n";
3959
			}
3960
			unset($trackiflist);
3961
		}
3962
	}
3963

    
3964
	/* wide-dhcp6c works for now. */
3965
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3966
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3967
		unset($dhcp6cconf);
3968
		return 1;
3969
	}
3970
	unset($dhcp6cconf);
3971

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

    
3986
	$rtsoldscript = "#!/bin/sh\n";
3987
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3988
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3989
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3990
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Recieved RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
3991
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3992
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3993
	$rtsoldscript .= "\t/bin/sleep 1\n";
3994
	$rtsoldscript .= "fi\n";
3995
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3996
	$rtsoldscript .= "/usr/local/sbin/dhcp6c {$debugOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3997
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3998
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3999
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4000
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4001
		unset($rtsoldscript);
4002
		return 1;
4003
	}
4004
	unset($rtsoldscript);
4005
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4006

    
4007
	/* accept router advertisements for this interface */
4008
	log_error("Accept router advertisements on interface {$wanif} ");
4009
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4010

    
4011
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
4012
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4013
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4014
		sleep(2);
4015
	}
4016
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
4017

    
4018
	/* NOTE: will be called from rtsold invoked script
4019
	 * link_interface_to_track6($interface, "update");
4020
	 */
4021

    
4022
	return 0;
4023
}
4024

    
4025
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4026
	global $g;
4027

    
4028
	$send_options = "";
4029
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4030
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_send_options']);
4031
		foreach ($options as $option) {
4032
			$send_options .= "\tsend " . trim($option) . ";\n";
4033
		}
4034
	}
4035

    
4036
	$request_options = "";
4037
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4038
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_request_options']);
4039
		foreach ($options as $option) {
4040
			$request_options .= "\trequest " . trim($option) . ";\n";
4041
		}
4042
	}
4043

    
4044
	$information_only = "";
4045
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4046
		$information_only = "\tinformation-only;\n";
4047
	}
4048

    
4049
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4050
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4051
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4052
	}
4053

    
4054
	$interface_statement  = "interface";
4055
	$interface_statement .= " {$wanif}";
4056
	$interface_statement .= " {\n";
4057
	$interface_statement .= "$send_options";
4058
	$interface_statement .= "$request_options";
4059
	$interface_statement .= "$information_only";
4060
	$interface_statement .= "$script";
4061
	$interface_statement .= "};\n";
4062

    
4063
	$id_assoc_statement_address = "";
4064
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4065
		$id_assoc_statement_address .= "id-assoc";
4066
		$id_assoc_statement_address .= " na";
4067
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4068
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4069
		}
4070
		$id_assoc_statement_address .= " { ";
4071

    
4072
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4073
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4074
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4075
			$id_assoc_statement_address .= "\n\taddress";
4076
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4077
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4078
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4079
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4080
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4081
			}
4082
			$id_assoc_statement_address .= ";\n";
4083
		}
4084

    
4085
		$id_assoc_statement_address .= "};\n";
4086
	}
4087

    
4088
	$id_assoc_statement_prefix = "";
4089
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4090
		$id_assoc_statement_prefix .= "id-assoc";
4091
		$id_assoc_statement_prefix .= " pd";
4092
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4093
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4094
		}
4095
		$id_assoc_statement_prefix .= " { ";
4096

    
4097
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4098
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4099
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4100
			$id_assoc_statement_prefix .= "\n\tprefix";
4101
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4102
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4103
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4104
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4105
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4106
			}
4107
			$id_assoc_statement_prefix .= ";";
4108
		}
4109

    
4110
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4111
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4112
			$id_assoc_statement_prefix .= " {$wanif}";
4113
			$id_assoc_statement_prefix .= " {\n";
4114
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4115
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4116
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4117
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4118
			}
4119
			$id_assoc_statement_prefix .= "\t};";
4120
		}
4121

    
4122
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4123
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4124
			$id_assoc_statement_prefix .= "\n";
4125
		}
4126

    
4127
		$id_assoc_statement_prefix .= "};\n";
4128
	}
4129

    
4130
	$authentication_statement = "";
4131
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4132
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4133
		$authentication_statement .= "authentication";
4134
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4135
		$authentication_statement .= " {\n";
4136
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4137
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4138
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4139
		}
4140
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4141
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4142
		}
4143
		$authentication_statement .= "};\n";
4144
	}
4145

    
4146
	$key_info_statement = "";
4147
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4148
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4149
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4150
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4151
		$key_info_statement .= "keyinfo";
4152
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4153
		$key_info_statement .= " {\n";
4154
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4155
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4156
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4157
		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'])) {
4158
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4159
		}
4160
		$key_info_statement .= "};\n";
4161
	}
4162

    
4163
	$dhcp6cconf  = $interface_statement;
4164
	$dhcp6cconf .= $id_assoc_statement_address;
4165
	$dhcp6cconf .= $id_assoc_statement_prefix;
4166
	$dhcp6cconf .= $authentication_statement;
4167
	$dhcp6cconf .= $key_info_statement;
4168

    
4169
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4170

    
4171
	return $dhcp6cconf;
4172
}
4173

    
4174

    
4175
function DHCP6_Config_File_Override($wancfg, $wanif) {
4176

    
4177
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4178

    
4179
	if ($dhcp6cconf === false) {
4180
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4181
		return '';
4182
	} else {
4183
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4184
	}
4185
}
4186

    
4187

    
4188
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4189

    
4190
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4191

    
4192
	return $dhcp6cconf;
4193
}
4194

    
4195

    
4196
function interface_dhcp_configure($interface = "wan") {
4197
	global $config, $g;
4198

    
4199
	$wancfg = $config['interfaces'][$interface];
4200
	$wanif = $wancfg['if'];
4201
	if (empty($wancfg)) {
4202
		$wancfg = array();
4203
	}
4204

    
4205
	/* generate dhclient_wan.conf */
4206
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4207
	if (!$fd) {
4208
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4209
		return 1;
4210
	}
4211

    
4212
	if ($wancfg['dhcphostname']) {
4213
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4214
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4215
	} else {
4216
		$dhclientconf_hostname = "";
4217
	}
4218

    
4219
	$wanif = get_real_interface($interface);
4220
	if (empty($wanif)) {
4221
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4222
		return 0;
4223
	}
4224
	$dhclientconf = "";
4225

    
4226
	$dhclientconf .= <<<EOD
4227
interface "{$wanif}" {
4228
timeout 60;
4229
retry 15;
4230
select-timeout 0;
4231
initial-interval 1;
4232
	{$dhclientconf_hostname}
4233
	script "/sbin/dhclient-script";
4234
EOD;
4235

    
4236
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4237
		$dhclientconf .= <<<EOD
4238

    
4239
	reject {$wancfg['dhcprejectfrom']};
4240
EOD;
4241
	}
4242
	$dhclientconf .= <<<EOD
4243

    
4244
}
4245

    
4246
EOD;
4247

    
4248
	// DHCP Config File Advanced
4249
	if ($wancfg['adv_dhcp_config_advanced']) {
4250
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4251
	}
4252

    
4253
	if (is_ipaddr($wancfg['alias-address'])) {
4254
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4255
		$dhclientconf .= <<<EOD
4256
alias {
4257
	interface "{$wanif}";
4258
	fixed-address {$wancfg['alias-address']};
4259
	option subnet-mask {$subnetmask};
4260
}
4261

    
4262
EOD;
4263
	}
4264

    
4265
	// DHCP Config File Override
4266
	if ($wancfg['adv_dhcp_config_file_override']) {
4267
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4268
	}
4269

    
4270
	fwrite($fd, $dhclientconf);
4271
	fclose($fd);
4272

    
4273
	/* bring wan interface up before starting dhclient */
4274
	if ($wanif) {
4275
		interfaces_bring_up($wanif);
4276
	} else {
4277
		log_error(sprintf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4278
	}
4279

    
4280
	/* Make sure dhclient is not running */
4281
	kill_dhclient_process($wanif);
4282

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

    
4286
	return 0;
4287
}
4288

    
4289
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4290

    
4291
	$hostname = "";
4292
	if ($wancfg['dhcphostname'] != '') {
4293
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4294
	}
4295

    
4296
	/* DHCP Protocol Timings */
4297
	$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");
4298
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4299
		$pt_variable = "{$Protocol_Timing}";
4300
		${$pt_variable} = "";
4301
		if ($wancfg[$Protocol_Timing] != "") {
4302
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4303
		}
4304
	}
4305

    
4306
	$send_options = "";
4307
	if ($wancfg['adv_dhcp_send_options'] != '') {
4308
		$options = explode(',', $wancfg['adv_dhcp_send_options']);
4309
		foreach ($options as $option) {
4310
			$send_options .= "\tsend " . trim($option) . ";\n";
4311
		}
4312
	}
4313

    
4314
	$request_options = "";
4315
	if ($wancfg['adv_dhcp_request_options'] != '') {
4316
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4317
	}
4318

    
4319
	$required_options = "";
4320
	if ($wancfg['adv_dhcp_required_options'] != '') {
4321
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4322
	}
4323

    
4324
	$option_modifiers = "";
4325
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4326
		$modifiers = explode(',', $wancfg['adv_dhcp_option_modifiers']);
4327
		foreach ($modifiers as $modifier) {
4328
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4329
		}
4330
	}
4331

    
4332
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4333
	$dhclientconf .= "\n";
4334
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4335
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4336
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4337
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4338
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4339
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4340
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4341
	$dhclientconf .= "\n";
4342
	$dhclientconf .= "# DHCP Protocol Options\n";
4343
	$dhclientconf .= "{$hostname}";
4344
	$dhclientconf .= "{$send_options}";
4345
	$dhclientconf .= "{$request_options}";
4346
	$dhclientconf .= "{$required_options}";
4347
	$dhclientconf .= "{$option_modifiers}";
4348
	$dhclientconf .= "\n";
4349
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4350
		$dhclientconf .= "reject {$wancfg['dhcprejectfrom']};\n";
4351
	}
4352
	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4353
	$dhclientconf .= "}\n";
4354

    
4355
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4356

    
4357
	return $dhclientconf;
4358
}
4359

    
4360

    
4361
function DHCP_Config_File_Override($wancfg, $wanif) {
4362

    
4363
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4364

    
4365
	if ($dhclientconf === false) {
4366
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading.\n"), $wancfg['adv_dhcp_config_file_override_path']));
4367
		return '';
4368
	} else {
4369
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4370
	}
4371
}
4372

    
4373

    
4374
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4375

    
4376
	/* Apply Interface Substitutions */
4377
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4378

    
4379
	/* Apply Hostname Substitutions */
4380
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4381

    
4382
	/* Arrays of MAC Address Types, Cases, Delimiters */
4383
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4384
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4385
	$various_mac_cases      = array("U", "L");
4386
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4387

    
4388
	/* Apply MAC Address Substitutions */
4389
	foreach ($various_mac_types as $various_mac_type) {
4390
		foreach ($various_mac_cases as $various_mac_case) {
4391
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4392

    
4393
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4394
				if ($res !== false) {
4395

    
4396
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4397
					if ("$various_mac_case" == "U") {
4398
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4399
					}
4400
					if ("$various_mac_case" == "L") {
4401
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4402
					}
4403

    
4404
					if ("$various_mac_type" == "mac_addr_hex") {
4405
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4406
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4407
						$dhcpclientconf_mac_hex = "";
4408
						$delimiter = "";
4409
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4410
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4411
							$delimiter = ":";
4412
						}
4413
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4414
					}
4415

    
4416
					/* MAC Address Delimiter Substitutions */
4417
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4418

    
4419
					/* Apply MAC Address Substitutions */
4420
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4421
				}
4422
			}
4423
		}
4424
	}
4425

    
4426
	return $dhclientconf;
4427
}
4428

    
4429
function interfaces_group_setup() {
4430
	global $config;
4431

    
4432
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4433
		return;
4434
	}
4435

    
4436
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4437
		interface_group_setup($groupar);
4438
	}
4439

    
4440
	return;
4441
}
4442

    
4443
function interface_group_setup(&$groupname /* The parameter is an array */) {
4444
	global $config;
4445

    
4446
	if (!is_array($groupname)) {
4447
		return;
4448
	}
4449
	$members = explode(" ", $groupname['members']);
4450
	foreach ($members as $ifs) {
4451
		$realif = get_real_interface($ifs);
4452
		if ($realif && does_interface_exist($realif)) {
4453
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4454
		}
4455
	}
4456

    
4457
	return;
4458
}
4459

    
4460
function is_interface_group($if) {
4461
	global $config;
4462

    
4463
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4464
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4465
			if ($groupentry['ifname'] === $if) {
4466
				return true;
4467
			}
4468
		}
4469
	}
4470

    
4471
	return false;
4472
}
4473

    
4474
function interface_group_add_member($interface, $groupname) {
4475
	$interface = get_real_interface($interface);
4476
	if (does_interface_exist($interface)) {
4477
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4478
	}
4479
}
4480

    
4481
/* COMPAT Function */
4482
function convert_friendly_interface_to_real_interface_name($interface) {
4483
	return get_real_interface($interface);
4484
}
4485

    
4486
/* COMPAT Function */
4487
function get_real_wan_interface($interface = "wan") {
4488
	return get_real_interface($interface);
4489
}
4490

    
4491
/* COMPAT Function */
4492
function get_current_wan_address($interface = "wan") {
4493
	return get_interface_ip($interface);
4494
}
4495

    
4496
/*
4497
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4498
 */
4499
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4500
	global $config;
4501

    
4502
	/* XXX: For speed reasons reference directly the interface array */
4503
	$ifdescrs = &$config['interfaces'];
4504
	//$ifdescrs = get_configured_interface_list(false, true);
4505

    
4506
	foreach ($ifdescrs as $if => $ifname) {
4507
		if ($if == $interface || $ifname['if'] == $interface) {
4508
			return $if;
4509
		}
4510

    
4511
		if (get_real_interface($if) == $interface) {
4512
			return $if;
4513
		}
4514

    
4515
		if ($checkparent == false) {
4516
			continue;
4517
		}
4518

    
4519
		$int = get_parent_interface($if, true);
4520
		if (is_array($int)) {
4521
			foreach ($int as $iface) {
4522
				if ($iface == $interface) {
4523
					return $if;
4524
				}
4525
			}
4526
		}
4527
	}
4528

    
4529
	if ($interface == "enc0") {
4530
		return 'IPsec';
4531
	}
4532
}
4533

    
4534
/* attempt to resolve interface to friendly descr */
4535
function convert_friendly_interface_to_friendly_descr($interface) {
4536
	global $config;
4537

    
4538
	switch ($interface) {
4539
		case "l2tp":
4540
			$ifdesc = "L2TP";
4541
			break;
4542
		case "pptp":
4543
			$ifdesc = "PPTP";
4544
			break;
4545
		case "pppoe":
4546
			$ifdesc = "PPPoE";
4547
			break;
4548
		case "openvpn":
4549
			$ifdesc = "OpenVPN";
4550
			break;
4551
		case "lo0":
4552
			$ifdesc = "Loopback";
4553
			break;
4554
		case "enc0":
4555
		case "ipsec":
4556
		case "IPsec":
4557
			$ifdesc = "IPsec";
4558
			break;
4559
		default:
4560
			if (isset($config['interfaces'][$interface])) {
4561
				if (empty($config['interfaces'][$interface]['descr'])) {
4562
					$ifdesc = strtoupper($interface);
4563
				} else {
4564
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4565
				}
4566
				break;
4567
			} else if (substr($interface, 0, 4) == '_vip') {
4568
				if (is_array($config['virtualip']['vip'])) {
4569
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
4570
						if ($vip['mode'] == "carp") {
4571
							if ($interface == "_vip{$vip['uniqid']}") {
4572
								return "{$vip['subnet']} - {$vip['descr']}";
4573
							}
4574
						}
4575
					}
4576
				}
4577
			} else if (substr($interface, 0, 5) == '_lloc') {
4578
				return get_interface_linklocal($interface);
4579
			} else {
4580
				/* if list */
4581
				$ifdescrs = get_configured_interface_with_descr(false, true);
4582
				foreach ($ifdescrs as $if => $ifname) {
4583
					if ($if == $interface || $ifname == $interface) {
4584
						return $ifname;
4585
					}
4586
				}
4587
			}
4588
			break;
4589
	}
4590

    
4591
	return $ifdesc;
4592
}
4593

    
4594
function convert_real_interface_to_friendly_descr($interface) {
4595

    
4596
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4597

    
4598
	if (!empty($ifdesc)) {
4599
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4600
	}
4601

    
4602
	return $interface;
4603
}
4604

    
4605
/*
4606
 *  get_parent_interface($interface):
4607
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4608
 *				or virtual interface (i.e. vlan)
4609
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4610
 *			-- returns $interface passed in if $interface parent is not found
4611
 *			-- returns empty array if an invalid interface is passed
4612
 *	(Only handles ppps and vlans now.)
4613
 */
4614
function get_parent_interface($interface, $avoidrecurse = false) {
4615
	global $config;
4616

    
4617
	$parents = array();
4618
	//Check that we got a valid interface passed
4619
	$realif = get_real_interface($interface);
4620
	if ($realif == NULL) {
4621
		return $parents;
4622
	}
4623

    
4624
	// If we got a real interface, find it's friendly assigned name
4625
	if ($interface == $realif && $avoidrecurse == false) {
4626
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4627
	}
4628

    
4629
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4630
		$ifcfg = $config['interfaces'][$interface];
4631
		switch ($ifcfg['ipaddr']) {
4632
			case "ppp":
4633
			case "pppoe":
4634
			case "pptp":
4635
			case "l2tp":
4636
				if (empty($parents)) {
4637
					if (is_array($config['ppps']['ppp'])) {
4638
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4639
							if ($ifcfg['if'] == $ppp['if']) {
4640
								$ports = explode(',', $ppp['ports']);
4641
								foreach ($ports as $pid => $parent_if) {
4642
									$parents[$pid] = get_real_interface($parent_if);
4643
								}
4644
								break;
4645
							}
4646
						}
4647
					}
4648
				}
4649
				break;
4650
			case "dhcp":
4651
			case "static":
4652
			default:
4653
				// Handle _vlans
4654
				if (strpos($realif, '_vlan') !== FALSE) {
4655
					if (is_array($config['vlans']['vlan'])) {
4656
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4657
							if ($ifcfg['if'] == $vlan['vlanif']) {
4658
								$parents[0] = $vlan['if'];
4659
								break;
4660
							}
4661
						}
4662
					}
4663
				}
4664
				break;
4665
		}
4666
	}
4667

    
4668
	if (empty($parents)) {
4669
		// Handle _vlans not assigned to an interface
4670
		if (strpos($realif, '_vlan') !== FALSE) {
4671
			if (is_array($config['vlans']['vlan'])) {
4672
				foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4673
					if ($realif == $vlan['vlanif']) {
4674
						$parents[0] = $vlan['if'];
4675
						break;
4676
					}
4677
				}
4678
			}
4679
		}
4680
	}
4681

    
4682
	if (empty($parents)) {
4683
		$parents[0] = $realif;
4684
	}
4685

    
4686
	return $parents;
4687
}
4688

    
4689
/*
4690
 *  get_parent_physical_interface($interface):
4691
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
4692
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
4693
 */
4694
function get_parent_physical_interface($interface) {
4695
	global $config;
4696

    
4697
	$realif = get_parent_interface($interface);
4698

    
4699
	if (substr($realif[0], 0, 4) == "lagg") {
4700
		foreach ($config['laggs']['lagg'] as $lagg) {
4701
			if ($realif[0] == $lagg['laggif']) {
4702
				return explode(",", $lagg['members']);
4703
			}
4704
		}
4705
	} else {
4706
		return $realif;
4707
	}
4708
}
4709

    
4710
function interface_is_wireless_clone($wlif) {
4711
	if (!stristr($wlif, "_wlan")) {
4712
		return false;
4713
	} else {
4714
		return true;
4715
	}
4716
}
4717

    
4718
function interface_get_wireless_base($wlif) {
4719
	if (!stristr($wlif, "_wlan")) {
4720
		return $wlif;
4721
	} else {
4722
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4723
	}
4724
}
4725

    
4726
function interface_get_wireless_clone($wlif) {
4727
	if (!stristr($wlif, "_wlan")) {
4728
		return $wlif . "_wlan0";
4729
	} else {
4730
		return $wlif;
4731
	}
4732
}
4733

    
4734
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4735
	global $config, $g;
4736

    
4737
	$wanif = NULL;
4738

    
4739
	switch ($interface) {
4740
		case "l2tp":
4741
			$wanif = "l2tp";
4742
			break;
4743
		case "pptp":
4744
			$wanif = "pptp";
4745
			break;
4746
		case "pppoe":
4747
			$wanif = "pppoe";
4748
			break;
4749
		case "openvpn":
4750
			$wanif = "openvpn";
4751
			break;
4752
		case "IPsec":
4753
		case "ipsec":
4754
		case "enc0":
4755
			$wanif = "enc0";
4756
			break;
4757
		case "ppp":
4758
			$wanif = "ppp";
4759
			break;
4760
		default:
4761
			if (substr($interface, 0, 4) == '_vip') {
4762
				$wanif = get_configured_vip_interface($interface);
4763
				if (!empty($wanif)) {
4764
					$wanif = get_real_interface($wanif);
4765
				}
4766
				break;
4767
			} else if (substr($interface, 0, 5) == '_lloc') {
4768
				$interface = substr($interface, 5);
4769
			} else if (strstr($interface, "_vlan") ||
4770
			    does_interface_exist($interface, $flush)) {
4771
				/*
4772
				 * If a real interface was already passed simply
4773
				 * pass the real interface back.  This encourages
4774
				 * the usage of this function in more cases so that
4775
				 * we can combine logic for more flexibility.
4776
				 */
4777
				$wanif = $interface;
4778
				break;
4779
			}
4780

    
4781
			if (empty($config['interfaces'][$interface])) {
4782
				break;
4783
			}
4784

    
4785
			$cfg = &$config['interfaces'][$interface];
4786

    
4787
			if ($family == "inet6") {
4788
				switch ($cfg['ipaddrv6']) {
4789
					case "6rd":
4790
					case "6to4":
4791
						$wanif = "{$interface}_stf";
4792
						break;
4793
					case 'pppoe':
4794
					case 'ppp':
4795
					case 'l2tp':
4796
					case 'pptp':
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
						break;
4803
					default:
4804
						switch ($cfg['ipaddr']) {
4805
							case 'pppoe':
4806
							case 'ppp':
4807
							case 'l2tp':
4808
							case 'pptp':
4809
								if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false) {
4810
									$wanif = $cfg['if'];
4811
								} else {
4812
									$parents = get_parent_interface($interface);
4813
									if (!empty($parents[0])) {
4814
										$wanif = $parents[0];
4815
									} else {
4816
										$wanif = $cfg['if'];
4817
									}
4818
								}
4819
								break;
4820
							default:
4821
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4822
									$wanif = interface_get_wireless_clone($cfg['if']);
4823
								} else {
4824
									$wanif = $cfg['if'];
4825
								}
4826
								break;
4827
						}
4828
						break;
4829
				}
4830
			} else {
4831
				// Wireless cloned NIC support (FreeBSD 8+)
4832
				// interface name format: $parentnic_wlanparentnic#
4833
				// example: ath0_wlan0
4834
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4835
					$wanif = interface_get_wireless_clone($cfg['if']);
4836
				} else {
4837
					$wanif = $cfg['if'];
4838
				}
4839
			}
4840
			break;
4841
	}
4842

    
4843
	return $wanif;
4844
}
4845

    
4846
/* Guess the physical interface by providing a IP address */
4847
function guess_interface_from_ip($ipaddress) {
4848

    
4849
	$family = '';
4850
	if (is_ipaddrv4($ipaddress)) {
4851
		$family = 'inet';
4852
	}
4853
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4854
		$family = 'inet6';
4855
	}
4856

    
4857
	if (empty($family)) {
4858
		return false;
4859
	}
4860

    
4861
	/* create a route table we can search */
4862
	$output = '';
4863
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4864
	$output[0] = trim($output[0], " \n");
4865
	if (!empty($output[0])) {
4866
		return $output[0];
4867
	}
4868

    
4869
	return false;
4870
}
4871

    
4872
/*
4873
 * find_ip_interface($ip): return the interface where an ip is defined
4874
 *   (or if $bits is specified, where an IP within the subnet is defined)
4875
 */
4876
function find_ip_interface($ip, $bits = null) {
4877
	if (!is_ipaddr($ip)) {
4878
		return false;
4879
	}
4880

    
4881
	$isv6ip = is_ipaddrv6($ip);
4882

    
4883
	/* if list */
4884
	$ifdescrs = get_configured_interface_list();
4885

    
4886
	foreach ($ifdescrs as $ifdescr => $ifname) {
4887
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4888
		if (is_null($ifip)) {
4889
			continue;
4890
		}
4891
		if (is_null($bits)) {
4892
			if ($ip == $ifip) {
4893
				$int = get_real_interface($ifname);
4894
				return $int;
4895
			}
4896
		} else {
4897
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4898
				$int = get_real_interface($ifname);
4899
				return $int;
4900
			}
4901
		}
4902
	}
4903

    
4904
	return false;
4905
}
4906

    
4907
/*
4908
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4909
 *   (or if $bits is specified, where an IP within the subnet is found)
4910
 */
4911
function find_virtual_ip_alias($ip, $bits = null) {
4912
	global $config;
4913

    
4914
	if (!is_array($config['virtualip']['vip'])) {
4915
		return false;
4916
	}
4917
	if (!is_ipaddr($ip)) {
4918
		return false;
4919
	}
4920

    
4921
	$isv6ip = is_ipaddrv6($ip);
4922

    
4923
	foreach ($config['virtualip']['vip'] as $vip) {
4924
		if ($vip['mode'] === "ipalias") {
4925
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
4926
				continue;
4927
			}
4928
			if (is_null($bits)) {
4929
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4930
					return $vip;
4931
				}
4932
			} else {
4933
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
4934
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4935
					return $vip;
4936
				}
4937
			}
4938
		}
4939
	}
4940
	return false;
4941
}
4942

    
4943
function link_interface_to_track6($int, $action = "") {
4944
	global $config;
4945

    
4946
	if (empty($int)) {
4947
		return;
4948
	}
4949

    
4950
	if (is_array($config['interfaces'])) {
4951
		$list = array();
4952
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4953
			if (!isset($ifcfg['enable'])) {
4954
				continue;
4955
			}
4956
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4957
				if ($action == "update") {
4958
					interface_track6_configure($ifname, $ifcfg);
4959
				} else if ($action == "") {
4960
					$list[$ifname] = $ifcfg;
4961
				}
4962
			}
4963
		}
4964
		return $list;
4965
	}
4966
}
4967

    
4968
function interface_find_child_cfgmtu($realiface) {
4969
	global $config;
4970

    
4971
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
4972
	$vlans = link_interface_to_vlans($realiface);
4973
	$bridge = link_interface_to_bridge($realiface);
4974
	if (!empty($interface)) {
4975
		$gifs = link_interface_to_gif($interface);
4976
		$gres = link_interface_to_gre($interface);
4977
	} else {
4978
		$gifs = array();
4979
		$gres = array();
4980
	}
4981

    
4982
	$mtu = 0;
4983
	if (is_array($vlans)) {
4984
		foreach ($vlans as $vlan) {
4985
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4986
			if (empty($ifass)) {
4987
				continue;
4988
			}
4989
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4990
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4991
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4992
				}
4993
			}
4994
		}
4995
	}
4996
	if (is_array($gifs)) {
4997
		foreach ($gifs as $gif) {
4998
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
4999
			if (empty($ifass)) {
5000
				continue;
5001
			}
5002
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5003
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5004
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5005
				}
5006
			}
5007
		}
5008
	}
5009
	if (is_array($gres)) {
5010
		foreach ($gres as $gre) {
5011
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5012
			if (empty($ifass)) {
5013
				continue;
5014
			}
5015
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5016
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5017
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5018
				}
5019
			}
5020
		}
5021
	}
5022
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5023
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5024
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5025
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5026
		}
5027
	}
5028
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5029

    
5030
	return $mtu;
5031
}
5032

    
5033
function link_interface_to_vlans($int, $action = "") {
5034
	global $config;
5035

    
5036
	if (empty($int)) {
5037
		return;
5038
	}
5039

    
5040
	if (is_array($config['vlans']['vlan'])) {
5041
		$ifaces = array();
5042
		foreach ($config['vlans']['vlan'] as $vlan) {
5043
			if ($int == $vlan['if']) {
5044
				if ($action == "update") {
5045
					interfaces_bring_up($int);
5046
				} else {
5047
					$ifaces[$vlan['tag']] = $vlan;
5048
				}
5049
			}
5050
		}
5051
		if (!empty($ifaces)) {
5052
			return $ifaces;
5053
		}
5054
	}
5055
}
5056

    
5057
function link_interface_to_vips($int, $action = "", $vhid = '') {
5058
	global $config;
5059

    
5060
	$updatevips = false;
5061
	if (is_array($config['virtualip']['vip'])) {
5062
		$result = array();
5063
		foreach ($config['virtualip']['vip'] as $vip) {
5064
			if (substr($vip['interface'], 0, 4) == "_vip") {
5065
				$iface = get_configured_vip_interface($vip['interface']);
5066
			} else {
5067
				$iface = $vip['interface'];
5068
			}
5069
			if ($int != $iface) {
5070
				continue;
5071
			}
5072
			if ($action == "update") {
5073
				$updatevips = true;
5074
			} else {
5075
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5076
				    substr($vip['interface'], 0, 4) == "_vip") {
5077
					$result[] = $vip;
5078
				}
5079
			}
5080
		}
5081
		if ($updatevips === true) {
5082
			interfaces_vips_configure($int);
5083
		}
5084
		return $result;
5085
	}
5086

    
5087
	return NULL;
5088
}
5089

    
5090
/****f* interfaces/link_interface_to_bridge
5091
 * NAME
5092
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5093
 * INPUTS
5094
 *   $ip
5095
 * RESULT
5096
 *   bridge[0-99]
5097
 ******/
5098
function link_interface_to_bridge($int) {
5099
	global $config;
5100

    
5101
	if (is_array($config['bridges']['bridged'])) {
5102
		foreach ($config['bridges']['bridged'] as $bridge) {
5103
			if (in_array($int, explode(',', $bridge['members']))) {
5104
				return "{$bridge['bridgeif']}";
5105
			}
5106
		}
5107
	}
5108
}
5109

    
5110
function link_interface_to_group($int) {
5111
	global $config;
5112

    
5113
	$result = array();
5114

    
5115
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5116
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5117
			if (in_array($int, explode(" ", $group['members']))) {
5118
				$result[$group['ifname']] = $int;
5119
			}
5120
		}
5121
	}
5122

    
5123
	return $result;
5124
}
5125

    
5126
function link_interface_to_gre($interface) {
5127
	global $config;
5128

    
5129
	$result = array();
5130

    
5131
	if (is_array($config['gres']['gre'])) {
5132
		foreach ($config['gres']['gre'] as $gre) {
5133
			if ($gre['if'] == $interface) {
5134
				$result[] = $gre;
5135
			}
5136
		}
5137
	}
5138

    
5139
	return $result;
5140
}
5141

    
5142
function link_interface_to_gif($interface) {
5143
	global $config;
5144

    
5145
	$result = array();
5146

    
5147
	if (is_array($config['gifs']['gif'])) {
5148
		foreach ($config['gifs']['gif'] as $gif) {
5149
			if ($gif['if'] == $interface) {
5150
				$result[] = $gif;
5151
			}
5152
		}
5153
	}
5154

    
5155
	return $result;
5156
}
5157

    
5158
/*
5159
 * find_interface_ip($interface): return the interface ip (first found)
5160
 */
5161
function find_interface_ip($interface, $flush = false) {
5162
	global $interface_ip_arr_cache;
5163
	global $interface_sn_arr_cache;
5164

    
5165
	$interface = str_replace("\n", "", $interface);
5166

    
5167
	if (!does_interface_exist($interface)) {
5168
		return;
5169
	}
5170

    
5171
	/* Setup IP cache */
5172
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5173
		$ifinfo = pfSense_get_interface_addresses($interface);
5174
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5175
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5176
	}
5177

    
5178
	return $interface_ip_arr_cache[$interface];
5179
}
5180

    
5181
/*
5182
 * find_interface_ipv6($interface): return the interface ip (first found)
5183
 */
5184
function find_interface_ipv6($interface, $flush = false) {
5185
	global $interface_ipv6_arr_cache;
5186
	global $interface_snv6_arr_cache;
5187
	global $config;
5188

    
5189
	$interface = trim($interface);
5190
	$interface = get_real_interface($interface);
5191

    
5192
	if (!does_interface_exist($interface)) {
5193
		return;
5194
	}
5195

    
5196
	/* Setup IP cache */
5197
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5198
		$ifinfo = pfSense_get_interface_addresses($interface);
5199
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5200
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5201
	}
5202

    
5203
	return $interface_ipv6_arr_cache[$interface];
5204
}
5205

    
5206
/*
5207
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5208
 */
5209
function find_interface_ipv6_ll($interface, $flush = false) {
5210
	global $interface_llv6_arr_cache;
5211
	global $config;
5212

    
5213
	$interface = str_replace("\n", "", $interface);
5214

    
5215
	if (!does_interface_exist($interface)) {
5216
		return;
5217
	}
5218

    
5219
	/* Setup IP cache */
5220
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5221
		$ifinfo = pfSense_getall_interface_addresses($interface);
5222
		foreach ($ifinfo as $line) {
5223
			if (strstr($line, ":")) {
5224
				$parts = explode("/", $line);
5225
				if (is_linklocal($parts[0])) {
5226
					$ifinfo['linklocal'] = $parts[0];
5227
				}
5228
			}
5229
		}
5230
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5231
	}
5232
	return $interface_llv6_arr_cache[$interface];
5233
}
5234

    
5235
function find_interface_subnet($interface, $flush = false) {
5236
	global $interface_sn_arr_cache;
5237
	global $interface_ip_arr_cache;
5238

    
5239
	$interface = str_replace("\n", "", $interface);
5240
	if (does_interface_exist($interface) == false) {
5241
		return;
5242
	}
5243

    
5244
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5245
		$ifinfo = pfSense_get_interface_addresses($interface);
5246
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5247
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5248
	}
5249

    
5250
	return $interface_sn_arr_cache[$interface];
5251
}
5252

    
5253
function find_interface_subnetv6($interface, $flush = false) {
5254
	global $interface_snv6_arr_cache;
5255
	global $interface_ipv6_arr_cache;
5256

    
5257
	$interface = str_replace("\n", "", $interface);
5258
	if (does_interface_exist($interface) == false) {
5259
		return;
5260
	}
5261

    
5262
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5263
		$ifinfo = pfSense_get_interface_addresses($interface);
5264
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5265
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5266
	}
5267

    
5268
	return $interface_snv6_arr_cache[$interface];
5269
}
5270

    
5271
function ip_in_interface_alias_subnet($interface, $ipalias) {
5272
	global $config;
5273

    
5274
	if (empty($interface) || !is_ipaddr($ipalias)) {
5275
		return false;
5276
	}
5277
	if (is_array($config['virtualip']['vip'])) {
5278
		foreach ($config['virtualip']['vip'] as $vip) {
5279
			switch ($vip['mode']) {
5280
				case "ipalias":
5281
					if ($vip['interface'] <> $interface) {
5282
						break;
5283
					}
5284
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5285
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5286
						return true;
5287
					}
5288
					break;
5289
			}
5290
		}
5291
	}
5292

    
5293
	return false;
5294
}
5295

    
5296
function get_possible_listen_ips($include_ipv6_link_local=false) {
5297

    
5298
	$interfaces = get_configured_interface_with_descr();
5299
	foreach ($interfaces as $iface => $ifacename) {
5300
		if ($include_ipv6_link_local) {
5301
			/* This is to avoid going though added ll below */
5302
			if (substr($iface, 0, 5) == '_lloc') {
5303
				continue;
5304
			}
5305
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5306
			if (!empty($llip)) {
5307
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5308
			}
5309
		}
5310
	}
5311
	$viplist = get_configured_vip_list();
5312
	foreach ($viplist as $vip => $address) {
5313
		$interfaces[$vip] = $address;
5314
		if (get_vip_descr($address)) {
5315
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5316
		}
5317
	}
5318

    
5319
	$interfaces['lo0'] = 'Localhost';
5320

    
5321
	return $interfaces;
5322
}
5323

    
5324
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5325
	global $config;
5326

    
5327
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5328
	foreach (array('server', 'client') as $mode) {
5329
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5330
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5331
				if (!isset($setting['disable'])) {
5332
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5333
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5334
				}
5335
			}
5336
		}
5337
	}
5338
	return $sourceips;
5339
}
5340

    
5341
function get_interface_ip($interface = "wan") {
5342

    
5343
	if (substr($interface, 0, 4) == '_vip') {
5344
		return get_configured_vip_ipv4($interface);
5345
	} else if (substr($interface, 0, 5) == '_lloc') {
5346
		/* No link-local address for v4. */
5347
		return null;
5348
	}
5349

    
5350
	$realif = get_failover_interface($interface, 'inet');
5351
	if (!$realif) {
5352
		return null;
5353
	}
5354

    
5355
	if (substr($realif, 0, 4) == '_vip') {
5356
		return get_configured_vip_ipv4($realif);
5357
	} else if (substr($realif, 0, 5) == '_lloc') {
5358
		/* No link-local address for v4. */
5359
		return null;
5360
	}
5361

    
5362
	if (is_array($config['interfaces'][$interface]) &&
5363
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5364
		return ($config['interfaces'][$interface]['ipaddr']);
5365
	}
5366

    
5367
	/*
5368
	 * Beaware that find_interface_ip() is our last option, it will
5369
	 * return the first IP it find on interface, not necessarily the
5370
	 * main IP address.
5371
	 */
5372
	$curip = find_interface_ip($realif);
5373
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5374
		return $curip;
5375
	} else {
5376
		return null;
5377
	}
5378
}
5379

    
5380
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5381
	global $config;
5382

    
5383
	if (substr($interface, 0, 4) == '_vip') {
5384
		return get_configured_vip_ipv6($interface);
5385
	} else if (substr($interface, 0, 5) == '_lloc') {
5386
		return get_interface_linklocal($interface);
5387
	}
5388

    
5389
	$realif = get_failover_interface($interface, 'inet6');
5390
	if (!$realif) {
5391
		return null;
5392
	}
5393

    
5394
	if (substr($realif, 0, 4) == '_vip') {
5395
		return get_configured_vip_ipv6($realif);
5396
	} else if (substr($realif, 0, 5) == '_lloc') {
5397
		return get_interface_linklocal($realif);
5398
	}
5399

    
5400
	if (is_array($config['interfaces'][$interface])) {
5401
		switch ($config['interfaces'][$interface]['ipaddr']) {
5402
			case 'pppoe':
5403
			case 'l2tp':
5404
			case 'pptp':
5405
			case 'ppp':
5406
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5407
					$realif = get_real_interface($interface, 'inet6', false);
5408
				}
5409
				break;
5410
		}
5411
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5412
			return ($config['interfaces'][$interface]['ipaddrv6']);
5413
		}
5414
	}
5415

    
5416
	/*
5417
	 * Beaware that find_interface_ip() is our last option, it will
5418
	 * return the first IP it find on interface, not necessarily the
5419
	 * main IP address.
5420
	 */
5421
	$curip = find_interface_ipv6($realif, $flush);
5422
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5423
		return $curip;
5424
	} else {
5425
		/*
5426
		 * NOTE: On the case when only the prefix is requested,
5427
		 * the communication on WAN will be done over link-local.
5428
		 */
5429
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
5430
			$curip = find_interface_ipv6_ll($realif, $flush);
5431
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5432
				return $curip;
5433
			}
5434
		}
5435
	}
5436
	return null;
5437
}
5438

    
5439
function get_interface_linklocal($interface = "wan") {
5440

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

    
5446
	if (substr($interface, 0, 4) == '_vip') {
5447
		$realif = get_real_interface($interface);
5448
	} else if (substr($interface, 0, 5) == '_lloc') {
5449
		$realif = get_real_interface(substr($interface, 5));
5450
	}
5451

    
5452
	$curip = find_interface_ipv6_ll($realif);
5453
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5454
		return $curip;
5455
	} else {
5456
		return null;
5457
	}
5458
}
5459

    
5460
function get_interface_subnet($interface = "wan") {
5461

    
5462
	if (substr($interface, 0, 4) == '_vip') {
5463
		return (get_configured_vip_subnetv4($interface));
5464
	}
5465

    
5466
	$realif = get_real_interface($interface);
5467
	if (!$realif) {
5468
		return (NULL);
5469
	}
5470

    
5471
	$cursn = find_interface_subnet($realif);
5472
	if (!empty($cursn)) {
5473
		return ($cursn);
5474
	}
5475

    
5476
	return (NULL);
5477
}
5478

    
5479
function get_interface_subnetv6($interface = "wan") {
5480

    
5481
	if (substr($interface, 0, 4) == '_vip') {
5482
		return (get_configured_vip_subnetv6($interface));
5483
	} else if (substr($interface, 0, 5) == '_lloc') {
5484
		$interface = substr($interface, 5);
5485
	}
5486

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

    
5492
	$cursn = find_interface_subnetv6($realif);
5493
	if (!empty($cursn)) {
5494
		return ($cursn);
5495
	}
5496

    
5497
	return (NULL);
5498
}
5499

    
5500
/* return outside interfaces with a gateway */
5501
function get_interfaces_with_gateway() {
5502
	global $config;
5503

    
5504
	$ints = array();
5505

    
5506
	/* loop interfaces, check config for outbound */
5507
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5508
		switch ($ifname['ipaddr']) {
5509
			case "dhcp":
5510
			case "pppoe":
5511
			case "pptp":
5512
			case "l2tp":
5513
			case "ppp":
5514
				$ints[$ifdescr] = $ifdescr;
5515
				break;
5516
			default:
5517
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5518
				    !empty($ifname['gateway'])) {
5519
					$ints[$ifdescr] = $ifdescr;
5520
				}
5521
				break;
5522
		}
5523
	}
5524
	return $ints;
5525
}
5526

    
5527
/* return true if interface has a gateway */
5528
function interface_has_gateway($friendly) {
5529
	global $config;
5530

    
5531
	if (!empty($config['interfaces'][$friendly])) {
5532
		$ifname = &$config['interfaces'][$friendly];
5533
		switch ($ifname['ipaddr']) {
5534
			case "dhcp":
5535
			case "pppoe":
5536
			case "pptp":
5537
			case "l2tp":
5538
			case "ppp":
5539
				return true;
5540
			break;
5541
			default:
5542
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5543
					return true;
5544
				}
5545
				$tunnelif = substr($ifname['if'], 0, 3);
5546
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5547
					if (find_interface_ip($ifname['if'])) {
5548
						return true;
5549
					}
5550
				}
5551
				if (!empty($ifname['gateway'])) {
5552
					return true;
5553
				}
5554
			break;
5555
		}
5556
	}
5557

    
5558
	return false;
5559
}
5560

    
5561
/* return true if interface has a gateway */
5562
function interface_has_gatewayv6($friendly) {
5563
	global $config;
5564

    
5565
	if (!empty($config['interfaces'][$friendly])) {
5566
		$ifname = &$config['interfaces'][$friendly];
5567
		switch ($ifname['ipaddrv6']) {
5568
			case "slaac":
5569
			case "dhcp6":
5570
			case "6to4":
5571
			case "6rd":
5572
				return true;
5573
				break;
5574
			default:
5575
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5576
					return true;
5577
				}
5578
				$tunnelif = substr($ifname['if'], 0, 3);
5579
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5580
					if (find_interface_ipv6($ifname['if'])) {
5581
						return true;
5582
					}
5583
				}
5584
				if (!empty($ifname['gatewayv6'])) {
5585
					return true;
5586
				}
5587
				break;
5588
		}
5589
	}
5590

    
5591
	return false;
5592
}
5593

    
5594
/****f* interfaces/is_altq_capable
5595
 * NAME
5596
 *   is_altq_capable - Test if interface is capable of using ALTQ
5597
 * INPUTS
5598
 *   $int            - string containing interface name
5599
 * RESULT
5600
 *   boolean         - true or false
5601
 ******/
5602

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

    
5617
	$int_family = remove_ifindex($int);
5618

    
5619
	if (in_array($int_family, $capable)) {
5620
		return true;
5621
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5622
		return true;
5623
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5624
		return true;
5625
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5626
		return true;
5627
	} else {
5628
		return false;
5629
	}
5630
}
5631

    
5632
/****f* interfaces/is_interface_wireless
5633
 * NAME
5634
 *   is_interface_wireless - Returns if an interface is wireless
5635
 * RESULT
5636
 *   $tmp       - Returns if an interface is wireless
5637
 ******/
5638
function is_interface_wireless($interface) {
5639
	global $config, $g;
5640

    
5641
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5642
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5643
		if (preg_match($g['wireless_regex'], $interface)) {
5644
			if (isset($config['interfaces'][$friendly])) {
5645
				$config['interfaces'][$friendly]['wireless'] = array();
5646
			}
5647
			return true;
5648
		}
5649
		return false;
5650
	} else {
5651
		return true;
5652
	}
5653
}
5654

    
5655
function get_wireless_modes($interface) {
5656
	/* return wireless modes and channels */
5657
	$wireless_modes = array();
5658

    
5659
	$cloned_interface = get_real_interface($interface);
5660

    
5661
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5662
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5663
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5664
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5665

    
5666
		$interface_channels = "";
5667
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5668
		$interface_channel_count = count($interface_channels);
5669

    
5670
		$c = 0;
5671
		while ($c < $interface_channel_count) {
5672
			$channel_line = explode(",", $interface_channels["$c"]);
5673
			$wireless_mode = trim($channel_line[0]);
5674
			$wireless_channel = trim($channel_line[1]);
5675
			if (trim($wireless_mode) != "") {
5676
				/* if we only have 11g also set 11b channels */
5677
				if ($wireless_mode == "11g") {
5678
					if (!isset($wireless_modes["11b"])) {
5679
						$wireless_modes["11b"] = array();
5680
					}
5681
				} else if ($wireless_mode == "11g ht") {
5682
					if (!isset($wireless_modes["11b"])) {
5683
						$wireless_modes["11b"] = array();
5684
					}
5685
					if (!isset($wireless_modes["11g"])) {
5686
						$wireless_modes["11g"] = array();
5687
					}
5688
					$wireless_mode = "11ng";
5689
				} else if ($wireless_mode == "11a ht") {
5690
					if (!isset($wireless_modes["11a"])) {
5691
						$wireless_modes["11a"] = array();
5692
					}
5693
					$wireless_mode = "11na";
5694
				}
5695
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5696
			}
5697
			$c++;
5698
		}
5699
	}
5700
	return($wireless_modes);
5701
}
5702

    
5703
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5704
function get_wireless_channel_info($interface) {
5705
	$wireless_channels = array();
5706

    
5707
	$cloned_interface = get_real_interface($interface);
5708

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

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

    
5717
		foreach ($interface_channels as $channel_line) {
5718
			$channel_line = explode(",", $channel_line);
5719
			if (!isset($wireless_channels[$channel_line[0]])) {
5720
				$wireless_channels[$channel_line[0]] = $channel_line;
5721
			}
5722
		}
5723
	}
5724
	return($wireless_channels);
5725
}
5726

    
5727
function set_interface_mtu($interface, $mtu) {
5728

    
5729
	/* LAGG interface must be destroyed and re-created to change MTU */
5730
	if (substr($interface, 0, 4) == 'lagg') {
5731
		if (isset($config['laggs']['lagg']) &&
5732
		    is_array($config['laggs']['lagg'])) {
5733
			foreach ($config['laggs']['lagg'] as $lagg) {
5734
				if ($lagg['laggif'] == $interface) {
5735
					interface_lagg_configure($lagg);
5736
					break;
5737
				}
5738
			}
5739
		}
5740
	} else {
5741
		pfSense_interface_mtu($interface, $mtu);
5742
	}
5743
}
5744

    
5745
/****f* interfaces/get_interface_mtu
5746
 * NAME
5747
 *   get_interface_mtu - Return the mtu of an interface
5748
 * RESULT
5749
 *   $tmp       - Returns the mtu of an interface
5750
 ******/
5751
function get_interface_mtu($interface) {
5752
	$mtu = pfSense_interface_getmtu($interface);
5753
	return $mtu['mtu'];
5754
}
5755

    
5756
function get_interface_mac($interface) {
5757

    
5758
	$macinfo = pfSense_get_interface_addresses($interface);
5759
	return $macinfo["macaddr"];
5760
}
5761

    
5762
/****f* pfsense-utils/generate_random_mac_address
5763
 * NAME
5764
 *   generate_random_mac - generates a random mac address
5765
 * INPUTS
5766
 *   none
5767
 * RESULT
5768
 *   $mac - a random mac address
5769
 ******/
5770
function generate_random_mac_address() {
5771
	$mac = "02";
5772
	for ($x = 0; $x < 5; $x++) {
5773
		$mac .= ":" . dechex(rand(16, 255));
5774
	}
5775
	return $mac;
5776
}
5777

    
5778
/****f* interfaces/is_jumbo_capable
5779
 * NAME
5780
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5781
 * INPUTS
5782
 *   $int             - string containing interface name
5783
 * RESULT
5784
 *   boolean          - true or false
5785
 ******/
5786
function is_jumbo_capable($iface) {
5787
	$iface = trim($iface);
5788
	$capable = pfSense_get_interface_addresses($iface);
5789

    
5790
	if (isset($capable['caps']['vlanmtu'])) {
5791
		return true;
5792
	}
5793

    
5794
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5795
	if (substr($iface, 0, 4) == "lagg") {
5796
		return true;
5797
	}
5798

    
5799
	return false;
5800
}
5801

    
5802
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5803
	global $g;
5804

    
5805
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5806

    
5807
	if (!empty($iface) && !empty($pppif)) {
5808
		$cron_cmd = <<<EOD
5809
#!/bin/sh
5810
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5811
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5812

    
5813
EOD;
5814

    
5815
		@file_put_contents($cron_file, $cron_cmd);
5816
		chmod($cron_file, 0755);
5817
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5818
	} else {
5819
		unlink_if_exists($cron_file);
5820
	}
5821
}
5822

    
5823
function get_interface_default_mtu($type = "ethernet") {
5824
	switch ($type) {
5825
		case "gre":
5826
			return 1476;
5827
			break;
5828
		case "gif":
5829
			return 1280;
5830
			break;
5831
		case "tun":
5832
		case "vlan":
5833
		case "tap":
5834
		case "ethernet":
5835
		default:
5836
			return 1500;
5837
			break;
5838
	}
5839

    
5840
	/* Never reached */
5841
	return 1500;
5842
}
5843

    
5844
function get_vip_descr($ipaddress) {
5845
	global $config;
5846

    
5847
	foreach ($config['virtualip']['vip'] as $vip) {
5848
		if ($vip['subnet'] == $ipaddress) {
5849
			return ($vip['descr']);
5850
		}
5851
	}
5852
	return "";
5853
}
5854

    
5855
function interfaces_staticarp_configure($if) {
5856
	global $config, $g;
5857
	if (isset($config['system']['developerspew'])) {
5858
		$mt = microtime();
5859
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5860
	}
5861

    
5862
	$ifcfg = $config['interfaces'][$if];
5863

    
5864
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5865
		return 0;
5866
	}
5867

    
5868
	/* Enable staticarp, if enabled */
5869
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5870
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5871
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5872
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5873
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5874
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5875
			}
5876
		}
5877
	} else {
5878
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5879
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5880
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5881
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5882
				if (isset($arpent['arp_table_static_entry'])) {
5883
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5884
				}
5885
			}
5886
		}
5887
	}
5888

    
5889
	return 0;
5890
}
5891

    
5892
function get_failover_interface($interface, $family = "all") {
5893
	global $config;
5894

    
5895
	/* shortcut to get_real_interface if we find it in the config */
5896
	if (is_array($config['interfaces'][$interface])) {
5897
		return get_real_interface($interface, $family);
5898
	}
5899

    
5900
	/* compare against gateway groups */
5901
	$a_groups = return_gateway_groups_array();
5902
	if (is_array($a_groups[$interface])) {
5903
		/* we found a gateway group, fetch the interface or vip */
5904
		if (!empty($a_groups[$interface][0]['vip'])) {
5905
			return $a_groups[$interface][0]['vip'];
5906
		} else {
5907
			return $a_groups[$interface][0]['int'];
5908
		}
5909
	}
5910
	/* fall through to get_real_interface */
5911
	/* XXX: Really needed? */
5912
	return get_real_interface($interface, $family);
5913
}
5914

    
5915
function remove_ifindex($ifname) {
5916
	return preg_replace("/[0-9]+$/", "", $ifname);
5917
}
5918

    
5919
?>
(25-25/65)