Project

General

Profile

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

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

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

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

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

    
83
	return $interface_arr_cache;
84
}
85

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

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

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

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

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

    
116

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

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

    
139
	return false;
140
}
141

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
269
	interfaces_bring_up($vlanif);
270

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

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

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

    
285
	return $vlanif;
286
}
287

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

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

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

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

    
308
	$vlanif = interface_vlan_configure($vlan);
309

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

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

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

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

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

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

    
364
	return $vlanif;
365
}
366

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

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

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

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

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

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

    
409
	return $vlanif;
410
}
411

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

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

    
419
	$iflist = get_configured_interface_list();
420

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

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

    
444
}
445

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

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

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

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

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

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

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

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

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

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

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

    
549
	$checklist = get_configured_interface_list();
550

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

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

    
572
	interface_bridge_configure_advanced($bridge);
573

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
804
	interfaces_bring_up($laggif);
805

    
806
	return $laggif;
807
}
808

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

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

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

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

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

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

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

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

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

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

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

    
896
	interfaces_bring_up($greif);
897

    
898
	return $greif;
899
}
900

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

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

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

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

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

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

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

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

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

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

    
1032

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

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

    
1047
	interfaces_bring_up($gifif);
1048

    
1049
	return $gifif;
1050
}
1051

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

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

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

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

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

    
1067
	interfaces_qinq_configure();
1068

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

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

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

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

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

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

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

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

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

    
1131
		interface_configure($if, $reload);
1132

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

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

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

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

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

    
1155
		interface_configure($if, $reload);
1156

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

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

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

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

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

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

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

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

    
1193
		/* 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 for original issue
1799
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some 
1800
 * edge case. redmine #6495 open to address. 
1801
 */
1802
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1803
		$setdefaultgw = true;
1804
		$mpdconf .= <<<EOD
1805
	set iface route default
1806

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

    
1813
EOD;
1814

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

    
1819
EOD;
1820
	}
1821

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

    
1830
EOD;
1831

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

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

    
1842
EOD;
1843
	}
1844

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

    
1850
EOD;
1851
	}
1852

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

    
1857
EOD;
1858
	}
1859

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

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

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

    
1875
EOD;
1876
		}
1877

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

    
1882
EOD;
1883
		}
1884

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

    
1889
EOD;
1890
		}
1891

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

    
1897
EOD;
1898

    
1899

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

    
1904
EOD;
1905
		}
1906

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

    
1920
EOD;
1921
		}
1922

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

    
1927
EOD;
1928
		}
1929

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

    
1934
EOD;
1935
		}
1936

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

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

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

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

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

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

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

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

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

    
2001
EOD;
2002
		}
2003

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

    
2009
EOD;
2010
		}
2011

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

    
2015

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

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

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

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

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

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

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

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

    
2126
	return 1;
2127
}
2128

    
2129
function interfaces_sync_setup() {
2130
	global $g, $config;
2131

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

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

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

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

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

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

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

    
2174
		sleep(1);
2175

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

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

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

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

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

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

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

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

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

    
2241
				$paa[$proxyif][] = $vipent;
2242
			}
2243
		}
2244
	}
2245

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

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

    
2284
	if (is_array($config['virtualip']['vip'])) {
2285
		foreach ($config['virtualip']['vip'] as $vip) {
2286

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

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

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

    
2361
function interface_ipalias_configure(&$vip) {
2362
	global $config;
2363

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

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

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

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

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

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

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

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

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

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

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

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

    
2439
	return $realif;
2440
}
2441

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

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

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

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

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

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

    
2517
	$baseif = interface_get_wireless_base($ifcfg['if']);
2518

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

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

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

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

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

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

    
2594
	// Clone wireless nic if needed.
2595
	interface_wireless_clone($if, $wl);
2596

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2741
	kill_hostapd($if);
2742
	mwexec(kill_wpasupplicant("{$if}"));
2743

    
2744
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2745
	conf_mount_rw();
2746

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

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

    
2800
EOD;
2801

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

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

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

    
2820
auth_server_addr={$wlcfg['auth_server_addr']}
2821
auth_server_port={$auth_server_port}
2822
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2823

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

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

    
2836
EOD;
2837
						}
2838
					}
2839
				}
2840

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

    
2847
	/*
2848
	 *    all variables are set, lets start up everything
2849
	 */
2850

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

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

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

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

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

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

    
2900
	fclose($fd_set);
2901
	conf_mount_ro();
2902

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

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

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

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

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

    
2940
		$wlregcmd_args = implode(" ", $wlregcmd);
2941

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

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

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

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

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

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

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

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

    
3003
	unset($wlcmd_args, $wlcmd);
3004

    
3005

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

    
3010
	return 0;
