Project

General

Profile

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

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

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

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

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

    
83
	return $interface_arr_cache;
84
}
85

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

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

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

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

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

    
116

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

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

    
139
	return false;
140
}
141

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
269
	interfaces_bring_up($vlanif);
270

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

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

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

    
285
	return $vlanif;
286
}
287

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

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

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

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

    
308
	$vlanif = interface_vlan_configure($vlan);
309

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

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

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

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

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

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

    
364
	return $vlanif;
365
}
366

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

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

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

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

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

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

    
409
	return $vlanif;
410
}
411

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

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

    
419
	$iflist = get_configured_interface_list();
420

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

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

    
444
}
445

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

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

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

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

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

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

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

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

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

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

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

    
549
	$checklist = get_configured_interface_list();
550

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

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

    
572
	interface_bridge_configure_advanced($bridge);
573

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
804
	interfaces_bring_up($laggif);
805

    
806
	return $laggif;
807
}
808

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

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

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

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

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

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

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

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

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

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

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

    
896
	interfaces_bring_up($greif);
897

    
898
	return $greif;
899
}
900

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

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

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

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

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

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

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

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

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

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

    
1032

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

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

    
1047
	interfaces_bring_up($gifif);
1048

    
1049
	return $gifif;
1050
}
1051

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

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

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

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

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

    
1067
	interfaces_qinq_configure();
1068

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

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

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

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

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

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

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

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

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

    
1131
		interface_configure($if, $reload);
1132

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

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

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

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

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

    
1155
		interface_configure($if, $reload);
1156

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

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

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

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

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

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

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

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

    
1193
		/* restart dns servers (defering dhcpd reload) */
1194
		if (isset($config['dnsmasq']['enable'])) {
1195
			services_dnsmasq_configure(false);
1196
		}
1197
		if (isset($config['unbound']['enable'])) {
1198
			services_unbound_configure(false);
1199
		}
1200

    
1201
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1202
		services_dhcpd_configure();
1203
	}
1204

    
1205
	return 0;
1206
}
1207

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1428
	return;
1429
}
1430

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

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

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

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

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

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

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

    
1480
	return false;
1481
}
1482

    
1483
function interfaces_ptpid_next() {
1484

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

    
1490
	return $ptpid;
1491
}
1492

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

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

    
1505
	return NULL;
1506
}
1507

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

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

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

    
1518
	$itemhash = getMPDCRONSettings($pppif);
1519

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1812
EOD;
1813

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

    
1818
EOD;
1819
	}
1820

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

    
1829
EOD;
1830

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

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

    
1841
EOD;
1842
	}
1843

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

    
1849
EOD;
1850
	}
1851

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

    
1856
EOD;
1857
	}
1858

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

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

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

    
1874
EOD;
1875
		}
1876

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

    
1881
EOD;
1882
		}
1883

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

    
1888
EOD;
1889
		}
1890

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

    
1896
EOD;
1897

    
1898

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

    
1903
EOD;
1904
		}
1905

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

    
1919
EOD;
1920
		}
1921

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

    
1926
EOD;
1927
		}
1928

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

    
1933
EOD;
1934
		}
1935

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

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

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

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

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

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

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

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

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

    
2000
EOD;
2001
		}
2002

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

    
2008
EOD;
2009
		}
2010

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

    
2014

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

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

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

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

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

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

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

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

    
2125
	return 1;
2126
}
2127

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

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

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

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

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

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

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

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

    
2173
		sleep(1);
2174

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2438
	return $realif;
2439
}
2440

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2797
EOD;
2798

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

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

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

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

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

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

    
2833
EOD;
2834
						}
2835
					}
2836
				}
2837

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

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

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

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

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

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

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

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

    
2894
	fclose($fd_set);
2895
	conf_mount_ro();
2896

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

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

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

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

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

    
2934
		$wlregcmd_args = implode(" ", $wlregcmd);
2935

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

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

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

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

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

    
2983
	/* The mode must be specified in a separate command before ifconfig
2984
	 * will allow the mode and channel at the same time in the next.
2985
	 * Only do this for AP mode as this breaks client mode (PR 198680).
2986
	 */
2987
	if ($wlcfg['mode'] == "hostap") {
2988
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2989
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
2990
	}
2991

    
2992
	/* configure wireless */
2993
	$wlcmd_args = implode(" ", $wlcmd);
2994
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2995
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
2996
	/* Bring the interface up only after setting up all the other parameters. */
2997
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
2998
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
2999
	fclose($wlan_setup_log);
