Project

General

Profile

Download (173 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * interfaces.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 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 (!is_ipaddr($gateways[$pid])) {
1686
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $dhcp_gateway, $gway));
1687
					return 0;
1688
				}
1689
				pfSense_ngctl_attach(".", $port);
1690
				break;
1691
			case "ppp":
1692
				if (!file_exists("{$port}")) {
1693
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1694
					return 0;
1695
				}
1696
				break;
1697
			default:
1698
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1699
				break;
1700
		}
1701
	}
1702

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

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

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

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

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

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

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

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

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

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

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

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

    
1809
EOD;
1810

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

    
1815
EOD;
1816
	}
1817

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

    
1826
EOD;
1827

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

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

    
1838
EOD;
1839
	}
1840

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

    
1846
EOD;
1847
	}
1848

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

    
1853
EOD;
1854
	}
1855

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

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

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

    
1871
EOD;
1872
		}
1873

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

    
1878
EOD;
1879
		}
1880

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

    
1885
EOD;
1886
		}
1887

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

    
1893
EOD;
1894

    
1895

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

    
1900
EOD;
1901
		}
1902

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

    
1916
EOD;
1917
		}
1918

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

    
1923
EOD;
1924
		}
1925

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

    
1930
EOD;
1931
		}
1932

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

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

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

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

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

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

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

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

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

    
1997
EOD;
1998
		}
1999

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

    
2005
EOD;
2006
		}
2007

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

    
2011

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

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

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

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

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

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

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

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

    
2122
	return 1;
2123
}
2124

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

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

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

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

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

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

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

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

    
2170
		sleep(1);
2171

    
2172
		/* XXX: Handle an issue with pfsync(4) and carp(4). In a cluster carp will come up before pfsync(4) has updated and so will cause issues
2173
		 * for existing sessions.
2174
		 */
2175
		log_error(gettext("waiting for pfsync..."));
2176
		$i = 0;
2177
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2178
			$i++;
2179
			sleep(1);
2180
		}
2181
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2182
		log_error(gettext("Configuring CARP settings finalize..."));
2183
	} else {
2184
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2185
	}
2186

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2435
	return $realif;
2436
}
2437

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2796
EOD;
2797

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

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

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

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

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

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

    
2832
EOD;
2833
						}
2834
					}
2835
				}
2836

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2997
	unset($wlcmd_args, $wlcmd);
2998

    
2999

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

    
3004
	return 0;
3005

    
3006
}
3007

    
3008
function kill_hostapd($interface) {
3009
	global $g;
3010

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

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

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

    
3027
	return intval($pid);
3028
}
3029

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

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

    
3046
function find_dhcp6c_process($interface) {
3047
	global $g;
3048

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

    
3055
	return intval($pid);
3056
}
3057

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

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

    
3069
function interface_virtual_create($interface) {
3070
	global $config;
3071

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

    
3111
function interface_vlan_mtu_configured($iface) {
3112
	global $config;
3113

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

    
3118
			if ($vlan['vlanif'] != $iface)
3119
				continue;
3120

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

    
3132
	return $mtu;
3133
}
3134

    
3135
function interface_mtu_wanted_for_pppoe($realif) {
3136
	global $config;
3137

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

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

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

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

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

    
3175
	return $mtu;
3176
}
3177

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

    
3183
	$wancfg = $config['interfaces'][$interface];
3184

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3334
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3335

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

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

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

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

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

    
3423
	interface_netgraph_needed($interface);
3424

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

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

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

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

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

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

    
3462
		if ($reloadall == true) {
3463

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3572
	return 0;
3573
}
3574

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

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

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

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

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

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

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

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

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

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

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

    
3636
	return 0;
3637
}
3638

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

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

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

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

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

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

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

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

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

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

    
3696
	return 0;
3697
}
3698

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

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

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

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

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

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

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

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

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

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

    
3751

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

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

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

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

    
3786
	return 0;
3787
}
3788

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3892
	return 0;
3893
}
3894

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4049
	return 0;
4050
}
4051

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4198
	return $dhcp6cconf;
4199
}
4200

    
4201

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

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

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

    
4214

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

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

    
4219
	return $dhcp6cconf;
4220
}
4221

    
4222

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

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

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

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

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

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

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

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

    
4271
}
4272

    
4273
EOD;
4274

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

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

    
4289
EOD;
4290
	}
4291

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

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

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

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

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

    
4313
	return 0;
4314
}
4315

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

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

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

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

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

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

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

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

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

    
4384
	return $dhclientconf;
4385
}
4386

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

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

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

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

    
4404

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

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

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

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

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

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

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

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

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

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

    
4457
	return $dhclientconf;
4458
}
4459

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

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

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

    
4471
	return;
4472
}
4473

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

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

    
4488
	return;
4489
}
4490

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

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

    
4502
	return false;
4503
}
4504

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4622
	return $ifdesc;
4623
}
4624

    
4625
function convert_real_interface_to_friendly_descr($interface) {
4626

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

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

    
4633
	return $interface;
4634
}
4635

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

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

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

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

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

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

    
4717
	return $parents;
4718
}
4719

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

    
4728
	$realif = get_parent_interface($interface);
4729

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

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

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

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

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

    
4768
	$wanif = NULL;
4769

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

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

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

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

    
4874
	return $wanif;
4875
}
4876

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

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

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

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

    
4900
	return false;
4901
}
4902

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

    
4912
	$isv6ip = is_ipaddrv6($ip);
4913

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

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

    
4935
	return false;
4936
}
4937

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

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

    
4952
	$isv6ip = is_ipaddrv6($ip);
4953

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

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

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

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

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

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

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

    
5075
	return $mtu;
5076
}
5077

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

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

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

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

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

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

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

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

    
5156
	return NULL;
5157
}
5158

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

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

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

    
5182
	$result = array();
5183

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

    
5192
	return $result;
5193
}
5194

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

    
5198
	$result = array();
5199

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

    
5208
	return $result;
5209
}
5210

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

    
5214
	$result = array();
5215

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

    
5224
	return $result;
5225
}
5226

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
5362
	return false;
5363
}
5364

    
5365
function get_possible_listen_ips($include_ipv6_link_local=false) {
5366

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

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

    
5390
	return $interfaces;
5391
}
5392

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
5545
	return (NULL);
5546
}
5547

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

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

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

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

    
5566
	return (NULL);
5567
}
5568

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

    
5573
	$ints = array();
5574

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

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

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

    
5627
	return false;
5628
}
5629

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

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

    
5660
	return false;
5661
}
5662

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

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

    
5686
	$int_family = remove_ifindex($int);
5687

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

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

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

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

    
5728
	$cloned_interface = get_real_interface($interface);
5729

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

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

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

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

    
5776
	$cloned_interface = get_real_interface($interface);
5777

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

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

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

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

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

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

    
5825
function get_interface_mac($interface) {
5826

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

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

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

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

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

    
5868
	return false;
5869
}
5870

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

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

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

    
5882
EOD;
5883

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

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

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

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

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

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

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

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

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

    
5958
	return 0;
5959
}
5960

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

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

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

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

    
5988
?>
(25-25/65)