3011

    
3012
}
3013

    
3014
function kill_hostapd($interface) {
3015
	global $g;
3016

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

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

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

    
3033
	return intval($pid);
3034
}
3035

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

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

    
3052
function find_dhcp6c_process($interface) {
3053
	global $g;
3054

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

    
3061
	return intval($pid);
3062
}
3063

    
3064
function interface_virtual_create($interface) {
3065
	global $config;
3066

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

    
3106
function interface_vlan_mtu_configured($iface) {
3107
	global $config;
3108

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

    
3113
			if ($vlan['vlanif'] != $iface)
3114
				continue;
3115

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

    
3127
	return $mtu;
3128
}
3129

    
3130
function interface_mtu_wanted_for_pppoe($realif) {
3131
	global $config;
3132

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

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

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

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

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

    
3170
	return $mtu;
3171
}
3172

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

    
3178
	$wancfg = $config['interfaces'][$interface];
3179

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

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

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

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

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

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

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

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

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

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

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

    
3275
	/* Apply hw offloading policies as configured */
3276
	enable_hardware_offloading($interface);
3277

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

    
3285
	$tunnelif = substr($realif, 0, 3);
3286

    
3287
	$mtuif = $realif;
3288
	$mtuhwif = $realhwif;
3289

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

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

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

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

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

    
3329
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3330

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

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

    
3363
	if (does_interface_exist($wancfg['if'])) {
3364
		interfaces_bring_up($wancfg['if']);
3365
	}
3366

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

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

    
3418
	interface_netgraph_needed($interface);
3419

    
3420
	if (!platform_booting()) {
3421
		link_interface_to_vips($interface, "update");
3422

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

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

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

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

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

    
3457
		if ($reloadall == true) {
3458

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

    
3462
			/* reload ipsec tunnels */
3463
			send_event("service reload ipsecdns");
3464

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

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

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

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

    
3484
	interfaces_staticarp_configure($interface);
3485
	return 0;
3486
}
3487

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

    
3491
	if (!is_array($wancfg)) {
3492
		return;
3493
	}
3494

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

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

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

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

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

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

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

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

    
3563
		services_dhcpd_configure("inet6");
3564
	}
3565

    
3566
	return 0;
3567
}
3568

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

    
3574
	if (!is_array($lancfg)) {
3575
		return;
3576
	}
3577

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

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

    
3589
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3590
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3591
		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']));
3592
		return;
3593
	}
3594
	$hexwanv4 = return_hex_ipv4($ip4address);
3595

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

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

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

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

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

    
3620
	$lanif = get_real_interface($interface);
3621
	$oip = find_interface_ipv6($lanif);
3622
	if (is_ipaddrv6($oip)) {
3623
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3624
	}
3625
	unset($interface_ipv6_arr_cache[$lanif]);
3626
	unset($interface_snv6_arr_cache[$lanif]);
3627
	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));
3628
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3629

    
3630
	return 0;
3631
}
3632

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

    
3638
	if (!is_array($lancfg)) {
3639
		return;
3640
	}
3641

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

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

    
3653
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3654
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3655
		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']));
3656
		return;
3657
	}
3658
	$hexwanv4 = return_hex_ipv4($ip4address);
3659

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

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

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

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

    
3680
	$lanif = get_real_interface($interface);
3681
	$oip = find_interface_ipv6($lanif);
3682
	if (is_ipaddrv6($oip)) {
3683
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3684
	}
3685
	unset($interface_ipv6_arr_cache[$lanif]);
3686
	unset($interface_snv6_arr_cache[$lanif]);
3687
	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));
3688
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3689

    
3690
	return 0;
3691
}
3692

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

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

    
3699
	if (!is_array($wancfg)) {
3700
		return;
3701
	}
3702

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

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

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

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

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

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

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

    
3745

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

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

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

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

    
3780
	return 0;
3781
}
3782

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

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

    
3789
	if (!is_array($wancfg)) {
3790
		return;
3791
	}
3792

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3886
	return 0;
3887
}
3888

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

    
3892
	if (!is_array($wancfg)) {
3893
		return;
3894
	}
3895

    
3896
	$wanif = get_real_interface($interface, "inet6");
3897
	$dhcp6cconf = "";
3898

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

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

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

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

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

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

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

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

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

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

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

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

    
4024
	return 0;
4025
}
4026

    
4027
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4028
	global $g;
4029

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

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

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

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

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

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

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

    
4087
		$id_assoc_statement_address .= "};\n";
4088
	}
4089

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

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

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

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

    
4129
		$id_assoc_statement_prefix .= "};\n";
4130
	}
4131

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

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

    
4165
	$dhcp6cconf  = $interface_statement;
4166
	$dhcp6cconf .= $id_assoc_statement_address;
4167
	$dhcp6cconf .= $id_assoc_statement_prefix;
4168
	$dhcp6cconf .= $authentication_statement;