3000

    
3001
	unset($wlcmd_args, $wlcmd);
3002

    
3003

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

    
3008
	return 0;
3009

    
3010
}
3011

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

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

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

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

    
3031
	return intval($pid);
3032
}
3033

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

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

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

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

    
3059
	return intval($pid);
3060
}
3061

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

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

    
3073
function interface_virtual_create($interface) {
3074
	global $config;
3075

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

    
3115
function interface_vlan_mtu_configured($iface) {
3116
	global $config;
3117

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

    
3122
			if ($vlan['vlanif'] != $iface)
3123
				continue;
3124

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

    
3136
	return $mtu;
3137
}
3138

    
3139
function interface_mtu_wanted_for_pppoe($realif) {
3140
	global $config;
3141

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

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

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

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

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

    
3179
	return $mtu;
3180
}
3181

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

    
3187
	$wancfg = $config['interfaces'][$interface];
3188

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

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

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

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

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

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

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

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

    
3246
	$mac = get_interface_mac($realhwif);
3247
	/*
3248
	 * Don't try to reapply the spoofed MAC if it's already applied.
3249
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3250
	 * the interface config again, which attempts to spoof the MAC again,
3251
	 * which cycles the link again...
3252
	 */
3253
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
3254
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3255
			" link " . escapeshellarg($wancfg['spoofmac']));
3256
	} elseif ($mac == "ff:ff:ff:ff:ff:ff") {
3257
		/*   this is not a valid mac address.  generate a
3258
		 *   temporary mac address so the machine can get online.
3259
		 */
3260
		echo gettext("Generating new MAC address.");
3261
		$random_mac = generate_random_mac_address();
3262
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3263
			" link " . escapeshellarg($random_mac));
3264
		$wancfg['spoofmac'] = $random_mac;
3265
		write_config();
3266
		file_notice("MAC Address altered", sprintf(gettext('The INVALID MAC address (ff:ff:ff:ff:ff:ff) on interface %1$s has been automatically replaced with %2$s'), $realif, $random_mac), "Interfaces");
3267
	}
3268

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

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

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

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

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

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

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

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

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

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

    
3335
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3336

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

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

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

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

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

    
3424
	interface_netgraph_needed($interface);
3425

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

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

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

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

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

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

    
3463
		if ($reloadall == true) {
3464

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3573
	return 0;
3574
}
3575

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

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

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

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

    
3596
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3597
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3598
		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']));
3599
		return;
3600
	}
3601
	$hexwanv4 = return_hex_ipv4($ip4address);
3602

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

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

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

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

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

    
3627
	$lanif = get_real_interface($interface);
3628
	$oip = find_interface_ipv6($lanif);
3629
	if (is_ipaddrv6($oip)) {
3630
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3631
	}
3632
	unset($interface_ipv6_arr_cache[$lanif]);
3633
	unset($interface_snv6_arr_cache[$lanif]);
3634
	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));
3635
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3636

    
3637
	return 0;
3638
}
3639

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

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

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

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

    
3660
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3661
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3662
		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']));
3663
		return;
3664
	}
3665
	$hexwanv4 = return_hex_ipv4($ip4address);
3666

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

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

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

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

    
3687
	$lanif = get_real_interface($interface);
3688
	$oip = find_interface_ipv6($lanif);
3689
	if (is_ipaddrv6($oip)) {
3690
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3691
	}
3692
	unset($interface_ipv6_arr_cache[$lanif]);
3693
	unset($interface_snv6_arr_cache[$lanif]);
3694
	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));
3695
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3696

    
3697
	return 0;
3698
}
3699

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

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

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

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

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

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

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

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

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

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

    
3752

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

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

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

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

    
3787
	return 0;
3788
}
3789

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3893
	return 0;
3894
}
3895

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4014

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

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

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

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

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

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

    
4052
	return 0;
4053
}
4054

    
4055
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4056
	global $g;
4057

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

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

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

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

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

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

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

    
4115
		$id_assoc_statement_address .= "};\n";
4116
	}
4117

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

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

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

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

    
4157
		$id_assoc_statement_prefix .= "};\n";
4158
	}
4159

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

    
4176
	$key_info_statement = "";
4177
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4178
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4179
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4180
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4181
		$key_info_statement .= "keyinfo";
4182
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4183
		$key_info_statement .= " {\n";
4184
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4185
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4186
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4187
		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'])) {
4188
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4189
		}
4190
		$key_info_statement .= "};\n";
4191
	}