4169
	$dhcp6cconf .= $key_info_statement;
4170

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

    
4173
	return $dhcp6cconf;
4174
}
4175

    
4176

    
4177
function DHCP6_Config_File_Override($wancfg, $wanif) {
4178

    
4179
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4180

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

    
4189

    
4190
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4191

    
4192
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4193

    
4194
	return $dhcp6cconf;
4195
}
4196

    
4197

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

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

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

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

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

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

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

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

    
4246
}
4247

    
4248
EOD;
4249

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

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

    
4264
EOD;
4265
	}
4266

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

    
4272
	fwrite($fd, $dhclientconf);
4273
	fclose($fd);
4274

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

    
4282
	/* Make sure dhclient is not running */
4283
	kill_dhclient_process($wanif);
4284

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

    
4288
	return 0;
4289
}
4290

    
4291
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4292

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

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

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

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

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

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

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

    
4357
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4358

    
4359
	return $dhclientconf;
4360
}
4361

    
4362
function DHCP_Config_Option_Split($option_string) {
4363
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4364
	return $matches ? $matches[0] : [];
4365
}
4366

    
4367
function DHCP_Config_File_Override($wancfg, $wanif) {
4368

    
4369
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4370

    
4371
	if ($dhclientconf === false) {
4372
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading.\n"), $wancfg['adv_dhcp_config_file_override_path']));
4373
		return '';
4374
	} else {
4375
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4376
	}
4377
}
4378

    
4379

    
4380
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4381

    
4382
	/* Apply Interface Substitutions */
4383
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4384

    
4385
	/* Apply Hostname Substitutions */
4386
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4387

    
4388
	/* Arrays of MAC Address Types, Cases, Delimiters */
4389
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4390
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4391
	$various_mac_cases      = array("U", "L");
4392
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4393

    
4394
	/* Apply MAC Address Substitutions */
4395
	foreach ($various_mac_types as $various_mac_type) {
4396
		foreach ($various_mac_cases as $various_mac_case) {
4397
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4398

    
4399
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4400
				if ($res !== false) {
4401

    
4402
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4403
					if ("$various_mac_case" == "U") {
4404
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4405
					}
4406
					if ("$various_mac_case" == "L") {
4407
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4408
					}
4409

    
4410
					if ("$various_mac_type" == "mac_addr_hex") {
4411
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4412
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4413
						$dhcpclientconf_mac_hex = "";
4414
						$delimiter = "";
4415
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4416
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4417
							$delimiter = ":";
4418
						}
4419
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4420
					}
4421

    
4422
					/* MAC Address Delimiter Substitutions */
4423
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4424

    
4425
					/* Apply MAC Address Substitutions */
4426
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4427
				}
4428
			}
4429
		}
4430
	}
4431

    
4432
	return $dhclientconf;
4433
}
4434

    
4435
function interfaces_group_setup() {
4436
	global $config;
4437

    
4438
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4439
		return;
4440
	}
4441

    
4442
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4443
		interface_group_setup($groupar);
4444
	}
4445

    
4446
	return;
4447
}
4448

    
4449
function interface_group_setup(&$groupname /* The parameter is an array */) {
4450
	global $config;
4451

    
4452
	if (!is_array($groupname)) {
4453
		return;
4454
	}
4455
	$members = explode(" ", $groupname['members']);
4456
	foreach ($members as $ifs) {
4457
		$realif = get_real_interface($ifs);
4458
		if ($realif && does_interface_exist($realif)) {
4459
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4460
		}
4461
	}
4462

    
4463
	return;
4464
}
4465

    
4466
function is_interface_group($if) {
4467
	global $config;
4468

    
4469
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4470
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4471
			if ($groupentry['ifname'] === $if) {
4472
				return true;
4473
			}
4474
		}
4475
	}
4476

    
4477
	return false;
4478
}
4479

    
4480
function interface_group_add_member($interface, $groupname) {
4481
	$interface = get_real_interface($interface);
4482
	if (does_interface_exist($interface)) {
4483
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4484
	}
4485
}
4486

    
4487
/* COMPAT Function */
4488
function convert_friendly_interface_to_real_interface_name($interface) {
4489
	return get_real_interface($interface);
4490
}
4491

    
4492
/* COMPAT Function */
4493
function get_real_wan_interface($interface = "wan") {
4494
	return get_real_interface($interface);
4495
}
4496

    
4497
/* COMPAT Function */
4498
function get_current_wan_address($interface = "wan") {
4499
	return get_interface_ip($interface);
4500
}
4501

    
4502
/*
4503
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4504
 */
4505
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4506
	global $config;
4507

    
4508
	/* XXX: For speed reasons reference directly the interface array */
4509
	$ifdescrs = &$config['interfaces'];
4510
	//$ifdescrs = get_configured_interface_list(false, true);
4511

    
4512
	foreach ($ifdescrs as $if => $ifname) {
4513
		if ($if == $interface || $ifname['if'] == $interface) {
4514
			return $if;
4515
		}
4516

    
4517
		if (get_real_interface($if) == $interface) {
4518
			return $if;
4519
		}
4520

    
4521
		if ($checkparent == false) {
4522
			continue;
4523
		}
4524

    
4525
		$int = get_parent_interface($if, true);
4526
		if (is_array($int)) {
4527
			foreach ($int as $iface) {
4528
				if ($iface == $interface) {
4529
					return $if;
4530
				}
4531
			}
4532
		}
4533
	}
4534

    
4535
	if ($interface == "enc0") {
4536
		return 'IPsec';
4537
	}
4538
}
4539

    
4540
/* attempt to resolve interface to friendly descr */
4541
function convert_friendly_interface_to_friendly_descr($interface) {
4542
	global $config;
4543

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

    
4597
	return $ifdesc;
4598
}
4599

    
4600
function convert_real_interface_to_friendly_descr($interface) {
4601

    
4602
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4603

    
4604
	if (!empty($ifdesc)) {
4605
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4606
	}
4607

    
4608
	return $interface;
4609
}
4610

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

    
4623
	$parents = array();
4624
	//Check that we got a valid interface passed
4625
	$realif = get_real_interface($interface);
4626
	if ($realif == NULL) {
4627
		return $parents;
4628
	}
4629

    
4630
	// If we got a real interface, find it's friendly assigned name
4631
	if ($interface == $realif && $avoidrecurse == false) {
4632
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4633
	}
4634

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

    
4674
	if (empty($parents)) {
4675
		// Handle _vlans not assigned to an interface
4676
		if (strpos($realif, '_vlan') !== FALSE) {
4677
			if (is_array($config['vlans']['vlan'])) {
4678
				foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4679
					if ($realif == $vlan['vlanif']) {
4680
						$parents[0] = $vlan['if'];
4681
						break;
4682
					}
4683
				}
4684
			}
4685
		}
4686
	}
4687

    
4688
	if (empty($parents)) {
4689
		$parents[0] = $realif;
4690
	}
4691

    
4692
	return $parents;
4693
}
4694

    
4695
/*
4696
 *  get_parent_physical_interface($interface):
4697
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
4698
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
4699
 */
4700
function get_parent_physical_interface($interface) {
4701
	global $config;
4702

    
4703
	$realif = get_parent_interface($interface);
4704

    
4705
	if (substr($realif[0], 0, 4) == "lagg") {
4706
		foreach ($config['laggs']['lagg'] as $lagg) {
4707
			if ($realif[0] == $lagg['laggif']) {
4708
				return explode(",", $lagg['members']);
4709
			}
4710
		}
4711
	} else {
4712
		return $realif;
4713
	}
4714
}
4715

    
4716
function interface_is_wireless_clone($wlif) {
4717
	if (!stristr($wlif, "_wlan")) {
4718
		return false;
4719
	} else {
4720
		return true;
4721
	}
4722
}
4723

    
4724
function interface_get_wireless_base($wlif) {
4725
	if (!stristr($wlif, "_wlan")) {
4726
		return $wlif;
4727
	} else {
4728
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4729
	}
4730
}
4731

    
4732
function interface_get_wireless_clone($wlif) {
4733
	if (!stristr($wlif, "_wlan")) {
4734
		return $wlif . "_wlan0";
4735
	} else {
4736
		return $wlif;
4737
	}
4738
}
4739

    
4740
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4741
	global $config, $g;
4742

    
4743
	$wanif = NULL;
4744

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

    
4787
			if (empty($config['interfaces'][$interface])) {
4788
				break;
4789
			}
4790

    
4791
			$cfg = &$config['interfaces'][$interface];
4792

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

    
4849
	return $wanif;
4850
}
4851

    
4852
/* Guess the physical interface by providing a IP address */
4853
function guess_interface_from_ip($ipaddress) {
4854

    
4855
	$family = '';
4856
	if (is_ipaddrv4($ipaddress)) {
4857
		$family = 'inet';
4858
	}
4859
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4860
		$family = 'inet6';
4861
	}
4862

    
4863
	if (empty($family)) {
4864
		return false;
4865
	}
4866

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

    
4875
	return false;
4876
}
4877

    
4878
/*
4879
 * find_ip_interface($ip): return the interface where an ip is defined
4880
 *   (or if $bits is specified, where an IP within the subnet is defined)
4881
 */