4192

    
4193
	$dhcp6cconf  = $interface_statement;
4194
	$dhcp6cconf .= $id_assoc_statement_address;
4195
	$dhcp6cconf .= $id_assoc_statement_prefix;
4196
	$dhcp6cconf .= $authentication_statement;
4197
	$dhcp6cconf .= $key_info_statement;
4198

    
4199
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4200

    
4201
	return $dhcp6cconf;
4202
}
4203

    
4204

    
4205
function DHCP6_Config_File_Override($wancfg, $wanif) {
4206

    
4207
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4208

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

    
4217

    
4218
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4219

    
4220
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4221

    
4222
	return $dhcp6cconf;
4223
}
4224

    
4225

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

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

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

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

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

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

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

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

    
4274
}
4275

    
4276
EOD;
4277

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

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

    
4292
EOD;
4293
	}
4294

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

    
4300
	fwrite($fd, $dhclientconf);
4301
	fclose($fd);
4302

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

    
4310
	/* Make sure dhclient is not running */
4311
	kill_dhclient_process($wanif);
4312

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

    
4316
	return 0;
4317
}
4318

    
4319
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4320

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

    
4326
	/* DHCP Protocol Timings */
4327
	$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");
4328
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4329
		$pt_variable = "{$Protocol_Timing}";
4330
		${$pt_variable} = "";
4331
		if ($wancfg[$Protocol_Timing] != "") {
4332
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4333
		}
4334
	}
4335

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

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

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

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

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

    
4385
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4386

    
4387
	return $dhclientconf;
4388
}
4389

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

    
4395
function DHCP_Config_File_Override($wancfg, $wanif) {
4396

    
4397
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4398

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

    
4407

    
4408
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4409

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

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

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

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

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

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

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

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

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

    
4460
	return $dhclientconf;
4461
}
4462

    
4463
function interfaces_group_setup() {
4464
	global $config;
4465

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

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

    
4474
	return;
4475
}
4476

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

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

    
4491
	return;
4492
}
4493

    
4494
function is_interface_group($if) {
4495
	global $config;
4496

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

    
4505
	return false;
4506
}
4507

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

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

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

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

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

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

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

    
4545
		if (get_real_interface($if) == $interface) {
4546
			return $if;
4547
		}
4548

    
4549
		if ($checkparent == false) {
4550
			continue;
4551
		}
4552

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

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

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

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

    
4625
	return $ifdesc;
4626
}
4627

    
4628
function convert_real_interface_to_friendly_descr($interface) {
4629

    
4630
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4631

    
4632
	if (!empty($ifdesc)) {
4633
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4634
	}
4635

    
4636
	return $interface;
4637
}
4638

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

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

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

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

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

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

    
4720
	return $parents;
4721
}
4722

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

    
4731
	$realif = get_parent_interface($interface);
4732

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

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

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

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

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

    
4771
	$wanif = NULL;
4772

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

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

    
4819
			$cfg = &$config['interfaces'][$interface];
4820

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

    
4877
	return $wanif;
4878
}
4879

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

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

    
4891
	if (empty($family)) {
4892
		return false;
4893
	}
4894

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

    
4903
	return false;
4904
}
4905

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

    
4915
	$isv6ip = is_ipaddrv6($ip);
4916

    
4917
	/* if list */
4918
	$ifdescrs = get_configured_interface_list();
4919

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

    
4938
	return false;
4939
}
4940

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

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

    
4955
	$isv6ip = is_ipaddrv6($ip);