4882
function find_ip_interface($ip, $bits = null) {
4883
	if (!is_ipaddr($ip)) {
4884
		return false;
4885
	}
4886

    
4887
	$isv6ip = is_ipaddrv6($ip);
4888

    
4889
	/* if list */
4890
	$ifdescrs = get_configured_interface_list();
4891

    
4892
	foreach ($ifdescrs as $ifdescr => $ifname) {
4893
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4894
		if (is_null($ifip)) {
4895
			continue;
4896
		}
4897
		if (is_null($bits)) {
4898
			if ($ip == $ifip) {
4899
				$int = get_real_interface($ifname);
4900
				return $int;
4901
			}
4902
		} else {
4903
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4904
				$int = get_real_interface($ifname);
4905
				return $int;
4906
			}
4907
		}
4908
	}
4909

    
4910
	return false;
4911
}
4912

    
4913
/*
4914
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4915
 *   (or if $bits is specified, where an IP within the subnet is found)
4916
 */
4917
function find_virtual_ip_alias($ip, $bits = null) {
4918
	global $config;
4919

    
4920
	if (!is_array($config['virtualip']['vip'])) {
4921
		return false;
4922
	}
4923
	if (!is_ipaddr($ip)) {
4924
		return false;
4925
	}
4926

    
4927
	$isv6ip = is_ipaddrv6($ip);
4928

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

    
4949
function link_interface_to_track6($int, $action = "") {
4950
	global $config;
4951

    
4952
	if (empty($int)) {
4953
		return;
4954
	}
4955

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

    
4974
function interface_find_child_cfgmtu($realiface) {
4975
	global $config;
4976

    
4977
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
4978
	$vlans = link_interface_to_vlans($realiface);
4979
	$bridge = link_interface_to_bridge($realiface);
4980
	if (!empty($interface)) {
4981
		$gifs = link_interface_to_gif($interface);
4982
		$gres = link_interface_to_gre($interface);
4983
	} else {
4984
		$gifs = array();
4985
		$gres = array();
4986
	}
4987

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

    
5036
	return $mtu;
5037
}
5038

    
5039
function link_interface_to_vlans($int, $action = "") {
5040
	global $config;
5041

    
5042
	if (empty($int)) {
5043
		return;
5044
	}
5045

    
5046
	if (is_array($config['vlans']['vlan'])) {
5047
		$ifaces = array();
5048
		foreach ($config['vlans']['vlan'] as $vlan) {
5049
			if ($int == $vlan['if']) {
5050
				if ($action == "update") {
5051
					interfaces_bring_up($int);
5052
				} else {
5053
					$ifaces[$vlan['tag']] = $vlan;
5054
				}
5055
			}
5056
		}
5057
		if (!empty($ifaces)) {
5058
			return $ifaces;
5059
		}
5060
	}
5061
}
5062

    
5063
function link_interface_to_vips($int, $action = "", $vhid = '') {
5064
	global $config;
5065

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

    
5093
	return NULL;
5094
}
5095

    
5096
/****f* interfaces/link_interface_to_bridge
5097
 * NAME
5098
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5099
 * INPUTS
5100
 *   $ip
5101
 * RESULT
5102
 *   bridge[0-99]
5103
 ******/
5104
function link_interface_to_bridge($int) {
5105
	global $config;
5106

    
5107
	if (is_array($config['bridges']['bridged'])) {
5108
		foreach ($config['bridges']['bridged'] as $bridge) {
5109
			if (in_array($int, explode(',', $bridge['members']))) {
5110
				return "{$bridge['bridgeif']}";
5111
			}
5112
		}
5113
	}
5114
}
5115

    
5116
function link_interface_to_group($int) {
5117
	global $config;
5118

    
5119
	$result = array();
5120

    
5121
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5122
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5123
			if (in_array($int, explode(" ", $group['members']))) {
5124
				$result[$group['ifname']] = $int;
5125
			}
5126
		}
5127
	}
5128

    
5129
	return $result;
5130
}
5131

    
5132
function link_interface_to_gre($interface) {
5133
	global $config;
5134

    
5135
	$result = array();
5136

    
5137
	if (is_array($config['gres']['gre'])) {
5138
		foreach ($config['gres']['gre'] as $gre) {
5139
			if ($gre['if'] == $interface) {
5140
				$result[] = $gre;
5141
			}
5142
		}
5143
	}
5144

    
5145
	return $result;
5146
}
5147

    
5148
function link_interface_to_gif($interface) {
5149
	global $config;
5150

    
5151
	$result = array();
5152

    
5153
	if (is_array($config['gifs']['gif'])) {
5154
		foreach ($config['gifs']['gif'] as $gif) {
5155
			if ($gif['if'] == $interface) {
5156
				$result[] = $gif;
5157
			}
5158
		}
5159
	}
5160

    
5161
	return $result;
5162
}
5163

    
5164
/*
5165
 * find_interface_ip($interface): return the interface ip (first found)
5166
 */
5167
function find_interface_ip($interface, $flush = false) {
5168
	global $interface_ip_arr_cache;
5169
	global $interface_sn_arr_cache;
5170

    
5171
	$interface = str_replace("\n", "", $interface);
5172

    
5173
	if (!does_interface_exist($interface)) {
5174
		return;
5175
	}
5176

    
5177
	/* Setup IP cache */
5178
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5179
		$ifinfo = pfSense_get_interface_addresses($interface);
5180
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5181
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5182
	}
5183

    
5184
	return $interface_ip_arr_cache[$interface];
5185
}
5186

    
5187
/*
5188
 * find_interface_ipv6($interface): return the interface ip (first found)
5189
 */
5190
function find_interface_ipv6($interface, $flush = false) {
5191
	global $interface_ipv6_arr_cache;
5192
	global $interface_snv6_arr_cache;
5193
	global $config;
5194

    
5195
	$interface = trim($interface);
5196
	$interface = get_real_interface($interface);
5197

    
5198
	if (!does_interface_exist($interface)) {
5199
		return;
5200
	}
5201

    
5202
	/* Setup IP cache */
5203
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5204
		$ifinfo = pfSense_get_interface_addresses($interface);
5205
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5206
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5207
	}
5208

    
5209
	return $interface_ipv6_arr_cache[$interface];
5210
}
5211

    
5212
/*
5213
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5214
 */
5215
function find_interface_ipv6_ll($interface, $flush = false) {
5216
	global $interface_llv6_arr_cache;
5217
	global $config;
5218

    
5219
	$interface = str_replace("\n", "", $interface);
5220

    
5221
	if (!does_interface_exist($interface)) {
5222
		return;
5223
	}
5224

    
5225
	/* Setup IP cache */
5226
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5227
		$ifinfo = pfSense_getall_interface_addresses($interface);
5228
		foreach ($ifinfo as $line) {
5229
			if (strstr($line, ":")) {
5230
				$parts = explode("/", $line);
5231
				if (is_linklocal($parts[0])) {
5232
					$ifinfo['linklocal'] = $parts[0];
5233
				}
5234
			}
5235
		}
5236
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5237
	}
5238
	return $interface_llv6_arr_cache[$interface];
5239
}
5240

    
5241
function find_interface_subnet($interface, $flush = false) {
5242
	global $interface_sn_arr_cache;
5243
	global $interface_ip_arr_cache;
5244

    
5245
	$interface = str_replace("\n", "", $interface);
5246
	if (does_interface_exist($interface) == false) {
5247
		return;
5248
	}
5249

    
5250
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5251
		$ifinfo = pfSense_get_interface_addresses($interface);
5252
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5253
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5254
	}
5255

    
5256
	return $interface_sn_arr_cache[$interface];
5257
}
5258

    
5259
function find_interface_subnetv6($interface, $flush = false) {
5260
	global $interface_snv6_arr_cache;
5261
	global $interface_ipv6_arr_cache;
5262

    
5263
	$interface = str_replace("\n", "", $interface);
5264
	if (does_interface_exist($interface) == false) {
5265
		return;
5266
	}
5267

    
5268
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5269
		$ifinfo = pfSense_get_interface_addresses($interface);
5270
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5271
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5272
	}
5273

    
5274
	return $interface_snv6_arr_cache[$interface];
5275
}
5276

    
5277
function ip_in_interface_alias_subnet($interface, $ipalias) {
5278
	global $config;
5279

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

    
5299
	return false;
5300
}
5301

    
5302
function get_possible_listen_ips($include_ipv6_link_local=false) {
5303

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

    
5325
	$interfaces['lo0'] = 'Localhost';
5326

    
5327
	return $interfaces;
5328
}
5329

    
5330
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5331
	global $config;