4956

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

    
4977
function link_interface_to_track6($int, $action = "") {
4978
	global $config;
4979

    
4980
	if (empty($int)) {
4981
		return;
4982
	}
4983

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

    
5002
function interface_find_child_cfgmtu($realiface) {
5003
	global $config;
5004

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

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

    
5078
	return $mtu;
5079
}
5080

    
5081
function link_interface_to_vlans($int, $action = "") {
5082
	global $config;
5083

    
5084
	if (empty($int)) {
5085
		return;
5086
	}
5087

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

    
5105
function link_interface_to_qinqs($int, $action = "") {
5106
	global $config;
5107

    
5108
	if (empty($int)) {
5109
		return;
5110
	}
5111

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

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

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

    
5159
	return NULL;
5160
}
5161

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

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

    
5182
function link_interface_to_group($int) {
5183
	global $config;
5184

    
5185
	$result = array();
5186

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

    
5195
	return $result;
5196
}
5197

    
5198
function link_interface_to_gre($interface) {
5199
	global $config;
5200

    
5201
	$result = array();
5202

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

    
5211
	return $result;
5212
}
5213

    
5214
function link_interface_to_gif($interface) {
5215
	global $config;
5216

    
5217
	$result = array();
5218

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

    
5227
	return $result;
5228
}
5229

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

    
5237
	$interface = str_replace("\n", "", $interface);
5238

    
5239
	if (!does_interface_exist($interface)) {
5240
		return;
5241
	}
5242

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

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

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

    
5261
	$interface = trim($interface);
5262
	$interface = get_real_interface($interface);
5263

    
5264
	if (!does_interface_exist($interface)) {
5265
		return;
5266
	}
5267

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

    
5275
	return $interface_ipv6_arr_cache[$interface];
5276
}
5277

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

    
5285
	$interface = str_replace("\n", "", $interface);
5286

    
5287
	if (!does_interface_exist($interface)) {
5288
		return;
5289
	}
5290

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

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

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

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

    
5322
	return $interface_sn_arr_cache[$interface];
5323
}
5324

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

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

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

    
5340
	return $interface_snv6_arr_cache[$interface];
5341
}
5342

    
5343
function ip_in_interface_alias_subnet($interface, $ipalias) {
5344
	global $config;
5345

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

    
5365
	return false;
5366
}
5367

    
5368
function get_possible_listen_ips($include_ipv6_link_local=false) {
5369

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

    
5391
	$interfaces['lo0'] = 'Localhost';
5392

    
5393
	return $interfaces;
5394
}
5395

    
5396
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5397
	global $config;
5398

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

    
5413
function get_interface_ip($interface = "wan") {
5414

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

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

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

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

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

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

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

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

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

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

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

    
5511
function get_interface_linklocal($interface = "wan") {
5512

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

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

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

    
5532
function get_interface_subnet($interface = "wan") {
5533

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

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

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

    
5548
	return (NULL);
5549
}
5550

    
5551
function get_interface_subnetv6($interface = "wan") {
5552

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

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

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

    
5569
	return (NULL);
5570
}
5571

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

    
5576
	$ints = array();
5577

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

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

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

    
5630
	return false;
5631
}
5632

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

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

    
5663
	return false;
5664
}
5665

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

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

    
5689
	$int_family = remove_ifindex($int);
5690

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

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

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

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

    
5731
	$cloned_interface = get_real_interface($interface);
5732

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

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

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

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

    
5779
	$cloned_interface = get_real_interface($interface);
5780

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

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

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

    
5799
function set_interface_mtu($interface, $mtu) {
5800

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

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

    
5828
function get_interface_mac($interface) {
5829

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

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

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

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

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

    
5871
	return false;
5872
}
5873

    
5874
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5875
	global $g;
5876

    
5877
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5878

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

    
5885
EOD;
5886

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

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

    
5912
	/* Never reached */
5913
	return 1500;
5914
}
5915

    
5916
function get_vip_descr($ipaddress) {
5917
	global $config;
5918

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

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

    
5934
	$ifcfg = $config['interfaces'][$if];
5935

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

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

    
5961
	return 0;
5962
}
5963

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

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

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

    
5987
/****f* interfaces/interface_has_dhcp
5988
 * NAME
5989
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
5990
 * INPUTS
5991
 *   interface or gateway group name
5992
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
5993
 * RESULT
5994
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
5995
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
5996
 ******/
5997
function interface_has_dhcp($interface, $family = 4) {
5998
	global $config;
5999

    
6000
	if ($config['interfaces'][$interface]) {
6001
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6002
			return true;
6003
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6004
			return true;
6005
		} else {
6006
			return false;
6007
		}
6008
	}
6009

    
6010
	if (!is_array($config['gateways']['gateway_group'])) {
6011
		return false;
6012
	}
6013

    
6014
	if ($family == 6) {
6015
		$dhcp_string = "_DHCP6";
6016
	} else {
6017
		$dhcp_string = "_DHCP";
6018
	}
6019

    
6020
	foreach ($config['gateways']['gateway_group'] as $group) {
6021
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6022
			continue;
6023
		}
6024
		foreach ($group['item'] as $item) {
6025
			$item_data = explode("|", $item);
6026
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6027
				return true;
6028
			}
6029
		}
6030
	}
6031

    
6032
	return false;
6033
}
6034

    
6035
function remove_ifindex($ifname) {
6036
	return preg_replace("/[0-9]+$/", "", $ifname);
6037
}
6038

    
6039
?>
(25-25/65)