5332

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

    
5347
function get_interface_ip($interface = "wan") {
5348

    
5349
	if (substr($interface, 0, 4) == '_vip') {
5350
		return get_configured_vip_ipv4($interface);
5351
	} else if (substr($interface, 0, 5) == '_lloc') {
5352
		/* No link-local address for v4. */
5353
		return null;
5354
	}
5355

    
5356
	$realif = get_failover_interface($interface, 'inet');
5357
	if (!$realif) {
5358
		return null;
5359
	}
5360

    
5361
	if (substr($realif, 0, 4) == '_vip') {
5362
		return get_configured_vip_ipv4($realif);
5363
	} else if (substr($realif, 0, 5) == '_lloc') {
5364
		/* No link-local address for v4. */
5365
		return null;
5366
	}
5367

    
5368
	if (is_array($config['interfaces'][$interface]) &&
5369
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5370
		return ($config['interfaces'][$interface]['ipaddr']);
5371
	}
5372

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

    
5386
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5387
	global $config;
5388

    
5389
	if (substr($interface, 0, 4) == '_vip') {
5390
		return get_configured_vip_ipv6($interface);
5391
	} else if (substr($interface, 0, 5) == '_lloc') {
5392
		return get_interface_linklocal($interface);
5393
	}
5394

    
5395
	$realif = get_failover_interface($interface, 'inet6');
5396
	if (!$realif) {
5397
		return null;
5398
	}
5399

    
5400
	if (substr($realif, 0, 4) == '_vip') {
5401
		return get_configured_vip_ipv6($realif);
5402
	} else if (substr($realif, 0, 5) == '_lloc') {
5403
		return get_interface_linklocal($realif);
5404
	}
5405

    
5406
	if (is_array($config['interfaces'][$interface])) {
5407
		switch ($config['interfaces'][$interface]['ipaddr']) {
5408
			case 'pppoe':
5409
			case 'l2tp':
5410
			case 'pptp':
5411
			case 'ppp':
5412
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5413
					$realif = get_real_interface($interface, 'inet6', false);
5414
				}
5415
				break;
5416
		}
5417
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5418
			return ($config['interfaces'][$interface]['ipaddrv6']);
5419
		}
5420
	}
5421

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

    
5445
function get_interface_linklocal($interface = "wan") {
5446

    
5447
	$realif = get_failover_interface($interface, 'inet6');
5448
	if (!$realif) {
5449
		return null;
5450
	}
5451

    
5452
	if (substr($interface, 0, 4) == '_vip') {
5453
		$realif = get_real_interface($interface);
5454
	} else if (substr($interface, 0, 5) == '_lloc') {
5455
		$realif = get_real_interface(substr($interface, 5));
5456
	}
5457

    
5458
	$curip = find_interface_ipv6_ll($realif);
5459
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5460
		return $curip;
5461
	} else {
5462
		return null;
5463
	}
5464
}
5465

    
5466
function get_interface_subnet($interface = "wan") {
5467

    
5468
	if (substr($interface, 0, 4) == '_vip') {
5469
		return (get_configured_vip_subnetv4($interface));
5470
	}
5471

    
5472
	$realif = get_real_interface($interface);
5473
	if (!$realif) {
5474
		return (NULL);
5475
	}
5476

    
5477
	$cursn = find_interface_subnet($realif);
5478
	if (!empty($cursn)) {
5479
		return ($cursn);
5480
	}
5481

    
5482
	return (NULL);
5483
}
5484

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

    
5487
	if (substr($interface, 0, 4) == '_vip') {
5488
		return (get_configured_vip_subnetv6($interface));
5489
	} else if (substr($interface, 0, 5) == '_lloc') {
5490
		$interface = substr($interface, 5);
5491
	}
5492

    
5493
	$realif = get_real_interface($interface, 'inet6');
5494
	if (!$realif) {
5495
		return (NULL);
5496
	}
5497

    
5498
	$cursn = find_interface_subnetv6($realif);
5499
	if (!empty($cursn)) {
5500
		return ($cursn);
5501
	}
5502

    
5503
	return (NULL);
5504
}
5505

    
5506
/* return outside interfaces with a gateway */
5507
function get_interfaces_with_gateway() {
5508
	global $config;
5509

    
5510
	$ints = array();
5511

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

    
5533
/* return true if interface has a gateway */
5534
function interface_has_gateway($friendly) {
5535
	global $config;
5536

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

    
5564
	return false;
5565
}
5566

    
5567
/* return true if interface has a gateway */
5568
function interface_has_gatewayv6($friendly) {
5569
	global $config;
5570

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

    
5597
	return false;
5598
}
5599

    
5600
/****f* interfaces/is_altq_capable
5601
 * NAME
5602
 *   is_altq_capable - Test if interface is capable of using ALTQ
5603
 * INPUTS
5604
 *   $int            - string containing interface name
5605
 * RESULT
5606
 *   boolean         - true or false
5607
 ******/
5608

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

    
5623
	$int_family = remove_ifindex($int);
5624

    
5625
	if (in_array($int_family, $capable)) {
5626
		return true;
5627
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5628
		return true;
5629
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5630
		return true;
5631
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5632
		return true;
5633
	} else {
5634
		return false;
5635
	}
5636
}
5637

    
5638
/****f* interfaces/is_interface_wireless
5639
 * NAME
5640
 *   is_interface_wireless - Returns if an interface is wireless
5641
 * RESULT
5642
 *   $tmp       - Returns if an interface is wireless
5643
 ******/
5644
function is_interface_wireless($interface) {
5645
	global $config, $g;
5646

    
5647
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5648
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5649
		if (preg_match($g['wireless_regex'], $interface)) {
5650
			if (isset($config['interfaces'][$friendly])) {
5651
				$config['interfaces'][$friendly]['wireless'] = array();
5652
			}
5653
			return true;
5654
		}
5655
		return false;
5656
	} else {
5657
		return true;
5658
	}
5659
}
5660

    
5661
function get_wireless_modes($interface) {
5662
	/* return wireless modes and channels */
5663
	$wireless_modes = array();
5664

    
5665
	$cloned_interface = get_real_interface($interface);
5666

    
5667
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5668
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5669
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5670
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5671

    
5672
		$interface_channels = "";
5673
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5674
		$interface_channel_count = count($interface_channels);
5675

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

    
5709
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5710
function get_wireless_channel_info($interface) {
5711
	$wireless_channels = array();
5712

    
5713
	$cloned_interface = get_real_interface($interface);
5714

    
5715
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5716
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5717
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5718
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5719

    
5720
		$interface_channels = "";
5721
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5722

    
5723
		foreach ($interface_channels as $channel_line) {
5724
			$channel_line = explode(",", $channel_line);
5725
			if (!isset($wireless_channels[$channel_line[0]])) {
5726
				$wireless_channels[$channel_line[0]] = $channel_line;
5727
			}
5728
		}
5729
	}
5730
	return($wireless_channels);
5731
}
5732

    
5733
function set_interface_mtu($interface, $mtu) {
5734

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

    
5751
/****f* interfaces/get_interface_mtu
5752
 * NAME
5753
 *   get_interface_mtu - Return the mtu of an interface
5754
 * RESULT
5755
 *   $tmp       - Returns the mtu of an interface
5756
 ******/
5757
function get_interface_mtu($interface) {
5758
	$mtu = pfSense_interface_getmtu($interface);
5759
	return $mtu['mtu'];
5760
}
5761

    
5762
function get_interface_mac($interface) {
5763

    
5764
	$macinfo = pfSense_get_interface_addresses($interface);
5765
	return $macinfo["macaddr"];
5766
}
5767

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

    
5784
/****f* interfaces/is_jumbo_capable
5785
 * NAME
5786
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5787
 * INPUTS
5788
 *   $int             - string containing interface name
5789
 * RESULT
5790
 *   boolean          - true or false
5791
 ******/
5792
function is_jumbo_capable($iface) {
5793
	$iface = trim($iface);
5794
	$capable = pfSense_get_interface_addresses($iface);
5795

    
5796
	if (isset($capable['caps']['vlanmtu'])) {
5797
		return true;
5798
	}
5799

    
5800
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5801
	if (substr($iface, 0, 4) == "lagg") {
5802
		return true;
5803
	}
5804

    
5805
	return false;
5806
}
5807

    
5808
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5809
	global $g;
5810

    
5811
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5812

    
5813
	if (!empty($iface) && !empty($pppif)) {
5814
		$cron_cmd = <<<EOD
5815
#!/bin/sh
5816
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5817
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5818

    
5819
EOD;
5820

    
5821
		@file_put_contents($cron_file, $cron_cmd);
5822
		chmod($cron_file, 0755);
5823
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5824
	} else {
5825
		unlink_if_exists($cron_file);
5826
	}
5827
}
5828

    
5829
function get_interface_default_mtu($type = "ethernet") {
5830
	switch ($type) {
5831
		case "gre":
5832
			return 1476;
5833
			break;
5834
		case "gif":
5835
			return 1280;
5836
			break;
5837
		case "tun":
5838
		case "vlan":
5839
		case "tap":
5840
		case "ethernet":
5841
		default:
5842
			return 1500;
5843
			break;
5844
	}
5845

    
5846
	/* Never reached */
5847
	return 1500;
5848
}
5849

    
5850
function get_vip_descr($ipaddress) {
5851
	global $config;
5852

    
5853
	foreach ($config['virtualip']['vip'] as $vip) {
5854
		if ($vip['subnet'] == $ipaddress) {
5855
			return ($vip['descr']);
5856
		}
5857
	}
5858
	return "";
5859
}
5860

    
5861
function interfaces_staticarp_configure($if) {
5862
	global $config, $g;
5863
	if (isset($config['system']['developerspew'])) {
5864
		$mt = microtime();
5865
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5866
	}
5867

    
5868
	$ifcfg = $config['interfaces'][$if];
5869

    
5870
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5871
		return 0;
5872
	}
5873

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

    
5895
	return 0;
5896
}
5897

    
5898
function get_failover_interface($interface, $family = "all") {
5899
	global $config;
5900

    
5901
	/* shortcut to get_real_interface if we find it in the config */
5902
	if (is_array($config['interfaces'][$interface])) {
5903
		return get_real_interface($interface, $family);
5904
	}
5905

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

    
5921
function remove_ifindex($ifname) {
5922
	return preg_replace("/[0-9]+$/", "", $ifname);
5923
}
5924

    
5925
?>
(25-25/65)